KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > palette > PaletteUtils


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.form.palette;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.lang.ref.WeakReference JavaDoc;
25 import java.util.*;
26 import java.text.MessageFormat JavaDoc;
27 import java.io.File JavaDoc;
28 import java.io.IOException JavaDoc;
29
30 import org.netbeans.spi.palette.*;
31 import org.openide.ErrorManager;
32 import org.openide.nodes.*;
33 import org.openide.loaders.DataFolder;
34 import org.openide.loaders.DataObject;
35 import org.openide.filesystems.*;
36 import org.openide.util.*;
37 import org.openide.util.lookup.*;
38
39 import org.netbeans.api.java.classpath.ClassPath;
40 import org.netbeans.api.project.libraries.Library;
41 import org.netbeans.api.project.libraries.LibraryManager;
42 import org.netbeans.api.project.Project;
43 import org.netbeans.api.project.FileOwnerQuery;
44
45 import org.netbeans.modules.form.project.ClassSource;
46
47 /**
48  * Class providing various useful methods for palette classes.
49  *
50  * @author Tomas Pavek, Jan Stola
51  */

52
53 public final class PaletteUtils {
54     
55     private static FileObject paletteFolder;
56     private static DataFolder paletteDataFolder;
57
58     private static FileObject context;
59     private static Map<Project, ProjectPaletteInfo> palettes = new WeakHashMap();
60
61     private static class ProjectPaletteInfo {
62         PaletteLookup paletteLookup;
63         ClassPathFilter paletteFilter;
64         List<PropertyChangeListener JavaDoc> paletteListeners;
65
66         PaletteController getPalette() {
67             return paletteLookup.lookup(PaletteController.class);
68         }
69     }
70
71     private PaletteUtils() {
72     }
73     
74     static String JavaDoc getItemComponentDescription(PaletteItem item) {
75         ClassSource classSource = item.getComponentClassSource();
76         
77         if (classSource == null || classSource.getCPRootCount() == 0) {
78             String JavaDoc className = classSource.getClassName();
79             if (className != null) {
80                 if (className.startsWith("javax.") // NOI18N
81
|| className.startsWith("java.")) // NOI18N
82
return getBundleString("MSG_StandardJDKComponent"); // NOI18N
83
if (className.startsWith("org.netbeans.")) // NOI18N
84
return getBundleString("MSG_NetBeansComponent"); // NOI18N
85
}
86         }
87         else {
88             String JavaDoc type = classSource.getCPRootType(0);
89             String JavaDoc name = classSource.getCPRootName(0);
90             
91             if (ClassSource.JAR_SOURCE.equals(type)) {
92                 return MessageFormat.format(
93                         getBundleString("FMT_ComponentFromJar"), // NOI18N
94
new Object JavaDoc[] { name });
95             }
96             else if (ClassSource.LIBRARY_SOURCE.equals(type)) {
97                 Library lib = LibraryManager.getDefault().getLibrary(name);
98                 return MessageFormat.format(
99                         getBundleString("FMT_ComponentFromLibrary"), // NOI18N
100
new Object JavaDoc[] { lib != null ? lib.getDisplayName() : name });
101             }
102             else if (ClassSource.PROJECT_SOURCE.equals(type)) {
103                 try {
104                     Project project = FileOwnerQuery.getOwner(new File JavaDoc(name).toURI());
105                     return MessageFormat.format(
106                             getBundleString("FMT_ComponentFromProject"), // NOI18N
107
new Object JavaDoc[] { project == null ? name :
108                                 FileUtil.getFileDisplayName(project.getProjectDirectory()) });
109                 } catch (Exception JavaDoc ex) {
110                     // XXX must catch specific exceptions and notify them or explain why they are ignored!
111
}
112             }
113         }
114         
115         return getBundleString("MSG_UnspecifiedComponent"); // NOI18N
116
}
117     
118     public static FileObject getPaletteFolder() {
119         if (paletteFolder != null)
120             return paletteFolder;
121         
122         try {
123             paletteFolder = Repository.getDefault().getDefaultFileSystem()
124                     .findResource("FormDesignerPalette"); // NOI18N
125
if (paletteFolder == null) // not found, create new folder
126
paletteFolder = Repository.getDefault().getDefaultFileSystem()
127                         .getRoot().createFolder("FormDesignerPalette"); // NOI18N
128
}
129         catch (java.io.IOException JavaDoc ex) {
130             throw new IllegalStateException JavaDoc("Palette folder not found and cannot be created."); // NOI18N
131
}
132         return paletteFolder;
133     }
134     
135     public static Node getPaletteNode() {
136         return getPaletteDataFolder().getNodeDelegate();
137     }
138
139     public static void showPaletteManager() {
140         try {
141             PaletteFactory.createPalette("FormDesignerPalette", // NOI18N
142
new FormPaletteActions(),
143                                          new ClassPathFilter(null), // filters out only invisible Layouts category
144
null)
145                     .showCustomizer();
146         }
147         catch (IOException JavaDoc ex) {
148             ErrorManager.getDefault().notify(ex);
149         }
150     }
151
152     public static void setContext(FileObject fileInProject) {
153         context = fileInProject;
154     }
155
156     public static synchronized void addPaletteListener(PropertyChangeListener JavaDoc listener,
157                                                        FileObject context)
158     {
159         ProjectPaletteInfo pInfo = preparePalette(context);
160         if (pInfo != null) {
161             if (pInfo.paletteListeners == null) {
162                 pInfo.paletteListeners = new LinkedList();
163             }
164             pInfo.paletteListeners.add(listener);
165             pInfo.getPalette().addPropertyChangeListener(listener);
166         }
167     }
168
169     public static synchronized void removePaletteListener(PropertyChangeListener JavaDoc listener,
170                                                           FileObject context)
171     {
172         Project project = FileOwnerQuery.getOwner(context);
173         if (project != null) {
174             ProjectPaletteInfo pInfo = palettes.get(project);
175             if (pInfo != null && pInfo.paletteListeners != null) {
176                 pInfo.paletteListeners.remove(listener);
177                 pInfo.getPalette().removePropertyChangeListener(listener);
178             }
179         }
180     }
181
182     public static Lookup getPaletteLookup(FileObject context) {
183         ProjectPaletteInfo pInfo = preparePalette(context);
184         return pInfo != null ? pInfo.paletteLookup : Lookups.fixed(new Object JavaDoc[0]);
185     }
186
187     private static PaletteController getPalette() {
188         ProjectPaletteInfo pInfo = preparePalette(context);
189         return pInfo != null ? pInfo.getPalette() : null;
190     }
191
192     private static ClassPathFilter getPaletteFilter() {
193         if (context != null) {
194             Project project = FileOwnerQuery.getOwner(context);
195             if (project != null) {
196                 ProjectPaletteInfo pInfo = palettes.get(project);
197                 if (pInfo != null)
198                     return pInfo.paletteFilter;
199             }
200         }
201         return null;
202     }
203
204     /**
205      * Gets the registered palette and related data for given context (project
206      * of given file). Creates new palette if does not exist yet.
207      */

208     private static ProjectPaletteInfo preparePalette(FileObject context) {
209         if (context == null)
210             return null;
211
212         Project project = FileOwnerQuery.getOwner(context);
213         if (project == null)
214             return null;
215
216         ProjectPaletteInfo pInfo = palettes.get(project);
217         if (pInfo == null) {
218             ClassPath classPath = ClassPath.getClassPath(context, ClassPath.BOOT);
219             classPath.addPropertyChangeListener(new ClassPathListener(classPath, project));
220
221             PaletteLookup lookup = new PaletteLookup();
222             ClassPathFilter filter = new ClassPathFilter(classPath);
223             lookup.setPalette(createPalette(filter));
224
225             pInfo = new ProjectPaletteInfo();
226             pInfo.paletteLookup = lookup;
227             pInfo.paletteFilter = filter;
228             palettes.put(project, pInfo);
229         }
230         return pInfo;
231     }
232
233     /**
234      * Creates a new palette with filter for given ClassPath.
235      */

236     private static PaletteController createPalette(ClassPathFilter filter) {
237         try {
238             return PaletteFactory.createPalette("FormDesignerPalette", // NOI18N
239
new FormPaletteActions(),
240                                                 filter,
241                                                 null);
242         }
243         catch (IOException JavaDoc ex) {
244             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
245             return null;
246         }
247     }
248
249     /**
250      * Called when the project's boot classpath changes (typically means that
251      * the project's platform has changed). This method creates a new palette
252      * with a filter based on the new classpath, updating the lookup providing
253      * the palette. Palette listeners are transferred automatically.
254      */

255     private static synchronized void bootClassPathChanged(Project p, ClassPath cp) {
256         ProjectPaletteInfo pInfo = palettes.get(p);
257         if (pInfo != null) {
258             PaletteLookup lookup = pInfo.paletteLookup;
259             PaletteController oldPalette = pInfo.getPalette();
260             oldPalette.clearSelection();
261             ClassPathFilter newFilter = new ClassPathFilter(cp);
262             PaletteController newPalette = createPalette(newFilter);
263             if (pInfo.paletteListeners != null) {
264                 for (PropertyChangeListener JavaDoc l : pInfo.paletteListeners) {
265                     oldPalette.removePropertyChangeListener(l);
266                     newPalette.addPropertyChangeListener(l);
267                 }
268             }
269             lookup.setPalette(newPalette);
270             pInfo.paletteFilter = newFilter;
271         }
272     }
273
274     static DataFolder getPaletteDataFolder() {
275         if (paletteDataFolder == null)
276             paletteDataFolder = DataFolder.findFolder(getPaletteFolder());
277         return paletteDataFolder;
278     }
279     
280     public static void clearPaletteSelection() {
281         getPalette().clearSelection();
282     }
283     
284     public static PaletteItem getSelectedItem() {
285         PaletteController palette = getPalette();
286         if( null == palette )
287             return null;
288         Lookup lkp = palette.getSelectedItem();
289         
290         return (PaletteItem)lkp.lookup( PaletteItem.class );
291     }
292     
293     public static void selectItem( PaletteItem item ) {
294         if( null == item ) {
295             getPalette().clearSelection();
296         } else {
297             // This is not the node returned by getPaletteNode()!
298
Node paletteNode = (Node)getPalette().getRoot().lookup(Node.class);
299             Node[] categories = getCategoryNodes(paletteNode, true, true, true);
300             for( int i=0; i<categories.length; i++ ) {
301                 Node[] items = getItemNodes( categories[i], true );
302                 for( int j=0; j<items.length; j++ ) {
303                     PaletteItem formItem = (PaletteItem)items[j].getLookup().lookup( PaletteItem.class );
304                     if( item.equals( formItem ) ) {
305                         getPalette().setSelectedItem( categories[i].getLookup(), items[j].getLookup() );
306                     }
307                 }
308             }
309         }
310     }
311     
312     public static PaletteItem[] getAllItems() {
313         HashSet uniqueItems = null;
314         // collect valid items from all categories (including invisible)
315
Node[] categories = getCategoryNodes(getPaletteNode(), false, true, false);
316         for( int i=0; i<categories.length; i++ ) {
317             Node[] items = getItemNodes( categories[i], true );
318             for( int j=0; j<items.length; j++ ) {
319                 PaletteItem formItem = (PaletteItem)items[j].getLookup().lookup( PaletteItem.class );
320                 if( null != formItem ) {
321                     if( null == uniqueItems ) {
322                         uniqueItems = new HashSet();
323                     }
324                     uniqueItems.add( formItem );
325                 }
326             }
327         }
328         PaletteItem[] res;
329         if( null != uniqueItems ) {
330             res = (PaletteItem[]) uniqueItems.toArray( new PaletteItem[uniqueItems.size()] );
331         } else {
332             res = new PaletteItem[0];
333         }
334         return res;
335     }
336     
337     static String JavaDoc getBundleString(String JavaDoc key) {
338         return NbBundle.getBundle(PaletteUtils.class).getString(key);
339     }
340     
341     /**
342      * Get an array of Node for the given category.
343      *
344      * @param categoryNode Category node.
345      * @param mustBeValid True if all the nodes returned must be valid palette items.
346      * @return An array of Nodes for the given category.
347      */

348     public static Node[] getItemNodes( Node categoryNode, boolean mustBeValid ) {
349         Node[] nodes = categoryNode.getChildren().getNodes( true );
350         if (!mustBeValid)
351             return nodes;
352
353         ClassPathFilter filter = getPaletteFilter();
354         if (filter == null)
355             return nodes;
356
357         List validList = null;
358         for (int i=0; i < nodes.length; i++) {
359             PaletteItem item = (PaletteItem) nodes[i].getCookie(PaletteItem.class);
360             if (filter.isValidItem(item)) {
361                 if (validList != null)
362                     validList.add(nodes[i]);
363             }
364             else if (validList == null) {
365                 validList = new ArrayList(nodes.length);
366                 for (int j=0; j < i; j++) {
367                     validList.add(nodes[j]);
368                 }
369             }
370         }
371         if (validList != null)
372             nodes = (Node[]) validList.toArray(new Node[validList.size()]);
373
374         return nodes;
375     }
376     
377     /**
378      * Get an array of all categories in the given palette.
379      *
380      * @param paletteNode Palette's root node.
381      * @param mustBeVisible True to return only visible categories, false to return also
382      * categories with Hidden flag.
383      * @return An array of categories in the given palette.
384      */

385     public static Node[] getCategoryNodes(Node paletteNode, boolean mustBeVisible) {
386         return getCategoryNodes(paletteNode, mustBeVisible, mustBeVisible, true);
387     }
388     
389     /**
390      * Get an array of all categories in the given palette.
391      *
392      * @param paletteNode Palette's root node.
393      * @param mustBeVisible True to return only visible categories, false to return also
394      * categories with Hidden flag (user can setup what's visibile in palette manager).
395      * @param mustBeValid True to return only categories containing some
396      * classpath-valid items, false to don't care about platform classpath.
397      * @param mustBePaletteCategory True to return only categories not tagged as
398      * 'isNoPaletteCategory' (marks a never visible category like Layouts)
399      * @return An array of category nodes in the given palette.
400      */

401     private static Node[] getCategoryNodes(Node paletteNode,
402                                            boolean mustBeVisible,
403                                            boolean mustBeValid,
404                                            boolean mustBePaletteCategory)
405     {
406         if (mustBeVisible)
407             mustBeValid = mustBePaletteCategory = true;
408
409         Node[] nodes = paletteNode.getChildren().getNodes(true);
410
411         ClassPathFilter filter = mustBeValid ? getPaletteFilter() : null;
412         java.util.List JavaDoc list = null; // don't create until needed
413
for( int i=0; i<nodes.length; i++ ) {
414             if ((!mustBeVisible || isVisibleCategoryNode(nodes[i]))
415                 && (!mustBeValid || filter == null || filter.isValidCategory(nodes[i]))
416                 && (!mustBePaletteCategory || representsShowableCategory(nodes[i])))
417             { // this is a relevant category
418
if( list != null ) {
419                     list.add(nodes[i]);
420                 }
421             } else if( list == null ) {
422                 list = new ArrayList( nodes.length );
423                 for( int j=0; j < i; j++ ) {
424                     list.add(nodes[j]);
425                 }
426             }
427         }
428         if( list != null ) {
429             nodes = new Node[list.size()];
430             list.toArray(nodes);
431         }
432         return nodes;
433     }
434     
435     /**
436      * @return True if the given node is a DataFolder and does not have Hidden flag set.
437      */

438     private static boolean isVisibleCategoryNode(Node node) {
439         DataFolder df = (DataFolder) node.getCookie(DataFolder.class);
440         if (df != null) {
441             Object JavaDoc value = node.getValue("psa_" + PaletteController.ATTR_IS_VISIBLE); // NOI18N
442
if (null == value || "null".equals(value)) { // NOI18N
443
value = df.getPrimaryFile().getAttribute(PaletteController.ATTR_IS_VISIBLE);
444             }
445             if (value == null) {
446                 value = Boolean.TRUE;
447             }
448             return Boolean.valueOf(value.toString()).booleanValue();
449         }
450         return false;
451     }
452
453     private static boolean representsShowableCategory(Node node) {
454         DataFolder df = (DataFolder) node.getCookie(DataFolder.class);
455         return (df != null) && !Boolean.TRUE.equals(df.getPrimaryFile().getAttribute("isNoPaletteCategory")); // NOI18N
456
}
457     
458     // -----
459

460     /**
461      * Filter for PaletteController. Filters items from platform (i.e. not user
462      * beans) based on given classpath. If classpath is null, all items pass.
463      * Also filters out categories containing only unavailable items.
464      * Always filters out permanently invisible categories (e.g. Layouts).
465      */

466     private static class ClassPathFilter extends PaletteFilter {
467         private ClassPath classPath;
468         private Set<PaletteItem> validItems;
469         private Set<PaletteItem> invalidItems;
470
471         ClassPathFilter(ClassPath cp) {
472             if (cp != null) {
473                 validItems = new WeakSet();
474                 invalidItems = new WeakSet();
475             }
476             classPath = cp;
477         }
478
479         public boolean isValidCategory(Lookup lkp) {
480             Node categoryNode = lkp.lookup(Node.class);
481             if (!representsShowableCategory(categoryNode))
482                 return false; // filter out categories that should never be visible (e.g. Layouts)
483

484             return isValidCategory(categoryNode);
485         }
486
487         boolean isValidCategory(Node node) {
488             if (classPath == null)
489                 return true;
490
491             // check if there is some valid item in this category
492
// [ideally we should listen on the category for adding/removing items,
493
// practically we just need to hide Swing categories on some mobile platforms]
494
DataFolder folder = (DataFolder) node.getCookie(DataFolder.class);
495             if (folder == null)
496                 return false;
497
498             DataObject[] dobjs = folder.getChildren();
499             for (int i=0; i < dobjs.length; i++) {
500                 PaletteItem item = (PaletteItem) dobjs[i].getCookie(PaletteItem.class);
501                 if (item == null || isValidItem(item))
502                     return true;
503             }
504             return dobjs.length == 0;
505         }
506
507         public boolean isValidItem(Lookup lkp) {
508             return isValidItem((PaletteItem) lkp.lookup(PaletteItem.class));
509         }
510
511         boolean isValidItem(PaletteItem item) {
512             if (classPath == null)
513                 return true;
514             
515             if (item == null) // Issue 81506
516
return false;
517
518             if (item.getComponentClassSource().getCPRootCount() > 0
519                 || "chooseBean".equals(item.getExplicitComponentType()) // NOI18N
520
|| "org.netbeans.modules.form.layoutsupport.delegates.NullLayoutSupport".equals(item.getComponentClassName())) // NOI18N
521
return true; // this is not a platform component
522

523            if (validItems.contains(item)) {
524                 return true;
525             }
526             else if (invalidItems.contains(item)) {
527                 return false;
528             }
529
530             // check if the class is available on platform classpath
531
String JavaDoc resName = item.getComponentClassName().replace('.', '/').concat(".class"); // NOI18N
532
if (classPath.findResource(resName) != null) {
533                 validItems.add(item);
534                 return true;
535             }
536             else {
537                 invalidItems.add(item);
538                 return false;
539             }
540         }
541     }
542
543     /**
544      * Reacts on classpath changes and updates the palette for given project
545      * accordingly (in lookup).
546      */

547     private static class ClassPathListener implements PropertyChangeListener JavaDoc {
548         private ClassPath classPath;
549         private WeakReference JavaDoc projRef;
550
551         ClassPathListener(ClassPath cp, Project p) {
552             classPath = cp;
553             projRef = new WeakReference JavaDoc(p);
554         }
555
556         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
557             if (ClassPath.PROP_ROOTS.equals(evt.getPropertyName())) {
558                 Project p = (Project) projRef.get();
559                 if (p != null)
560                     PaletteUtils.bootClassPathChanged(p, classPath);
561                 else
562                     classPath.removePropertyChangeListener(this);
563             }
564         }
565     }
566
567     /**
568      * Lookup providing a PaletteController. Can be updated with a new instance.
569      */

570     private static class PaletteLookup extends AbstractLookup {
571         private InstanceContent content;
572
573         PaletteLookup() {
574             this(new InstanceContent());
575         }
576
577         private PaletteLookup(InstanceContent content) {
578             super(content);
579             this.content = content;
580         }
581
582         void setPalette(PaletteController palette) {
583             content.set(Arrays.asList(new PaletteController[] { palette }), null);
584         }
585     }
586 }
587
Popular Tags