KickJava   Java API By Example, From Geeks To Geeks.

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


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 package org.openide.explorer.propertysheet;
20
21 import org.openide.nodes.*;
22 import org.openide.util.*;
23
24 import java.beans.PropertyChangeEvent JavaDoc;
25
26 import java.util.*;
27 import java.util.logging.Level JavaDoc;
28 import java.util.logging.Logger JavaDoc;
29 import org.openide.nodes.Node.PropertySet;
30
31
32 /**
33  * A node used by PropertySheet to display common properties of
34  * more nodes.
35  * @author David Strupl
36  */

37 final class ProxyNode extends AbstractNode {
38     private static final int MAX_NAMES = 2;
39     private Node[] original;
40     private ArrayList<Node.PropertySet[]> originalPropertySets;
41     private NodeListener pcl;
42     String JavaDoc displayName = null;
43     private String JavaDoc shortDescription = null;
44
45     ProxyNode(Node[] original) {
46         super(Children.LEAF);
47         this.original = original;
48         pcl = new NodeAdapter() {
49                     public void propertyChange(PropertyChangeEvent JavaDoc pce) {
50                         String JavaDoc nm = pce.getPropertyName();
51
52                         if (PROP_COOKIE.equals(nm)) {
53                             fireCookieChange();
54                         } else if (PROP_DISPLAY_NAME.equals(nm)) {
55                             displayName = null;
56                             fireDisplayNameChange((String JavaDoc) pce.getOldValue(), getDisplayName());
57                         } else if (PROP_ICON.equals(nm)) {
58                             fireIconChange();
59                         } else if (PROP_OPENED_ICON.equals(nm)) {
60                             fireOpenedIconChange();
61                         } else if (PROP_NAME.equals(nm)) {
62                             fireNameChange((String JavaDoc) pce.getOldValue(), getName());
63                         } else if (PROP_PROPERTY_SETS.equals(nm)) {
64                             PropertySet[] old = getPropertySets();
65                             setSheet(createSheet());
66                             firePropertySetsChange(old, getPropertySets());
67                         } else if (PROP_SHORT_DESCRIPTION.equals(nm)) {
68                             fireShortDescriptionChange((String JavaDoc) pce.getOldValue(), getShortDescription());
69                         } else if (PROP_LEAF.equals(nm)) {
70                             //Not interesting to property sheet
71
} else if (PROP_PARENT_NODE.equals(nm)) {
72                             //Not interesting to property sheet
73
} else {
74                             Node.PropertySet[] pss = getPropertySets();
75                             boolean exists = false;
76
77                             for (int i = 0; i < pss.length && !exists; i++) {
78                                 Node.Property[] ps = pss[i].getProperties();
79
80                                 for (int j = 0; j < ps.length && !exists; j++) {
81                                     if (ps[j].getName().equals(nm)) {
82                                         exists = true;
83                                     }
84                                 }
85                             }
86                             if( exists ) {
87                                 firePropertyChange(pce.getPropertyName(), pce.getOldValue(), pce.getNewValue());
88                             }
89                         }
90                     }
91
92                     public void nodeDestroyed(NodeEvent ev) {
93                         int idx = Arrays.asList(ProxyNode.this.original).indexOf((Node) ev.getSource());
94
95                         if (idx != -1) {
96                             HashSet<Node> set = new HashSet<Node>(Arrays.asList(ProxyNode.this.original));
97                             set.remove(ev.getSource());
98                             ProxyNode.this.original = set.toArray(new Node[0]);
99
100                             if (set.size() == 0) {
101                                 ProxyNode.this.fireNodeDestroyed();
102                             }
103                         }
104                     }
105                 };
106
107         for (int i = 0; i < original.length; i++) {
108             original[i].addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(pcl, original[i]));
109             original[i].addNodeListener(
110                 org.openide.util.WeakListeners.create(NodeListener.class, pcl, original[i])
111             );
112         }
113     }
114
115     public HelpCtx getHelpCtx() {
116         for (int i = 0; i < original.length; i++) {
117             if (original[i].getHelpCtx() != HelpCtx.DEFAULT_HELP) {
118                 return original[i].getHelpCtx();
119             }
120         }
121
122         return HelpCtx.DEFAULT_HELP;
123     }
124
125     public Node cloneNode() {
126         return new ProxyNode(original);
127     }
128
129     protected Sheet createSheet() {
130         Sheet sheet = super.createSheet();
131         Sheet.Set[] computedSet = computePropertySets();
132
133         for (int i = 0; i < computedSet.length; i++) {
134             sheet.put(computedSet[i]);
135         }
136
137         return sheet;
138     }
139
140     /** */
141     Node[] getOriginalNodes() {
142         return original;
143     }
144
145     public String JavaDoc getDisplayName() {
146         if (displayName == null) {
147             //Issue 40821, don't display extremely long names, they make
148
//the property sheet huge if opened in a window
149
displayName = getConcatenatedName(MAX_NAMES);
150         }
151
152         return displayName;
153     }
154
155     private String JavaDoc getConcatenatedName(int limit) {
156         Node[] n = getOriginalNodes();
157         StringBuffer JavaDoc name = new StringBuffer JavaDoc();
158         String JavaDoc delim = NbBundle.getMessage(ProxyNode.class, "CTL_List_Delimiter"); //NOI18N
159

160         for (int i = 0; i < n.length; i++) {
161             name.append(n[i].getDisplayName());
162
163             if (i != (n.length - 1)) {
164                 name.append(delim);
165             }
166
167             if ((i >= limit) && (i != (n.length - 1))) {
168                 name.append(NbBundle.getMessage(ProxyNode.class, "MSG_ELLIPSIS"));
169
170                 break;
171             }
172         }
173
174         return name.toString();
175     }
176
177     public String JavaDoc getShortDescription() {
178         if (getOriginalNodes().length < MAX_NAMES) {
179             return NbBundle.getMessage(ProxyNode.class, "CTL_Multiple_Selection"); //NOI18N
180
} else {
181             if (shortDescription == null) {
182                 shortDescription = getConcatenatedName(Integer.MAX_VALUE);
183             }
184
185             return shortDescription;
186         }
187     }
188     
189     private ArrayList<Node.PropertySet[]> getOriginalPropertySets() {
190         if( null == originalPropertySets ) {
191             originalPropertySets = new ArrayList<Node.PropertySet[]>( original.length );
192             
193             for( int i=0; i<original.length; i++) {
194                 Node.PropertySet[] p = original[i].getPropertySets();
195                 originalPropertySets.add( p );
196             }
197             
198         }
199         return originalPropertySets;
200     }
201
202     /** Computes intersection of tabs and intersection
203      * of properties in those tabs.
204      */

205     private Sheet.Set[] computePropertySets() {
206         if (original.length > 0) {
207             Node.PropertySet[] firstSet = getOriginalPropertySets().get( 0 );
208             java.util.Set JavaDoc<Node.PropertySet> sheets = new HashSet<Node.PropertySet>(Arrays.asList(firstSet));
209
210             // compute intersection of all Node.PropertySets for given nodes
211
for (int i = 1; i < original.length; i++) {
212                 sheets.retainAll(new HashSet(Arrays.asList(getOriginalPropertySets().get(i))));
213             }
214
215             ArrayList<Sheet.Set> resultSheets = new ArrayList<Sheet.Set>(sheets.size());
216
217             // now for all resulting sheets take common properties
218
for (int i = 0; i < firstSet.length; i++) {
219                 if (!sheets.contains(firstSet[i]) || firstSet[i].isHidden()) {
220                     continue;
221                 }
222
223                 Node.PropertySet current = firstSet[i];
224
225                 // creates an empty Sheet.Set with same names as current
226
Sheet.Set res = new Sheet.Set();
227                 res.setName(current.getName());
228                 res.setDisplayName(current.getDisplayName());
229                 res.setShortDescription(current.getShortDescription());
230
231                 String JavaDoc tabName = (String JavaDoc) current.getValue("tabName"); //NOI18N
232

233                 if (tabName != null) {
234                     res.setValue("tabName", tabName); //NOI18N
235
}
236
237                 java.util.Set JavaDoc<Property> props = new HashSet<Property>(Arrays.asList(current.getProperties()));
238
239                 String JavaDoc propsHelpID = null;
240
241                 // intersection of properties from the corresponding tabs
242
for (int j = 0; j < original.length; j++) {
243                     Node.PropertySet[] p = getOriginalPropertySets().get(j);
244
245                     for (int k = 0; k < p.length; k++) {
246                         if (current.getName().equals(p[k].getName())) {
247                             props.retainAll(new HashSet<Property>(Arrays.asList(p[k].getProperties())));
248                         }
249                     }
250                 }
251
252                 Node.Property[] p = current.getProperties();
253
254                 for (int j = 0; j < p.length; j++) {
255                     if (!props.contains(p[j])) {
256                         continue;
257                     }
258
259                     if (p[j].isHidden()) {
260                         continue;
261                     }
262
263                     ProxyProperty pp = createProxyProperty(p[j].getName(), res.getName());
264                     res.put(pp);
265                 }
266
267                 resultSheets.add(res);
268             }
269
270             return resultSheets.toArray(new Sheet.Set[resultSheets.size()]);
271         }
272
273         return new Sheet.Set[0];
274     }
275
276     /** Finds properties in original with specified
277      * name in all tabs and constructs a ProxyProperty instance.
278      */

279     private ProxyProperty createProxyProperty(String JavaDoc propName, String JavaDoc setName) {
280         Node.Property[] arr = new Node.Property[original.length];
281
282         for (int i = 0; i < original.length; i++) {
283             Node.PropertySet[] p = getOriginalPropertySets().get(i);
284
285             for (int j = 0; j < p.length; j++) {
286                 if (p[j].getName().equals(setName)) {
287                     Node.Property[] np = p[j].getProperties();
288
289                     for (int k = 0; k < np.length; k++) {
290                         if (np[k].getName().equals(propName)) {
291                             arr[i] = np[k];
292                         }
293                     }
294                 }
295             }
296         }
297
298         return new ProxyProperty(arr);
299     }
300
301     /** Property delegating to an array of Properties. It either
302      * delegates to original[0] or applies changes to all
303      * original properties.
304      */

305     private static class ProxyProperty extends Node.Property {
306         private Node.Property[] original;
307
308         /** It sets name, displayName and short description.
309          * Remembers original.
310          */

311         public ProxyProperty(Node.Property[] original) {
312             super(original[0].getValueType());
313             this.original = original;
314             setName(original[0].getName());
315             setDisplayName(original[0].getDisplayName());
316             setShortDescription(original[0].getShortDescription());
317         }
318
319         /** Test whether the property is writable.Calls all delegates.
320          * If any of them returns false returns false, otherwise return true.
321          */

322         public boolean canWrite() {
323             for (int i = 0; i < original.length; i++) {
324                 if (!original[i].canWrite()) {
325                     return false;
326                 }
327             }
328
329             return true;
330         }
331
332         /** Test whether the property is readable. Calls all delegates.
333          * If any of them returns false returns false, otherwise return true.
334          * @return <CODE>true</CODE> if all delegates returned true
335          */

336         public boolean canRead() {
337             for (int i = 0; i < original.length; i++) {
338                 if (!original[i].canRead()) {
339                     return false;
340                 }
341             }
342
343             return true;
344         }
345
346         /** If all values are the same returns the value otherwise returns null.
347          * @return the value of the property
348          * @exception IllegalAccessException cannot access the called method
349          * @exception InvocationTargetException an exception during invocation
350          */

351         public Object JavaDoc getValue() throws IllegalAccessException JavaDoc, java.lang.reflect.InvocationTargetException JavaDoc {
352             Object JavaDoc o = original[0].getValue();
353
354             if (o == null) {
355                 return null;
356             }
357
358             for (int i = 0; i < original.length; i++) {
359                 if (!o.equals(original[i].getValue())) {
360                     throw new DifferentValuesException();
361                 }
362             }
363
364             return o;
365         }
366
367         /** Set the value. Calls setValue on all delegates.
368          * @param val the new value of the property
369          * @exception IllegalAccessException cannot access the called method
370          * @exception IllegalArgumentException wrong argument
371          * @exception InvocationTargetException an exception during invocation
372          */

373         public void setValue(Object JavaDoc val)
374         throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, java.lang.reflect.InvocationTargetException JavaDoc {
375             for (int i = 0; i < original.length; i++) {
376                 original[i].setValue(val);
377             }
378         }
379
380         /** Retrieve a named attribute with this feature.
381          * If all values are the same returns the value otherwise returns null.
382          * @param attributeName The locale-independent name of the attribute
383          * @return The value of the attribute. May be null if
384          * the attribute is unknown.
385          */

386         public Object JavaDoc getValue(String JavaDoc attributeName) {
387             Object JavaDoc o = original[0].getValue(attributeName);
388
389             if (Boolean.FALSE.equals(o)) {
390                 //issue 38319 - Boolean.FALSE should override even null -
391
//relevant primarily to the general hint canEditAsText,
392
//but makes sense generally
393
return o;
394             }
395
396             if (o == null) {
397                 return null;
398             }
399
400             for (int i = 1; i < original.length; i++) {
401                 if (Boolean.FALSE.equals(original[i])) {
402                     // issue 38319, see comment above
403
return original[i];
404                 }
405                 if (!o.equals(original[i].getValue(attributeName))) {
406                     // Optionally log it and return null
407
if (Boolean.getBoolean("netbeans.ps.logDifferentValues")) {
408                         Logger.getLogger(ProxyNode.class.getName()).log(Level.WARNING, null,
409                                           new DifferentValuesException("Different values in attribute " +
410                                                                        attributeName +
411                                                                        " for proxy property " +
412                                                                        getDisplayName() +
413                                                                        "(" +
414                                                                        this +
415                                                                        ") first value=" +
416                                                                        o +
417                                                                        " property " +
418                                                                        i + "(" +
419                                                                        original[i].getClass().getName() +
420                                                                        " returns " +
421                                                                        original[i].getValue(attributeName)));
422                     }
423                     return null;
424                 }
425             }
426
427             return o;
428         }
429
430         /** Associate a named attribute with this feature. Calls setValue on all delegates.
431          * @param attributeName The locale-independent name of the attribute
432          * @param value The value.
433          */

434         public void setValue(String JavaDoc attributeName, Object JavaDoc value) {
435             for (int i = 0; i < original.length; i++) {
436                 original[i].setValue(attributeName, value);
437             }
438         }
439
440         /**
441          * @returns property editor from the first delegate
442          */

443         public java.beans.PropertyEditor JavaDoc getPropertyEditor() {
444             return original[0].getPropertyEditor();
445         }
446
447         /** Test whether the property has a default value. If any of
448          * the delegates does not support default value returns false,
449          * otherwise returns true.
450          * @return <code>true</code> if all delegates returned true
451          */

452         public boolean supportsDefaultValue() {
453             for (int i = 0; i < original.length; i++) {
454                 if (!original[i].supportsDefaultValue()) {
455                     return false;
456                 }
457             }
458
459             return true;
460         }
461
462         /**
463          * Calls restoreDefaultValue on all delegates (original).
464          * @exception IllegalAccessException cannot access the called method
465          * @exception InvocationTargetException an exception during invocation
466          */

467         public void restoreDefaultValue() throws IllegalAccessException JavaDoc, java.lang.reflect.InvocationTargetException JavaDoc {
468             for (int i = 0; i < original.length; i++) {
469                 original[i].restoreDefaultValue();
470             }
471         }
472
473         public String JavaDoc toString() {
474             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Proxy property for: ");
475             sb.append(getDisplayName());
476             sb.append('[');
477
478             for (int i = 0; i < original.length; i++) {
479                 sb.append(original[i].getClass().getName());
480
481                 if (i < (original.length - 1)) {
482                     sb.append(',');
483                 }
484             }
485
486             sb.append(']');
487
488             return sb.toString();
489         }
490     }
491
492     /** We cannot return a single value when there are different values */
493     static class DifferentValuesException extends RuntimeException JavaDoc {
494         public DifferentValuesException() {
495             super();
496         }
497
498         public DifferentValuesException(String JavaDoc message) {
499             super(message);
500         }
501     }
502 }
503
Popular Tags