f@0: /* f@0: CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool f@0: f@0: Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com) f@0: Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) f@0: f@0: This program is free software: you can redistribute it and/or modify f@0: it under the terms of the GNU General Public License as published by f@0: the Free Software Foundation, either version 3 of the License, or f@0: (at your option) any later version. f@0: f@0: This program is distributed in the hope that it will be useful, f@0: but WITHOUT ANY WARRANTY; without even the implied warranty of f@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the f@0: GNU General Public License for more details. f@0: f@0: You should have received a copy of the GNU General Public License f@0: along with this program. If not, see . f@0: */ f@0: f@0: package uk.ac.qmul.eecs.ccmi.gui; f@0: f@0: import java.awt.Color; f@0: import java.awt.Component; f@0: import java.awt.Graphics; f@0: import java.awt.Graphics2D; f@0: import java.awt.event.ActionEvent; f@0: import java.awt.event.ActionListener; f@0: import java.awt.geom.AffineTransform; f@0: import java.awt.geom.Line2D; f@0: import java.awt.geom.Point2D; f@0: import java.awt.geom.Rectangle2D; f@0: import java.util.Enumeration; f@0: import java.util.ResourceBundle; f@0: f@0: import javax.swing.ButtonGroup; f@0: import javax.swing.Icon; f@0: import javax.swing.JButton; f@0: import javax.swing.JToggleButton; f@0: import javax.swing.JToolBar; f@0: f@0: f@0: /** f@0: A Toolbar that contains node and edge prototype icons. By using the toolbar f@0: the user can create nodes and edges in the diagram out of clonation from the prototype. f@0: */ f@0: @SuppressWarnings("serial") f@0: public class GraphToolbar extends JToolBar { f@0: /** f@0: * Constructs a tool bar with no icons. f@0: * f@0: * @param diagram the diagram this toolbar is related to f@0: */ f@0: public GraphToolbar(Diagram diagram){ f@0: /* creates icon for select button */ f@0: Icon icon = new Icon(){ f@0: public int getIconHeight() { return BUTTON_SIZE; } f@0: public int getIconWidth() { return BUTTON_SIZE; } f@0: public void paintIcon(Component c, Graphics g, f@0: int x, int y){ f@0: Graphics2D g2 = (Graphics2D)g; f@0: GraphPanel.drawGrabber(g2, x + OFFSET, y + OFFSET); f@0: GraphPanel.drawGrabber(g2, x + OFFSET, y + BUTTON_SIZE - OFFSET); f@0: GraphPanel.drawGrabber(g2, x + BUTTON_SIZE - OFFSET, y + OFFSET); f@0: GraphPanel.drawGrabber(g2, x + BUTTON_SIZE - OFFSET, y + BUTTON_SIZE - OFFSET); f@0: } f@0: }; f@0: /* add selection button */ f@0: ResourceBundle resources = f@0: ResourceBundle.getBundle(EditorFrame.class.getName()); f@0: String text = resources.getString("grabber.text"); f@0: selectButton = new NodeButton(null,icon); f@0: selectButton.setToolTipText(text); f@0: nodeButtonsGroup = new ButtonGroup(); f@0: nodeButtonsGroup.add(selectButton); f@0: add(selectButton); f@0: f@0: /* add diagram buttons to the toolbar */ f@0: Node[] nodeTypes = diagram.getNodePrototypes(); f@0: for (int i = 0; i < nodeTypes.length; i++){ f@0: text = nodeTypes[i].getType(); f@0: add(nodeTypes[i], text ); f@0: } f@0: f@0: /* select the select-button as default */ f@0: nodeButtonsGroup.setSelected(selectButton.getModel(), true); f@0: f@0: /* separate node buttons from edge buttons */ f@0: addSeparator(); f@0: f@0: /* add diagram edges to the toolbar */ f@0: Edge[] edgeTypes = diagram.getEdgePrototypes(); f@0: for (int i = 0; i < edgeTypes.length; i++){ f@0: text = edgeTypes[i].getType(); f@0: add(edgeTypes[i], text ); f@0: } f@0: } f@0: f@0: /** f@0: Gets the node prototype that is associated with f@0: the currently selected button f@0: @return a {@code Node} prototype f@0: */ f@0: public Node getSelectedTool() { f@0: @SuppressWarnings("rawtypes") f@0: Enumeration elements = nodeButtonsGroup.getElements(); f@0: while (elements.hasMoreElements()) { f@0: NodeButton b = (NodeButton)elements.nextElement(); f@0: if (b.isSelected()) { f@0: /* switch back to the select-button */ f@0: nodeButtonsGroup.setSelected(selectButton.getModel(), true); f@0: return b.getNode(); f@0: } f@0: } f@0: /* getting here means the selection button is selected */ f@0: return null; f@0: } f@0: f@0: /** f@0: Adds a node to the tool bar. f@0: @param n the node to add f@0: @param tip the tool tip appearing when hovering on this edge button f@0: */ f@0: public void add(final Node n, String tip){ f@0: Icon icon = new Icon(){ f@0: public int getIconHeight() { return BUTTON_SIZE; } f@0: public int getIconWidth() { return BUTTON_SIZE; } f@0: public void paintIcon(Component c, Graphics g, f@0: int x, int y){ f@0: double width = n.getBounds().getWidth(); f@0: double height = n.getBounds().getHeight(); f@0: Graphics2D g2 = (Graphics2D)g; f@0: double scaleX = (BUTTON_SIZE - OFFSET)/ width; f@0: double scaleY = (BUTTON_SIZE - OFFSET)/ height; f@0: double scale = Math.min(scaleX, scaleY); f@0: f@0: AffineTransform oldTransform = g2.getTransform(); f@0: g2.translate(x, y); f@0: g2.translate(OFFSET/2*scaleX,OFFSET/2*scaleY); f@0: g2.scale(scale, scale); f@0: g2.setColor(Color.black); f@0: n.draw(g2); f@0: g2.setTransform(oldTransform); f@0: } f@0: }; f@0: f@0: NodeButton button = new NodeButton(n, icon); f@0: button.setToolTipText(tip); f@0: f@0: add(button); f@0: nodeButtonsGroup.add(button); f@0: } f@0: f@0: /** f@0: Adds an edge to the tool bar. f@0: @param e the edge to add f@0: @param tip the tool tip appearing when hovering on this edge button f@0: */ f@0: public void add(final Edge e, String tip){ f@0: Icon icon = new Icon(){ f@0: public int getIconHeight() { return BUTTON_SIZE; } f@0: public int getIconWidth() { return BUTTON_SIZE; } f@0: public void paintIcon(Component c, Graphics g, f@0: int x, int y){ f@0: Graphics2D g2 = (Graphics2D)g; f@0: /* create two points */ f@0: Point2D p = new Point2D.Double(); f@0: Point2D q = new Point2D.Double(); f@0: p.setLocation(OFFSET, OFFSET); f@0: q.setLocation(BUTTON_SIZE - OFFSET, BUTTON_SIZE - OFFSET); f@0: f@0: Line2D line = new Line2D.Double(p,q); f@0: Rectangle2D bounds = new Rectangle2D.Double(); f@0: bounds.add(line.getBounds2D()); f@0: f@0: double width = bounds.getWidth(); f@0: double height = bounds.getHeight(); f@0: double scaleX = (BUTTON_SIZE - OFFSET)/ width; f@0: double scaleY = (BUTTON_SIZE - OFFSET)/ height; f@0: double scale = Math.min(scaleX, scaleY); f@0: f@0: AffineTransform oldTransform = g2.getTransform(); f@0: g2.translate(x, y); f@0: g2.scale(scale, scale); f@0: g2.translate(Math.max((height - width) / 2, 0), Math.max((width - height) / 2, 0)); f@0: f@0: g2.setColor(Color.black); f@0: g2.setStroke(e.getStyle().getStroke()); f@0: g2.draw(line); f@0: g2.setTransform(oldTransform); f@0: } f@0: }; f@0: final JButton button = new JButton(icon); f@0: button.setToolTipText(tip); f@0: button.setFocusable(false); f@0: f@0: button.addActionListener(new ActionListener(){ f@0: @Override f@0: public void actionPerformed(ActionEvent evt) { f@0: edgeCreatedListener.edgeCreated((Edge)e.clone()); f@0: }}); f@0: add(button); f@0: } f@0: f@0: /** f@0: * Sets the {@code EdgeCreatedListener} for this toolbar. Any previous set listener f@0: * will be overwritten. f@0: * f@0: * @param edgeCreatedListener the new {@code EdgeCreatedListener} for this toolbar f@0: */ f@0: public void setEdgeCreatedListener(EdgeCreatedListener edgeCreatedListener){ f@0: this.edgeCreatedListener = edgeCreatedListener; f@0: } f@0: f@0: private class NodeButton extends JToggleButton{ f@0: public NodeButton(Node node, Icon icon){ f@0: super(icon); f@0: setFocusable(false); f@0: this.node = node; f@0: } f@0: f@0: public Node getNode(){ f@0: return node; f@0: } f@0: Node node; f@0: } f@0: f@0: /** f@0: * The listener interface receiving events when the user clicks on f@0: * an {@code Edge} button. Unlike {@code Node} buttons which are {@code JTobbleButton} f@0: * objects to select the {@code Node} returned by {@code getSelectedTool()}, f@0: * the {@code Edge} buttons just trigger the registered listener with an immediate effect. f@0: */ f@0: public interface EdgeCreatedListener { f@0: /** f@0: * Invoked when an {@code Edge} button is pressed. f@0: * @param e the {@code Edge} related to the pressed button f@0: */ f@0: void edgeCreated(Edge e); f@0: } f@0: f@0: private ButtonGroup nodeButtonsGroup; f@0: private EdgeCreatedListener edgeCreatedListener; f@0: private NodeButton selectButton; f@0: f@0: private static final int BUTTON_SIZE = 30; f@0: private static final int OFFSET = 5; f@0: } f@0: