001: /*
002: * Copyright (C) 2004 NNL Technology AB
003: * Visit www.infonode.net for information about InfoNode(R)
004: * products and how to contact NNL Technology AB.
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
019: * MA 02111-1307, USA.
020: */
021:
022: // $Id: HoverManager.java,v 1.14 2005/12/04 13:46:03 jesper Exp $
023: package net.infonode.gui.hover.hoverable;
024:
025: import net.infonode.gui.ComponentUtil;
026: import net.infonode.util.ArrayUtil;
027:
028: import javax.swing.*;
029: import javax.swing.event.MouseInputAdapter;
030: import java.awt.*;
031: import java.awt.event.AWTEventListener;
032: import java.awt.event.HierarchyEvent;
033: import java.awt.event.HierarchyListener;
034: import java.awt.event.MouseEvent;
035: import java.util.ArrayList;
036: import java.util.HashSet;
037:
038: /**
039: * @author johan
040: */
041: public class HoverManager {
042: private static HoverManager INSTANCE = new HoverManager();
043:
044: private HierarchyListener hierarchyListener = new HierarchyListener() {
045: public void hierarchyChanged(final HierarchyEvent e) {
046: SwingUtilities.invokeLater(new Runnable() {
047: public void run() {
048: if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
049: if (((Component) e.getSource()).isShowing()) {
050: addHoverListeners((Hoverable) e.getSource());
051: } else {
052: removeHoverListeners((Hoverable) e
053: .getSource());
054: }
055: }
056: }
057: });
058: }
059: };
060:
061: private MouseInputAdapter mouseAdapter = new MouseInputAdapter() {
062: };
063:
064: private HashSet hoverableComponents = new HashSet();
065: private ArrayList enteredComponents = new ArrayList();
066:
067: private boolean enabled = true;
068: private boolean hasPermission = true;
069:
070: private boolean active = true;
071:
072: private boolean gotEnterAfterExit = false;
073: private boolean isDrag = false;
074:
075: private AWTEventListener eventListener = new AWTEventListener() {
076: public void eventDispatched(final AWTEvent e) {
077: if (active) {
078: HoverManager.this .eventDispatched(e);
079: }
080: }
081: };
082:
083: private void eventDispatched(final AWTEvent e) {
084: MouseEvent event = (MouseEvent) e;
085:
086: if (event.getID() == MouseEvent.MOUSE_PRESSED
087: || event.getID() == MouseEvent.MOUSE_RELEASED) {
088: handleButtonEvent(event);
089: } else if (event.getID() == MouseEvent.MOUSE_ENTERED
090: || event.getID() == MouseEvent.MOUSE_MOVED) {
091: handleEnterEvent(event);
092: } else if (event.getID() == MouseEvent.MOUSE_EXITED) {
093: handleExitEvent(event);
094: } else if (event.getID() == MouseEvent.MOUSE_DRAGGED) {
095: isDrag = true;
096: }
097: }
098:
099: private void handleButtonEvent(MouseEvent event) {
100: if (event.getID() == MouseEvent.MOUSE_PRESSED
101: && event.getButton() == MouseEvent.BUTTON1) {
102: enabled = false;
103: isDrag = false;
104: } else if (!enabled
105: && event.getID() == MouseEvent.MOUSE_RELEASED) {
106: enabled = true;
107:
108: if (isDrag) {
109: final Component top = ComponentUtil
110: .getTopLevelAncestor((Component) event
111: .getSource());
112: if (top == null)
113: exitAll();
114: else if (!((Component) event.getSource())
115: .contains(event.getPoint())) {
116: final Point p = SwingUtilities.convertPoint(
117: (Component) event.getSource(), event
118: .getPoint(), top);
119: if (!top.contains(p.x, p.y)) {
120: exitAll();
121: } else if (top instanceof Container) {
122: SwingUtilities.invokeLater(new Runnable() {
123: public void run() {
124: SwingUtilities
125: .invokeLater(new Runnable() {
126: public void run() {
127: Component c = ComponentUtil
128: .findComponentUnderGlassPaneAt(
129: p, top);
130:
131: if (c != null) {
132: Point p2 = SwingUtilities
133: .convertPoint(
134: top,
135: p,
136: c);
137: eventDispatched(new MouseEvent(
138: c,
139: MouseEvent.MOUSE_ENTERED,
140: 0, 0, p2.x,
141: p2.y, 0,
142: false));
143: }
144: }
145: });
146: }
147: });
148: }
149: }
150: }
151: }
152: }
153:
154: private void handleEnterEvent(MouseEvent event) {
155: gotEnterAfterExit = true;
156:
157: ArrayList exitables = new ArrayList(enteredComponents);
158: ArrayList enterables = new ArrayList();
159:
160: Component c = (Component) event.getSource();
161: while (c != null) {
162: if (hoverableComponents.contains(c)) {
163: exitables.remove(c);
164: enterables.add(c);
165: }
166:
167: c = c.getParent();
168: }
169:
170: if (enterables.size() > 0) {
171: Object obj[] = enterables.toArray();
172: for (int i = obj.length - 1; i >= 0; i--) {
173: if (!((Hoverable) obj[i]).acceptHover(enterables)) {
174: enterables.remove(obj[i]);
175: exitables.add(obj[i]);
176: }
177: }
178: }
179:
180: for (int i = exitables.size() - 1; i >= 0; i--) {
181: dispatchExit((Hoverable) exitables.get(i));
182: }
183:
184: for (int i = enterables.size() - 1; i >= 0; i--) {
185: dispatchEnter((Hoverable) enterables.get(i));
186: }
187: }
188:
189: private void handleExitEvent(MouseEvent event) {
190: gotEnterAfterExit = false;
191:
192: SwingUtilities.invokeLater(new Runnable() {
193: public void run() {
194: if (!gotEnterAfterExit)
195: exitAll();
196: }
197: });
198: }
199:
200: public static HoverManager getInstance() {
201: return INSTANCE;
202: }
203:
204: private HoverManager() {
205: try {
206: SecurityManager sm = System.getSecurityManager();
207: if (sm != null)
208: sm.checkPermission(new AWTPermission(
209: "listenToAllAWTEvents"));
210: } catch (SecurityException e) {
211: hasPermission = false;
212: }
213: }
214:
215: private void exitAll() {
216: gotEnterAfterExit = false;
217: Object[] obj = enteredComponents.toArray();
218: for (int i = obj.length - 1; i >= 0; i--) {
219: dispatchExit((Hoverable) obj[i]);
220: }
221: }
222:
223: public void init() {
224: gotEnterAfterExit = false;
225: isDrag = false;
226: enabled = true;
227: }
228:
229: public void setEventListeningActive(boolean active) {
230: this .active = active;
231: }
232:
233: public void dispatchEvent(MouseEvent event) {
234: eventDispatched(event);
235: }
236:
237: private void addHoverListeners(Hoverable hoverable) {
238: if (hoverableComponents.add(hoverable)) {
239: Component c = (Component) hoverable;
240: c.addMouseListener(mouseAdapter);
241: c.addMouseMotionListener(mouseAdapter);
242:
243: if (active && hoverableComponents.size() == 1) {
244: try {
245: Toolkit.getDefaultToolkit().addAWTEventListener(
246: eventListener,
247: AWTEvent.MOUSE_EVENT_MASK
248: | AWTEvent.MOUSE_MOTION_EVENT_MASK);
249: hasPermission = true;
250: } catch (SecurityException e) {
251: hasPermission = false;
252: }
253: }
254: }
255: }
256:
257: private void removeHoverListeners(Hoverable hoverable) {
258: if (hoverableComponents.remove(hoverable)) {
259: ((Component) hoverable).removeMouseListener(mouseAdapter);
260: ((Component) hoverable)
261: .removeMouseMotionListener(mouseAdapter);
262: dispatchExit(hoverable);
263:
264: if (hasPermission && hoverableComponents.size() == 0) {
265: Toolkit.getDefaultToolkit().removeAWTEventListener(
266: eventListener);
267: }
268: }
269: }
270:
271: public void addHoverable(Hoverable hoverable) {
272: if (hoverable instanceof Component) {
273: Component c = (Component) hoverable;
274:
275: if (ArrayUtil.contains(c.getHierarchyListeners(),
276: hierarchyListener))
277: return;
278:
279: c.addHierarchyListener(hierarchyListener);
280:
281: if (c.isShowing())
282: addHoverListeners(hoverable);
283: }
284: }
285:
286: public void removeHoverable(Hoverable hoverable) {
287: Component c = (Component) hoverable;
288: c.removeHierarchyListener(hierarchyListener);
289: removeHoverListeners(hoverable);
290: }
291:
292: public boolean isHovered(Hoverable c) {
293: return enteredComponents.contains(c);
294: }
295:
296: public boolean isEventListeningActive() {
297: return active && hasPermission;
298: }
299:
300: private void dispatchEnter(Hoverable hoverable) {
301: if (enabled && !enteredComponents.contains(hoverable)) {
302: enteredComponents.add(hoverable);
303: hoverable.hoverEnter();
304: }
305: }
306:
307: private void dispatchExit(Hoverable hoverable) {
308: if (enabled && enteredComponents.remove(hoverable))
309: hoverable.hoverExit();
310: }
311: }
|