KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > explorer > propertysheet > PropertySetModelImpl


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  * PropertySetModel.java
21  *
22  * Created on December 28, 2002, 6:57 PM
23  */

24 package org.openide.explorer.propertysheet;
25
26 import org.openide.nodes.Node;
27 import org.openide.nodes.Node.Property;
28 import org.openide.nodes.Node.PropertySet;
29 import org.openide.util.NbBundle;
30
31 import java.beans.*;
32
33 import java.util.*;
34
35 import javax.swing.SwingUtilities JavaDoc;
36 import javax.swing.event.*;
37
38
39 /** A model defining the expansion state for property sets, and
40  * thus the index order of properties. The model exposes both
41  * properties and property sets. For cases where only a subset of
42  * the property sets available on the node should be displayed in
43  * a table, this class can be subclassed to do such filtering.
44  * <P><B>Implementation note:</B>
45  * The current implementation is fairly naive, in order to get the
46  * rest of the new PropertySheet code working - it builds a list of
47  * the properties and property sets it will expose, and rebuilds it
48  * on a change. This should eventually be replaced by a better
49  * performing implementation.
50  *
51   * @author Tim Boudreau
52  */

53 class PropertySetModelImpl implements PropertySetModel, Runnable JavaDoc {
54     private static boolean filterHiddenProperties = !Boolean.getBoolean("netbeans.ps.showHiddenProperties"); //NOI18N
55

56     /** Retains the persistent list of sets the user has explicitly
57      * closed, so they remain closed for other similar nodes
58      */

59     static Set<String JavaDoc> closedSets = new HashSet<String JavaDoc>(5);
60
61     static {
62         closedSets.addAll(Arrays.asList(PropUtils.getSavedClosedSetNames()));
63     }
64
65     private boolean[] expanded = null;
66     private List<FeatureDescriptor> fds = new ArrayList<FeatureDescriptor>();
67     private Comparator<Node.Property> comparator = null;
68     private transient List<PropertySetModelListener> listenerList;
69     private PropertySet[] sets = null;
70     private transient int setCount = 0;
71
72     /** A single event that can be reused. */
73     private transient PropertySetModelEvent event = null;
74
75     public PropertySetModelImpl() {
76     }
77
78     public PropertySetModelImpl(PropertySet[] ps) {
79         if (ps == null) {
80             ps = new PropertySet[0];
81         }
82
83         setPropertySets(ps);
84     }
85
86     public int getCount() {
87         return fds.size();
88     }
89
90     public FeatureDescriptor getFeatureDescriptor(int index) {
91         if (index == -1) {
92             return null;
93         }
94
95         return (FeatureDescriptor) fds.get(index);
96     }
97
98     public int indexOf(FeatureDescriptor fd) {
99         return fds.indexOf(fd);
100     }
101
102     public boolean isProperty(int index) {
103         return getFeatureDescriptor(index) instanceof Node.Property;
104     }
105
106     public void setComparator(Comparator<Node.Property> c) {
107         if (c != comparator) {
108             firePendingChange(true);
109             comparator = c;
110             fds.clear();
111             init();
112             fireChange(true);
113         }
114     }
115
116     public void setPropertySets(PropertySet[] sets) {
117         setCount = (sets == null) ? 0 : sets.length;
118
119         if (sets == null) {
120             sets = new PropertySet[0];
121         }
122
123         if ((setCount == 0) && !SwingUtilities.isEventDispatchThread()) {
124             //Allow thread safe access for node destroyed events to
125
this.sets = new PropertySet[0];
126             resetArray(sets);
127             fds.clear();
128             SwingUtilities.invokeLater(this);
129
130             return;
131         }
132
133         firePendingChange(false);
134         this.sets = sets;
135         resetArray(sets);
136         init();
137         run();
138     }
139
140     public void run() {
141         fireChange(false);
142     }
143
144     private void init() {
145         fds.clear();
146
147         if (comparator == null) {
148             initExpandable();
149         } else {
150             initPlain();
151         }
152     }
153
154     private void initPlain() {
155         if (sets == null) {
156             return;
157         }
158
159         int pcount = 0;
160
161         for (int i = 0; i < sets.length; i++) {
162             Property[] p = sets[i].getProperties();
163
164             if (p == null) {
165                 throw new NullPointerException JavaDoc("Null is not a legal return" + " value for PropertySet.getProperties()");
166             }
167
168             pcount += p.length;
169         }
170
171         Property[] props = new Property[pcount];
172         int l = 0;
173
174         for (int i = 0; i < sets.length; i++) {
175             Property[] p = sets[i].getProperties();
176             System.arraycopy(p, 0, props, l, p.length);
177             l += p.length;
178         }
179
180         Arrays.sort(props, comparator);
181         fds.addAll(propsToList(props));
182     }
183
184     private void initExpandable() {
185         if ((sets == null) || (sets.length == 0)) {
186             return;
187         }
188
189         Property[] p;
190
191         for (int i = 0; i < sets.length; i++) {
192             //Show the set expandable only if it's not the default set
193
if (PropUtils.hideSingleExpansion) {
194                 if (
195                     (sets.length > 1) ||
196                         ((sets.length == 1) &&
197                         (!NbBundle.getMessage(PropertySetModelImpl.class, "CTL_Properties").equals(
198                             sets[0].getDisplayName()
199                         )))
200                 ) { //NOI18N
201
fds.add(sets[i]);
202                 }
203             } else {
204                 if (!PropertySheet.forceTabs) {
205                     fds.add(sets[i]);
206                 }
207             }
208
209             if (expanded[i]) {
210                 p = sets[i].getProperties();
211
212                 if (p == null) {
213                     throw new NullPointerException JavaDoc(
214                         "Null is not a legal " + "return value for PropertySet.getProperties()"
215                     );
216                 }
217
218                 if (p.length > 0) {
219                     fds.addAll(propsToList(p));
220                 } else {
221                     fds.remove(sets[i]);
222                 }
223             }
224         }
225     }
226
227     private List<Property> propsToList(Property[] p) {
228         List<Property> result;
229
230         if (filterHiddenProperties) {
231             result = new ArrayList<Property>();
232
233             for (int i = 0; i < p.length; i++) {
234                 if (!p[i].isHidden()) {
235                     result.add(p[i]);
236                 }
237             }
238         } else {
239             result = Arrays.asList(p);
240         }
241
242         return result;
243     }
244
245     private void resetArray(PropertySet[] sets) {
246         int size = sets.length;
247
248         if ((expanded == null) || (expanded.length < size)) {
249             expanded = new boolean[size];
250         }
251
252         for (int i = 0; i < sets.length; i++) {
253             expanded[i] = !closedSets.contains(sets[i].getDisplayName());
254         }
255     }
256
257     private int lookupSet(FeatureDescriptor fd) {
258         if (sets != null) {
259             List l = Arrays.asList(sets);
260
261             return l.indexOf(fd);
262         } else {
263             return -1;
264         }
265     }
266
267     public boolean isExpanded(FeatureDescriptor set) {
268         int index = lookupSet(set);
269
270         if (index == -1) {
271             return false;
272         }
273
274         return expanded[index];
275     }
276
277     public void toggleExpanded(int index) {
278         FeatureDescriptor fd = getFeatureDescriptor(index);
279
280         if (fd instanceof Property) {
281             throw new IllegalArgumentException JavaDoc("Cannot expand a property."); //NOI18N
282
}
283
284         int setIndex = lookupSet(fd);
285         int eventType = expanded[setIndex] ? PropertySetModelEvent.TYPE_INSERT : PropertySetModelEvent.TYPE_REMOVE;
286         List <? extends FeatureDescriptor> props = propsToList(sets[setIndex].getProperties());
287         int len = props.size();
288
289         expanded[setIndex] = !expanded[setIndex];
290
291         firePendingChange(eventType, index + 1, index + len, false);
292
293         if (!expanded[setIndex]) {
294             closedSets.add(fd.getDisplayName());
295         } else {
296             closedSets.remove(fd.getDisplayName());
297         }
298
299         if (expanded[setIndex]) {
300             fds.addAll(index + 1, props);
301         } else {
302             for (int i = index + len; i > index; i--) {
303                 fds.remove(i);
304             }
305         }
306
307         fireChange(eventType, index + 1, index + len);
308         PropUtils.putSavedClosedSetNames(closedSets);
309     }
310
311     public final void addPropertySetModelListener(PropertySetModelListener listener) {
312         if (listenerList == null) {
313             listenerList = new java.util.ArrayList JavaDoc<PropertySetModelListener>();
314         }
315
316         listenerList.add(listener);
317     }
318
319     public final void removePropertySetModelListener(PropertySetModelListener listener) {
320         if (listenerList != null) {
321             listenerList.remove(listener);
322         }
323     }
324
325     /** Getter which lazily instantiates the single event that
326      * will be used for al model events. */

327     private PropertySetModelEvent getEvent() {
328         if (event == null) {
329             event = new PropertySetModelEvent(this);
330         }
331
332         return event;
333     }
334
335     /** Fire a change of type
336      * <code>PropertySetModelEvent.TYPE_WHOLESALE_CHANGE</code>. */

337     private final void firePendingChange(int type, int start, int end, boolean reordering) {
338         if (listenerList == null) {
339             return;
340         }
341
342         Iterator i = listenerList.iterator();
343         PropertySetModelListener curr;
344         getEvent().type = PropertySetModelEvent.TYPE_WHOLESALE_CHANGE;
345         event.start = start;
346         event.end = end;
347         event.type = type;
348         event.reordering = reordering;
349
350         while (i.hasNext()) {
351             curr = (PropertySetModelListener) i.next();
352             curr.pendingChange(event);
353         }
354     }
355
356     /** Fire a change of type
357      * <code>PropertySetModelEvent.TYPE_WHOLESALE_CHANGE</code>. */

358     private final void fireChange(boolean reordering) {
359         if (listenerList == null) {
360             return;
361         }
362
363         Iterator i = listenerList.iterator();
364         PropertySetModelListener curr;
365         getEvent().type = PropertySetModelEvent.TYPE_WHOLESALE_CHANGE;
366         event.reordering = reordering;
367
368         while (i.hasNext()) {
369             curr = (PropertySetModelListener) i.next();
370             curr.wholesaleChange(event);
371         }
372     }
373
374     /** Fire a change of type
375      * <code>PropertySetModelEvent.TYPE_WHOLESALE_CHANGE</code>. */

376     private final void firePendingChange(boolean reordering) {
377         if (listenerList == null) {
378             return;
379         }
380
381         Iterator i = listenerList.iterator();
382         PropertySetModelListener curr;
383         getEvent().type = PropertySetModelEvent.TYPE_WHOLESALE_CHANGE;
384         event.reordering = reordering;
385
386         while (i.hasNext()) {
387             curr = (PropertySetModelListener) i.next();
388             curr.pendingChange(event);
389         }
390     }
391
392     /** Fire a change with the given parameters.
393      *@param type The integer event type, as defined in <code>PropertySetModelEvent</code>.
394      *@param start The first affected row (note that when expanding, the first affected
395      *row is the first one <strong>following</strong> the row representing the property
396      *set that was expanded)
397      *@param end The last affected row. */

398     private final void fireChange(int type, int start, int end) {
399         if (listenerList == null) {
400             return;
401         }
402
403         getEvent().start = start;
404         event.end = end;
405         event.type = type;
406         event.reordering = false;
407
408         Iterator i = listenerList.iterator();
409         PropertySetModelListener curr;
410
411         while (i.hasNext()) {
412             curr = (PropertySetModelListener) i.next();
413             curr.boundedChange(event);
414         }
415     }
416
417     public Comparator getComparator() {
418         return comparator;
419     }
420
421     public int getSetCount() {
422         return setCount;
423     }
424 }
425
Popular Tags