1 package org.glassbox.graphview;
2
3 import java.awt.Graphics2D;
4 import java.awt.Graphics;
5 import java.awt.Component;
6 import java.awt.Point;
7 import java.awt.Rectangle;
8 import java.awt.Insets;
9 import java.awt.Cursor;
10 import java.awt.event.MouseEvent;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import javax.swing.Action;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Iterator;
17
18 import de.fzi.wim.guibase.graphview.graph.*;
19 import de.fzi.wim.guibase.graphview.view.*;
20
21 /***
22 A manipulator and decorator for a NodePainter which supplies a set of buttons to a node.
23 */
24 public class NodeButtonSet extends MouseMovementTracker implements ZoomableNodePainter {
25 public interface Button extends NodeIconSet.Icon {
26 /***
27 Paint the "rollover" Icon.
28 */
29 void paintRolloverIcon(Component c, Graphics g, int x, int y);
30 /***
31 Paint the "pressed" Icon.
32 */
33 void paintPressedIcon(Component c, Graphics g, int x, int y);
34 /***
35 Get the action associated with this button.
36 */
37 Action getAction();
38 }
39
40 /***
41 An internal extension of NodeIconSet to paint rollover & pressed icons of buttons.
42 */
43 private class NodeIconSetDelegate extends NodeIconSet {
44 public NodeIconSetDelegate(NodePainter painter, Insets insets, int orientation, int alignx, int aligny) {
45 super(painter, insets, orientation, alignx, aligny);
46 }
47
48 protected void paintIcon(JGraphPane grp, Graphics2D g, Node node, Icon icon, int x, int y) {
49 if (icon instanceof Button) {
50 Button button = (Button)icon;
51 boolean mouseover = button == getButtonAtMouse() && node == getNodeAtMouse();
52 boolean mousedown = mouseover && _mousedown;
53 if (mousedown) button.paintPressedIcon(grp, g, x, y);
54 else if (mouseover) button.paintRolloverIcon(grp, g, x, y);
55 else button.paintIcon(grp, g, x, y);
56 } else {
57 icon.paintIcon(grp, g, x, y);
58 }
59 }
60 }
61
62 private NodeIconSet _delegate;
63 private String _name;
64 private boolean _mousedown;
65 private Button _overbutton;
66 private Cursor _cursor;
67 private Cursor _last_cursor;
68 private Class _nodetype;
69
70 /***
71 Constructor.
72 @param name The name of this manipulator.
73 @param painter The <code>NodePainter</code> decorated by this painter.
74 @param insets The insets of each icon. <code>insets.left</code> / <code>insets.top</code> will be used in between icons.
75 @param orientation The orientation of the icons, either <code>HORIZONTAL</code> or <code>VERTICAL</code>.
76 @param alignx The horizontal align of the Icons, either <code>LEFT</code> or <code>RIGHT</code>.
77 @param aligny The vertical align of the Icons, one of <code>CENTER</code>, <code>TOP</code> or <code>BOTTOM</code>.
78 */
79 public NodeButtonSet(String name, NodePainter painter, Insets insets, int orientation, int alignx, int aligny) {
80 this(name, painter, insets, orientation, alignx, aligny, Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
81 }
82
83 /***
84 Constructor.
85 @param name The name of this manipulator.
86 @param painter The <code>NodePainter</code> decorated by this painter.
87 @param insets The insets of each icon. <code>insets.left</code> / <code>insets.top</code> will be used in between icons.
88 @param orientation The orientation of the icons, either <code>HORIZONTAL</code> or <code>VERTICAL</code>.
89 @param alignx The horizontal align of the Icons, either <code>LEFT</code> or <code>RIGHT</code>.
90 @param aligny The vertical align of the Icons, one of <code>CENTER</code>, <code>TOP</code> or <code>BOTTOM</code>.
91 @param cursor The cursor to use when the mouse is over a button.
92 */
93 public NodeButtonSet(String name, NodePainter painter, Insets insets, int orientation, int alignx, int aligny, Cursor cursor) {
94 this(name, painter, insets, orientation, alignx, aligny, cursor, null);
95 }
96
97 /***
98 Constructor.
99 @param name The name of this manipulator.
100 @param painter The <code>NodePainter</code> decorated by this painter.
101 @param insets The insets of each icon. <code>insets.left</code> / <code>insets.top</code> will be used in between icons.
102 @param orientation The orientation of the icons, either <code>HORIZONTAL</code> or <code>VERTICAL</code>.
103 @param alignx The horizontal align of the Icons, either <code>LEFT</code> or <code>RIGHT</code>.
104 @param aligny The vertical align of the Icons, one of <code>CENTER</code>, <code>TOP</code> or <code>BOTTOM</code>.
105 @param cursor The cursor to use when the mouse is over a button.
106 @param nodetype The type of nodes this manipulator is active for.
107 */
108 public NodeButtonSet(String name, NodePainter painter, Insets insets, int orientation, int alignx, int aligny, Cursor cursor, Class nodetype) {
109 super();
110 _delegate = new NodeIconSetDelegate(painter, insets, orientation, alignx, aligny);
111 _name = name;
112 _mousedown = false;
113 _overbutton = null;
114 _cursor = cursor;
115 _last_cursor = null;
116 _nodetype = nodetype;
117 }
118
119 public NodePainter getDelegate() {
120 return _delegate.getDelegate();
121 }
122
123 /***
124 Add a button or icon to this NodeButtonSet.
125 */
126 public void addButton(NodeIconSet.Icon icon) {
127 _delegate.addIcon(icon);
128 }
129
130 public Button getButtonAtPoint(JGraphPane graphpane, Node node, Point point) {
131 NodeIconSet.Icon icon = _delegate.getIconAtPoint(graphpane, node, point);
132 if (icon instanceof Button) return (Button)icon;
133 return null;
134 }
135
136 public Button getButtonAtMouse() {
137 return _overbutton;
138 }
139
140 protected void fireActionPerformed(Node node, Action action) {
141 ActionEvent e = new ActionEvent(node, ActionEvent.ACTION_PERFORMED, (String)action.getValue(Action.ACTION_COMMAND_KEY));
142 action.actionPerformed(e);
143 }
144
145
146
147
148
149 public void paintNode(JGraphPane graphpane,Graphics2D g,Node node) {
150 _delegate.paintNode(graphpane, g, node);
151 }
152
153 public boolean isInNode(JGraphPane graphpane,Node node,Point point) {
154 return _delegate.isInNode(graphpane, node, point);
155 }
156
157 public void getNodeScreenBounds(JGraphPane graphpane, Node node, Rectangle nodebounds) {
158 _delegate.getNodeScreenBounds(graphpane, node, nodebounds);
159 }
160
161 public String getToolTipText(JGraphPane graphpane,Node node,Point point) {
162 return _delegate.getToolTipText(graphpane, node, point);
163 }
164
165 public void setZoomFactor(double zf) {
166 _delegate.setZoomFactor(zf);
167 }
168
169
170
171
172
173 protected boolean acceptNode(Node node, Point mpoint) {
174 if (_nodetype == null || node.getClass().equals(_nodetype)) {
175 Button button = getButtonAtPoint(m_graphPane, node, mpoint);
176 return (button!=null);
177 }
178 return false;
179 }
180
181 protected boolean acceptEdge(Edge edge, Point mpoint) {
182 return false;
183 }
184
185 public String getName() {
186 return _name;
187 }
188
189 public void mousePressed(MouseEvent e) {
190 Node node = getNodeAtMouse();
191 if (node!=null && acceptNode(node, e.getPoint())) {
192 _mousedown = true;
193 updateButton(e);
194 e.consume();
195 } else {
196 super.mousePressed(e);
197 }
198 }
199
200 public void mouseClicked(MouseEvent e) {
201 Node context = getNodeAtMouse();
202 Button target = getButtonAtMouse();
203 if (target!=null && context!=null) {
204 fireActionPerformed(context, target.getAction());
205 e.consume();
206 } else {
207 super.mouseClicked(e);
208 }
209 }
210
211 public void mouseReleased(MouseEvent e) {
212 _mousedown = false;
213 updateButton(e);
214 }
215
216 public void mouseMoved(MouseEvent e) {
217 super.mouseMoved(e);
218 _mousedown = false;
219 if (e.isConsumed()) updateButton(e);
220 }
221
222 public void mouseDragged(MouseEvent e) {
223 if (getButtonAtMouse()!=null) e.consume();
224 }
225
226 public void mouseExited(MouseEvent e) {
227 super.mouseExited(e);
228 _mousedown = false;
229 setButtonAtMouse(null);
230 }
231
232 private void updateButton(MouseEvent e) {
233 if (m_graphPane.isEnabled()) {
234 Point point=e.getPoint();
235 Node node=getNodeAtMouse();
236 if (node!=null) {
237 Button button = getButtonAtPoint(m_graphPane, node, point);
238 setButtonAtMouse(button);
239 if (button!=null) e.consume();
240 } else {
241 setButtonAtMouse(null);
242 }
243 } else {
244 setButtonAtMouse(null);
245 }
246 }
247
248 private void setButtonAtMouse(Button button) {
249 if (button!=null) {
250 m_graphPane.setCursor(_cursor);
251 }
252 _overbutton = button;
253 Node overnode = getNodeAtMouse();
254 if (overnode!=null) m_graphPane.repaintNode(overnode);
255 }
256 }