Index: arch.xml =================================================================== RCS file: /cvs/apisupport/project/arch.xml,v retrieving revision 1.10 diff -u -r1.10 arch.xml --- arch.xml 15 Aug 2006 15:21:08 -0000 1.10 +++ arch.xml 13 Feb 2007 10:11:48 -0000 @@ -1035,9 +1035,33 @@ --> -

- No. -

+ +

+ "Projects/org-netbeans-modules-apisupport-project/Lookup" folder's content is used to construct the project's additional lookup. + It's content is expected to be LookupProvider instances. Apisupport project provides LookupMergers + for Sources, PrivilegedTemplates and RecommendedTemplates. Implementations added by 3rd parties + will be merged into a single instance in the project's lookup. +

+
+ +

+ "Projects/org-netbeans-modules-apisupport-project-suite/Lookup" folder's content is used to construct the project's additional lookup. + It's content is expected to be LookupProvider instances. +

+
+ +

+ "Projects/org-netbeans-modules-apisupport-project/Nodes" folder's content is used to construct the project's child nodes. + It's content is expected to be NodeFactory instances. +

+
+ +

+ "Projects/org-netbeans-modules-apisupport-project-suite/Nodes" folder's content is used to construct the project's child nodes. + It's content is expected to be NodeFactory instances. +

+
+
@@ -1072,6 +1096,87 @@

No. +

+
+ + + + + + + + + + + + + +

+ XXX no answer for compat-deprecation +

+
+ + + + + +

+ XXX no answer for exec-ant-tasks +

+
+ + + + + +

+ XXX no answer for resources-preferences

Index: nbproject/project.properties =================================================================== RCS file: /cvs/apisupport/project/nbproject/project.properties,v retrieving revision 1.35 diff -u -r1.35 project.properties --- nbproject/project.properties 1 Nov 2006 13:51:58 -0000 1.35 +++ nbproject/project.properties 13 Feb 2007 10:11:48 -0000 @@ -17,7 +17,7 @@ javac.compilerargs=-Xlint -Xlint:-serial javac.source=1.5 -spec.version.base=1.13.0 +spec.version.base=1.14.0 ant.jar=${ant.home}/lib/ant.jar antsrc.cp=\ Index: src/org/netbeans/modules/apisupport/project/NbModuleProject.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/NbModuleProject.java,v retrieving revision 1.148 diff -u -r1.148 NbModuleProject.java --- src/org/netbeans/modules/apisupport/project/NbModuleProject.java 20 Nov 2006 20:40:32 -0000 1.148 +++ src/org/netbeans/modules/apisupport/project/NbModuleProject.java 13 Feb 2007 10:11:50 -0000 @@ -85,7 +85,9 @@ import org.netbeans.modules.apisupport.project.ui.ModuleLogicalView; import org.netbeans.modules.apisupport.project.ui.ModuleOperations; import org.netbeans.modules.apisupport.project.universe.LocalizedBundleInfo; +import org.netbeans.spi.project.support.LookupProviderSupport; import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.support.UILookupMergerSupport; /** * A NetBeans module project. @@ -103,7 +105,7 @@ private final AntProjectHelper helper; private final Evaluator eval; - private final Lookup lookup; + private Lookup lookup; private Map extraCompilationUnits; private final GeneratedFilesHelper genFilesHelper; private final NbModuleTypeProviderImpl typeProvider; @@ -190,6 +192,7 @@ } }); lookup = Lookups.fixed(new Object[] { + this, new Info(), helper.createAuxiliaryConfiguration(), helper.createCacheDirectoryProvider(), @@ -209,7 +212,7 @@ // currently these are hardcoded "build", // NOI18N }), - sourcesHelper.createSources(), + sourcesHelper.createSources(), new AntArtifactProviderImpl(this, helper, evaluator()), new CustomizerProviderImpl(this, getHelper(), evaluator()), new SuiteProviderImpl(), @@ -218,8 +221,13 @@ new ModuleProjectClassPathExtender(this), new LocalizedBundleInfoProvider(), new ModuleOperations(this), - new ServiceNodeHandler(this) + new ServiceNodeHandler(this), + LookupProviderSupport.createSourcesMerger(), + UILookupMergerSupport.createPrivilegedTemplatesMerger(), + UILookupMergerSupport.createRecommendedTemplatesMerger(), + }); + lookup = LookupProviderSupport.createCompositeLookup(lookup, "Projects/org-netbeans-modules-apisupport-project/Lookup"); //NOI18N } public String toString() { @@ -627,7 +635,7 @@ public void setRunInAtomicAction(boolean runInAtomicAction) { eval.setRunInAtomicAction(runInAtomicAction); } - + private final class Info implements ProjectInformation, PropertyChangeListener { private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); @@ -764,7 +772,7 @@ public void notifyDeleting() { eval.removeListeners(); } - + private final class SavedHook extends ProjectXmlSavedHook { SavedHook() {} Index: src/org/netbeans/modules/apisupport/project/suite/SuiteProject.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/suite/SuiteProject.java,v retrieving revision 1.32 diff -u -r1.32 SuiteProject.java --- src/org/netbeans/modules/apisupport/project/suite/SuiteProject.java 31 Oct 2006 23:34:29 -0000 1.32 +++ src/org/netbeans/modules/apisupport/project/suite/SuiteProject.java 13 Feb 2007 10:11:51 -0000 @@ -42,6 +42,7 @@ import org.netbeans.modules.apisupport.project.ui.customizer.SuiteCustomizer; import org.netbeans.modules.apisupport.project.ui.customizer.SuiteProperties; import org.netbeans.modules.apisupport.project.universe.NbPlatform; +import org.netbeans.spi.project.support.LookupProviderSupport; import org.netbeans.spi.project.support.ant.AntProjectEvent; import org.netbeans.spi.project.support.ant.AntProjectHelper; import org.netbeans.spi.project.support.ant.AntProjectListener; @@ -54,6 +55,7 @@ import org.netbeans.spi.project.ui.PrivilegedTemplates; import org.netbeans.spi.project.ui.ProjectOpenedHook; import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.support.UILookupMergerSupport; import org.openide.ErrorManager; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -73,7 +75,7 @@ "org/netbeans/modules/apisupport/project/suite/resources/suite.gif"; // NOI18N private final AntProjectHelper helper; - private final Lookup lookup; + private Lookup lookup; private final PropertyEvaluator eval; private final GeneratedFilesHelper genFilesHelper; @@ -83,6 +85,7 @@ genFilesHelper = new GeneratedFilesHelper(helper); Util.err.log("Loading suite project in " + getProjectDirectory()); lookup = Lookups.fixed(new Object[] { + this, new Info(), helper.createAuxiliaryConfiguration(), helper.createCacheDirectoryProvider(), @@ -97,6 +100,7 @@ new PrivilegedTemplatesImpl(), new SuiteOperations(this), }); + lookup = LookupProviderSupport.createCompositeLookup(lookup, "Projects/org-netbeans-modules-apisupport-project-suite/Lookup"); } public String toString() { Index: src/org/netbeans/modules/apisupport/project/ui/ImportantFilesNodeFactory.java =================================================================== RCS file: src/org/netbeans/modules/apisupport/project/ui/ImportantFilesNodeFactory.java diff -N src/org/netbeans/modules/apisupport/project/ui/ImportantFilesNodeFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/netbeans/modules/apisupport/project/ui/ImportantFilesNodeFactory.java 13 Feb 2007 10:11:52 -0000 @@ -0,0 +1,460 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.apisupport.project.ui; + +import java.awt.Image; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; +import javax.swing.event.ChangeListener; +import org.netbeans.api.project.Project; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.modules.apisupport.project.layers.LayerNode; +import org.netbeans.modules.apisupport.project.layers.LayerUtils; +import org.netbeans.modules.apisupport.project.metainf.ServiceNodeHandler; +import org.netbeans.modules.apisupport.project.suite.SuiteProject; +import org.netbeans.spi.project.ui.support.NodeFactory; +import org.netbeans.spi.project.ui.support.NodeList; +import org.openide.ErrorManager; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileStateInvalidException; +import org.openide.filesystems.FileSystem; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.nodes.Children; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; +import org.openide.util.Utilities; + +/** + * + * @author mkleint + */ +public class ImportantFilesNodeFactory implements NodeFactory { + /** Package private for unit tests. */ + static final String IMPORTANT_FILES_NAME = "important.files"; // NOI18N + /** Package private for unit tests only. */ + static final RequestProcessor RP = new RequestProcessor(); + + /** Creates a new instance of ImportantFilesNodeFactory */ + public ImportantFilesNodeFactory() { + } + + public NodeList createNodes(Project p) { + return new ImpFilesNL(p); + } + + private static class ImpFilesNL implements NodeList { + private Project project; + + public ImpFilesNL(Project p) { + project = p; + } + + public List keys() { + return Collections.singletonList(IMPORTANT_FILES_NAME); + } + + public void addChangeListener(ChangeListener l) { + //ignore, doesn't change + } + + public void removeChangeListener(ChangeListener l) { + //ignore, doesn't change + } + + public Node node(String key) { + assert key == IMPORTANT_FILES_NAME; + if (project instanceof NbModuleProject) { + return new ImportantFilesNode((NbModuleProject)project); + } + if (project instanceof SuiteProject) { + return new ImportantFilesNode(new SuiteImportantFilesChildren((SuiteProject)project)); + } + return null; + } + + public void addNotify() { + } + + public void removeNotify() { + } + } + /** + * Show node "Important Files" with various config and docs files beneath it. + */ + static final class ImportantFilesNode extends AnnotatedNode { + + public ImportantFilesNode(NbModuleProject project) { + super(new ImportantFilesChildren(project)); + } + + ImportantFilesNode(Children ch) { + super(ch); + } + + public String getName() { + return IMPORTANT_FILES_NAME; + } + + private Image getIcon(boolean opened) { + Image badge = Utilities.loadImage("org/netbeans/modules/apisupport/project/resources/config-badge.gif", true); + return Utilities.mergeImages(UIUtil.getTreeFolderIcon(opened), badge, 8, 8); + } + + private static final String DISPLAY_NAME = NbBundle.getMessage(ModuleLogicalView.class, "LBL_important_files"); + + public String getDisplayName() { + return annotateName(DISPLAY_NAME); + } + + public String getHtmlDisplayName() { + return computeAnnotatedHtmlDisplayName(DISPLAY_NAME, getFiles()); + } + + public Image getIcon(int type) { + return annotateIcon(getIcon(false), type); + } + + public Image getOpenedIcon(int type) { + return annotateIcon(getIcon(true), type); + } + + } + + /** + * Actual list of important files. + */ + private static final class ImportantFilesChildren extends Children.Keys { + + private List visibleFiles = new ArrayList(); + private FileChangeListener fcl; + + /** Abstract location to display name. */ + private static final java.util.Map FILES = new LinkedHashMap(); + static { + FILES.put("${manifest.mf}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_module_manifest")); + FILES.put("${javadoc.arch}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_arch_desc")); + FILES.put("${javadoc.apichanges}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_api_changes")); + FILES.put("${javadoc.overview}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_javadoc_overview")); + FILES.put("build.xml", NbBundle.getMessage(ModuleLogicalView.class, "LBL_build.xml")); + FILES.put("nbproject/project.xml", NbBundle.getMessage(ModuleLogicalView.class, "LBL_project.xml")); + FILES.put("nbproject/project.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_project.properties")); + FILES.put("nbproject/private/private.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_private.properties")); + FILES.put("nbproject/suite.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_suite.properties")); + FILES.put("nbproject/private/suite-private.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_suite-private.properties")); + FILES.put("nbproject/platform.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_platform.properties")); + FILES.put("nbproject/private/platform-private.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_platform-private.properties")); + } + + private final NbModuleProject project; + + public ImportantFilesChildren(NbModuleProject project) { + this.project = project; + } + + protected void addNotify() { + super.addNotify(); + attachListeners(); + refreshKeys(); + } + + protected void removeNotify() { + setKeys(Collections.EMPTY_SET); + removeListeners(); + super.removeNotify(); + } + + protected Node[] createNodes(Object key) { + if (key instanceof String) { + String loc = (String) key; + String locEval = project.evaluator().evaluate(loc); + FileObject file = project.getHelper().resolveFileObject(locEval); + try { + Node orig = DataObject.find(file).getNodeDelegate(); + return new Node[] {new SpecialFileNode(orig, (String) FILES.get(loc))}; + } catch (DataObjectNotFoundException e) { + throw new AssertionError(e); + } + } else if (key instanceof LayerUtils.LayerHandle) { + return new Node[] {/* #68240 */ new SpecialFileNode(new LayerNode((LayerUtils.LayerHandle) key), null)}; + } else if (key instanceof ServiceNodeHandler) { + return new Node[]{((ServiceNodeHandler)key).createServiceRootNode()}; + } else { + throw new AssertionError(key); + } + } + + private void refreshKeys() { + Set files = new HashSet(); + List newVisibleFiles = new ArrayList(); + LayerUtils.LayerHandle handle = LayerUtils.layerForProject(project); + FileObject layerFile = handle.getLayerFile(); + if (layerFile != null) { + newVisibleFiles.add(handle); + files.add(layerFile); + } + Iterator it = FILES.keySet().iterator(); + while (it.hasNext()) { + String loc = (String) it.next(); + String locEval = project.evaluator().evaluate(loc); + if (locEval == null) { + newVisibleFiles.remove(loc); // XXX why? + continue; + } + FileObject file = project.getHelper().resolveFileObject(locEval); + if (file != null) { + newVisibleFiles.add(loc); + files.add(file); + } + } + if (!isInitialized() || !newVisibleFiles.equals(visibleFiles)) { + visibleFiles = newVisibleFiles; + visibleFiles.add(project.getLookup().lookup(ServiceNodeHandler.class)); + RP.post(new Runnable() { // #72471 + public void run() { + setKeys(visibleFiles); + } + }); + ((ImportantFilesNode) getNode()).setFiles(files); + } + } + + private void attachListeners() { + try { + if (fcl == null) { + fcl = new FileChangeAdapter() { + public void fileDataCreated(FileEvent fe) { + refreshKeys(); + } + public void fileDeleted(FileEvent fe) { + refreshKeys(); + } + }; + project.getProjectDirectory().getFileSystem().addFileChangeListener(fcl); + } + } catch (FileStateInvalidException e) { + assert false : e; + } + } + + private void removeListeners() { + if (fcl != null) { + try { + project.getProjectDirectory().getFileSystem().removeFileChangeListener(fcl); + } catch (FileStateInvalidException e) { + assert false : e; + } + fcl = null; + } + } + + } + /** + * Node to represent some special file in a project. + * Mostly just a wrapper around the normal data node. + */ + static final class SpecialFileNode extends FilterNode { + + private final String displayName; + + public SpecialFileNode(Node orig, String displayName) { + super(orig); + this.displayName = displayName; + } + + public String getDisplayName() { + if (displayName != null) { + return displayName; + } else { + return super.getDisplayName(); + } + } + + public boolean canRename() { + return false; + } + + public boolean canDestroy() { + return false; + } + + public boolean canCut() { + return false; + } + + public String getHtmlDisplayName() { + String result = null; + DataObject dob = (DataObject) getLookup().lookup(DataObject.class); + if (dob != null) { + Set files = dob.files(); + result = computeAnnotatedHtmlDisplayName(getDisplayName(), files); + } + return result; + } + + } + + /** + * Annotates htmlDisplayName, if it is needed, and returns the + * result; null otherwise. + */ + private static String computeAnnotatedHtmlDisplayName( + final String htmlDisplayName, final Set files) { + + String result = null; + if (files != null && files.iterator().hasNext()) { + try { + FileObject fo = (FileObject) files.iterator().next(); + FileSystem.Status stat = fo.getFileSystem().getStatus(); + if (stat instanceof FileSystem.HtmlStatus) { + FileSystem.HtmlStatus hstat = (FileSystem.HtmlStatus) stat; + + String annotated = hstat.annotateNameHtml(htmlDisplayName, files); + + // Make sure the super string was really modified (XXX why?) + if (!htmlDisplayName.equals(annotated)) { + result = annotated; + } + } + } catch (FileStateInvalidException e) { + ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); + } + } + return result; + } + + /** + * Actual list of important files. + */ + private static final class SuiteImportantFilesChildren extends Children.Keys { + + private List visibleFiles = new ArrayList(); + private FileChangeListener fcl; + + /** Abstract location to display name. */ + private static final java.util.Map FILES = new LinkedHashMap(); + static { + FILES.put("master.jnlp", NbBundle.getMessage(SuiteLogicalView.class,"LBL_jnlp_master")); + FILES.put("build.xml", NbBundle.getMessage(SuiteLogicalView.class,"LBL_build.xml")); + FILES.put("nbproject/project.properties", NbBundle.getMessage(SuiteLogicalView.class,"LBL_project.properties")); + FILES.put("nbproject/private/private.properties", NbBundle.getMessage(SuiteLogicalView.class,"LBL_private.properties")); + FILES.put("nbproject/platform.properties", NbBundle.getMessage(SuiteLogicalView.class,"LBL_platform.properties")); + FILES.put("nbproject/private/platform-private.properties", NbBundle.getMessage(SuiteLogicalView.class,"LBL_platform-private.properties")); + } + + private final SuiteProject project; + + public SuiteImportantFilesChildren(SuiteProject project) { + this.project = project; + } + + protected void addNotify() { + super.addNotify(); + attachListeners(); + refreshKeys(); + } + + protected void removeNotify() { + setKeys(Collections.EMPTY_SET); + removeListeners(); + super.removeNotify(); + } + + protected Node[] createNodes(String loc) { + String locEval = project.getEvaluator().evaluate(loc); + FileObject file = project.getHelper().resolveFileObject(locEval); + + try { + Node orig = DataObject.find(file).getNodeDelegate(); + return new Node[] {new SpecialFileNode(orig, (String) FILES.get(loc))}; + } catch (DataObjectNotFoundException e) { + throw new AssertionError(e); + } + } + + private void refreshKeys() { + List newVisibleFiles = new ArrayList(); + Iterator it = FILES.keySet().iterator(); + Set files = new HashSet(); + while (it.hasNext()) { + String loc = (String) it.next(); + String locEval = project.getEvaluator().evaluate(loc); + if (locEval == null) { + continue; + } + FileObject file = project.getHelper().resolveFileObject(locEval); + if (file != null) { + newVisibleFiles.add(loc); + files.add(file); + } + } + if (!isInitialized() || !newVisibleFiles.equals(visibleFiles)) { + visibleFiles = newVisibleFiles; + RP.post(new Runnable() { // #72471 + public void run() { + setKeys(visibleFiles); + } + }); + ((ImportantFilesNode) getNode()).setFiles(files); // #72439 + } + } + + private void attachListeners() { + try { + if (fcl == null) { + fcl = new FileChangeAdapter() { + public void fileDataCreated(FileEvent fe) { + refreshKeys(); + } + public void fileDeleted(FileEvent fe) { + refreshKeys(); + } + }; + project.getProjectDirectory().getFileSystem().addFileChangeListener(fcl); + } + } catch (FileStateInvalidException e) { + assert false : e; + } + } + + private void removeListeners() { + if (fcl != null) { + try { + project.getProjectDirectory().getFileSystem().removeFileChangeListener(fcl); + } catch (FileStateInvalidException e) { + assert false : e; + } + fcl = null; + } + } + + } + +} Index: src/org/netbeans/modules/apisupport/project/ui/LibrariesNode.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/ui/LibrariesNode.java,v retrieving revision 1.16 diff -u -r1.16 LibrariesNode.java --- src/org/netbeans/modules/apisupport/project/ui/LibrariesNode.java 1 Feb 2007 14:57:24 -0000 1.16 +++ src/org/netbeans/modules/apisupport/project/ui/LibrariesNode.java 13 Feb 2007 10:11:54 -0000 @@ -43,6 +43,7 @@ import org.netbeans.modules.apisupport.project.NbModuleTypeProvider; import org.netbeans.modules.apisupport.project.ProjectXMLManager; import org.netbeans.modules.apisupport.project.Util; +import org.netbeans.modules.apisupport.project.ui.ModulesNodeFactory.AddNewLibraryWrapperAction; import org.netbeans.modules.apisupport.project.ui.customizer.AddModulePanel; import org.netbeans.modules.apisupport.project.ui.customizer.EditDependencyPanel; import org.netbeans.modules.apisupport.project.ui.customizer.ModuleDependency; @@ -100,7 +101,7 @@ if (Util.getModuleType(project) == NbModuleTypeProvider.SUITE_COMPONENT) { actions = new Action[] { new AddModuleDependencyAction(project), - new SuiteLogicalView.AddNewLibraryWrapperAction(project, project) + new AddNewLibraryWrapperAction(project, project) }; } else { actions = new Action[] { Index: src/org/netbeans/modules/apisupport/project/ui/LibrariesNodeFactory.java =================================================================== RCS file: src/org/netbeans/modules/apisupport/project/ui/LibrariesNodeFactory.java diff -N src/org/netbeans/modules/apisupport/project/ui/LibrariesNodeFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/netbeans/modules/apisupport/project/ui/LibrariesNodeFactory.java 13 Feb 2007 10:11:54 -0000 @@ -0,0 +1,97 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.apisupport.project.ui; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.event.ChangeListener; +import org.netbeans.api.project.Project; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.spi.project.ui.support.NodeFactory; +import org.netbeans.spi.project.ui.support.NodeList; +import org.openide.filesystems.FileObject; +import org.openide.nodes.Node; + +/** + * + * @author mkleint + */ +public class LibrariesNodeFactory implements NodeFactory { + + /** Creates a new instance of LibrariesNodeFactory */ + public LibrariesNodeFactory() { + } + + public NodeList createNodes(Project p) { + NbModuleProject proj = p.getLookup().lookup(NbModuleProject.class); + assert proj != null; + return new LibraryNL(proj); + } + + private static class LibraryNL implements NodeList { + + private NbModuleProject project; + + LibraryNL(NbModuleProject prj) { + project = prj; + } + + public List keys() { + List toRet = new ArrayList(); + toRet.add(LibrariesNode.LIBRARIES_NAME); + if(resolveFileObjectFromProperty("test.unit.src.dir") != null) { //NOI18N + toRet.add(UnitTestLibrariesNode.UNIT_TEST_LIBRARIES_NAME); + } + return toRet; + } + + private FileObject resolveFileObjectFromProperty(String property){ + String filename = project.evaluator().getProperty(property); + if (filename == null) { + return null; + } + return project.getHelper().resolveFileObject(filename); + } + + public void addChangeListener(ChangeListener l) { + } + + public void removeChangeListener(ChangeListener l) { + } + + public Node node(String key) { + if (key == LibrariesNode.LIBRARIES_NAME) { + return new LibrariesNode(project); + } else if (key == UnitTestLibrariesNode.UNIT_TEST_LIBRARIES_NAME) { + return new UnitTestLibrariesNode(project); + } + throw new AssertionError("Unknown key: " + key); + } + + public void addNotify() { + //TODO shall we somehow listen on project and ech for the + // test.unit.src.dir prop appearance/disappearance ?? + } + + public void removeNotify() { + } +} + +} Index: src/org/netbeans/modules/apisupport/project/ui/ModuleLogicalView.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/ui/ModuleLogicalView.java,v retrieving revision 1.29 diff -u -r1.29 ModuleLogicalView.java --- src/org/netbeans/modules/apisupport/project/ui/ModuleLogicalView.java 6 Dec 2006 15:16:25 -0000 1.29 +++ src/org/netbeans/modules/apisupport/project/ui/ModuleLogicalView.java 13 Feb 2007 10:11:54 -0000 @@ -22,46 +22,24 @@ import java.awt.Image; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Set; import javax.swing.Action; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import org.netbeans.modules.apisupport.project.metainf.ServiceNodeHandler; -import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.project.ProjectUtils; import org.netbeans.spi.java.project.support.ui.PackageView; import org.netbeans.api.project.ProjectInformation; import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.Sources; import org.netbeans.modules.apisupport.project.NbModuleProject; -import org.netbeans.modules.apisupport.project.layers.LayerNode; -import org.netbeans.modules.apisupport.project.layers.LayerUtils; -import org.netbeans.spi.project.support.GenericSources; import org.netbeans.spi.project.ui.LogicalViewProvider; import org.netbeans.spi.project.ui.support.DefaultProjectOperations; -import org.openide.ErrorManager; -import org.openide.filesystems.FileChangeAdapter; -import org.openide.filesystems.FileChangeListener; -import org.openide.filesystems.FileEvent; +import org.netbeans.spi.project.ui.support.NodeFactorySupport; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileStateInvalidException; -import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; -import org.openide.nodes.Children; -import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.openide.util.NbBundle; -import org.openide.util.RequestProcessor; -import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; /** @@ -70,8 +48,6 @@ */ public final class ModuleLogicalView implements LogicalViewProvider { - /** Package private for unit tests only. */ - static final RequestProcessor RP = new RequestProcessor(); private final NbModuleProject project; @@ -113,7 +89,7 @@ return found; } // For Important Files node: - if (rootChildren[i].getName().equals(IMPORTANT_FILES_NAME)) { + if (rootChildren[i].getName().equals(ImportantFilesNodeFactory.IMPORTANT_FILES_NAME)) { Node[] ifChildren = rootChildren[i].getChildren().getNodes(true); for (int j = 0; j < ifChildren.length; j++) { if (ifChildren[j].getCookie(DataObject.class) == file) { @@ -133,7 +109,8 @@ public RootNode(NbModuleProject project) { // XXX add a NodePathResolver impl to lookup - super(new RootChildren(project), Lookups.fixed(new Object[] {project})); + super(NodeFactorySupport.createCompositeChildren(project, "Projects/org-netbeans-modules-apisupport-project/Nodes"), + Lookups.fixed(new Object[] {project})); this.project = project; setForceAnnotation(true); setIconBaseWithExtension(NbModuleProject.NB_PROJECT_ICON_PATH); @@ -199,344 +176,4 @@ } } - - /** Package private for unit tests. */ - static final String IMPORTANT_FILES_NAME = "important.files"; // NOI18N - - /** Accessor for SuiteLogicalView to create its important node which shall - * be as similar as module's project one - */ - static Node createImportantFilesNode(Children ch) { - return new ImportantFilesNode(ch); - } - - private static final class RootChildren extends Children.Keys implements ChangeListener { - - private static final String[] SOURCE_GROUP_TYPES = { - JavaProjectConstants.SOURCES_TYPE_JAVA, - NbModuleProject.SOURCES_TYPE_JAVAHELP, - }; - - private final NbModuleProject project; - - RootChildren(NbModuleProject project) { - this.project = project; - } - - protected void addNotify() { - super.addNotify(); - refreshKeys(); - ProjectUtils.getSources(project).addChangeListener(this); - } - - private void refreshKeys() { - List l = new ArrayList(); - Sources s = ProjectUtils.getSources(project); - for (int i = 0; i < SOURCE_GROUP_TYPES.length; i++) { - SourceGroup[] groups = s.getSourceGroups(SOURCE_GROUP_TYPES[i]); - l.addAll(Arrays.asList(groups)); - } - SourceGroup javadocDocfiles = makeJavadocDocfilesSourceGroup(); - if (javadocDocfiles != null) { - l.add(javadocDocfiles); - } - l.add(IMPORTANT_FILES_NAME); - l.add(LibrariesNode.LIBRARIES_NAME); - if(resolveFileObjectFromProperty("test.unit.src.dir") != null) { //NOI18N - l.add(UnitTestLibrariesNode.UNIT_TEST_LIBRARIES_NAME); - } - setKeys(l); - } - - private FileObject resolveFileObjectFromProperty(String property){ - String filename = project.evaluator().getProperty(property); - if (filename == null) { - return null; - } - return project.getHelper().resolveFileObject(filename); - } - - protected void removeNotify() { - ProjectUtils.getSources(project).removeChangeListener(this); - setKeys(Collections.EMPTY_SET); - super.removeNotify(); - } - - protected Node[] createNodes(Object key) { - Node n; - if (key instanceof SourceGroup) { - n = PackageView.createPackageView((SourceGroup) key); - } else if (key == IMPORTANT_FILES_NAME) { - n = new ImportantFilesNode(project); - } else if (key == LibrariesNode.LIBRARIES_NAME) { - n = new LibrariesNode(project); - } else if (key == UnitTestLibrariesNode.UNIT_TEST_LIBRARIES_NAME) { - n = new UnitTestLibrariesNode(project); - } else { - throw new AssertionError("Unknown key: " + key); - } - return new Node[] {n}; - } - - - private SourceGroup makeJavadocDocfilesSourceGroup() { - String propname = "javadoc.docfiles"; // NOI18N - FileObject root = resolveFileObjectFromProperty(propname); - if(root == null) { - return null; - } - return GenericSources.group(project, root, propname, NbBundle.getMessage(ModuleLogicalView.class, "LBL_extra_javadoc_files"), null, null); - } - - public void stateChanged(ChangeEvent e) { - refreshKeys(); - } - - } - - /** - * Show node "Important Files" with various config and docs files beneath it. - */ - static final class ImportantFilesNode extends AnnotatedNode { - - public ImportantFilesNode(NbModuleProject project) { - super(new ImportantFilesChildren(project)); - } - - ImportantFilesNode(Children ch) { - super(ch); - } - - public String getName() { - return IMPORTANT_FILES_NAME; - } - - private Image getIcon(boolean opened) { - Image badge = Utilities.loadImage("org/netbeans/modules/apisupport/project/resources/config-badge.gif", true); - return Utilities.mergeImages(UIUtil.getTreeFolderIcon(opened), badge, 8, 8); - } - - private static final String DISPLAY_NAME = NbBundle.getMessage(ModuleLogicalView.class, "LBL_important_files"); - - public String getDisplayName() { - return annotateName(DISPLAY_NAME); - } - - public String getHtmlDisplayName() { - return computeAnnotatedHtmlDisplayName(DISPLAY_NAME, getFiles()); - } - - public Image getIcon(int type) { - return annotateIcon(getIcon(false), type); - } - - public Image getOpenedIcon(int type) { - return annotateIcon(getIcon(true), type); - } - - } - - /** - * Actual list of important files. - */ - private static final class ImportantFilesChildren extends Children.Keys { - - private List visibleFiles = new ArrayList(); - private FileChangeListener fcl; - - /** Abstract location to display name. */ - private static final java.util.Map FILES = new LinkedHashMap(); - static { - FILES.put("${manifest.mf}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_module_manifest")); - FILES.put("${javadoc.arch}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_arch_desc")); - FILES.put("${javadoc.apichanges}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_api_changes")); - FILES.put("${javadoc.overview}", NbBundle.getMessage(ModuleLogicalView.class, "LBL_javadoc_overview")); - FILES.put("build.xml", NbBundle.getMessage(ModuleLogicalView.class, "LBL_build.xml")); - FILES.put("nbproject/project.xml", NbBundle.getMessage(ModuleLogicalView.class, "LBL_project.xml")); - FILES.put("nbproject/project.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_project.properties")); - FILES.put("nbproject/private/private.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_private.properties")); - FILES.put("nbproject/suite.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_suite.properties")); - FILES.put("nbproject/private/suite-private.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_suite-private.properties")); - FILES.put("nbproject/platform.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_platform.properties")); - FILES.put("nbproject/private/platform-private.properties", NbBundle.getMessage(ModuleLogicalView.class, "LBL_platform-private.properties")); - } - - private final NbModuleProject project; - - public ImportantFilesChildren(NbModuleProject project) { - this.project = project; - } - - protected void addNotify() { - super.addNotify(); - attachListeners(); - refreshKeys(); - } - - protected void removeNotify() { - setKeys(Collections.EMPTY_SET); - removeListeners(); - super.removeNotify(); - } - - protected Node[] createNodes(Object key) { - if (key instanceof String) { - String loc = (String) key; - String locEval = project.evaluator().evaluate(loc); - FileObject file = project.getHelper().resolveFileObject(locEval); - try { - Node orig = DataObject.find(file).getNodeDelegate(); - return new Node[] {new SpecialFileNode(orig, (String) FILES.get(loc))}; - } catch (DataObjectNotFoundException e) { - throw new AssertionError(e); - } - } else if (key instanceof LayerUtils.LayerHandle) { - return new Node[] {/* #68240 */ new SpecialFileNode(new LayerNode((LayerUtils.LayerHandle) key), null)}; - } else if (key instanceof ServiceNodeHandler) { - return new Node[]{((ServiceNodeHandler)key).createServiceRootNode()}; - } else { - throw new AssertionError(key); - } - } - - private void refreshKeys() { - Set files = new HashSet(); - List newVisibleFiles = new ArrayList(); - LayerUtils.LayerHandle handle = LayerUtils.layerForProject(project); - FileObject layerFile = handle.getLayerFile(); - if (layerFile != null) { - newVisibleFiles.add(handle); - files.add(layerFile); - } - Iterator it = FILES.keySet().iterator(); - while (it.hasNext()) { - String loc = (String) it.next(); - String locEval = project.evaluator().evaluate(loc); - if (locEval == null) { - newVisibleFiles.remove(loc); // XXX why? - continue; - } - FileObject file = project.getHelper().resolveFileObject(locEval); - if (file != null) { - newVisibleFiles.add(loc); - files.add(file); - } - } - if (!isInitialized() || !newVisibleFiles.equals(visibleFiles)) { - visibleFiles = newVisibleFiles; - visibleFiles.add(project.getLookup().lookup(ServiceNodeHandler.class)); - RP.post(new Runnable() { // #72471 - public void run() { - setKeys(visibleFiles); - } - }); - ((ImportantFilesNode) getNode()).setFiles(files); - } - } - - private void attachListeners() { - try { - if (fcl == null) { - fcl = new FileChangeAdapter() { - public void fileDataCreated(FileEvent fe) { - refreshKeys(); - } - public void fileDeleted(FileEvent fe) { - refreshKeys(); - } - }; - project.getProjectDirectory().getFileSystem().addFileChangeListener(fcl); - } - } catch (FileStateInvalidException e) { - assert false : e; - } - } - - private void removeListeners() { - if (fcl != null) { - try { - project.getProjectDirectory().getFileSystem().removeFileChangeListener(fcl); - } catch (FileStateInvalidException e) { - assert false : e; - } - fcl = null; - } - } - - } - - /** - * Node to represent some special file in a project. - * Mostly just a wrapper around the normal data node. - */ - static final class SpecialFileNode extends FilterNode { - - private final String displayName; - - public SpecialFileNode(Node orig, String displayName) { - super(orig); - this.displayName = displayName; - } - - public String getDisplayName() { - if (displayName != null) { - return displayName; - } else { - return super.getDisplayName(); - } - } - - public boolean canRename() { - return false; - } - - public boolean canDestroy() { - return false; - } - - public boolean canCut() { - return false; - } - - public String getHtmlDisplayName() { - String result = null; - DataObject dob = (DataObject) getLookup().lookup(DataObject.class); - if (dob != null) { - Set files = dob.files(); - result = computeAnnotatedHtmlDisplayName(getDisplayName(), files); - } - return result; - } - - } - - /** - * Annotates htmlDisplayName, if it is needed, and returns the - * result; null otherwise. - */ - private static String computeAnnotatedHtmlDisplayName( - final String htmlDisplayName, final Set files) { - - String result = null; - if (files != null && files.iterator().hasNext()) { - try { - FileObject fo = (FileObject) files.iterator().next(); - FileSystem.Status stat = fo.getFileSystem().getStatus(); - if (stat instanceof FileSystem.HtmlStatus) { - FileSystem.HtmlStatus hstat = (FileSystem.HtmlStatus) stat; - - String annotated = hstat.annotateNameHtml(htmlDisplayName, files); - - // Make sure the super string was really modified (XXX why?) - if (!htmlDisplayName.equals(annotated)) { - result = annotated; - } - } - } catch (FileStateInvalidException e) { - ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); - } - } - return result; - } - } Index: src/org/netbeans/modules/apisupport/project/ui/ModulesNodeFactory.java =================================================================== RCS file: src/org/netbeans/modules/apisupport/project/ui/ModulesNodeFactory.java diff -N src/org/netbeans/modules/apisupport/project/ui/ModulesNodeFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/netbeans/modules/apisupport/project/ui/ModulesNodeFactory.java 13 Feb 2007 10:11:55 -0000 @@ -0,0 +1,363 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.apisupport.project.ui; + +import java.awt.EventQueue; +import java.awt.Image; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.util.Collections; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectInformation; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.modules.apisupport.project.Util; +import org.netbeans.modules.apisupport.project.suite.SuiteProject; +import org.netbeans.modules.apisupport.project.ui.customizer.SuiteUtils; +import org.netbeans.modules.apisupport.project.ui.wizard.NewNbModuleWizardIterator; +import org.netbeans.spi.project.SubprojectProvider; +import org.netbeans.spi.project.ui.support.NodeFactory; +import org.netbeans.spi.project.ui.support.NodeFactorySupport; +import org.netbeans.spi.project.ui.support.NodeList; +import org.openide.DialogDisplayer; +import org.openide.ErrorManager; +import org.openide.NotifyDescriptor; +import org.openide.awt.StatusDisplayer; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; +import org.openide.util.Utilities; +import org.openide.util.actions.CookieAction; +import org.openide.util.actions.NodeAction; +import org.openide.util.lookup.Lookups; +import org.openide.windows.WindowManager; + +/** + * + * @author mkleint + */ +public class ModulesNodeFactory implements NodeFactory { + + /** Creates a new instance of ImportantFilesNodeFactory */ + public ModulesNodeFactory() { + } + + public NodeList createNodes(Project p) { + SuiteProject prj = p.getLookup().lookup(SuiteProject.class); + assert prj != null; + return NodeFactorySupport.fixedNodeList(new ModulesNode(prj)); + } + + private static String getMessage(final String key) { + return NbBundle.getMessage(SuiteLogicalView.class, key); + } + + + /** Represent Modules node in the Suite Logical View. */ + static final class ModulesNode extends AbstractNode { + + private SuiteProject suite; + + ModulesNode(final SuiteProject suite) { + super(new ModuleChildren(suite)); + this.suite = suite; + setName("modules"); // NOI18N + setDisplayName(getMessage("CTL_Modules")); + } + + public Action[] getActions(boolean context) { + return new Action[] { + new AddNewSuiteComponentAction(suite), + new AddNewLibraryWrapperAction(suite), + new AddSuiteComponentAction(suite), + }; + } + + private Image getIcon(boolean opened) { + Image badge = Utilities.loadImage("org/netbeans/modules/apisupport/project/suite/resources/module-badge.gif", true); + return Utilities.mergeImages(UIUtil.getTreeFolderIcon(opened), badge, 9, 9); + } + + public Image getIcon(int type) { + return getIcon(false); + } + + public Image getOpenedIcon(int type) { + return getIcon(true); + } + + static final class ModuleChildren extends Children.Keys implements ChangeListener { + + private final SuiteProject suite; + + public ModuleChildren(SuiteProject suite) { + suite.getLookup().lookup(SubprojectProvider.class).addChangeListener(this); + this.suite = suite; + } + + protected void addNotify() { + updateKeys(); + } + + private void updateKeys() { + // e.g.(?) Explorer view under Children.MUTEX subsequently calls e.g. + // SuiteProject$Info.getSimpleName() which acquires ProjectManager.mutex(). And + // since this method might be called under ProjectManager.mutex() write access + // and updateKeys() --> setKeys() in turn calls Children.MUTEX write access, + // deadlock is here, so preventing it... (also got this under read access) + EventQueue.invokeLater(new Runnable() { + public void run() { + // #70112: sort them. + SortedSet subModules = new TreeSet(Util.projectDisplayNameComparator()); + subModules.addAll(SuiteUtils.getSubProjects(suite)); + setKeys(subModules); + } + }); + } + + protected void removeNotify() { + suite.getLookup().lookup(SubprojectProvider.class).removeChangeListener(this); + setKeys(Collections.EMPTY_SET); + } + + protected Node[] createNodes(NbModuleProject p) { + return new Node[] {new SuiteComponentNode(p)}; + } + + public void stateChanged(ChangeEvent ev) { + updateKeys(); + } + + } + + } + + private static final class AddSuiteComponentAction extends AbstractAction { + + private final SuiteProject suite; + + public AddSuiteComponentAction(final SuiteProject suite) { + super(getMessage("CTL_AddModule")); + this.suite = suite; + } + + public void actionPerformed(ActionEvent evt) { + NbModuleProject project = UIUtil.chooseSuiteComponent( + WindowManager.getDefault().getMainWindow(), + suite); + if (project != null) { + if (!SuiteUtils.contains(suite, project)) { + try { + SuiteUtils.addModule(suite, (NbModuleProject) project); + ProjectManager.getDefault().saveProject(suite); + } catch (IOException ex) { + ErrorManager.getDefault().notify(ex); + } + } else { + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( + NbBundle.getMessage(SuiteLogicalView.class, "MSG_SuiteAlreadyContainsCNB", project.getCodeNameBase()))); + } + } + } + + } + + private static final class AddNewSuiteComponentAction extends AbstractAction { + + private final SuiteProject suite; + + public AddNewSuiteComponentAction(final SuiteProject suite) { + super(getMessage("CTL_AddNewModule")); + this.suite = suite; + } + + public void actionPerformed(ActionEvent evt) { + NewNbModuleWizardIterator iterator = NewNbModuleWizardIterator.createSuiteComponentIterator(suite); + UIUtil.runProjectWizard(iterator, "CTL_NewModuleProject"); // NOI18N + } + + } + + static final class AddNewLibraryWrapperAction extends AbstractAction { + + private final Project suiteProvider; + private final NbModuleProject target; + + public AddNewLibraryWrapperAction(final Project suiteProvider, final NbModuleProject target) { + super(getMessage("CTL_AddNewLibrary")); + this.suiteProvider = suiteProvider; + this.target = target; + } + + public AddNewLibraryWrapperAction(final Project suiteProvider) { + this(suiteProvider, null); + } + + public void actionPerformed(ActionEvent evt) { + NbModuleProject project = UIUtil.runLibraryWrapperWizard(suiteProvider); + if (project != null && target != null) { + try { + Util.addDependency(target, project); + ProjectManager.getDefault().saveProject(target); + } catch (IOException e) { + assert false : e; + } + } + } + + } + + /** Represent one module (a suite component) node. */ + private static final class SuiteComponentNode extends AbstractNode { + + private final static Action REMOVE_ACTION = new RemoveSuiteComponentAction(); + private final static Action OPEN_ACTION = new OpenProjectAction(); + + public SuiteComponentNode(final NbModuleProject suiteComponent) { + super(Children.LEAF, Lookups.fixed(new Object[] {suiteComponent})); + ProjectInformation info = ProjectUtils.getInformation(suiteComponent); + setName(info.getName()); + setDisplayName(info.getDisplayName()); + setIconBaseWithExtension(NbModuleProject.NB_PROJECT_ICON_PATH); + info.addPropertyChangeListener(new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName() == ProjectInformation.PROP_DISPLAY_NAME) { + SuiteComponentNode.this.setDisplayName((String) evt.getNewValue()); + } else if (evt.getPropertyName() == ProjectInformation.PROP_NAME) { + SuiteComponentNode.this.setName((String) evt.getNewValue()); + } + } + }); + } + + public Action[] getActions(boolean context) { + return new Action[] { + OPEN_ACTION, REMOVE_ACTION + }; + } + + public Action getPreferredAction() { + return OPEN_ACTION; + } + + } + + private static final class RemoveSuiteComponentAction extends NodeAction { + + protected void performAction(Node[] activatedNodes) { + for (int i = 0; i < activatedNodes.length; i++) { + final NbModuleProject suiteComponent = + (NbModuleProject) activatedNodes[i].getLookup().lookup(NbModuleProject.class); + assert suiteComponent != null : "NbModuleProject in lookup"; // NOI18N + try { + NbModuleProject[] modules = SuiteUtils.getDependentModules(suiteComponent); + boolean remove = true; + if (modules.length > 0) { + StringBuffer sb = new StringBuffer("
    "); // NOI18N + for (int j = 0; j < modules.length; j++) { + sb.append("
  • " + ProjectUtils.getInformation(modules[j]).getDisplayName() + "
  • "); // NOI18N + } + sb.append("
"); // NOI18N + String displayName = ProjectUtils.getInformation(suiteComponent).getDisplayName(); + String confirmMessage = NbBundle.getMessage(SuiteLogicalView.class, + "MSG_RemovingModuleMessage", displayName, sb.toString()); // NOI18N + remove = UIUtil.showAcceptCancelDialog( + NbBundle.getMessage(SuiteLogicalView.class, "CTL_RemovingModuleTitle", displayName), + confirmMessage, getMessage("CTL_RemoveDependency"), null, NotifyDescriptor.QUESTION_MESSAGE); + } + if (remove) { + SuiteUtils.removeModuleFromSuiteWithDependencies(suiteComponent); + } + } catch (IOException ex) { + ErrorManager.getDefault().notify(ex); + } + } + } + + protected boolean enable(Node[] activatedNodes) { + return true; + } + + public String getName() { + return getMessage("CTL_RemoveModule"); + } + + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + protected boolean asynchronous() { + return false; + } + + } + + private static final class OpenProjectAction extends CookieAction { + + protected void performAction(Node[] activatedNodes) { + final Project[] projects = new Project[activatedNodes.length]; + for (int i = 0; i < activatedNodes.length; i++) { + Project project = (Project) activatedNodes[i].getLookup().lookup(Project.class); + projects[i] = project; + } + RequestProcessor.getDefault().post(new Runnable() { + public void run() { + StatusDisplayer.getDefault().setStatusText(getMessage("MSG_OpeningProjects")); + OpenProjects.getDefault().open(projects, false); + } + }); + } + + public String getName() { + return getMessage("CTL_OpenProject"); + } + + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + protected boolean asynchronous() { + return false; + } + + protected int mode() { + return CookieAction.MODE_ALL; + } + + protected Class[] cookieClasses() { + return new Class[] { Project.class }; + } + + } + +} Index: src/org/netbeans/modules/apisupport/project/ui/SourcesNodeFactory.java =================================================================== RCS file: src/org/netbeans/modules/apisupport/project/ui/SourcesNodeFactory.java diff -N src/org/netbeans/modules/apisupport/project/ui/SourcesNodeFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/netbeans/modules/apisupport/project/ui/SourcesNodeFactory.java 13 Feb 2007 10:11:55 -0000 @@ -0,0 +1,126 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.apisupport.project.ui; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.spi.java.project.support.ui.PackageView; +import org.netbeans.spi.project.support.GenericSources; +import org.netbeans.spi.project.ui.support.NodeFactory; +import org.netbeans.spi.project.ui.support.NodeList; +import org.openide.filesystems.FileObject; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; + +/** + * + * @author mkleint + */ +public class SourcesNodeFactory implements NodeFactory { + + /** Creates a new instance of SourcesNodeFactory */ + public SourcesNodeFactory() { + } + + public NodeList createNodes(Project p) { + NbModuleProject prj = p.getLookup().lookup(NbModuleProject.class); + return new SourceNL(prj); + } + + + private static class SourceNL implements NodeList, ChangeListener { + private List list = new ArrayList(); + private static final String[] SOURCE_GROUP_TYPES = { + JavaProjectConstants.SOURCES_TYPE_JAVA, + NbModuleProject.SOURCES_TYPE_JAVAHELP, + }; + + private final NbModuleProject project; + + SourceNL(NbModuleProject prj) { + project = prj; + } + public void addChangeListener(ChangeListener l) { + list.add(l); + } + + public void removeChangeListener(ChangeListener l) { + list.remove(l); + } + + public void addNotify() { + ProjectUtils.getSources(project).addChangeListener(this); + } + + public void removeNotify() { + ProjectUtils.getSources(project).removeChangeListener(this); + } + + public Node node(SourceGroup key) { + return PackageView.createPackageView(key); + } + + public List keys() { + List l = new ArrayList(); + Sources s = ProjectUtils.getSources(project); + for (int i = 0; i < SOURCE_GROUP_TYPES.length; i++) { + SourceGroup[] groups = s.getSourceGroups(SOURCE_GROUP_TYPES[i]); + l.addAll(Arrays.asList(groups)); + } + SourceGroup javadocDocfiles = makeJavadocDocfilesSourceGroup(); + if (javadocDocfiles != null) { + l.add(javadocDocfiles); + } + return l; + } + + private SourceGroup makeJavadocDocfilesSourceGroup() { + String propname = "javadoc.docfiles"; // NOI18N + FileObject root = resolveFileObjectFromProperty(propname); + if(root == null) { + return null; + } + return GenericSources.group(project, root, propname, NbBundle.getMessage(ModuleLogicalView.class, "LBL_extra_javadoc_files"), null, null); + } + + private FileObject resolveFileObjectFromProperty(String property){ + String filename = project.evaluator().getProperty(property); + if (filename == null) { + return null; + } + return project.getHelper().resolveFileObject(filename); + } + + public void stateChanged(ChangeEvent arg0) { + for (ChangeListener lst : list) { + lst.stateChanged(new ChangeEvent(this)); + } + } +} +} Index: src/org/netbeans/modules/apisupport/project/ui/SuiteLogicalView.java =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/ui/SuiteLogicalView.java,v retrieving revision 1.45 diff -u -r1.45 SuiteLogicalView.java --- src/org/netbeans/modules/apisupport/project/ui/SuiteLogicalView.java 23 Nov 2006 16:05:59 -0000 1.45 +++ src/org/netbeans/modules/apisupport/project/ui/SuiteLogicalView.java 13 Feb 2007 10:11:56 -0000 @@ -19,64 +19,29 @@ package org.netbeans.modules.apisupport.project.ui; -import java.awt.EventQueue; import java.awt.Image; -import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import javax.swing.AbstractAction; import javax.swing.Action; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import org.netbeans.api.project.FileOwnerQuery; -import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectInformation; -import org.netbeans.api.project.ProjectManager; import org.netbeans.api.project.ProjectUtils; -import org.netbeans.api.project.ui.OpenProjects; -import org.netbeans.modules.apisupport.project.NbModuleProject; -import org.netbeans.modules.apisupport.project.Util; import org.netbeans.modules.apisupport.project.suite.SuiteProject; -import org.netbeans.modules.apisupport.project.ui.customizer.SuiteUtils; -import org.netbeans.modules.apisupport.project.ui.wizard.NewNbModuleWizardIterator; -import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.ui.LogicalViewProvider; import org.netbeans.spi.project.ui.support.DefaultProjectOperations; -import org.openide.DialogDisplayer; -import org.openide.ErrorManager; -import org.openide.NotifyDescriptor; -import org.openide.awt.StatusDisplayer; -import org.openide.filesystems.FileChangeAdapter; +import org.netbeans.spi.project.ui.support.NodeFactorySupport; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; -import org.openide.filesystems.FileChangeListener; -import org.openide.filesystems.FileEvent; -import org.openide.filesystems.FileStateInvalidException; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.Children; import org.openide.nodes.Node; -import org.openide.util.HelpCtx; import org.openide.util.NbBundle; -import org.openide.util.RequestProcessor; import org.openide.util.Utilities; import org.openide.util.WeakListeners; -import org.openide.util.actions.CookieAction; -import org.openide.util.actions.NodeAction; import org.openide.util.lookup.Lookups; -import org.openide.windows.WindowManager; /** * Provides a logical view of a NetBeans suite project. @@ -128,10 +93,6 @@ return null; } - private static String getMessage(final String key) { - return NbBundle.getMessage(SuiteLogicalView.class, key); - } - /** Package private for unit test only. */ static final class SuiteRootNode extends AnnotatedNode implements PropertyChangeListener { @@ -142,7 +103,8 @@ private final ProjectInformation info; SuiteRootNode(final SuiteProject suite) { - super(createRootChildren(suite), Lookups.fixed(new Object[] {suite})); + super(NodeFactorySupport.createCompositeChildren(suite, "Projects/org-netbeans-modules-apisupport-project-suite/Nodes"), + Lookups.fixed(new Object[] {suite})); this.suite = suite; info = ProjectUtils.getInformation(suite); info.addPropertyChangeListener(WeakListeners.propertyChange(this, info)); @@ -204,399 +166,4 @@ } } - - private static Children createRootChildren(final SuiteProject suite) { - ImportantFilesChildren ch = new ImportantFilesChildren(suite); - Node ifn = ModuleLogicalView.createImportantFilesNode(ch); - - Node[] nodes = new Node[] { new ModulesNode(suite), ifn, }; - Children children = new Children.Array(); - children.add(nodes); - return children; - } - - /** Represent Modules node in the Suite Logical View. */ - static final class ModulesNode extends AbstractNode { - - private SuiteProject suite; - - ModulesNode(final SuiteProject suite) { - super(new ModuleChildren(suite)); - this.suite = suite; - setName("modules"); // NOI18N - setDisplayName(getMessage("CTL_Modules")); - } - - public Action[] getActions(boolean context) { - return new Action[] { - new AddNewSuiteComponentAction(suite), - new AddNewLibraryWrapperAction(suite), - new AddSuiteComponentAction(suite), - }; - } - - private Image getIcon(boolean opened) { - Image badge = Utilities.loadImage("org/netbeans/modules/apisupport/project/suite/resources/module-badge.gif", true); - return Utilities.mergeImages(UIUtil.getTreeFolderIcon(opened), badge, 9, 9); - } - - public Image getIcon(int type) { - return getIcon(false); - } - - public Image getOpenedIcon(int type) { - return getIcon(true); - } - - static final class ModuleChildren extends Children.Keys implements ChangeListener { - - private final SuiteProject suite; - - public ModuleChildren(SuiteProject suite) { - suite.getLookup().lookup(SubprojectProvider.class).addChangeListener(this); - this.suite = suite; - } - - protected void addNotify() { - updateKeys(); - } - - private void updateKeys() { - // e.g.(?) Explorer view under Children.MUTEX subsequently calls e.g. - // SuiteProject$Info.getSimpleName() which acquires ProjectManager.mutex(). And - // since this method might be called under ProjectManager.mutex() write access - // and updateKeys() --> setKeys() in turn calls Children.MUTEX write access, - // deadlock is here, so preventing it... (also got this under read access) - EventQueue.invokeLater(new Runnable() { - public void run() { - // #70112: sort them. - SortedSet subModules = new TreeSet(Util.projectDisplayNameComparator()); - subModules.addAll(SuiteUtils.getSubProjects(suite)); - setKeys(subModules); - } - }); - } - - protected void removeNotify() { - suite.getLookup().lookup(SubprojectProvider.class).removeChangeListener(this); - setKeys(Collections.EMPTY_SET); - } - - protected Node[] createNodes(NbModuleProject p) { - return new Node[] {new SuiteComponentNode(p)}; - } - - public void stateChanged(ChangeEvent ev) { - updateKeys(); - } - - } - - } - - private static final class AddSuiteComponentAction extends AbstractAction { - - private final SuiteProject suite; - - public AddSuiteComponentAction(final SuiteProject suite) { - super(getMessage("CTL_AddModule")); - this.suite = suite; - } - - public void actionPerformed(ActionEvent evt) { - NbModuleProject project = UIUtil.chooseSuiteComponent( - WindowManager.getDefault().getMainWindow(), - suite); - if (project != null) { - if (!SuiteUtils.contains(suite, project)) { - try { - SuiteUtils.addModule(suite, (NbModuleProject) project); - ProjectManager.getDefault().saveProject(suite); - } catch (IOException ex) { - ErrorManager.getDefault().notify(ex); - } - } else { - DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( - NbBundle.getMessage(SuiteLogicalView.class, "MSG_SuiteAlreadyContainsCNB", project.getCodeNameBase()))); - } - } - } - - } - - private static final class AddNewSuiteComponentAction extends AbstractAction { - - private final SuiteProject suite; - - public AddNewSuiteComponentAction(final SuiteProject suite) { - super(getMessage("CTL_AddNewModule")); - this.suite = suite; - } - - public void actionPerformed(ActionEvent evt) { - NewNbModuleWizardIterator iterator = NewNbModuleWizardIterator.createSuiteComponentIterator(suite); - UIUtil.runProjectWizard(iterator, "CTL_NewModuleProject"); // NOI18N - } - - } - - static final class AddNewLibraryWrapperAction extends AbstractAction { - - private final Project suiteProvider; - private final NbModuleProject target; - - public AddNewLibraryWrapperAction(final Project suiteProvider, final NbModuleProject target) { - super(getMessage("CTL_AddNewLibrary")); - this.suiteProvider = suiteProvider; - this.target = target; - } - - public AddNewLibraryWrapperAction(final Project suiteProvider) { - this(suiteProvider, null); - } - - public void actionPerformed(ActionEvent evt) { - NbModuleProject project = UIUtil.runLibraryWrapperWizard(suiteProvider); - if (project != null && target != null) { - try { - Util.addDependency(target, project); - ProjectManager.getDefault().saveProject(target); - } catch (IOException e) { - assert false : e; - } - } - } - - } - - /** Represent one module (a suite component) node. */ - private static final class SuiteComponentNode extends AbstractNode { - - private final static Action REMOVE_ACTION = new RemoveSuiteComponentAction(); - private final static Action OPEN_ACTION = new OpenProjectAction(); - - public SuiteComponentNode(final NbModuleProject suiteComponent) { - super(Children.LEAF, Lookups.fixed(new Object[] {suiteComponent})); - ProjectInformation info = ProjectUtils.getInformation(suiteComponent); - setName(info.getName()); - setDisplayName(info.getDisplayName()); - setIconBaseWithExtension(NbModuleProject.NB_PROJECT_ICON_PATH); - info.addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName() == ProjectInformation.PROP_DISPLAY_NAME) { - SuiteComponentNode.this.setDisplayName((String) evt.getNewValue()); - } else if (evt.getPropertyName() == ProjectInformation.PROP_NAME) { - SuiteComponentNode.this.setName((String) evt.getNewValue()); - } - } - }); - } - - public Action[] getActions(boolean context) { - return new Action[] { - OPEN_ACTION, REMOVE_ACTION - }; - } - - public Action getPreferredAction() { - return OPEN_ACTION; - } - - } - - private static final class RemoveSuiteComponentAction extends NodeAction { - - protected void performAction(Node[] activatedNodes) { - for (int i = 0; i < activatedNodes.length; i++) { - final NbModuleProject suiteComponent = - (NbModuleProject) activatedNodes[i].getLookup().lookup(NbModuleProject.class); - assert suiteComponent != null : "NbModuleProject in lookup"; // NOI18N - try { - NbModuleProject[] modules = SuiteUtils.getDependentModules(suiteComponent); - boolean remove = true; - if (modules.length > 0) { - StringBuffer sb = new StringBuffer("
    "); // NOI18N - for (int j = 0; j < modules.length; j++) { - sb.append("
  • " + ProjectUtils.getInformation(modules[j]).getDisplayName() + "
  • "); // NOI18N - } - sb.append("
"); // NOI18N - String displayName = ProjectUtils.getInformation(suiteComponent).getDisplayName(); - String confirmMessage = NbBundle.getMessage(SuiteLogicalView.class, - "MSG_RemovingModuleMessage", displayName, sb.toString()); // NOI18N - remove = UIUtil.showAcceptCancelDialog( - NbBundle.getMessage(SuiteLogicalView.class, "CTL_RemovingModuleTitle", displayName), - confirmMessage, getMessage("CTL_RemoveDependency"), null, NotifyDescriptor.QUESTION_MESSAGE); - } - if (remove) { - SuiteUtils.removeModuleFromSuiteWithDependencies(suiteComponent); - } - } catch (IOException ex) { - ErrorManager.getDefault().notify(ex); - } - } - } - - protected boolean enable(Node[] activatedNodes) { - return true; - } - - public String getName() { - return getMessage("CTL_RemoveModule"); - } - - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - - protected boolean asynchronous() { - return false; - } - - } - - private static final class OpenProjectAction extends CookieAction { - - protected void performAction(Node[] activatedNodes) { - final Project[] projects = new Project[activatedNodes.length]; - for (int i = 0; i < activatedNodes.length; i++) { - Project project = (Project) activatedNodes[i].getLookup().lookup(Project.class); - projects[i] = project; - } - RequestProcessor.getDefault().post(new Runnable() { - public void run() { - StatusDisplayer.getDefault().setStatusText(getMessage("MSG_OpeningProjects")); - OpenProjects.getDefault().open(projects, false); - } - }); - } - - public String getName() { - return getMessage("CTL_OpenProject"); - } - - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - - protected boolean asynchronous() { - return false; - } - - protected int mode() { - return CookieAction.MODE_ALL; - } - - protected Class[] cookieClasses() { - return new Class[] { Project.class }; - } - - } - - /** - * Actual list of important files. - */ - private static final class ImportantFilesChildren extends Children.Keys { - - private List visibleFiles = new ArrayList(); - private FileChangeListener fcl; - - /** Abstract location to display name. */ - private static final java.util.Map FILES = new LinkedHashMap(); - static { - FILES.put("master.jnlp", getMessage("LBL_jnlp_master")); - FILES.put("build.xml", getMessage("LBL_build.xml")); - FILES.put("nbproject/project.properties", getMessage("LBL_project.properties")); - FILES.put("nbproject/private/private.properties", getMessage("LBL_private.properties")); - FILES.put("nbproject/platform.properties", getMessage("LBL_platform.properties")); - FILES.put("nbproject/private/platform-private.properties", getMessage("LBL_platform-private.properties")); - } - - private final SuiteProject project; - - public ImportantFilesChildren(SuiteProject project) { - this.project = project; - } - - protected void addNotify() { - super.addNotify(); - attachListeners(); - refreshKeys(); - } - - protected void removeNotify() { - setKeys(Collections.EMPTY_SET); - removeListeners(); - super.removeNotify(); - } - - protected Node[] createNodes(String loc) { - String locEval = project.getEvaluator().evaluate(loc); - FileObject file = project.getHelper().resolveFileObject(locEval); - - try { - Node orig = DataObject.find(file).getNodeDelegate(); - return new Node[] {new ModuleLogicalView.SpecialFileNode(orig, (String) FILES.get(loc))}; - } catch (DataObjectNotFoundException e) { - throw new AssertionError(e); - } - } - - private void refreshKeys() { - List newVisibleFiles = new ArrayList(); - Iterator it = FILES.keySet().iterator(); - Set files = new HashSet(); - while (it.hasNext()) { - String loc = (String) it.next(); - String locEval = project.getEvaluator().evaluate(loc); - if (locEval == null) { - continue; - } - FileObject file = project.getHelper().resolveFileObject(locEval); - if (file != null) { - newVisibleFiles.add(loc); - files.add(file); - } - } - if (!isInitialized() || !newVisibleFiles.equals(visibleFiles)) { - visibleFiles = newVisibleFiles; - RequestProcessor.getDefault().post(new Runnable() { // #72471 - public void run() { - setKeys(visibleFiles); - } - }); - ((ModuleLogicalView.ImportantFilesNode) getNode()).setFiles(files); // #72439 - } - } - - private void attachListeners() { - try { - if (fcl == null) { - fcl = new FileChangeAdapter() { - public void fileDataCreated(FileEvent fe) { - refreshKeys(); - } - public void fileDeleted(FileEvent fe) { - refreshKeys(); - } - }; - project.getProjectDirectory().getFileSystem().addFileChangeListener(fcl); - } - } catch (FileStateInvalidException e) { - assert false : e; - } - } - - private void removeListeners() { - if (fcl != null) { - try { - project.getProjectDirectory().getFileSystem().removeFileChangeListener(fcl); - } catch (FileStateInvalidException e) { - assert false : e; - } - fcl = null; - } - } - - } - } Index: src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml =================================================================== RCS file: /cvs/apisupport/project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml,v retrieving revision 1.41 diff -u -r1.41 layer.xml --- src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml 30 Jun 2006 18:12:21 -0000 1.41 +++ src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml 13 Feb 2007 10:11:56 -0000 @@ -175,6 +175,24 @@ + + + + + + + + + + + + + + + + + +