01: package com.jidesoft.swing;
02:
03: import javax.swing.event.ChangeEvent;
04: import java.awt.event.ItemEvent;
05: import java.beans.PropertyChangeEvent;
06: import java.beans.PropertyChangeListener;
07: import java.lang.ref.WeakReference;
08: import java.lang.reflect.Method;
09:
10: /**
11: * How to use this:
12: * <code><pre>
13: * KeyboardFocusManager focusManager =
14: * KeyboardFocusManager.getCurrentKeyboardFocusManager();
15: * <p/>
16: * // instead of registering direclty use weak listener
17: * // focusManager.addPropertyChangeListener(focusOwnerListener);
18: * <p/>
19: * focusManager.addPropertyChangeListener(
20: * new WeakPropertyChangeListener(focusOwnerListener, focusManager));
21: * </pre></code>
22: * <p/>
23: * How does this work:
24: * <p/>
25: * Instead of registering propertyChangeListener directly to keyboardFocusManager, we wrap it inside WeakPropertyChangeListener and register this weak listener to keyboardFocusManager. This weak listener acts a delegate.
26: * It receives the propertyChangeEvents from keyboardFocusManager and delegates it the wrapped listener.
27: * <p/>
28: * The interesting part of this weak listener, it hold a weakReference to the original propertyChangeListener. so this delegate is eligible for garbage collection which it is no longer reachable via references. When it gets garbage
29: * collection, the weakReference will be pointing to null. On next propertyChangeEvent notification from keyboardFocusManager, it find that the weakReference is pointing to null, and unregisters itself from
30: * keyboardFocusManager. Thus the weak listener will also become eligible for garbage collection in next gc cycle.
31: * <p/>
32: * This concept is not something new. If you have a habit of looking into swing sources, you will find that AbstractButton actually adds a weak listener to its action. The weak listener class used for this is :
33: * javax.swing.AbstractActionPropertyChangeListener; This class is package-private, so you don't find it in javadoc.
34: * <p/>
35: * The full-fledged, generic implementation of weak listeners is available in Netbeans OpenAPI: WeakListeners.java . It is worth to have a look at it.
36: *
37: * @author Santhosh Kumar T - santhosh@in.fiorano.com
38: */
39: public class WeakPropertyChangeListener implements
40: PropertyChangeListener {
41: private WeakReference<PropertyChangeListener> _listenerRef;
42: private Object _src;
43:
44: public WeakPropertyChangeListener(PropertyChangeListener listener,
45: Object src) {
46: _listenerRef = new WeakReference(listener);
47: _src = src;
48: }
49:
50: public void propertyChange(PropertyChangeEvent evt) {
51: PropertyChangeListener listener = _listenerRef.get();
52: if (listener == null) {
53: removeListener();
54: } else
55: listener.propertyChange(evt);
56: }
57:
58: public void itemStateChanged(ItemEvent e) {
59:
60: }
61:
62: public void stateChanged(ChangeEvent e) {
63:
64: }
65:
66: private void removeListener() {
67: try {
68: Method method = _src.getClass().getMethod(
69: "removePropertyChangeListener",
70: new Class[] { PropertyChangeListener.class });
71: method.invoke(_src, new Object[] { this });
72: } catch (Exception e) {
73: e.printStackTrace();
74: }
75: }
76: }
|