KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > xam > AbstractComponent


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.xml.xam;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.List JavaDoc;
28
29 /**
30  *
31  * @author rico
32  * @author Vidhya Narayanan
33  * @author Nam Nguyen
34  * @author Chris Webster
35  */

36 public abstract class AbstractComponent<C extends Component<C>> implements Component<C> {
37     private C parent;
38     private List JavaDoc<C> children = null;
39     private AbstractModel model;
40     
41     public AbstractComponent(AbstractModel model) {
42         this.model = model;
43     }
44     
45     protected abstract void appendChildQuietly(C component, List JavaDoc<C> children);
46     
47     protected abstract void insertAtIndexQuietly(C newComponent, List JavaDoc<C> children, int index);
48     
49     protected abstract void removeChildQuietly(C component, List JavaDoc<C> children);
50
51     protected abstract void populateChildren(List JavaDoc<C> children);
52     
53     public final void removePropertyChangeListener(java.beans.PropertyChangeListener JavaDoc pcl) {
54         model.removePropertyChangeListener(pcl);
55     }
56     
57     public final void addPropertyChangeListener(java.beans.PropertyChangeListener JavaDoc pcl) {
58         model.addPropertyChangeListener(new DelegateListener(pcl));
59     }
60     
61     // Convenient method because WeakListener implmentation uses event source to unregister.
62
public void removeComponentListener(ComponentListener cl) {
63         if (getModel() != null) {
64             getModel().removeComponentListener(cl);
65         }
66     }
67     
68     public synchronized C getParent() {
69         return parent;
70     }
71     
72     protected synchronized void setParent(C component) {
73         parent = component;
74     }
75     
76     protected synchronized void setModel(AbstractModel aModel) {
77         model = aModel;
78         if (isChildrenInitialized()) {
79             for (C component : getChildren()) {
80                 ((AbstractComponent)component).setModel(aModel);
81             }
82         }
83     }
84     
85     private void _appendChildQuietly(C component, List JavaDoc<C> children) {
86         if (component.getModel() == null) {
87             throw new IllegalStateException JavaDoc("Cannot add a removed component, should use a fresh or a copy component.");
88         }
89         appendChildQuietly(component, children);
90         ((AbstractComponent)component).setModel(getModel());
91         ((AbstractComponent)component).setParent(this);
92     }
93
94     private void _insertAtIndexQuietly(C component, List JavaDoc<C> children, int index) {
95         if (component.getModel() == null) {
96             throw new IllegalStateException JavaDoc("Cannot add a removed component, should use a fresh or a copy component.");
97         }
98         insertAtIndexQuietly(component, children, index);
99         ((AbstractComponent)component).setModel(getModel());
100         ((AbstractComponent)component).setParent(this);
101     }
102
103     private void _removeChildQuietly(C component, List JavaDoc<C> children) {
104         removeChildQuietly(component, children);
105         ((AbstractComponent)component).setModel(null);
106         ((AbstractComponent)component).setParent(null);
107     }
108     
109     /**
110      * @return the contained elements, this is the model element
111      * representations of the DOM children. The returned list is unmodifiable.
112      */

113     public List JavaDoc<C> getChildren() {
114         _getChildren();
115         return Collections.unmodifiableList(children);
116     }
117     
118     /**
119      * This method provides the ability to detect whether calling getChildren()
120      * will trigger population of children. This can be used for meta models
121      * to determine whether cleanup below a set of children is necessary.
122      */

123     protected final boolean isChildrenInitialized() {
124     return children != null;
125     }
126     
127     private synchronized List JavaDoc<C> _getChildren() {
128         if (!isChildrenInitialized()) {
129             children = new ArrayList JavaDoc<C>();
130             populateChildren(children);
131             for (C child : children) {
132                 ((AbstractComponent)child).setParent(this);
133             }
134         }
135         return children;
136     }
137     
138     /**
139      * @return the contained elements, this is the model
140      * element representations of the DOM children.
141      *
142      * @param type Interested children type to
143      * return.
144      */

145     public <T extends C>List JavaDoc<T> getChildren(Class JavaDoc<T> type) {
146         List JavaDoc<T> result = new ArrayList JavaDoc<T>(_getChildren().size());
147         for (C child : _getChildren()) {
148             if (type.isAssignableFrom(child.getClass())) {
149                 result.add(type.cast(child));
150             }
151         }
152         return Collections.unmodifiableList(result);
153     }
154     
155     /**
156      * @return the contained elements, this is the model
157      * element representations of the DOM children.
158      *
159      * @param typeList Collection that accepts the interested types and filters
160      * the return list of Children.
161      */

162     public List JavaDoc<C> getChildren(Collection JavaDoc<Class JavaDoc<? extends C>> typeList) {
163         List JavaDoc<C> comps = new ArrayList JavaDoc<C>();
164         // createChildren is not necessary because this method delegates
165
// to another getChildren which ensures initialization
166
for(Class JavaDoc<? extends C> type : typeList) {
167             comps.addAll(getChildren(type));
168         }
169         return Collections.unmodifiableList(comps);
170     }
171     
172     public synchronized AbstractModel getModel() {
173         return model;
174     }
175     
176     protected void verifyWrite() {
177         getModel().validateWrite();
178     }
179     
180     protected void firePropertyChange(String JavaDoc propName, Object JavaDoc oldValue, Object JavaDoc newValue) {
181         PropertyChangeEvent JavaDoc event =
182                 new PropertyChangeEvent JavaDoc(this,propName,oldValue,newValue);
183         getModel().firePropertyChangeEvent(event);
184     }
185     
186     protected void fireValueChanged() {
187         getModel().fireComponentChangedEvent(new ComponentEvent(this,
188                 ComponentEvent.EventType.VALUE_CHANGED));
189     }
190     
191     protected void fireChildRemoved() {
192         getModel().fireComponentChangedEvent(new ComponentEvent(this,
193                 ComponentEvent.EventType.CHILD_REMOVED));
194     }
195     
196     protected void fireChildAdded() {
197         getModel().fireComponentChangedEvent(new ComponentEvent(this,
198                 ComponentEvent.EventType.CHILD_ADDED));
199     }
200     
201     protected <T extends C> T getChild(Class JavaDoc<T> type) {
202         List JavaDoc<T> result = getChildren(type);
203         T value = null;
204         if (!result.isEmpty()) {
205             value = result.get(0);
206         }
207         return value;
208     }
209     
210     /**
211      * Adds a element before all other children whose types are in the typeList Collection.
212      */

213     protected synchronized void addBefore(String JavaDoc propertyName, C component,
214             Collection JavaDoc<Class JavaDoc<? extends C>> typeList){
215         verifyWrite();
216         checkNullOrDuplicateChild(component);
217         addChild(propertyName, component, typeList, true);
218         firePropertyChange(propertyName, null, component);
219         fireChildAdded();
220     }
221     
222     /**
223      * Adds a element after all other children whose types are in the typeList Collection.
224      */

225     protected synchronized void addAfter(String JavaDoc propertyName, C component,
226             Collection JavaDoc<Class JavaDoc<? extends C>> typeList){
227         verifyWrite();
228         checkNullOrDuplicateChild(component);
229         addChild(propertyName, component, typeList, false);
230         firePropertyChange(propertyName, null, component);
231         fireChildAdded();
232     }
233     
234     /**
235      * Adds the New Element in the DOM model.
236      *
237      * @param component The element that needs to be set
238      * @param typeList The collection list that contains the class names
239      * of types of children
240      * @param before boolean to indicate to add before/after the typelist
241      */

242     private void addChild(String JavaDoc propertyName, C component,
243             Collection JavaDoc<Class JavaDoc<? extends C>> typeList, boolean before) {
244         assert(component != null);
245         
246         if (typeList == null) {
247             throw new IllegalArgumentException JavaDoc("typeList == null"); //NOI18N
248
}
249         
250         List JavaDoc<? extends C> childnodes = getChildren();
251         if (typeList.isEmpty() || childnodes.isEmpty()) {
252             _appendChildQuietly(component, _getChildren());
253         } else {
254             int lastIndex = before ? childnodes.size() : -1;
255             for (Class JavaDoc<? extends C> type : typeList) {
256                 for (C child : childnodes) {
257                     if (type.isAssignableFrom(child.getClass())) {
258                         int i = childnodes.indexOf(child);
259                         if (!before) {
260                             if (i > lastIndex) lastIndex = i;
261                         } else {
262                             if (i < lastIndex) lastIndex = i;
263                         }
264                     }
265                 }
266             }
267             if (!before) {
268                 lastIndex++;
269                 for (int i=lastIndex ; i<childnodes.size() ; i++) {
270                     if (childnodes.get(i).getClass().equals(component.getClass())) {
271                         lastIndex++;
272                     } else {
273                         break;
274                     }
275                 }
276             }
277             _insertAtIndexQuietly(component, _getChildren(), lastIndex);
278         }
279     }
280
281     protected void checkNullOrDuplicateChild(C child) {
282         if (child == null) {
283             throw new IllegalArgumentException JavaDoc("child == null"); //NOI18N
284
}
285         if (_getChildren().contains(child)) {
286             throw new IllegalArgumentException JavaDoc("child already in children list"); //NOI18N
287
}
288     }
289     
290     protected synchronized void appendChild(String JavaDoc propertyName, C child) {
291         verifyWrite();
292         checkNullOrDuplicateChild(child);
293         _appendChildQuietly(child, _getChildren());
294         firePropertyChange(propertyName, null, child);
295         fireChildAdded();
296     }
297     
298     /**
299      * Inserts a Component child at the specified index relative to
300      * the provided type. This method is expected to be used only in
301      * sequence.
302      * @param propertyName to fire event on
303      * @param component to insert
304      * @param index relative to first instance of type, index = firstpos
305      * @param type which index should be relative to
306      */

307     protected synchronized void insertAtIndex(String JavaDoc propertyName,
308             C component, int index,
309             Class JavaDoc<? extends C> type) {
310         verifyWrite();
311         checkNullOrDuplicateChild(component);
312         if (type != null) {
313             int trueIndex = 0;
314             for (C child: getChildren()) {
315                 if (type.isAssignableFrom(child.getClass())) {
316                     break;
317                 }
318                 trueIndex++;
319             }
320             index += trueIndex;
321         }
322         _insertAtIndexQuietly(component, _getChildren(), index);
323         firePropertyChange(propertyName, null, component);
324         fireChildAdded();
325     }
326     
327     public synchronized void insertAtIndex(String JavaDoc propertyName, C component, int index) {
328         insertAtIndex(propertyName, component, index, null);
329     }
330     
331     public synchronized void removeChild(String JavaDoc propertyName, C component) {
332         verifyWrite();
333         if (component == null) {
334             throw new IllegalArgumentException JavaDoc("component == null"); //NOI18N
335
}
336         if (! _getChildren().contains(component)) {
337             throw new IllegalArgumentException JavaDoc("component to be deleted is not a child"); //NOI18N
338
}
339         _removeChildQuietly(component, _getChildren());
340         firePropertyChange(propertyName, component, null);
341         fireChildRemoved();
342     }
343     
344     /**
345      * When a child element is set using this method:
346      * (1) All children that are of the same or derived type as classType are removed.
347      * (2) newEl is added as a child after any children that are of the same
348      * type as any of the types listed in typeList
349      * @param classType Class of the Component that is being added as a child
350      * @param propertyName Property name used for firing events
351      * @param newComponent Component that is being added as a child
352      * @param typeList Collection of java.lang.Class-es. newEl will be added as
353      * a child after any children whose types belong to any listed in this. An
354      * empty collection will append the child
355      */

356     protected void setChild(Class JavaDoc<? extends C> classType, String JavaDoc propertyName,
357             C newComponent, Collection JavaDoc<Class JavaDoc<? extends C>> typeList){
358         setChildAfter(classType, propertyName, newComponent, typeList);
359     }
360     
361     protected void setChildAfter(Class JavaDoc<? extends C> classType, String JavaDoc propertyName,
362             C newComponent, Collection JavaDoc<Class JavaDoc<? extends C>> typeList){
363         setChild(classType, propertyName, newComponent, typeList, false);
364     }
365     
366     protected void setChildBefore(Class JavaDoc<? extends C> classType, String JavaDoc propertyName,
367             C newComponent, Collection JavaDoc<Class JavaDoc<? extends C>> typeList){
368         setChild(classType, propertyName, newComponent, typeList, true);
369     }
370     
371     protected synchronized void setChild(Class JavaDoc<? extends C> classType, String JavaDoc propertyName,
372             C newComponent, Collection JavaDoc<Class JavaDoc<? extends C>> typeList, boolean before){
373         //remove all children of type classType
374
verifyWrite();
375         List JavaDoc<? extends C> childComponents = getChildren(classType);
376         if (childComponents.contains(newComponent)) {
377             return; // no change
378
}
379         C old = childComponents.isEmpty() ? null : childComponents.get(childComponents.size()-1);
380         for (C child : childComponents) {
381             _removeChildQuietly(child, _getChildren());
382             fireChildRemoved();
383         }
384         if (newComponent != null) {
385             addChild(propertyName, newComponent, typeList, before);
386             fireChildAdded();
387         }
388         
389         firePropertyChange(propertyName, old, newComponent);
390     }
391     
392     private class DelegateListener implements PropertyChangeListener JavaDoc {
393         private final PropertyChangeListener JavaDoc delegate;
394         
395         public DelegateListener(PropertyChangeListener JavaDoc pcl) {
396             delegate = pcl;
397         }
398         
399         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
400             if (evt.getSource() == AbstractComponent.this) {
401                 delegate.propertyChange(evt);
402             }
403         }
404         
405         public boolean equals(Object JavaDoc obj) {
406             return delegate == obj;
407         }
408         
409         public int hashCode() {
410             return delegate.hashCode();
411         }
412     }
413
414     
415     /**
416      * Default implementation, subclass need to override if needed.
417      */

418     public boolean canPaste(Component child) {
419         return true;
420     }
421 }
422
423
Popular Tags