001: /*
002: * $Id: JGraphpadFocusManager.java,v 1.4 2006/01/30 15:33:27 gaudenz Exp $
003: * Copyright (c) 2001-2005, Gaudenz Alder
004: *
005: * All rights reserved.
006: *
007: * See LICENSE file for license details. If you are unable to locate
008: * this file please contact info (at) jgraph (dot) com.
009: */
010: package com.jgraph.pad.util;
011:
012: import java.awt.AWTEventMulticaster;
013: import java.awt.Component;
014: import java.awt.KeyboardFocusManager;
015: import java.awt.event.MouseEvent;
016: import java.awt.event.MouseListener;
017: import java.awt.event.MouseMotionListener;
018: import java.beans.PropertyChangeEvent;
019: import java.beans.PropertyChangeListener;
020: import java.util.EventListener;
021: import java.util.Observable;
022:
023: import javax.swing.event.EventListenerList;
024: import javax.swing.event.SwingPropertyChangeSupport;
025: import javax.swing.event.UndoableEditEvent;
026: import javax.swing.event.UndoableEditListener;
027:
028: import org.jgraph.JGraph;
029: import org.jgraph.event.GraphLayoutCacheEvent;
030: import org.jgraph.event.GraphLayoutCacheListener;
031: import org.jgraph.event.GraphModelEvent;
032: import org.jgraph.event.GraphModelListener;
033: import org.jgraph.event.GraphSelectionEvent;
034: import org.jgraph.event.GraphSelectionListener;
035:
036: /**
037: * Indirection to dispatch events from the permanent focus owner graph to the
038: * registered listeners. For redispatching mouse events the built-in
039: * multicasters are used.
040: *
041: * @see AWTEventMulticaster
042: */
043: public class JGraphpadFocusManager extends Observable implements
044: GraphLayoutCacheListener, GraphModelListener,
045: GraphSelectionListener, MouseListener, MouseMotionListener,
046: UndoableEditListener, PropertyChangeListener {
047:
048: /**
049: * Bound property name for <code>focusedGraph</code>.
050: */
051: public final static String FOCUSED_GRAPH_PROPERTY = "focusedGraph";
052:
053: /**
054: * Bound property name for model changes. This is fired whenever a graph
055: * model event is received from the focused graph.
056: */
057: public final static String MODEL_CHANGE_NOTIFICATION = "modelChange";
058:
059: /**
060: * Bound property name for graph layout changes. This is fired whenever a
061: * graph layout event is received from the focused graph.
062: */
063: public final static String GRAPHLAYOUT_CHANGE_NOTIFICATION = "graphLayoutChange";
064:
065: /**
066: * Bound property name for graph selection changes. This is fired whenever a
067: * graph selection event is received from the focused graph.
068: */
069: public final static String SELECTION_CHANGE_NOTIFICATION = "selectionChange";
070:
071: /**
072: * Bound property name for graph undoable changes. This is fired whenever a
073: * graph undoable event is received from the focused graph.
074: */
075: public final static String UNDOABLE_CHANGE_NOTIFICATION = "undoableChange";
076:
077: /**
078: * Shared singleton instance.
079: */
080: public static JGraphpadFocusManager currentGraphFocusManager = new JGraphpadFocusManager();
081:
082: /**
083: * Listeners to all graph-specific events (the other use event
084: * multicasters).
085: */
086: protected transient EventListenerList listenerList = new EventListenerList();
087:
088: /**
089: * Property change support for event notification.
090: */
091: protected SwingPropertyChangeSupport changeSupport = new SwingPropertyChangeSupport(
092: this );
093:
094: /**
095: * Used to manage mouse listeners as an event multicaster.
096: */
097: protected MouseListener mouseListener;
098:
099: /**
100: * Used to manage mouse motion listeners as an event multicaster.
101: */
102: protected MouseMotionListener mouseMotionListener;
103:
104: /**
105: * Reference to the current and last focused graph.
106: */
107: protected JGraph focusedGraph;
108:
109: /**
110: * Constructs a new focus manager.
111: */
112: public JGraphpadFocusManager() {
113: KeyboardFocusManager focusManager = KeyboardFocusManager
114: .getCurrentKeyboardFocusManager();
115: focusManager
116: .addPropertyChangeListener(new PropertyChangeListener() {
117:
118: /*
119: * (non-Javadoc)
120: */
121: public void propertyChange(PropertyChangeEvent e) {
122: String prop = e.getPropertyName();
123: if (("permanentFocusOwner".equals(prop))
124: && (e.getNewValue() != null)
125: && ((e.getNewValue()) instanceof Component)) {
126: if (e.getNewValue() instanceof JGraph)
127: setFocusedGraph((JGraph) e
128: .getNewValue());
129: else
130: setFocusedGraph(null);
131: }
132: }
133: });
134: }
135:
136: /**
137: * Returns the shared graph focused manager.
138: *
139: * @return Returns the shared graph focus manager.
140: */
141: public static JGraphpadFocusManager getCurrentGraphFocusManager() {
142: return currentGraphFocusManager;
143: }
144:
145: /**
146: * Returns the focused graph.
147: *
148: * @return Returns the focused graph.
149: */
150: public JGraph getFocusedGraph() {
151: return focusedGraph;
152: }
153:
154: /**
155: * Sets the focused graph to the specified value. If the current focused
156: * graph points to a different instance then <code>newGraph</code> then
157: * this implementation updates the last focused graph with the current
158: * focused graph and removes all listeners from either the current graph or
159: * the last focused graph if the current graph is null. This method fires a
160: * property change event for {@link #FOCUSED_GRAPH_PROPERTY}.
161: *
162: * @param newGraph
163: * The new focused graph.
164: */
165: public void setFocusedGraph(JGraph newGraph) {
166: JGraph oldValue = getFocusedGraph();
167: if (oldValue != newGraph) {
168:
169: // Uninstalls the listeners from the previous graph
170: if (oldValue != null) {
171: uninstallListeners(oldValue);
172: }
173:
174: // Installs the listeners into the new graph and fires a property
175: // change event
176: this .focusedGraph = newGraph;
177: installListeners(newGraph);
178: changeSupport.firePropertyChange(FOCUSED_GRAPH_PROPERTY,
179: oldValue, newGraph);
180: }
181: }
182:
183: /**
184: * Installs all listeners in the specified graph.
185: *
186: * @param graph
187: * The graph to install the listeners to.
188: */
189: protected void installListeners(JGraph graph) {
190: if (graph != null) {
191: graph.getModel().addGraphModelListener(this );
192: graph.getModel().addUndoableEditListener(this );
193: graph.addGraphSelectionListener(this );
194: graph.getGraphLayoutCache().addGraphLayoutCacheListener(
195: this );
196: graph.addMouseListener(this );
197: graph.addMouseMotionListener(this );
198: graph.addPropertyChangeListener(this );
199: }
200: }
201:
202: /**
203: * Uninstalls all listeners previously registered using
204: * {@link #installListeners(JGraph)} from the specified graph.
205: *
206: * @param graph
207: * The graph to uninstall the listeners from.
208: */
209: protected void uninstallListeners(JGraph graph) {
210: if (graph != null) {
211: graph.getModel().removeGraphModelListener(this );
212: graph.getModel().removeUndoableEditListener(this );
213: graph.removeGraphSelectionListener(this );
214: graph.getGraphLayoutCache().removeGraphLayoutCacheListener(
215: this );
216: graph.removeMouseListener(this );
217: graph.removeMouseMotionListener(this );
218: graph.removePropertyChangeListener(this );
219: }
220: }
221:
222: //
223: // PropertyChangeListener
224: //
225:
226: /**
227: * Adds a PropertyChangeListener to the listener list. The listener is
228: * registered for all properties.
229: *
230: * @param listener
231: * the PropertyChangeListener to be added
232: */
233: public synchronized void addPropertyChangeListener(
234: PropertyChangeListener listener) {
235: changeSupport.addPropertyChangeListener(listener);
236: }
237:
238: /**
239: * Removes a PropertyChangeListener from the listener list. This removes a
240: * PropertyChangeListener that was registered for all properties.
241: *
242: * @param listener
243: * the PropertyChangeListener to be removed
244: */
245: public synchronized void removePropertyChangeListener(
246: PropertyChangeListener listener) {
247: changeSupport.removePropertyChangeListener(listener);
248: }
249:
250: /**
251: * Redispatches the property change event using the {@link #changeSupport}.
252: */
253: public void propertyChange(PropertyChangeEvent evt) {
254: changeSupport.firePropertyChange(evt);
255: }
256:
257: //
258: // UndoableEditListener
259: //
260:
261: /**
262: * Fires a property change for <code>UNDOABLE_CHANGE_NOTIFICATION</code>.
263: *
264: * @see javax.swing.event.UndoableEditListener#undoableEditHappened(javax.swing.event.UndoableEditEvent)
265: */
266: public void undoableEditHappened(UndoableEditEvent e) {
267: changeSupport.firePropertyChange(UNDOABLE_CHANGE_NOTIFICATION,
268: focusedGraph, e);
269: }
270:
271: //
272: // GraphLayoutCacheListener
273: //
274:
275: /**
276: * Redispatches the graph layout cache event and fires a property change for
277: * <code>UNDOABLE_CHANGE_NOTIFICATION</code>.
278: *
279: * @see javax.swing.event.UndoableEditListener#undoableEditHappened(javax.swing.event.UndoableEditEvent)
280: */
281: public void graphLayoutCacheChanged(GraphLayoutCacheEvent e) {
282: setChanged();
283: fireGraphLayoutCacheChanged(e);
284: changeSupport.firePropertyChange(
285: GRAPHLAYOUT_CHANGE_NOTIFICATION, focusedGraph, e);
286: }
287:
288: /**
289: * Adds a listener for the GraphLayoutCacheEvent posted after the graph
290: * layout cache changes.
291: *
292: * @see #removeGraphLayoutCacheListener(GraphLayoutCacheListener)
293: * @param l
294: * the listener to add
295: */
296: public void addGraphLayoutCacheListener(GraphLayoutCacheListener l) {
297: listenerList.add(GraphLayoutCacheListener.class, l);
298: }
299:
300: /**
301: * Removes a listener previously added with <B>addGraphModelListener() </B>.
302: *
303: * @see #addGraphLayoutCacheListener(GraphLayoutCacheListener)
304: * @param l
305: * the listener to remove
306: */
307: public void removeGraphLayoutCacheListener(
308: GraphLayoutCacheListener l) {
309: listenerList.remove(GraphLayoutCacheListener.class, l);
310: }
311:
312: /**
313: * Notifies all listeners that have registered interest for notification on
314: * this event type. The event instance is lazily created using the
315: * parameters passed into the fire method.
316: *
317: * @see EventListenerList
318: */
319: protected void fireGraphLayoutCacheChanged(GraphLayoutCacheEvent e) {
320: Object[] listeners = listenerList.getListenerList();
321: for (int i = listeners.length - 2; i >= 0; i -= 2) {
322: if (listeners[i] == GraphLayoutCacheListener.class) {
323: ((GraphLayoutCacheListener) listeners[i + 1])
324: .graphLayoutCacheChanged(e);
325: }
326: }
327: }
328:
329: /**
330: * Returns an array of all GraphModelListeners that were added to this
331: * model.
332: */
333: public GraphLayoutCacheListener[] getGraphLayoutCacheListeners() {
334: return (GraphLayoutCacheListener[]) listenerList
335: .getListeners(GraphLayoutCacheListener.class);
336: }
337:
338: //
339: // GraphModelListener
340: //
341:
342: /**
343: * Redispatches the graph model event and fires a property change for
344: * <code>MODEL_CHANGE_NOTIFICATION</code>.
345: *
346: * @see org.jgraph.event.GraphModelListener#graphChanged(org.jgraph.event.GraphModelEvent)
347: */
348: public void graphChanged(GraphModelEvent e) {
349: fireGraphChanged(e);
350: changeSupport.firePropertyChange(MODEL_CHANGE_NOTIFICATION,
351: focusedGraph, e);
352: }
353:
354: /**
355: * Adds a listener for the GraphModelEvent posted after the graph changes.
356: *
357: * @see #removeGraphModelListener(GraphModelListener)
358: * @param l
359: * the listener to add
360: */
361: public void addGraphModelListener(GraphModelListener l) {
362: listenerList.add(GraphModelListener.class, l);
363: }
364:
365: /**
366: * Removes a listener previously added with <B>addGraphModelListener() </B>.
367: *
368: * @see #addGraphModelListener(GraphModelListener)
369: * @param l
370: * the listener to remove
371: */
372: public void removeGraphModelListener(GraphModelListener l) {
373: listenerList.remove(GraphModelListener.class, l);
374: }
375:
376: /**
377: * Notify all listeners that have registered interest for notification on
378: * this event type. The event instance is lazily created using the
379: * parameters passed into the fire method.
380: *
381: * @see EventListenerList
382: */
383: protected void fireGraphChanged(GraphModelEvent e) {
384: Object[] listeners = listenerList.getListenerList();
385: for (int i = listeners.length - 2; i >= 0; i -= 2)
386: if (listeners[i] == GraphModelListener.class)
387: ((GraphModelListener) listeners[i + 1]).graphChanged(e);
388: }
389:
390: /**
391: * Return an array of all graph model listeners.
392: */
393: public GraphModelListener[] getGraphModelListeners() {
394: return (GraphModelListener[]) listenerList
395: .getListeners(GraphModelListener.class);
396: }
397:
398: //
399: // GraphSelectionListener
400: //
401:
402: /**
403: * Redirects the value change event and fires a property change for
404: * <code>SELECTION_CHANGE_NOTIFICATION</code>.
405: *
406: * @see org.jgraph.event.GraphSelectionListener#valueChanged(org.jgraph.event.GraphSelectionEvent)
407: */
408: public void valueChanged(GraphSelectionEvent e) {
409: fireValueChanged(e);
410: changeSupport.firePropertyChange(SELECTION_CHANGE_NOTIFICATION,
411: focusedGraph, e);
412: }
413:
414: /**
415: * Adds <code>x</code> to the list of listeners that are notified each
416: * time the set of selected cells changes.
417: *
418: * @param x
419: * the new listener to be added
420: */
421: public void addGraphSelectionListener(GraphSelectionListener x) {
422: listenerList.add(GraphSelectionListener.class, x);
423: }
424:
425: /**
426: * Removes <code>x</code> from the list of listeners that are notified
427: * each time the set of selected cells changes.
428: *
429: * @param x
430: * the listener to remove
431: */
432: public void removeGraphSelectionListener(GraphSelectionListener x) {
433: listenerList.remove(GraphSelectionListener.class, x);
434: }
435:
436: /**
437: * Notifies all listeners that are registered for graph selection events on
438: * this object.
439: *
440: * @see #addGraphSelectionListener(GraphSelectionListener)
441: * @see EventListenerList
442: */
443: protected void fireValueChanged(GraphSelectionEvent e) {
444: Object[] listeners = listenerList.getListenerList();
445: for (int i = listeners.length - 2; i >= 0; i -= 2)
446: if (listeners[i] == GraphSelectionListener.class)
447: ((GraphSelectionListener) listeners[i + 1])
448: .valueChanged(e);
449: }
450:
451: /**
452: * Returns an array of all the listeners of the given type that were added
453: * to this manager.
454: *
455: * @return all of the objects receiving <em>listenerType</em>
456: * notifications from this model
457: */
458: public EventListener[] getListeners(Class listenerType) {
459: return listenerList.getListeners(listenerType);
460: }
461:
462: //
463: // MouseListeners
464: //
465:
466: /**
467: * Adds a listener for the MouseEvent.
468: *
469: * @see #removeMouseListener(MouseListener)
470: * @param l
471: * the listener to add
472: */
473: public synchronized void addMouseListener(MouseListener l) {
474: mouseListener = AWTEventMulticaster.add(mouseListener, l);
475: }
476:
477: /**
478: * Removes a listener previously added with <B>addMouseListener() </B>.
479: *
480: * @see #addMouseListener(MouseListener)
481: * @param l
482: * the listener to remove
483: */
484: public synchronized void removeMouseListener(MouseListener l) {
485: mouseListener = AWTEventMulticaster.remove(mouseListener, l);
486: }
487:
488: /**
489: * Adds a listener for the MouseMotionEvent.
490: *
491: * @see #removeMouseMotionListener(MouseMotionListener)
492: * @param l
493: * the listener to add
494: */
495: public synchronized void addMouseMotionListener(
496: MouseMotionListener l) {
497: mouseMotionListener = AWTEventMulticaster.add(
498: mouseMotionListener, l);
499: }
500:
501: /**
502: * Removes a listener previously added with
503: * <B>addMouseMotionListeneraddMouseMotionListener() </B>.
504: *
505: * @see #addMouseListener(MouseListener)
506: * @param l
507: * the listener to remove
508: */
509: public synchronized void removeMouseMotionListener(
510: MouseMotionListener l) {
511: mouseMotionListener = AWTEventMulticaster.remove(
512: mouseMotionListener, l);
513: }
514:
515: /**
516: * Redirects the mouse event to the registered listeners.
517: *
518: * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
519: */
520: public void mouseClicked(MouseEvent arg0) {
521: MouseListener listener = mouseListener;
522: if (listener != null) {
523: listener.mouseClicked(arg0);
524: }
525: }
526:
527: /**
528: * Redirects the mouse event to the registered listeners.
529: *
530: * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
531: */
532: public void mousePressed(MouseEvent arg0) {
533: MouseListener listener = mouseListener;
534: if (listener != null) {
535: listener.mousePressed(arg0);
536: }
537: }
538:
539: /**
540: * Redirects the mouse event to the registered listeners.
541: *
542: * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
543: */
544: public void mouseReleased(MouseEvent arg0) {
545: MouseListener listener = mouseListener;
546: if (listener != null) {
547: listener.mouseReleased(arg0);
548: }
549: }
550:
551: /**
552: * Redirects the mouse event to the registered listeners.
553: *
554: * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
555: */
556: public void mouseEntered(MouseEvent arg0) {
557: MouseListener listener = mouseListener;
558: if (listener != null) {
559: listener.mouseEntered(arg0);
560: }
561: }
562:
563: /**
564: * Redirects the mouse event to the registered listeners.
565: *
566: * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
567: */
568: public void mouseExited(MouseEvent arg0) {
569: MouseListener listener = mouseListener;
570: if (listener != null) {
571: listener.mouseExited(arg0);
572: }
573: }
574:
575: /**
576: * Redirects the mouse event to the registered listeners.
577: *
578: * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
579: */
580: public void mouseDragged(MouseEvent arg0) {
581: MouseMotionListener listener = mouseMotionListener;
582: if (listener != null) {
583: listener.mouseDragged(arg0);
584: }
585: }
586:
587: /**
588: * Redirects the mouse event to the registered listeners.
589: *
590: * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
591: */
592: public void mouseMoved(MouseEvent arg0) {
593: MouseMotionListener listener = mouseMotionListener;
594: if (listener != null) {
595: listener.mouseMoved(arg0);
596: }
597: }
598:
599: }
|