1 /*
2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package javax.swing;
27 
28 
29 import javax.swing.event.*;
30 import java.awt.event.*;
31 
32 import java.awt.Component;
33 import java.awt.Container;
34 import java.awt.Window;
35 import java.beans.PropertyChangeListener;
36 import java.beans.PropertyChangeEvent;
37 
38 import java.io.Serializable;
39 
40 
41 /**
42  * @author Dave Moore
43  */
44 
45 @SuppressWarnings("serial")
46 class AncestorNotifier implements ComponentListener, PropertyChangeListener, Serializable
47 {
48     transient Component firstInvisibleAncestor;
49     EventListenerList listenerList = new EventListenerList();
50     JComponent root;
51 
AncestorNotifier(JComponent root)52     AncestorNotifier(JComponent root) {
53         this.root = root;
54         addListeners(root, true);
55     }
56 
addAncestorListener(AncestorListener l)57     void addAncestorListener(AncestorListener l) {
58         listenerList.add(AncestorListener.class, l);
59     }
60 
removeAncestorListener(AncestorListener l)61     void removeAncestorListener(AncestorListener l) {
62         listenerList.remove(AncestorListener.class, l);
63     }
64 
getAncestorListeners()65     AncestorListener[] getAncestorListeners() {
66         return listenerList.getListeners(AncestorListener.class);
67     }
68 
69     /**
70      * Notify all listeners that have registered interest for
71      * notification on this event type.  The event instance
72      * is lazily created using the parameters passed into
73      * the fire method.
74      * @see EventListenerList
75      */
fireAncestorAdded(JComponent source, int id, Container ancestor, Container ancestorParent)76     protected void fireAncestorAdded(JComponent source, int id, Container ancestor, Container ancestorParent) {
77         // Guaranteed to return a non-null array
78         Object[] listeners = listenerList.getListenerList();
79         // Process the listeners last to first, notifying
80         // those that are interested in this event
81         for (int i = listeners.length-2; i>=0; i-=2) {
82             if (listeners[i]==AncestorListener.class) {
83                 // Lazily create the event:
84                 AncestorEvent ancestorEvent =
85                     new AncestorEvent(source, id, ancestor, ancestorParent);
86                 ((AncestorListener)listeners[i+1]).ancestorAdded(ancestorEvent);
87             }
88         }
89     }
90 
91     /**
92      * Notify all listeners that have registered interest for
93      * notification on this event type.  The event instance
94      * is lazily created using the parameters passed into
95      * the fire method.
96      * @see EventListenerList
97      */
fireAncestorRemoved(JComponent source, int id, Container ancestor, Container ancestorParent)98     protected void fireAncestorRemoved(JComponent source, int id, Container ancestor, Container ancestorParent) {
99         // Guaranteed to return a non-null array
100         Object[] listeners = listenerList.getListenerList();
101         // Process the listeners last to first, notifying
102         // those that are interested in this event
103         for (int i = listeners.length-2; i>=0; i-=2) {
104             if (listeners[i]==AncestorListener.class) {
105                 // Lazily create the event:
106                 AncestorEvent ancestorEvent =
107                     new AncestorEvent(source, id, ancestor, ancestorParent);
108                 ((AncestorListener)listeners[i+1]).ancestorRemoved(ancestorEvent);
109             }
110         }
111     }
112     /**
113      * Notify all listeners that have registered interest for
114      * notification on this event type.  The event instance
115      * is lazily created using the parameters passed into
116      * the fire method.
117      * @see EventListenerList
118      */
fireAncestorMoved(JComponent source, int id, Container ancestor, Container ancestorParent)119     protected void fireAncestorMoved(JComponent source, int id, Container ancestor, Container ancestorParent) {
120         // Guaranteed to return a non-null array
121         Object[] listeners = listenerList.getListenerList();
122         // Process the listeners last to first, notifying
123         // those that are interested in this event
124         for (int i = listeners.length-2; i>=0; i-=2) {
125             if (listeners[i]==AncestorListener.class) {
126                 // Lazily create the event:
127                 AncestorEvent ancestorEvent =
128                     new AncestorEvent(source, id, ancestor, ancestorParent);
129                 ((AncestorListener)listeners[i+1]).ancestorMoved(ancestorEvent);
130             }
131         }
132     }
133 
removeAllListeners()134     void removeAllListeners() {
135         removeListeners(root);
136     }
137 
addListeners(Component ancestor, boolean addToFirst)138     void addListeners(Component ancestor, boolean addToFirst) {
139         Component a;
140 
141         firstInvisibleAncestor = null;
142         for (a = ancestor;
143              firstInvisibleAncestor == null;
144              a = a.getParent()) {
145             if (addToFirst || a != ancestor) {
146                 a.addComponentListener(this);
147 
148                 if (a instanceof JComponent) {
149                     JComponent jAncestor = (JComponent)a;
150 
151                     jAncestor.addPropertyChangeListener(this);
152                 }
153             }
154             if (!a.isVisible() || a.getParent() == null || a instanceof Window) {
155                 firstInvisibleAncestor = a;
156             }
157         }
158         if (firstInvisibleAncestor instanceof Window &&
159             firstInvisibleAncestor.isVisible()) {
160             firstInvisibleAncestor = null;
161         }
162     }
163 
removeListeners(Component ancestor)164     void removeListeners(Component ancestor) {
165         Component a;
166         for (a = ancestor; a != null; a = a.getParent()) {
167             a.removeComponentListener(this);
168             if (a instanceof JComponent) {
169                 JComponent jAncestor = (JComponent)a;
170                 jAncestor.removePropertyChangeListener(this);
171             }
172             if (a == firstInvisibleAncestor || a instanceof Window) {
173                 break;
174             }
175         }
176     }
177 
componentResized(ComponentEvent e)178     public void componentResized(ComponentEvent e) {}
179 
componentMoved(ComponentEvent e)180     public void componentMoved(ComponentEvent e) {
181         Component source = e.getComponent();
182 
183         fireAncestorMoved(root, AncestorEvent.ANCESTOR_MOVED,
184                           (Container)source, source.getParent());
185     }
186 
componentShown(ComponentEvent e)187     public void componentShown(ComponentEvent e) {
188         Component ancestor = e.getComponent();
189 
190         if (ancestor == firstInvisibleAncestor) {
191             addListeners(ancestor, false);
192             if (firstInvisibleAncestor == null) {
193                 fireAncestorAdded(root, AncestorEvent.ANCESTOR_ADDED,
194                                   (Container)ancestor, ancestor.getParent());
195             }
196         }
197     }
198 
componentHidden(ComponentEvent e)199     public void componentHidden(ComponentEvent e) {
200         Component ancestor = e.getComponent();
201         boolean needsNotify = firstInvisibleAncestor == null;
202 
203         if ( !(ancestor instanceof Window) ) {
204             removeListeners(ancestor.getParent());
205         }
206         firstInvisibleAncestor = ancestor;
207         if (needsNotify) {
208             fireAncestorRemoved(root, AncestorEvent.ANCESTOR_REMOVED,
209                                 (Container)ancestor, ancestor.getParent());
210         }
211     }
212 
propertyChange(PropertyChangeEvent evt)213     public void propertyChange(PropertyChangeEvent evt) {
214         String s = evt.getPropertyName();
215 
216         if (s!=null && (s.equals("parent") || s.equals("ancestor"))) {
217             JComponent component = (JComponent)evt.getSource();
218 
219             if (evt.getNewValue() != null) {
220                 if (component == firstInvisibleAncestor) {
221                     addListeners(component, false);
222                     if (firstInvisibleAncestor == null) {
223                         fireAncestorAdded(root, AncestorEvent.ANCESTOR_ADDED,
224                                           component, component.getParent());
225                     }
226                 }
227             } else {
228                 boolean needsNotify = firstInvisibleAncestor == null;
229                 Container oldParent = (Container)evt.getOldValue();
230 
231                 removeListeners(oldParent);
232                 firstInvisibleAncestor = component;
233                 if (needsNotify) {
234                     fireAncestorRemoved(root, AncestorEvent.ANCESTOR_REMOVED,
235                                         component, oldParent);
236                 }
237             }
238         }
239     }
240 }
241