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

edu.cmu.tetradapp.app.SessionEditorToolbar Maven / Gradle / Ivy

There is a newer version: 7.6.6
Show newest version
///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard        //
// Scheines, Joseph Ramsey, and Clark Glymour.                               //
//                                                                           //
// 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 2 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, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////
package edu.cmu.tetradapp.app;

import edu.cmu.tetradapp.util.ImageUtils;
import edu.cmu.tetradapp.workbench.AbstractWorkbench;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;

/**
 * Displays a vertical list of buttons that determine the next action the user can take in the session editor workbench,
 * whether it's selecting and moving a node, adding a node of a particular type, or adding an edge.
 *
 * @author josephramsey
 * @see SessionEditor
 * @see SessionEditorToolbar
 */
final class SessionEditorToolbar extends JPanel {

    /**
     * The node type of the button that is used for the Select/Move tool.
     */
    private final String selectType = "Select";
    private final String edgeSelectType = "Edge";
    /**
     * \ The map from JToggleButtons to String node types.
     */
    private final Map nodeTypes = new HashMap<>();
    /**
     * The workbench this toolbar controls.
     */
    private final SessionEditorWorkbench workbench;
    /**
     * True iff the toolbar is responding to events.
     */
    private boolean respondingToEvents = true;
    /**
     * True iff the shift key was down on last click.
     */
    private boolean shiftDown;

    /**
     * Constructs a new session toolbar.
     *
     * @param workbench the workbench this toolbar controls.
     */
    public SessionEditorToolbar(SessionEditorWorkbench workbench) {
        if (workbench == null) {
            throw new NullPointerException("Workbench must not be null.");
        }

        this.workbench = workbench;

        // Set up panel.
        Box buttonsPanel = Box.createVerticalBox();
//        buttonsPanel.setBackground(new Color(198, 232, 252));
        buttonsPanel.setBorder(new EmptyBorder(10, 10, 10, 10));

        // Create buttons.
        /*
      Node infos for all of the nodes.
         */
        ButtonInfo[] buttonInfos = {
                new ButtonInfo("Select", "Select and Move", "move",
                        "Select and move nodes or groups of nodes "
                                + "
on the workbench."), new ButtonInfo("Edge", "Draw Edge", "flow", "Add an edge from one node to another to declare" + "
that the object in the first node should be used " + "
to construct the object in the second node." + "
As a shortcut, hold down the Control key." + ""), new ButtonInfo("Graph", "Graph", "graph", "Add a graph node."), new ButtonInfo("Compare", "Compare", "compare", "Add a node to compare graphs or SEM IM's."), new ButtonInfo("PM", "Parametric Model", "pm", "Add a node for a parametric model."), new ButtonInfo("IM", "Instantiated Model", "im", "Add a node for an instantiated model."), new ButtonInfo("Estimator", "Estimator", "estimator", "Add a node for an estimator."), new ButtonInfo("Data", "Data", "data", "Add a node for a data object."), new ButtonInfo("Simulation", "Simulation", "simulation", "Add a node for a simulation object."), new ButtonInfo("Search", "Search", "search", "Add a node for a search algorithm."), new ButtonInfo("Knowledge", "Knowledge", "knowledge", "Add a knowledge box node."), new ButtonInfo("Updater", "Updater", "updater", "Add a node for an updater."), //new ButtonInfo("Classify", "Classify", "search", //"Add a node for a classifier."), new ButtonInfo("Regression", "Regression", "regression", "Add a node for a regression."), new ButtonInfo("Note", "Note", "note", "Add a note to the session.") }; JToggleButton[] buttons = new JToggleButton[buttonInfos.length]; for (int i = 0; i < buttonInfos.length; i++) { buttons[i] = constructButton(buttonInfos[i]); } // Add all buttons to a button group. ButtonGroup buttonGroup = new ButtonGroup(); for (int i = 0; i < buttonInfos.length; i++) { buttonGroup.add(buttons[i]); } // This seems to be fixed. Now creating weirdness. jdramsey 3/4/2014 // // Add a focus listener to help buttons not deselect when the // // mouse slides away from the button. // FocusListener focusListener = new FocusAdapter() { // public void focusGained(FocusEvent e) { // JToggleButton component = (JToggleButton) e.getComponent(); // component.getModel().setSelected(true); // } // }; // // for (int i = 0; i < buttonInfos.length; i++) { // buttons[i].addFocusListener(focusListener); // } // Add an action listener to help send messages to the // workbench. ChangeListener changeListener = e -> { JToggleButton _button = (JToggleButton) e.getSource(); if (_button.getModel().isSelected()) { setWorkbenchMode(_button); // setCursor(workbench.getCursor()); } }; for (int i = 0; i < buttonInfos.length; i++) { buttons[i].addChangeListener(changeListener); } // Select the Select button. JToggleButton button = getButtonForType(this.selectType); assert button != null; button.getModel().setSelected(true); // Add the buttons to the workbench. for (int i = 0; i < buttonInfos.length; i++) { buttonsPanel.add(buttons[i]); buttonsPanel.add(Box.createVerticalStrut(5)); } // Put the panel in a scrollpane. this.setLayout(new BorderLayout()); JScrollPane scroll = new JScrollPane(buttonsPanel); scroll.setPreferredSize(new Dimension(130, 1000)); add(scroll, BorderLayout.CENTER); // Add property change listener so that selection can be moved // back to "SELECT_MOVE" after an action. workbench.addPropertyChangeListener(e -> { if (!isRespondingToEvents()) { return; } String propertyName = e.getPropertyName(); if ("nodeAdded".equals(propertyName)) { if (!isShiftDown()) { resetSelectMove(); } } else if ("edgeAdded".equals(propertyName)) { // keep edge select type selected JToggleButton selectButton = getButtonForType(SessionEditorToolbar.this.edgeSelectType); assert selectButton != null; if (!(selectButton.isSelected())) { selectButton.doClick(); selectButton.requestFocus(); } } }); KeyboardFocusManager.getCurrentKeyboardFocusManager() .addKeyEventDispatcher(e -> { int keyCode = e.getKeyCode(); int id = e.getID(); if (keyCode == KeyEvent.VK_SHIFT) { if (id == KeyEvent.KEY_PRESSED) { setShiftDown(true); } else if (id == KeyEvent.KEY_RELEASED) { setShiftDown(false); resetSelectMove(); } } return false; }); resetSelectMove(); } /** * Sets the selection back to move/select. */ private void resetSelectMove() { JToggleButton selectButton = getButtonForType(this.selectType); assert selectButton != null; if (!(selectButton.isSelected())) { selectButton.doClick(); selectButton.requestFocus(); } } /** * True iff the toolbar is responding to events. This may need to be turned off temporarily. */ private boolean isRespondingToEvents() { return this.respondingToEvents; } /** * Sets whether the toolbar should react to events. This may need to be turned off temporarily. */ public void setRespondingToEvents(boolean respondingToEvents) { this.respondingToEvents = respondingToEvents; } protected void processKeyEvent(KeyEvent e) { System.out.println("process key event " + e); super.processKeyEvent(e); } /** * Constructs the button with the given node type and image prefix. If the node type is "Select", constructs a * button that allows nodes to be selected and moved. If the node type is "Edge", constructs a button that allows * edges to be drawn. For other node types, constructs buttons that allow those type of nodes to be added to the * workbench. If a non-null image prefix is provided, images for Up.gif, Down.gif, * Off.gif and Roll.gif are loaded from the /images * directory relative to this compiled class and used to provide up, down, off, and rollover images for the * constructed button. On construction, nodes are mapped to their node types in the Map, nodeTypes. * Listeners are added to the node. * * @param buttonInfo contains the info needed to construct the button. */ private JToggleButton constructButton(ButtonInfo buttonInfo) { String imagePrefix = buttonInfo.getImagePrefix(); if (imagePrefix == null) { throw new NullPointerException("Image prefix must not be null."); } JToggleButton button = new JToggleButton(); button.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { super.mouseClicked(e); setShiftDown(e.isShiftDown()); // setControlDown(e.isControlDown()); } }); if ("Select".equals(buttonInfo.getNodeTypeName())) { button.setIcon(new ImageIcon(ImageUtils.getImage(this, "move.gif"))); } else if ("Edge".equals(buttonInfo.getNodeTypeName())) { button.setIcon( new ImageIcon(ImageUtils.getImage(this, "flow.gif"))); } else { button.setName(buttonInfo.getNodeTypeName()); button.setText("
" + buttonInfo.getDisplayName() + "
"); } button.setMaximumSize(new Dimension(110, 40)); // For a vertical box. button.setToolTipText(buttonInfo.getToolTipText()); this.nodeTypes.put(button, buttonInfo.getNodeTypeName()); return button; } /** * Sets the state of the workbench in response to a button press. * * @param button the JToggleButton whose workbench state is to be set. */ private void setWorkbenchMode(JToggleButton button) { String nodeType = this.nodeTypes.get(button); /* The node type of the button that is used for the edge-drawing tool. */ final String edgeType = "Edge"; if (this.selectType.equals(nodeType)) { this.workbench.setWorkbenchMode(AbstractWorkbench.SELECT_MOVE); this.workbench.setNextButtonType(null); setCursor(new Cursor(Cursor.HAND_CURSOR)); this.workbench.setCursor(new Cursor(Cursor.HAND_CURSOR)); } else if (edgeType.equals(nodeType)) { this.workbench.setWorkbenchMode(AbstractWorkbench.ADD_EDGE); this.workbench.setNextButtonType(null); setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); this.workbench.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } else { this.workbench.setWorkbenchMode(AbstractWorkbench.ADD_NODE); this.workbench.setNextButtonType(nodeType); setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); this.workbench.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); } } /** * @return the JToggleButton for the given node type, or null if no such button exists. */ private JToggleButton getButtonForType(String nodeType) { for (JToggleButton o : this.nodeTypes.keySet()) { if (nodeType.equals(this.nodeTypes.get(o))) { return o; } } return null; } private boolean isShiftDown() { return this.shiftDown; } private void setShiftDown(boolean shiftDown) { this.shiftDown = shiftDown; } /** * Holds info for constructing a single button. */ private static final class ButtonInfo { /** * This is the name used to construct nodes on the graph of this type. Need to coordinate with session. */ private final String nodeTypeName; /** * The name displayed on the button. */ private final String displayName; /** * The prefixes for images for this button. It is assumed that files * Up.gif, Down.gif, Off.gif and * Roll.gif are located in the /images directory relative to * this compiled class. */ private final String imagePrefix; /** * Tool tip text displayed for the button. */ private final String toolTipText; public ButtonInfo(String nodeTypeName, String displayName, String imagePrefix, String toolTipText) { this.nodeTypeName = nodeTypeName; this.displayName = displayName; this.imagePrefix = imagePrefix; this.toolTipText = toolTipText; } public String getNodeTypeName() { return this.nodeTypeName; } public String getDisplayName() { return this.displayName; } public String getImagePrefix() { return this.imagePrefix; } public String getToolTipText() { return this.toolTipText; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy