All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.tudelft.goal.SimpleIDE.FilePanel Maven / Gradle / Ivy

/**
 * GOAL interpreter that facilitates developing and executing GOAL multi-agent
 * programs. Copyright (C) 2011 K.V. Hindriks, W. Pasman
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see .
 */

package nl.tudelft.goal.SimpleIDE;

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import goal.tools.errorhandling.Resources;
import goal.tools.errorhandling.Warning;
import goal.tools.errorhandling.WarningStrings;
import goal.util.Observer;
import nl.tudelft.goal.SimpleIDE.actions.CloseAndRemoveAction;
import nl.tudelft.goal.SimpleIDE.actions.DeleteAction;
import nl.tudelft.goal.SimpleIDE.actions.EditAction;
import nl.tudelft.goal.SimpleIDE.actions.InfoAction;
import nl.tudelft.goal.SimpleIDE.actions.NewFileAction;
import nl.tudelft.goal.SimpleIDE.actions.OpenFileAction;
import nl.tudelft.goal.SimpleIDE.actions.QuitAction;
import nl.tudelft.goal.SimpleIDE.actions.ReloadFileAction;
import nl.tudelft.goal.SimpleIDE.actions.RenameAction;
import nl.tudelft.goal.SimpleIDE.actions.RunAction;
import nl.tudelft.goal.SimpleIDE.actions.SaveFileAction;
import nl.tudelft.goal.SimpleIDE.filenodes.AbstractFileNode;
import nl.tudelft.goal.SimpleIDE.filenodes.FileRootNode;
import nl.tudelft.goal.SimpleIDE.filenodes.NodeRenderer;

/**
 * Panel that displays the contents of the {@link IdeFiles}.
 *
 * @author W.Pasman 25aug15
 *
 */
public class FilePanel extends JPanel {
	private static final long serialVersionUID = 1085401469943214372L;

	/**
	 * The tree-visualizer for the files.
	 */
	private final JTree fileTree;

	private final TreeModel model;

	/**
	 *
	 * @param mainp the main panel, for centering dialogs.
	 * @param files the {@link IdeFiles}
	 */
	FilePanel(final JPanel mainp, final IdeFiles files) {
		this.model = new DefaultTreeModel(new FileRootNode(files));
		this.fileTree = new MyTree(this.model, files);

		// add the various event listeners
		addListeners();

		// double-click should not toggle the tree
		this.fileTree.setToggleClickCount(-1);

		// set the layout
		setLayout(new BorderLayout());
		this.fileTree.setEditable(false);
		this.fileTree.setRootVisible(false);
		this.fileTree.setShowsRootHandles(true);
		this.fileTree.setCellRenderer(new NodeRenderer());
		// include tree view in pane
		final JScrollPane fileTreeView = new JScrollPane(this.fileTree);
		this.add(new JLabel("Files"), BorderLayout.NORTH); //$NON-NLS-1$
		this.add(fileTreeView, BorderLayout.CENTER);

	}

	private JPopupMenu createPopupMenu() throws ReflectiveOperationException {
		final JPopupMenu popup = new JPopupMenu();
		popup.add(new JMenuItem(ActionFactory.getAction(EditAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(SaveFileAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(ReloadFileAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(CloseAndRemoveAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(RenameAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(InfoAction.class)));
		popup.add(new JSeparator());
		popup.add(new JMenuItem(ActionFactory.getAction(OpenFileAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(NewFileAction.class)));
		popup.add(new JMenuItem(ActionFactory.getAction(DeleteAction.class)));
		popup.add(new JSeparator());
		popup.add(new JMenuItem(ActionFactory.getAction(RunAction.class)));
		popup.add(new JSeparator());
		popup.add(new JMenuItem(ActionFactory.getAction(QuitAction.class)));
		return popup;

	}

	/**
	 * Adds all relevant listeners to this FilePanel's tree.
	 */
	private void addListeners() {
		// add mouse listener
		this.fileTree.addMouseListener(new myMouseListener());

		// add tree selection listener
		this.fileTree.addTreeSelectionListener(e -> ActionFactory.broadcastStateChange());
		// tree expansion listener
		this.fileTree.addTreeExpansionListener(new TreeExpansionListener() {
			@Override
			public void treeExpanded(final TreeExpansionEvent event) {
				// theIDE.refreshMenuItemsAndButtons();
				ActionFactory.broadcastStateChange();
			}

			@Override
			public void treeCollapsed(final TreeExpansionEvent event) {
				// theIDE.refreshMenuItemsAndButtons();
				ActionFactory.broadcastStateChange();
			}
		});
	}

	/**
	 * This object handles mouse clicks in the panel. Its jobs:
	 * 
    *
  • Create popup menu *
  • Handle double click to open editor. * * @author W.Pasman 18jul2011 * */ private class myMouseListener extends MouseAdapter { /** * Handles double click events on file nodes, in order to open editor panels for * the file(s) that are selected. Single click events are handled by the tree * selection listener. * * @see http ://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JTree.html for * code. */ @Override public void mousePressed(final MouseEvent event) { if (event.isPopupTrigger()) { try { createPopupMenu().show(FilePanel.this.fileTree, event.getX(), event.getY()); } catch (final Exception e) { new Warning(Resources.get(WarningStrings.FAILED_POPUP_WINDOW_CREATE), e).emit(); } } final TreePath selPath = FilePanel.this.fileTree.getPathForLocation(event.getX(), event.getY()); // path is null if nothing is selected if (selPath == null) { return; } final AbstractFileNode node = (AbstractFileNode) selPath.getLastPathComponent(); if (node != null && event.getClickCount() == 2) { // user double clicked process node try { ActionFactory.getAction(EditAction.class).Execute(node, null); } catch (final Exception e) { new Warning(Resources.get(WarningStrings.FAILED_FILE_EDIT), e).emit(); } } } @Override public void mouseReleased(final MouseEvent event) { if (event.isPopupTrigger()) { try { createPopupMenu().show(FilePanel.this.fileTree, event.getX(), event.getY()); } catch (final Exception e) { new Warning(Resources.get(WarningStrings.FAILED_POPUP_WINDOW_CREATE), e).emit(); } } } } /** * Get ALL selected {@link AbstractFileNode}s in the panel's tree, on * top-to-bottom order. See #545. If nothing is selected, returns list with the * root node only. * * @return list of all selected nodes. */ public List getSelectedNodes() { final TreePath[] paths = this.fileTree.getSelectionPaths(); final List nodes = new ArrayList<>(); if (paths == null) { nodes.add((AbstractFileNode) this.model.getRoot()); } else { for (final TreePath path : paths) { nodes.add((AbstractFileNode) path.getLastPathComponent()); } } return nodes; } } /** * A JTree that re-loads the structure when a change occurs in the underlying * model. *

    Technical details

    * * The default JTree needs to be *exactly* informed by the model about changes. * A model can issue a {@link TreeModelEvent} to the listeners (a.o. the JTree). * However, this event can only pass the object that has changed (e.g. the * removed or added file) and then JTree still has to figure out the * consequences for the entire tree. This is pretty complex and the default * JTree only collapses the entire tree in such events. *

    * * @author W.Pasman 31aug15 */ class MyTree extends JTree implements Observer { private static final long serialVersionUID = -5366113509674951407L; public MyTree(final TreeModel model, final IdeFiles files) { super(model); files.addObserver(this); } @Override public void eventOccured(final IdeFiles source, final File evt) { /** * Computing what exactly happened is very complex. We would have to compare the * current tree with the tree on the screen. Instead, it showed much easier to * reload the entire model and re-open the nodes that were open before the * reload. */ SwingUtilities.invokeLater(() -> { final TreePath rootpath = new TreePath(getModel().getRoot()); final Enumeration oldState = getExpandedDescendants(rootpath); ((DefaultTreeModel) MyTree.this.treeModel).reload(); // re-open the old state while (oldState.hasMoreElements()) { setExpandedState(oldState.nextElement(), true); } }); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy