fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
fiore@0
|
3
|
fiore@0
|
4 Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)
|
fiore@0
|
5 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
6
|
fiore@0
|
7 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
8 it under the terms of the GNU General Public License as published by
|
fiore@0
|
9 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
10 (at your option) any later version.
|
fiore@0
|
11
|
fiore@0
|
12 This program is distributed in the hope that it will be useful,
|
fiore@0
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
15 GNU General Public License for more details.
|
fiore@0
|
16
|
fiore@0
|
17 You should have received a copy of the GNU General Public License
|
fiore@0
|
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@0
|
19 */
|
fiore@0
|
20
|
fiore@0
|
21 package uk.ac.qmul.eecs.ccmi.gui;
|
fiore@0
|
22
|
fiore@0
|
23 import java.awt.Color;
|
fiore@0
|
24 import java.awt.Component;
|
fiore@0
|
25 import java.awt.Graphics;
|
fiore@0
|
26 import java.awt.Graphics2D;
|
fiore@0
|
27 import java.awt.event.ActionEvent;
|
fiore@0
|
28 import java.awt.event.ActionListener;
|
fiore@0
|
29 import java.awt.geom.AffineTransform;
|
fiore@0
|
30 import java.awt.geom.Line2D;
|
fiore@0
|
31 import java.awt.geom.Point2D;
|
fiore@0
|
32 import java.awt.geom.Rectangle2D;
|
fiore@0
|
33 import java.util.Enumeration;
|
fiore@0
|
34 import java.util.ResourceBundle;
|
fiore@0
|
35
|
fiore@0
|
36 import javax.swing.ButtonGroup;
|
fiore@0
|
37 import javax.swing.Icon;
|
fiore@0
|
38 import javax.swing.JButton;
|
fiore@0
|
39 import javax.swing.JToggleButton;
|
fiore@0
|
40 import javax.swing.JToolBar;
|
fiore@0
|
41
|
fiore@0
|
42
|
fiore@0
|
43 /**
|
fiore@0
|
44 A Toolbar that contains node and edge prototype icons. By using the toolbar
|
fiore@0
|
45 the user can create nodes and edges in the diagram out of clonation from the prototype.
|
fiore@0
|
46 */
|
fiore@0
|
47 @SuppressWarnings("serial")
|
fiore@0
|
48 public class GraphToolbar extends JToolBar {
|
fiore@0
|
49 /**
|
fiore@0
|
50 Constructs a tool bar with no icons.
|
fiore@0
|
51 */
|
fiore@0
|
52 public GraphToolbar(Diagram diagram){
|
fiore@0
|
53 /* creates icon for select button */
|
fiore@0
|
54 Icon icon = new Icon(){
|
fiore@0
|
55 public int getIconHeight() { return BUTTON_SIZE; }
|
fiore@0
|
56 public int getIconWidth() { return BUTTON_SIZE; }
|
fiore@0
|
57 public void paintIcon(Component c, Graphics g,
|
fiore@0
|
58 int x, int y){
|
fiore@0
|
59 Graphics2D g2 = (Graphics2D)g;
|
fiore@0
|
60 GraphPanel.drawGrabber(g2, x + OFFSET, y + OFFSET);
|
fiore@0
|
61 GraphPanel.drawGrabber(g2, x + OFFSET, y + BUTTON_SIZE - OFFSET);
|
fiore@0
|
62 GraphPanel.drawGrabber(g2, x + BUTTON_SIZE - OFFSET, y + OFFSET);
|
fiore@0
|
63 GraphPanel.drawGrabber(g2, x + BUTTON_SIZE - OFFSET, y + BUTTON_SIZE - OFFSET);
|
fiore@0
|
64 }
|
fiore@0
|
65 };
|
fiore@0
|
66 /* add selection button */
|
fiore@0
|
67 ResourceBundle resources =
|
fiore@0
|
68 ResourceBundle.getBundle(EditorFrame.class.getName());
|
fiore@0
|
69 String text = resources.getString("grabber.text");
|
fiore@0
|
70 selectButton = new NodeButton(null,icon);
|
fiore@0
|
71 selectButton.setToolTipText(text);
|
fiore@0
|
72 nodeButtonsGroup = new ButtonGroup();
|
fiore@0
|
73 nodeButtonsGroup.add(selectButton);
|
fiore@0
|
74 add(selectButton);
|
fiore@0
|
75
|
fiore@0
|
76 /* add diagram buttons to the toolbar */
|
fiore@0
|
77 Node[] nodeTypes = diagram.getNodePrototypes();
|
fiore@0
|
78 for (int i = 0; i < nodeTypes.length; i++){
|
fiore@0
|
79 text = nodeTypes[i].getType();
|
fiore@0
|
80 add(nodeTypes[i], text );
|
fiore@0
|
81 }
|
fiore@0
|
82
|
fiore@0
|
83 /* select the select-button as default */
|
fiore@0
|
84 nodeButtonsGroup.setSelected(selectButton.getModel(), true);
|
fiore@0
|
85
|
fiore@0
|
86 /* separate node buttons from edge buttons */
|
fiore@0
|
87 addSeparator();
|
fiore@0
|
88
|
fiore@0
|
89 /* add diagram edges to the toolbar */
|
fiore@0
|
90 Edge[] edgeTypes = diagram.getEdgePrototypes();
|
fiore@0
|
91 for (int i = 0; i < edgeTypes.length; i++){
|
fiore@0
|
92 text = edgeTypes[i].getType();
|
fiore@0
|
93 add(edgeTypes[i], text );
|
fiore@0
|
94 }
|
fiore@0
|
95 }
|
fiore@0
|
96
|
fiore@0
|
97 /**
|
fiore@0
|
98 Gets the node prototype that is associated with
|
fiore@0
|
99 the currently selected button
|
fiore@0
|
100 @return a Node or Edge prototype
|
fiore@0
|
101 */
|
fiore@0
|
102 public Node getSelectedTool() {
|
fiore@0
|
103 @SuppressWarnings("rawtypes")
|
fiore@0
|
104 Enumeration elements = nodeButtonsGroup.getElements();
|
fiore@0
|
105 while (elements.hasMoreElements()) {
|
fiore@0
|
106 NodeButton b = (NodeButton)elements.nextElement();
|
fiore@0
|
107 if (b.isSelected()) {
|
fiore@0
|
108 /* switch back to the select-button */
|
fiore@0
|
109 nodeButtonsGroup.setSelected(selectButton.getModel(), true);
|
fiore@0
|
110 return b.getNode();
|
fiore@0
|
111 }
|
fiore@0
|
112 }
|
fiore@0
|
113 /* getting here means the selection button is selected */
|
fiore@0
|
114 return null;
|
fiore@0
|
115 }
|
fiore@0
|
116
|
fiore@0
|
117 /**
|
fiore@0
|
118 Adds a node to the tool bar.
|
fiore@0
|
119 @param n the node to add
|
fiore@0
|
120 @param tip the tool tip
|
fiore@0
|
121 */
|
fiore@0
|
122 public void add(final Node n, String text){
|
fiore@0
|
123 Icon icon = new Icon(){
|
fiore@0
|
124 public int getIconHeight() { return BUTTON_SIZE; }
|
fiore@0
|
125 public int getIconWidth() { return BUTTON_SIZE; }
|
fiore@0
|
126 public void paintIcon(Component c, Graphics g,
|
fiore@0
|
127 int x, int y){
|
fiore@0
|
128 double width = n.getBounds().getWidth();
|
fiore@0
|
129 double height = n.getBounds().getHeight();
|
fiore@0
|
130 Graphics2D g2 = (Graphics2D)g;
|
fiore@0
|
131 double scaleX = (BUTTON_SIZE - OFFSET)/ width;
|
fiore@0
|
132 double scaleY = (BUTTON_SIZE - OFFSET)/ height;
|
fiore@0
|
133 double scale = Math.min(scaleX, scaleY);
|
fiore@0
|
134
|
fiore@0
|
135 AffineTransform oldTransform = g2.getTransform();
|
fiore@0
|
136 g2.translate(x, y);
|
fiore@0
|
137 g2.translate(OFFSET/2*scaleX,OFFSET/2*scaleY);
|
fiore@0
|
138 g2.scale(scale, scale);
|
fiore@0
|
139 g2.setColor(Color.black);
|
fiore@0
|
140 n.draw(g2);
|
fiore@0
|
141 g2.setTransform(oldTransform);
|
fiore@0
|
142 }
|
fiore@0
|
143 };
|
fiore@0
|
144
|
fiore@0
|
145 NodeButton button = new NodeButton(n, icon);
|
fiore@0
|
146 button.setToolTipText(text);
|
fiore@0
|
147
|
fiore@0
|
148 add(button);
|
fiore@0
|
149 nodeButtonsGroup.add(button);
|
fiore@0
|
150 }
|
fiore@0
|
151
|
fiore@0
|
152 /**
|
fiore@0
|
153 Adds an edge to the tool bar.
|
fiore@0
|
154 @param n the node to add
|
fiore@0
|
155 @param tip the tool tip
|
fiore@0
|
156 */
|
fiore@0
|
157 public void add(final Edge e, String text){
|
fiore@0
|
158 Icon icon = new Icon(){
|
fiore@0
|
159 public int getIconHeight() { return BUTTON_SIZE; }
|
fiore@0
|
160 public int getIconWidth() { return BUTTON_SIZE; }
|
fiore@0
|
161 public void paintIcon(Component c, Graphics g,
|
fiore@0
|
162 int x, int y){
|
fiore@0
|
163 Graphics2D g2 = (Graphics2D)g;
|
fiore@0
|
164 /* create two points */
|
fiore@0
|
165 Point2D p = new Point2D.Double();
|
fiore@0
|
166 Point2D q = new Point2D.Double();
|
fiore@0
|
167 p.setLocation(OFFSET, OFFSET);
|
fiore@0
|
168 q.setLocation(BUTTON_SIZE - OFFSET, BUTTON_SIZE - OFFSET);
|
fiore@0
|
169
|
fiore@0
|
170 Line2D line = new Line2D.Double(p,q);
|
fiore@0
|
171 Rectangle2D bounds = new Rectangle2D.Double();
|
fiore@0
|
172 bounds.add(line.getBounds2D());
|
fiore@0
|
173
|
fiore@0
|
174 double width = bounds.getWidth();
|
fiore@0
|
175 double height = bounds.getHeight();
|
fiore@0
|
176 double scaleX = (BUTTON_SIZE - OFFSET)/ width;
|
fiore@0
|
177 double scaleY = (BUTTON_SIZE - OFFSET)/ height;
|
fiore@0
|
178 double scale = Math.min(scaleX, scaleY);
|
fiore@0
|
179
|
fiore@0
|
180 AffineTransform oldTransform = g2.getTransform();
|
fiore@0
|
181 g2.translate(x, y);
|
fiore@0
|
182 g2.scale(scale, scale);
|
fiore@0
|
183 g2.translate(Math.max((height - width) / 2, 0), Math.max((width - height) / 2, 0));
|
fiore@0
|
184
|
fiore@0
|
185 g2.setColor(Color.black);
|
fiore@0
|
186 g2.setStroke(e.getStyle().getStroke());
|
fiore@0
|
187 g2.draw(line);
|
fiore@0
|
188 g2.setTransform(oldTransform);
|
fiore@0
|
189 }
|
fiore@0
|
190 };
|
fiore@0
|
191 final JButton button = new JButton(icon);
|
fiore@0
|
192 button.setToolTipText(text);
|
fiore@0
|
193 button.setFocusable(false);
|
fiore@0
|
194
|
fiore@0
|
195 button.addActionListener(new ActionListener(){
|
fiore@0
|
196 @Override
|
fiore@0
|
197 public void actionPerformed(ActionEvent evt) {
|
fiore@0
|
198 edgeCreatedListener.edgeCreated((Edge)e.clone());
|
fiore@0
|
199 }});
|
fiore@0
|
200 add(button);
|
fiore@0
|
201 }
|
fiore@0
|
202
|
fiore@0
|
203 public void addEdgeCreatedListener(EdgeCreatedListener edgeCreatedListener){
|
fiore@0
|
204 this.edgeCreatedListener = edgeCreatedListener;
|
fiore@0
|
205 }
|
fiore@0
|
206
|
fiore@0
|
207 private class NodeButton extends JToggleButton{
|
fiore@0
|
208 public NodeButton(Node node, Icon icon){
|
fiore@0
|
209 super(icon);
|
fiore@0
|
210 setFocusable(false);
|
fiore@0
|
211 this.node = node;
|
fiore@0
|
212 }
|
fiore@0
|
213
|
fiore@0
|
214 public Node getNode(){
|
fiore@0
|
215 return node;
|
fiore@0
|
216 }
|
fiore@0
|
217 Node node;
|
fiore@0
|
218 }
|
fiore@0
|
219
|
fiore@0
|
220 public interface EdgeCreatedListener {
|
fiore@0
|
221 void edgeCreated(Edge e);
|
fiore@0
|
222 }
|
fiore@0
|
223
|
fiore@0
|
224 private ButtonGroup nodeButtonsGroup;
|
fiore@0
|
225 private EdgeCreatedListener edgeCreatedListener;
|
fiore@0
|
226 private NodeButton selectButton;
|
fiore@0
|
227
|
fiore@0
|
228 private static final int BUTTON_SIZE = 30;
|
fiore@0
|
229 private static final int OFFSET = 5;
|
fiore@0
|
230 }
|
fiore@0
|
231
|