0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.openide.util;
0042:
0043: import java.util.logging.Logger;
0044: import org.openide.filesystems.*;
0045: import org.openide.nodes.*;
0046:
0047: import java.awt.event.FocusEvent;
0048: import java.awt.event.FocusListener;
0049:
0050: import java.beans.*;
0051:
0052: import java.lang.ref.*;
0053: import java.lang.reflect.*;
0054:
0055: import java.util.EventListener;
0056: import java.util.EventObject;
0057: import java.util.logging.Level;
0058:
0059: import javax.swing.event.*;
0060:
0061: /**
0062: * @deprecated Use {@link org.openide.util.WeakListeners} class.
0063: * @author Jaroslav Tulach
0064: */
0065: public abstract class WeakListener implements java.util.EventListener {
0066: /** weak reference to listener */
0067: private Reference ref;
0068:
0069: /** class of the listener */
0070: Class listenerClass;
0071:
0072: /** weak reference to source */
0073: private Reference source;
0074:
0075: /**
0076: * @param listenerClass class/interface of the listener
0077: * @param l listener to delegate to, <code>l</code> must be an instance of
0078: * listenerClass
0079: */
0080: protected WeakListener(Class listenerClass,
0081: java.util.EventListener l) {
0082: this .listenerClass = listenerClass;
0083: ref = new ListenerReference(l, this );
0084:
0085: if (!listenerClass.isAssignableFrom(l.getClass())) {
0086: throw new IllegalArgumentException(
0087: getClass().getName()
0088: + " constructor is calling WeakListner.<init> with illegal arguments"); // NOI18N
0089: }
0090: }
0091:
0092: /** Setter for the source field. If a WeakReference to an underlying listener is
0093: * cleared and enqueued, that is, the original listener is garbage collected,
0094: * then the source field is used for deregistration of this WeakListener, thus making
0095: * it eligible for garbage collection if no more references exist.
0096: *
0097: * This method is particularly useful in cases where the underlying listener was
0098: * garbage collected and the event source, on which this listener is listening on,
0099: * is quiet, i.e. does not fire any events for long periods. In this case, this listener
0100: * is not removed from the event source until an event is fired. If the source field is
0101: * set however, org.openide.util.WeakListeners that lost their underlying listeners are removed
0102: * as soon as the ReferenceQueue notifies the WeakListener.
0103: *
0104: * @param source is any Object or <code>null</code>, though only setting an object
0105: * that has an appropriate remove*listenerClass*Listener method and on which this listener is listening on,
0106: * is useful.
0107: */
0108: protected final void setSource(Object source) {
0109: if (source == null) {
0110: this .source = null;
0111: } else {
0112: this .source = new WeakReference(source);
0113: }
0114: }
0115:
0116: /** Method name to use for removing the listener.
0117: * @return name of method of the source object that should be used
0118: * to remove the listener from listening on source of events
0119: */
0120: protected abstract String removeMethodName();
0121:
0122: /** Getter for the target listener.
0123: * @param ev the event the we want to distribute
0124: * @return null if there is no listener because it has been finalized
0125: */
0126: protected final java.util.EventListener get(java.util.EventObject ev) {
0127: Object l = ref.get(); // get the consumer
0128:
0129: // if the event consumer is gone, unregister us from the event producer
0130: if (l == null) {
0131: removeListener((ev == null) ? null : ev.getSource());
0132: }
0133:
0134: return (EventListener) l;
0135: }
0136:
0137: /** Tries to find a remove method and invoke it.
0138: * It tries unregister itself from the registered source first
0139: * and then from the passed eventSource if they are not same.
0140: *
0141: * @param eventSource the source object to unregister from or null
0142: */
0143: private void removeListener(Object eventSource) {
0144: Object[] params = new Object[] { getImplementator() };
0145: Object src = (source == null) ? null : source.get();
0146:
0147: try {
0148: Method m = null;
0149:
0150: if (src != null) {
0151: m = getRemoveMethod(src.getClass(), removeMethodName(),
0152: listenerClass);
0153:
0154: if (m != null) {
0155: m.invoke(src, params);
0156: }
0157: }
0158:
0159: if ((eventSource != src) && (eventSource != null)) {
0160: m = getRemoveMethod(eventSource.getClass(),
0161: removeMethodName(), listenerClass);
0162:
0163: if (m != null) {
0164: m.invoke(eventSource, params);
0165: }
0166: }
0167:
0168: if ((m == null) && (source == null)) { // can't remove the listener
0169: Logger.getAnonymousLogger().warning(
0170: "Can't remove " + listenerClass.getName()
0171: + //NOI18N
0172: " using method " + removeMethodName()
0173: + //NOI18N
0174: " source=" + source
0175: + //NOI18N
0176: ", src=" + src + ", eventSource="
0177: + eventSource); //NOI18N
0178: }
0179: } catch (Exception ex) { // from invoke(), should not happen
0180: Logger.getLogger(WeakListener.class.getName()).log(
0181: Level.WARNING, null, ex);
0182: }
0183: }
0184:
0185: /* can return null */
0186: private static final Method getRemoveMethod(Class methodClass,
0187: String methodName, Class listenerClass) {
0188: final Class[] clarray = new Class[] { listenerClass };
0189: Method m = null;
0190:
0191: try {
0192: m = methodClass.getMethod(methodName, clarray);
0193: } catch (NoSuchMethodException e) {
0194: do {
0195: try {
0196: m = methodClass.getDeclaredMethod(methodName,
0197: clarray);
0198: } catch (NoSuchMethodException ex) {
0199: }
0200:
0201: methodClass = methodClass.getSuperclass();
0202: } while ((m == null) && (methodClass != Object.class));
0203: }
0204:
0205: if ((m != null)
0206: && (!Modifier.isPublic(m.getModifiers()) || !Modifier
0207: .isPublic(m.getDeclaringClass().getModifiers()))) {
0208: m.setAccessible(true);
0209: }
0210:
0211: return m;
0212: }
0213:
0214: Object getImplementator() {
0215: return this ;
0216: }
0217:
0218: public String toString() {
0219: Object listener = ref.get();
0220:
0221: return getClass().getName()
0222: + "["
0223: + ((listener == null) ? "null" : (listener.getClass()
0224: .getName() + "]"));
0225: }
0226:
0227: //
0228: // Methods for establishing connections
0229: //
0230:
0231: /** Creates a weak implementation of NodeListener.
0232: *
0233: * @param l the listener to delegate to
0234: * @param source the source that the listener should detach from when
0235: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0236: * @return a NodeListener delegating to <CODE>l</CODE>.
0237: * @deprecated Use {@link org.openide.nodes.NodeOp#weakNodeListener} or {@link org.openide.util.WeakListeners#create}
0238: */
0239: public static NodeListener node(NodeListener l, Object source) {
0240: WeakListener.Node wl = new WeakListener.Node(l);
0241: wl.setSource(source);
0242:
0243: return wl;
0244: }
0245:
0246: /** Creates a weak implementation of PropertyChangeListener.
0247: *
0248: * @param l the listener to delegate to
0249: * @param source the source that the listener should detach from when
0250: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0251: * @return a PropertyChangeListener delegating to <CODE>l</CODE>.
0252: * @deprecated Use {@link org.openide.util.WeakListeners#propertyChange}
0253: */
0254: public static PropertyChangeListener propertyChange(
0255: PropertyChangeListener l, Object source) {
0256: WeakListener.PropertyChange wl = new WeakListener.PropertyChange(
0257: l);
0258: wl.setSource(source);
0259:
0260: return wl;
0261: }
0262:
0263: /** Creates a weak implementation of VetoableChangeListener.
0264: *
0265: * @param l the listener to delegate to
0266: * @param source the source that the listener should detach from when
0267: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0268: * @return a VetoableChangeListener delegating to <CODE>l</CODE>.
0269: * @deprecated Use {@link org.openide.util.WeakListeners#vetoableChange}
0270: */
0271: public static VetoableChangeListener vetoableChange(
0272: VetoableChangeListener l, Object source) {
0273: WeakListener.VetoableChange wl = new WeakListener.VetoableChange(
0274: l);
0275: wl.setSource(source);
0276:
0277: return wl;
0278: }
0279:
0280: /** Creates a weak implementation of FileChangeListener.
0281: *
0282: * @param l the listener to delegate to
0283: * @param source the source that the listener should detach from when
0284: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0285: * @return a FileChangeListener delegating to <CODE>l</CODE>.
0286: * @deprecated Use {@link FileUtil#weakFileChangeListener} or {@link org.openide.util.WeakListeners#create}
0287: */
0288: public static FileChangeListener fileChange(FileChangeListener l,
0289: Object source) {
0290: WeakListener.FileChange wl = new WeakListener.FileChange(l);
0291: wl.setSource(source);
0292:
0293: return wl;
0294: }
0295:
0296: /** Creates a weak implementation of FileStatusListener.
0297: *
0298: * @param l the listener to delegate to
0299: * @param source the source that the listener should detach from when
0300: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0301: * @return a FileStatusListener delegating to <CODE>l</CODE>.
0302: * @deprecated Use {@link FileUtil#weakFileStatusListener} or {@link org.openide.util.WeakListeners#create}
0303: */
0304: public static FileStatusListener fileStatus(FileStatusListener l,
0305: Object source) {
0306: WeakListener.FileStatus wl = new WeakListener.FileStatus(l);
0307: wl.setSource(source);
0308:
0309: return wl;
0310: }
0311:
0312: /** Creates a weak implementation of RepositoryListener.
0313: *
0314: * @param l the listener to delegate to
0315: * @param source the source that the listener should detach from when
0316: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0317: * @return a RepositoryListener delegating to <CODE>l</CODE>.
0318: */
0319: public static RepositoryListener repository(RepositoryListener l,
0320: Object source) {
0321: WeakListener.Repository wl = new WeakListener.Repository(l);
0322: wl.setSource(source);
0323:
0324: return wl;
0325: }
0326:
0327: /** Creates a weak implementation of DocumentListener.
0328: *
0329: * @param l the listener to delegate to
0330: * @param source the source that the listener should detach from when
0331: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0332: * @return a DocumentListener delegating to <CODE>l</CODE>.
0333: * @deprecated Use {@link org.openide.util.WeakListeners#document}
0334: */
0335: public static DocumentListener document(DocumentListener l,
0336: Object source) {
0337: WeakListener.Document wl = new WeakListener.Document(l);
0338: wl.setSource(source);
0339:
0340: return wl;
0341: }
0342:
0343: /** Creates a weak implementation of ChangeListener.
0344: *
0345: * @param l the listener to delegate to
0346: * @param source the source that the listener should detach from when
0347: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0348: * @return a ChangeListener delegating to <CODE>l</CODE>.
0349: * @deprecated Use {@link org.openide.util.WeakListeners#change}
0350: */
0351: public static ChangeListener change(ChangeListener l, Object source) {
0352: WeakListener.Change wl = new WeakListener.Change(l);
0353: wl.setSource(source);
0354:
0355: return wl;
0356: }
0357:
0358: /** Creates a weak implementation of FocusListener.
0359: *
0360: * @param l the listener to delegate to
0361: * @param source the source that the listener should detach from when
0362: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0363: * @return a FocusListener delegating to <CODE>l</CODE>.
0364: * @deprecated Use {@link org.openide.util.WeakListeners#create}
0365: */
0366: public static FocusListener focus(FocusListener l, Object source) {
0367: WeakListener.Focus wl = new WeakListener.Focus(l);
0368: wl.setSource(source);
0369:
0370: return wl;
0371: }
0372:
0373: /** A generic WeakListener factory.
0374: * Creates a weak implementation of a listener of type <CODE>lType</CODE>.
0375: *
0376: * @param lType the type of listener to create. It can be any interface,
0377: * but only interfaces are allowed.
0378: * @param l the listener to delegate to, <CODE>l</CODE> must be an instance
0379: * of <CODE>lType</CODE>
0380: * @param source the source that the listener should detach from when
0381: * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
0382: * @return an instance of <CODE>lType</CODE> delegating all the interface
0383: * calls to <CODE>l</CODE>.
0384: * @deprecated Use {@link org.openide.util.WeakListeners#create}
0385: */
0386: public static EventListener create(Class lType, EventListener l,
0387: Object source) {
0388: ProxyListener pl = new ProxyListener(lType, l);
0389: pl.setSource(source);
0390:
0391: return (EventListener) pl.proxy;
0392: }
0393:
0394: /** Weak property change listener
0395: * @deprecated use appropriate method instead
0396: */
0397: public static class PropertyChange extends WeakListener implements
0398: PropertyChangeListener {
0399: /** Constructor.
0400: * @param l listener to delegate to
0401: */
0402: public PropertyChange(PropertyChangeListener l) {
0403: super (PropertyChangeListener.class, l);
0404: }
0405:
0406: /** Constructor.
0407: * @param clazz required class
0408: * @param l listener to delegate to
0409: */
0410: PropertyChange(Class clazz, PropertyChangeListener l) {
0411: super (clazz, l);
0412: }
0413:
0414: /** Tests if the object we reference to still exists and
0415: * if so, delegate to it. Otherwise remove from the source
0416: * if it has removePropertyChangeListener method.
0417: */
0418: public void propertyChange(PropertyChangeEvent ev) {
0419: PropertyChangeListener l = (PropertyChangeListener) super
0420: .get(ev);
0421:
0422: if (l != null) {
0423: l.propertyChange(ev);
0424: }
0425: }
0426:
0427: /** Method name to use for removing the listener.
0428: * @return name of method of the source object that should be used
0429: * to remove the listener from listening on source of events
0430: */
0431: protected String removeMethodName() {
0432: return "removePropertyChangeListener"; // NOI18N
0433: }
0434: }
0435:
0436: /** Weak vetoable change listener
0437: * @deprecated use appropriate method instead
0438: */
0439: public static class VetoableChange extends WeakListener implements
0440: VetoableChangeListener {
0441: /** Constructor.
0442: * @param l listener to delegate to
0443: */
0444: public VetoableChange(VetoableChangeListener l) {
0445: super (VetoableChangeListener.class, l);
0446: }
0447:
0448: /** Tests if the object we reference to still exists and
0449: * if so, delegate to it. Otherwise remove from the source
0450: * if it has removePropertyChangeListener method.
0451: */
0452: public void vetoableChange(PropertyChangeEvent ev)
0453: throws PropertyVetoException {
0454: VetoableChangeListener l = (VetoableChangeListener) super
0455: .get(ev);
0456:
0457: if (l != null) {
0458: l.vetoableChange(ev);
0459: }
0460: }
0461:
0462: /** Method name to use for removing the listener.
0463: * @return name of method of the source object that should be used
0464: * to remove the listener from listening on source of events
0465: */
0466: protected String removeMethodName() {
0467: return "removeVetoableChangeListener"; // NOI18N
0468: }
0469: }
0470:
0471: /** Weak file change listener.
0472: * @deprecated use appropriate method instead
0473: */
0474: public static class FileChange extends WeakListener implements
0475: FileChangeListener {
0476: /** Constructor.
0477: * @param l listener to delegate to
0478: */
0479: public FileChange(FileChangeListener l) {
0480: super (FileChangeListener.class, l);
0481: }
0482:
0483: /** Fired when a new folder has been created. This action can only be
0484: * listened in folders containing the created file up to the root of
0485: * file system.
0486: *
0487: * @param ev the event describing context where action has taken place
0488: */
0489: public void fileFolderCreated(FileEvent ev) {
0490: FileChangeListener l = (FileChangeListener) super .get(ev);
0491:
0492: if (l != null) {
0493: l.fileFolderCreated(ev);
0494: }
0495: }
0496:
0497: /** Fired when a new file has been created. This action can only be
0498: * listened in folders containing the created file up to the root of
0499: * file system.
0500: *
0501: * @param ev the event describing context where action has taken place
0502: */
0503: public void fileDataCreated(FileEvent ev) {
0504: FileChangeListener l = (FileChangeListener) super .get(ev);
0505:
0506: if (l != null) {
0507: l.fileDataCreated(ev);
0508: }
0509: }
0510:
0511: /** Fired when a file has been changed.
0512: * @param ev the event describing context where action has taken place
0513: */
0514: public void fileChanged(FileEvent ev) {
0515: FileChangeListener l = (FileChangeListener) super .get(ev);
0516:
0517: if (l != null) {
0518: l.fileChanged(ev);
0519: }
0520: }
0521:
0522: /** Fired when a file has been deleted.
0523: * @param ev the event describing context where action has taken place
0524: */
0525: public void fileDeleted(FileEvent ev) {
0526: FileChangeListener l = (FileChangeListener) super .get(ev);
0527:
0528: if (l != null) {
0529: l.fileDeleted(ev);
0530: }
0531: }
0532:
0533: /** Fired when a file has been renamed.
0534: * @param ev the event describing context where action has taken place
0535: * and the original name and extension.
0536: */
0537: public void fileRenamed(FileRenameEvent ev) {
0538: FileChangeListener l = (FileChangeListener) super .get(ev);
0539:
0540: if (l != null) {
0541: l.fileRenamed(ev);
0542: }
0543: }
0544:
0545: /** Fired when a file attribute has been changed.
0546: * @param ev the event describing context where action has taken place,
0547: * the name of attribute and old and new value.
0548: */
0549: public void fileAttributeChanged(FileAttributeEvent ev) {
0550: FileChangeListener l = (FileChangeListener) super .get(ev);
0551:
0552: if (l != null) {
0553: l.fileAttributeChanged(ev);
0554: }
0555: }
0556:
0557: /** Method name to use for removing the listener.
0558: * @return name of method of the source object that should be used
0559: * to remove the listener from listening on source of events
0560: */
0561: protected String removeMethodName() {
0562: return "removeFileChangeListener"; // NOI18N
0563: }
0564: }
0565:
0566: /** Weak file status listener.
0567: * @deprecated use appropriate method instead
0568: */
0569: public static class FileStatus extends WeakListener implements
0570: FileStatusListener {
0571: /** Constructor.
0572: */
0573: public FileStatus(FileStatusListener l) {
0574: super (FileStatusListener.class, l);
0575: }
0576:
0577: /** Notifies listener about change in annotataion of a few files.
0578: * @param ev event describing the change
0579: */
0580: public void annotationChanged(FileStatusEvent ev) {
0581: FileStatusListener l = (FileStatusListener) super .get(ev);
0582:
0583: if (l != null) {
0584: l.annotationChanged(ev);
0585: }
0586: }
0587:
0588: /** Method name to use for removing the listener.
0589: * @return name of method of the source object that should be used
0590: * to remove the listener from listening on source of events
0591: */
0592: protected String removeMethodName() {
0593: return "removeFileStatusListener"; // NOI18N
0594: }
0595: }
0596:
0597: /** Weak file system pool listener.
0598: * @deprecated use appropriate method instead
0599: */
0600: public static class Repository extends WeakListener implements
0601: RepositoryListener {
0602: /** Constructor.
0603: * @param l listener to delegate to
0604: */
0605: public Repository(RepositoryListener l) {
0606: super (RepositoryListener.class, l);
0607: }
0608:
0609: /** Called when new file system is added to the pool.
0610: * @param ev event describing the action
0611: */
0612: public void fileSystemAdded(RepositoryEvent ev) {
0613: RepositoryListener l = (RepositoryListener) super .get(ev);
0614:
0615: if (l != null) {
0616: l.fileSystemAdded(ev);
0617: }
0618: }
0619:
0620: /** Called when a file system is deleted from the pool.
0621: * @param ev event describing the action
0622: */
0623: public void fileSystemRemoved(RepositoryEvent ev) {
0624: RepositoryListener l = (RepositoryListener) super .get(ev);
0625:
0626: if (l != null) {
0627: l.fileSystemRemoved(ev);
0628: }
0629: }
0630:
0631: /** Called when a Repository is reordered. */
0632: public void fileSystemPoolReordered(RepositoryReorderedEvent ev) {
0633: RepositoryListener l = (RepositoryListener) super .get(ev);
0634:
0635: if (l != null) {
0636: l.fileSystemPoolReordered(ev);
0637: }
0638: }
0639:
0640: /** Method name to use for removing the listener.
0641: * @return name of method of the source object that should be used
0642: * to remove the listener from listening on source of events
0643: */
0644: protected String removeMethodName() {
0645: return "removeRepositoryListener"; // NOI18N
0646: }
0647: }
0648:
0649: /** Weak document modifications listener.
0650: * This class if final only for performance reasons,
0651: * can be happily unfinaled if desired.
0652: * @deprecated use appropriate method instead
0653: */
0654: public static final class Document extends WeakListener implements
0655: DocumentListener {
0656: /** Constructor.
0657: * @param l listener to delegate to
0658: */
0659: public Document(final DocumentListener l) {
0660: super (DocumentListener.class, l);
0661: }
0662:
0663: /** Gives notification that an attribute or set of attributes changed.
0664: * @param ev event describing the action
0665: */
0666: public void changedUpdate(DocumentEvent ev) {
0667: final DocumentListener l = docGet(ev);
0668:
0669: if (l != null) {
0670: l.changedUpdate(ev);
0671: }
0672: }
0673:
0674: /** Gives notification that there was an insert into the document.
0675: * @param ev event describing the action
0676: */
0677: public void insertUpdate(DocumentEvent ev) {
0678: final DocumentListener l = docGet(ev);
0679:
0680: if (l != null) {
0681: l.insertUpdate(ev);
0682: }
0683: }
0684:
0685: /** Gives notification that a portion of the document has been removed.
0686: * @param ev event describing the action
0687: */
0688: public void removeUpdate(DocumentEvent ev) {
0689: final DocumentListener l = docGet(ev);
0690:
0691: if (l != null) {
0692: l.removeUpdate(ev);
0693: }
0694: }
0695:
0696: /** Method name to use for removing the listener.
0697: * @return name of method of the source object that should be used
0698: * to remove the listener from listening on source of events
0699: */
0700: protected String removeMethodName() {
0701: return "removeDocumentListener"; // NOI18N
0702: }
0703:
0704: /** Getter for the target listener.
0705: * @param event the event the we want to distribute
0706: * @return null if there is no listener because it has been finalized
0707: */
0708: private DocumentListener docGet(DocumentEvent ev) {
0709: DocumentListener l = (DocumentListener) super .ref.get();
0710:
0711: if (l == null) {
0712: super .removeListener(ev.getDocument());
0713: }
0714:
0715: return l;
0716: }
0717: }
0718:
0719: // end of Document inner class
0720:
0721: /** Weak swing change listener.
0722: * This class if final only for performance reasons,
0723: * can be happily unfinaled if desired.
0724: * @deprecated use appropriate method instead
0725: */
0726: public static final class Change extends WeakListener implements
0727: ChangeListener {
0728: /** Constructor.
0729: * @param l listener to delegate to
0730: */
0731: public Change(ChangeListener l) {
0732: super (ChangeListener.class, l);
0733: }
0734:
0735: /** Called when new file system is added to the pool.
0736: * @param ev event describing the action
0737: */
0738: public void stateChanged(final ChangeEvent ev) {
0739: ChangeListener l = (ChangeListener) super .get(ev);
0740:
0741: if (l != null) {
0742: l.stateChanged(ev);
0743: }
0744: }
0745:
0746: /** Method name to use for removing the listener.
0747: * @return name of method of the source object that should be used
0748: * to remove the listener from listening on source of events
0749: */
0750: protected String removeMethodName() {
0751: return "removeChangeListener"; // NOI18N
0752: }
0753: }
0754:
0755: /** Weak version of listener for changes in one node.
0756: * This class if final only for performance reasons,
0757: * can be happily unfinaled if desired.
0758: * @deprecated use appropriate method instead
0759: */
0760: public static final class Node extends WeakListener.PropertyChange
0761: implements NodeListener {
0762: /** Constructor.
0763: * @param l listener to delegate to
0764: */
0765: public Node(NodeListener l) {
0766: super (NodeListener.class, l);
0767: }
0768:
0769: /** Delegates to the original listener.
0770: */
0771: public void childrenAdded(NodeMemberEvent ev) {
0772: NodeListener l = (NodeListener) super .get(ev);
0773:
0774: if (l != null) {
0775: l.childrenAdded(ev);
0776: }
0777: }
0778:
0779: /** Delegates to the original listener.
0780: */
0781: public void childrenRemoved(NodeMemberEvent ev) {
0782: NodeListener l = (NodeListener) super .get(ev);
0783:
0784: if (l != null) {
0785: l.childrenRemoved(ev);
0786: }
0787: }
0788:
0789: /** Delegates to the original listener.
0790: */
0791: public void childrenReordered(NodeReorderEvent ev) {
0792: NodeListener l = (NodeListener) super .get(ev);
0793:
0794: if (l != null) {
0795: l.childrenReordered(ev);
0796: }
0797: }
0798:
0799: /** Delegates to the original listener.
0800: */
0801: public void nodeDestroyed(NodeEvent ev) {
0802: NodeListener l = (NodeListener) super .get(ev);
0803:
0804: if (l != null) {
0805: l.nodeDestroyed(ev);
0806: }
0807: }
0808:
0809: /** Method name to use for removing the listener.
0810: * @return name of method of the source object that should be used
0811: * to remove the listener from listening on source of events
0812: */
0813: protected String removeMethodName() {
0814: return "removeNodeListener"; // NOI18N
0815: }
0816: }
0817:
0818: /** Weak version of focus listener.
0819: * This class if final only for performance reasons,
0820: * can be happily unfinaled if desired.
0821: * @deprecated use appropriate method instead
0822: */
0823: public static final class Focus extends WeakListener implements
0824: FocusListener {
0825: /** Constructor.
0826: * @param l listener to delegate to
0827: */
0828: public Focus(FocusListener l) {
0829: super (FocusListener.class, l);
0830: }
0831:
0832: /** Delegates to the original listener.
0833: */
0834: public void focusGained(FocusEvent ev) {
0835: FocusListener l = (FocusListener) super .get(ev);
0836:
0837: if (l != null) {
0838: l.focusGained(ev);
0839: }
0840: }
0841:
0842: /** Delegates to the original listener.
0843: */
0844: public void focusLost(FocusEvent ev) {
0845: FocusListener l = (FocusListener) super .get(ev);
0846:
0847: if (l != null) {
0848: l.focusLost(ev);
0849: }
0850: }
0851:
0852: /** Method name to use for removing the listener.
0853: * @return name of method of the source object that should be used
0854: * to remove the listener from listening on source of events
0855: */
0856: protected String removeMethodName() {
0857: return "removeFocusListener"; // NOI18N
0858: }
0859: }
0860:
0861: /** Proxy interface that delegates to listeners.
0862: */
0863: private static class ProxyListener extends WeakListener implements
0864: InvocationHandler {
0865: /** Equals method */
0866: private static Method equalsMth;
0867:
0868: /** proxy generated for this listener */
0869: public final Object proxy;
0870:
0871: /** @param listener listener to delegate to
0872: */
0873: public ProxyListener(Class c, java.util.EventListener listener) {
0874: super (c, listener);
0875:
0876: proxy = Proxy.newProxyInstance(c.getClassLoader(),
0877: new Class[] { c }, this );
0878: }
0879:
0880: /** */
0881: private static Method getEquals() {
0882: if (equalsMth == null) {
0883: try {
0884: equalsMth = Object.class.getMethod("equals",
0885: new Class[] { Object.class }); // NOI18N
0886: } catch (NoSuchMethodException e) {
0887: e.printStackTrace();
0888: }
0889: }
0890:
0891: return equalsMth;
0892: }
0893:
0894: public java.lang.Object invoke(Object proxy, Method method,
0895: Object[] args) throws Throwable {
0896: if (method.getDeclaringClass() == Object.class) {
0897: // a method from object => call it on your self
0898: if (method == getEquals()) {
0899: boolean ret = equals(args[0]);
0900:
0901: return (ret ? Boolean.TRUE : Boolean.FALSE);
0902: }
0903:
0904: return method.invoke(this , args);
0905: }
0906:
0907: // listeners method
0908: EventObject ev = (args[0] instanceof EventObject) ? (EventObject) args[0]
0909: : null;
0910:
0911: Object listener = super .get(ev);
0912:
0913: if (listener != null) {
0914: return method.invoke(listener, args);
0915: } else {
0916: return null;
0917: }
0918: }
0919:
0920: /** Remove method name is composed from the name of the listener.
0921: */
0922: protected String removeMethodName() {
0923: String name = listenerClass.getName();
0924:
0925: // strip package name
0926: int dot = name.lastIndexOf('.');
0927: name = name.substring(dot + 1);
0928:
0929: // in case of inner interfaces/classes we also strip the outer
0930: // class' name
0931: int i = name.lastIndexOf('$'); // NOI18N
0932:
0933: if (i >= 0) {
0934: name = name.substring(i + 1);
0935: }
0936:
0937: return "remove".concat(name); // NOI18N
0938: }
0939:
0940: /** To string prints class.
0941: */
0942: public String toString() {
0943: return super .toString() + "[" + listenerClass + "]"; // NOI18N
0944: }
0945:
0946: /** Equal is extended to equal also with proxy object.
0947: */
0948: public boolean equals(Object obj) {
0949: return (proxy == obj) || (this == obj);
0950: }
0951:
0952: Object getImplementator() {
0953: return proxy;
0954: }
0955: }
0956:
0957: /** Reference that also holds ref to WeakListener.
0958: */
0959: private static final class ListenerReference extends WeakReference
0960: implements Runnable {
0961: private static Class lastClass;
0962: private static String lastMethodName;
0963: private static Method lastRemove;
0964: private static Object LOCK = new Object();
0965: final WeakListener weakListener;
0966:
0967: public ListenerReference(Object ref, WeakListener weakListener) {
0968: super (ref, Utilities.activeReferenceQueue());
0969: this .weakListener = weakListener;
0970: }
0971:
0972: public void run() {
0973: ListenerReference lr = this ;
0974:
0975: // prepare array for passing arguments to getMethod/invoke
0976: Object[] params = new Object[1];
0977: Class[] types = new Class[1];
0978: Object src = null; // On whom we're listening
0979: Method remove = null;
0980:
0981: WeakListener ref = lr.weakListener;
0982:
0983: if ((ref.source == null)
0984: || ((src = ref.source.get()) == null)) {
0985: return;
0986: }
0987:
0988: Class methodClass = src.getClass();
0989: String methodName = ref.removeMethodName();
0990:
0991: synchronized (LOCK) {
0992: if ((lastClass == methodClass)
0993: && (lastMethodName == methodName)
0994: && (lastRemove != null)) {
0995: remove = lastRemove;
0996: }
0997: }
0998:
0999: // get the remove method or use the last one
1000: if (remove == null) {
1001: types[0] = ref.listenerClass;
1002: remove = getRemoveMethod(methodClass, methodName,
1003: types[0]);
1004:
1005: if (remove == null) {
1006: Logger.getAnonymousLogger().warning(
1007: "Can't remove "
1008: + ref.listenerClass.getName() + //NOI18N
1009: " using method " + methodName + //NOI18N
1010: " from " + src); //NOI18N
1011:
1012: return;
1013: } else {
1014: synchronized (LOCK) {
1015: lastClass = methodClass;
1016: lastMethodName = methodName;
1017: lastRemove = remove;
1018: }
1019: }
1020: }
1021:
1022: params[0] = ref.getImplementator(); // Whom to unregister
1023:
1024: try {
1025: remove.invoke(src, params);
1026: } catch (Exception ex) { // from invoke(), should not happen
1027: Exceptions.attachLocalizedMessage(ex,
1028: "Problem encountered while calling "
1029: + methodClass + "." + methodName
1030: + "(...) on " + src); // NOI18N
1031: Logger.getAnonymousLogger()
1032: .log(Level.WARNING, null, ex);
1033: }
1034: }
1035: }
1036: }
|