View Javadoc

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     /// Implementation of ZoomableNodePainter
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     /// Implementation of Manipulator
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 }