# HG changeset patch # User Jesse Glick # Date 1269569617 14400 Issue #182488: declarative registration of project root node actions. diff --git a/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java b/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java --- a/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java +++ b/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java @@ -63,6 +63,9 @@ import java.util.regex.PatternSyntaxException; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.JSeparator; import org.apache.tools.ant.module.api.support.ActionUtils; import org.netbeans.modules.ant.freeform.spi.support.Util; import org.netbeans.modules.ant.freeform.ui.TargetMappingPanel; @@ -76,12 +79,15 @@ import org.openide.ErrorManager; import org.openide.NotifyDescriptor; import org.openide.actions.FindAction; +import org.openide.awt.DynamicMenuContent; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; +import org.openide.util.ContextAwareAction; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.Utilities; +import org.openide.util.actions.Presenter; import org.openide.util.actions.SystemAction; import org.w3c.dom.Element; @@ -443,16 +449,59 @@ } TARGET_RUNNER.runTarget(scriptFile, targetNameArray, props); } + + public static final class Custom extends AbstractAction implements ContextAwareAction { + public Custom() { + setEnabled(false); + putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true); + } + public @Override void actionPerformed(ActionEvent e) { + assert false; + } + public @Override Action createContextAwareInstance(Lookup actionContext) { + Collection projects = actionContext.lookupAll(FreeformProject.class); + if (projects.size() != 1) { + return this; + } + final FreeformProject p = projects.iterator().next(); + class A extends AbstractAction implements Presenter.Popup { + public @Override void actionPerformed(ActionEvent e) { + assert false; + } + public @Override JMenuItem getPopupPresenter() { + class M extends JMenuItem implements DynamicMenuContent { + public @Override JComponent[] getMenuPresenters() { + Action[] actions = contextMenuCustomActions(p); + JComponent[] comps = new JComponent[actions.length]; + for (int i = 0; i < actions.length; i++) { + if (actions[i] != null) { + JMenuItem item = new JMenuItem(); + org.openide.awt.Actions.connect(item, actions[i], true); + comps[i] = item; + } else { + comps[i] = new JSeparator(); + } + } + return comps; + } + public @Override JComponent[] synchMenuPresenters(JComponent[] items) { + return getMenuPresenters(); + } + } + return new M(); + } + } + return new A(); + } + } /** * Build the context menu for a project. * @param p a freeform project * @return a list of actions (or null for separators) */ - public static Action[] createContextMenu(FreeformProject p) { + private static Action[] contextMenuCustomActions(FreeformProject p) { List actions = new ArrayList(); - actions.add(CommonProjectActions.newFileAction()); - // Requested actions. Element genldata = p.getPrimaryConfigurationData(); Element viewEl = Util.findElement(genldata, "view", FreeformProjectType.NS_GENERAL); // NOI18N if (viewEl != null) { @@ -479,25 +528,6 @@ } } } - actions.addAll(Utilities.actionsForPath("Projects/Profiler_Actions_temporary")); //NOI18N - // Back to generic actions. - actions.add(null); - actions.add(CommonProjectActions.setAsMainProjectAction()); - actions.add(CommonProjectActions.openSubprojectsAction()); - actions.add(CommonProjectActions.closeProjectAction()); - actions.add(null); - actions.add(CommonProjectActions.renameProjectAction()); - actions.add(CommonProjectActions.moveProjectAction()); - actions.add(CommonProjectActions.copyProjectAction()); - actions.add(CommonProjectActions.deleteProjectAction()); - actions.add(null); - actions.add(SystemAction.get(FindAction.class)); - - // honor #57874 contract, see #58624: - actions.addAll(Utilities.actionsForPath("Projects/Actions")); - - actions.add(null); - actions.add(CommonProjectActions.customizeProjectAction()); return actions.toArray(new Action[actions.size()]); } diff --git a/ant.freeform/src/org/netbeans/modules/ant/freeform/resources/layer.xml b/ant.freeform/src/org/netbeans/modules/ant/freeform/resources/layer.xml --- a/ant.freeform/src/org/netbeans/modules/ant/freeform/resources/layer.xml +++ b/ant.freeform/src/org/netbeans/modules/ant/freeform/resources/layer.xml @@ -58,6 +58,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ant.freeform/src/org/netbeans/modules/ant/freeform/ui/View.java b/ant.freeform/src/org/netbeans/modules/ant/freeform/ui/View.java --- a/ant.freeform/src/org/netbeans/modules/ant/freeform/ui/View.java +++ b/ant.freeform/src/org/netbeans/modules/ant/freeform/ui/View.java @@ -47,10 +47,10 @@ import java.util.StringTokenizer; import javax.swing.Action; import org.netbeans.api.project.ProjectUtils; -import org.netbeans.modules.ant.freeform.Actions; import org.netbeans.modules.ant.freeform.FreeformProject; import org.netbeans.modules.ant.freeform.spi.ProjectNature; import org.netbeans.spi.project.ui.LogicalViewProvider; +import org.netbeans.spi.project.ui.support.CommonProjectActions; import org.netbeans.spi.project.ui.support.DefaultProjectOperations; import org.netbeans.spi.project.ui.support.NodeFactorySupport; import org.openide.filesystems.FileObject; @@ -65,7 +65,6 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.NbCollections; -import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; /** @@ -158,7 +157,7 @@ @Override public Action[] getActions(boolean context) { - return Actions.createContextMenu(p); + return CommonProjectActions.forType("org-netbeans-modules-ant-freeform"); // NOI18N } @Override diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java @@ -92,7 +92,6 @@ import org.netbeans.spi.java.project.support.LookupMergerSupport; import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport; import org.netbeans.spi.project.AuxiliaryConfiguration; -import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.ant.AntArtifactProvider; import org.netbeans.spi.project.ant.AntBuildExtenderFactory; import org.netbeans.spi.project.support.LookupProviderSupport; @@ -122,7 +121,6 @@ import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; -import org.openide.modules.InstalledFileLocator; import org.openide.util.ChangeSupport; import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; @@ -315,7 +313,6 @@ private Lookup createLookup(final AuxiliaryConfiguration aux, final J2SEActionProvider actionProvider) { - final SubprojectProvider spp = refHelper.createSubprojectProvider(); FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), J2SEProjectProperties.SOURCE_ENCODING); @SuppressWarnings("deprecation") Object cpe = new org.netbeans.modules.java.api.common.classpath.ClassPathExtender( cpMod, ProjectProperties.JAVAC_CLASSPATH, null); @@ -326,9 +323,9 @@ aux, helper.createCacheDirectoryProvider(), helper.createAuxiliaryProperties(), - spp, + refHelper.createSubprojectProvider(), actionProvider, - new J2SELogicalViewProvider(this, this.updateHelper, evaluator(), spp, refHelper), + new J2SELogicalViewProvider(this, this.updateHelper, evaluator(), refHelper), // new J2SECustomizerProvider(this, this.updateHelper, evaluator(), refHelper), new CustomizerProviderImpl(this, this.updateHelper, evaluator(), refHelper, this.genFilesHelper), LookupMergerSupport.createClassPathProviderMerger(cpProvider), diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/Bundle.properties b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/Bundle.properties --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/Bundle.properties +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/Bundle.properties @@ -38,12 +38,6 @@ # made subject to such option by the copyright holder. #Actions -LBL_CleanAction_Name=Clean -LBL_BuildAction_Name=Build -LBL_RebuildAction_Name=Clean and Build -LBL_RunAction_Name=Run -LBL_JavadocAction_Name=Generate Javadoc -LBL_TestAction_Name=Test LBL_Properties_Action=Properties LBL_AddProject_Action=Add Project... LBL_AddLibrary_Action=Add Library... diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/J2SELogicalViewProvider.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/J2SELogicalViewProvider.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/J2SELogicalViewProvider.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/J2SELogicalViewProvider.java @@ -48,16 +48,13 @@ import java.io.CharConversionException; import java.io.IOException; import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.ResourceBundle; +import java.util.Collection; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.netbeans.api.java.platform.JavaPlatform; import org.netbeans.api.java.platform.JavaPlatformManager; -import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectUtils; @@ -70,29 +67,26 @@ import org.netbeans.modules.java.j2seproject.J2SEProject; import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport; import org.netbeans.spi.java.project.support.ui.PackageView; -import org.netbeans.spi.project.ActionProvider; -import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.support.ant.PropertyEvaluator; import org.netbeans.spi.project.support.ant.ReferenceHelper; import org.netbeans.spi.project.ui.support.CommonProjectActions; import org.netbeans.spi.project.ui.support.NodeFactorySupport; import org.netbeans.spi.project.ui.support.DefaultProjectOperations; -import org.netbeans.spi.project.ui.support.ProjectSensitiveActions; import org.openide.ErrorManager; -import org.openide.actions.FindAction; +import org.openide.awt.DynamicMenuContent; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.modules.SpecificationVersion; import org.openide.nodes.AbstractNode; import org.openide.nodes.Node; import org.openide.util.ChangeSupport; +import org.openide.util.ContextAwareAction; import org.openide.util.HelpCtx; import org.openide.util.ImageUtilities; +import org.openide.util.Lookup; 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.SystemAction; import org.openide.util.lookup.Lookups; import org.openide.xml.XMLUtil; @@ -107,21 +101,29 @@ private final J2SEProject project; private final UpdateHelper helper; private final PropertyEvaluator evaluator; - private final SubprojectProvider spp; private final ReferenceHelper resolver; private final ChangeSupport changeSupport = new ChangeSupport(this); + private final PropertyChangeListener pcl; - public J2SELogicalViewProvider(J2SEProject project, UpdateHelper helper, PropertyEvaluator evaluator, SubprojectProvider spp, ReferenceHelper resolver) { + public J2SELogicalViewProvider(J2SEProject project, UpdateHelper helper, PropertyEvaluator evaluator, ReferenceHelper resolver) { this.project = project; assert project != null; this.helper = helper; assert helper != null; this.evaluator = evaluator; assert evaluator != null; - this.spp = spp; - assert spp != null; this.resolver = resolver; assert resolver != null; + pcl = new PropertyChangeListener() { + public @Override void propertyChange(PropertyChangeEvent evt) { + testBroken(); + } + }; + evaluator.addPropertyChangeListener(pcl); + // When evaluator fires changes that platform properties were + // removed the platform still exists in JavaPlatformManager. + // That's why I have to listen here also on JPM: + JavaPlatformManager.getDefault().addPropertyChangeListener(WeakListeners.propertyChange(pcl, JavaPlatformManager.getDefault())); } public Node createLogicalView() { @@ -174,13 +176,32 @@ changeSupport.removeChangeListener(l); } + private final RequestProcessor.Task task = RP.create(new Runnable() { + public @Override void run() { + boolean old = broken; + boolean _broken = hasBrokenLinks(); + if (old != _broken) { + setBroken(_broken); + } + old = illegalState; + boolean _illegalState = hasInvalidJdkVersion(); + if (old != _illegalState) { + setIllegalState(_illegalState); + } + old = compileOnSaveDisabled; + boolean _compileOnSaveDisabled = isCompileOnSaveDisabled(); + if (old != _compileOnSaveDisabled) { + setCompileOnSaveDisabled(_compileOnSaveDisabled); + } + } + }); + /** * Used by J2SEProjectCustomizer to mark the project as broken when it warns user - * about project's broken references and advices him to use BrokenLinksAction to correct it. - * + * about project's broken references and advises him to use BrokenLinksAction to correct it. */ - public void testBroken() { - changeSupport.fireChange(); + public @Override void testBroken() { + task.schedule(100); } @@ -201,7 +222,7 @@ new String[] {J2SEProjectProperties.JAVA_PLATFORM}); } - public boolean hasInvalidJdkVersion () { + private boolean hasInvalidJdkVersion () { String javaSource = this.evaluator.getProperty("javac.source"); //NOI18N String javaTarget = this.evaluator.getProperty("javac.target"); //NOI18N if (javaSource == null && javaTarget == null) { @@ -250,16 +271,10 @@ String compileOnSaveDisabledTP = " " + NbBundle.getMessage(J2SELogicalViewProvider.class, "TP_CompileOnSaveDisabled"); compileOnSaveDisabledBadge = ImageUtilities.assignToolTipToImage(ImageUtilities.loadImage(COMPILE_ON_SAVE_DISABLED_BADGE_PATH), compileOnSaveDisabledTP); // NOI18N } - - /** Filter node containin additional features for the J2SE physical - */ - private final class J2SELogicalViewRootNode extends AbstractNode { + + private final class J2SELogicalViewRootNode extends AbstractNode implements ChangeListener { - private Action brokenLinksAction; - private boolean broken; //Represents a state where project has a broken reference repairable by broken reference support - private boolean illegalState; //Represents a state where project is not in legal state, eg invalid source/target level - private boolean compileOnSaveDisabled; //true iff Compile-on-Save is disabled - + @SuppressWarnings("LeakingThisInConstructor") public J2SELogicalViewRootNode() { super(NodeFactorySupport.createCompositeChildren(project, "Projects/org-netbeans-modules-java-j2seproject/Nodes"), Lookups.singleton(project)); @@ -272,7 +287,7 @@ illegalState = true; } compileOnSaveDisabled = isCompileOnSaveDisabled(); - brokenLinksAction = new BrokenLinksAction(); + addChangeListener(WeakListeners.change(this, J2SELogicalViewProvider.this)); } @Override @@ -315,9 +330,15 @@ } } + public @Override void stateChanged(ChangeEvent e) { + fireIconChange(); + fireOpenedIconChange(); + fireDisplayNameChange(null, null); + } + @Override public Action[] getActions( boolean context ) { - return getAdditionalActions(); + return CommonProjectActions.forType("org-netbeans-modules-java-j2seproject"); // NOI18N } @Override @@ -334,145 +355,77 @@ public HelpCtx getHelpCtx() { return new HelpCtx(J2SELogicalViewRootNode.class); } - - // Private methods ------------------------------------------------- - - private Action[] getAdditionalActions() { - - ResourceBundle bundle = NbBundle.getBundle(J2SELogicalViewProvider.class); - - List actions = new ArrayList(); - - actions.add(CommonProjectActions.newFileAction()); - actions.add(null); - actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_BUILD, bundle.getString("LBL_BuildAction_Name"), null)); // NOI18N - actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_REBUILD, bundle.getString("LBL_RebuildAction_Name"), null)); // NOI18N - actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_CLEAN, bundle.getString("LBL_CleanAction_Name"), null)); // NOI18N - actions.add(ProjectSensitiveActions.projectCommandAction(JavaProjectConstants.COMMAND_JAVADOC, bundle.getString("LBL_JavadocAction_Name"), null)); // NOI18N - actions.add(null); - actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_RUN, bundle.getString("LBL_RunAction_Name"), null)); // NOI18N - actions.addAll(Utilities.actionsForPath("Projects/Debugger_Actions_temporary")); //NOI18N - actions.addAll(Utilities.actionsForPath("Projects/Profiler_Actions_temporary")); //NOI18N - actions.add(ProjectSensitiveActions.projectCommandAction(ActionProvider.COMMAND_TEST, bundle.getString("LBL_TestAction_Name"), null)); // NOI18N - actions.add(CommonProjectActions.setProjectConfigurationAction()); - actions.add(null); - actions.add(CommonProjectActions.setAsMainProjectAction()); - actions.add(CommonProjectActions.openSubprojectsAction()); - actions.add(CommonProjectActions.closeProjectAction()); - actions.add(null); - actions.add(CommonProjectActions.renameProjectAction()); - actions.add(CommonProjectActions.moveProjectAction()); - actions.add(CommonProjectActions.copyProjectAction()); - actions.add(CommonProjectActions.deleteProjectAction()); - actions.add(null); - actions.add(SystemAction.get(FindAction.class)); - - // honor 57874 contact - actions.addAll(Utilities.actionsForPath("Projects/Actions")); //NOI18N - - actions.add(null); - if (broken) { - actions.add(brokenLinksAction); - } - actions.add(CommonProjectActions.customizeProjectAction()); - - return actions.toArray(new Action[actions.size()]); - - } - - private void setBroken(boolean broken) { - this.broken = broken; - brokenLinksAction.setEnabled(broken); - fireIconChange(); - fireOpenedIconChange(); - fireDisplayNameChange(null, null); - } - - private void setIllegalState (boolean illegalState) { - this.illegalState = illegalState; - fireIconChange(); - fireOpenedIconChange(); - fireDisplayNameChange(null, null); - } - - private void setCompileOnSaveDisabled (boolean value) { - this.compileOnSaveDisabled = value; - fireIconChange(); - fireOpenedIconChange(); - fireDisplayNameChange(null, null); + + } + + private boolean broken; //Represents a state where project has a broken reference repairable by broken reference support + private boolean illegalState; //Represents a state where project is not in legal state, eg invalid source/target level + private boolean compileOnSaveDisabled; //true iff Compile-on-Save is disabled + + // Private methods ------------------------------------------------- + + private void setBroken(boolean broken) { + this.broken = broken; + changeSupport.fireChange(); + } + + private void setIllegalState (boolean illegalState) { + this.illegalState = illegalState; + changeSupport.fireChange(); + } + + private void setCompileOnSaveDisabled (boolean value) { + this.compileOnSaveDisabled = value; + changeSupport.fireChange(); + } + + public static final class BrokenLinksActionFactory extends AbstractAction implements ContextAwareAction { + + /** for layer registration */ + public BrokenLinksActionFactory() { + setEnabled(false); + putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true); } - /** This action is created only when project has broken references. - * Once these are resolved the action is disabled. - */ - private class BrokenLinksAction extends AbstractAction implements PropertyChangeListener, ChangeListener, Runnable { - - private RequestProcessor.Task task = null; - - private PropertyChangeListener weakPCL; - - public BrokenLinksAction() { - putValue(Action.NAME, NbBundle.getMessage(J2SELogicalViewProvider.class, "LBL_Fix_Broken_Links_Action")); - setEnabled(broken); - evaluator.addPropertyChangeListener(this); - // When evaluator fires changes that platform properties were - // removed the platform still exists in JavaPlatformManager. - // That's why I have to listen here also on JPM: - weakPCL = WeakListeners.propertyChange(this, JavaPlatformManager.getDefault()); - JavaPlatformManager.getDefault().addPropertyChangeListener(weakPCL); - J2SELogicalViewProvider.this.addChangeListener(WeakListeners.change(this, J2SELogicalViewProvider.this)); + public @Override void actionPerformed(ActionEvent e) { + assert false; + } + + public @Override Action createContextAwareInstance(Lookup actionContext) { + Collection p = actionContext.lookupAll(Project.class); + if (p.size() != 1) { + return this; } - - public void actionPerformed(ActionEvent e) { - try { - helper.requestUpdate(); - BrokenReferencesSupport.showCustomizer(helper.getAntProjectHelper(), resolver, getBreakableProperties(), new String[] {J2SEProjectProperties.JAVA_PLATFORM}); - run(); - } catch (IOException ioe) { - ErrorManager.getDefault().notify(ioe); - } + J2SELogicalViewProvider lvp = p.iterator().next().getLookup().lookup(J2SELogicalViewProvider.class); + if (lvp == null) { + return this; } - - public void propertyChange(PropertyChangeEvent evt) { - refsMayChanged(); + return lvp.new BrokenLinksAction(); + } + + } + + /** This action is created only when project has broken references. + * Once these are resolved the action is disabled. + */ + private class BrokenLinksAction extends AbstractAction { + + public BrokenLinksAction() { + putValue(Action.NAME, NbBundle.getMessage(J2SELogicalViewProvider.class, "LBL_Fix_Broken_Links_Action")); + setEnabled(broken); + putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true); + } + + public void actionPerformed(ActionEvent e) { + try { + helper.requestUpdate(); + BrokenReferencesSupport.showCustomizer(helper.getAntProjectHelper(), resolver, getBreakableProperties(), new String[] {J2SEProjectProperties.JAVA_PLATFORM}); + testBroken(); + } catch (IOException ioe) { + ErrorManager.getDefault().notify(ioe); } - - - public void stateChanged(ChangeEvent evt) { - refsMayChanged(); - } - - public synchronized void run() { - boolean old = J2SELogicalViewRootNode.this.broken; - boolean broken = hasBrokenLinks(); - if (old != broken) { - setBroken(broken); - } - - old = J2SELogicalViewRootNode.this.illegalState; - broken = hasInvalidJdkVersion (); - if (old != broken) { - setIllegalState(broken); - } - old = J2SELogicalViewRootNode.this.compileOnSaveDisabled; - boolean cosDisabled = isCompileOnSaveDisabled(); - if (old != cosDisabled) { - setCompileOnSaveDisabled(cosDisabled); - } - } - - private void refsMayChanged() { - // check project state whenever there was a property change - // or change in list of platforms. - // Coalesce changes since they can come quickly: - if (task == null) { - task = RP.create(this); - } - task.schedule(100); - } - } - + } - + } diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/resources/layer.xml b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/resources/layer.xml --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/resources/layer.xml +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/resources/layer.xml @@ -100,9 +100,118 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/o.n.core/test/qa-functional/src/org/netbeans/core/validation/ValidateLayerConsistencyTest.java b/o.n.core/test/qa-functional/src/org/netbeans/core/validation/ValidateLayerConsistencyTest.java --- a/o.n.core/test/qa-functional/src/org/netbeans/core/validation/ValidateLayerConsistencyTest.java +++ b/o.n.core/test/qa-functional/src/org/netbeans/core/validation/ValidateLayerConsistencyTest.java @@ -435,7 +435,7 @@ continue; } if (fo.getPath().startsWith("NativeProjects/Actions/")) { - // I should probably report a bug for NativeProjects + // XXX should perhaps be replaced continue; } if (fo.getPath().startsWith("contextmenu/uml/")) { diff --git a/openide.awt/src/org/netbeans/modules/openide/awt/DefaultAWTBridge.java b/openide.awt/src/org/netbeans/modules/openide/awt/DefaultAWTBridge.java --- a/openide.awt/src/org/netbeans/modules/openide/awt/DefaultAWTBridge.java +++ b/openide.awt/src/org/netbeans/modules/openide/awt/DefaultAWTBridge.java @@ -59,7 +59,7 @@ import org.openide.util.lookup.ServiceProvider; import org.openide.util.actions.ActionPresenterProvider; -/** Default implementaiton of presenters for various action types. +/** Default implementation of presenters for various action types. */ @ServiceProvider(service=ActionPresenterProvider.class) public final class DefaultAWTBridge extends ActionPresenterProvider { @@ -76,17 +76,19 @@ return new Actions.MenuItem (action, true); } - public JMenuItem createPopupPresenter(Action action) { + public @Override JMenuItem createPopupPresenter(Action action) { + JMenuItem item; if (action instanceof BooleanStateAction) { BooleanStateAction b = (BooleanStateAction)action; - return new Actions.CheckboxMenuItem (b, false); + item = new Actions.CheckboxMenuItem (b, false); + } else if (action instanceof SystemAction) { + SystemAction s = (SystemAction)action; + item = new Actions.MenuItem (s, false); + } else { + item = new Actions.MenuItem (action, false); } - if (action instanceof SystemAction) { - SystemAction s = (SystemAction)action; - return new Actions.MenuItem (s, false); - } - - return new Actions.MenuItem (action, false); + item.putClientProperty(DynamicMenuContent.HIDE_WHEN_DISABLED, action.getValue(DynamicMenuContent.HIDE_WHEN_DISABLED)); + return item; } public Component createToolbarPresenter(Action action) { @@ -105,7 +107,13 @@ return new JPopupMenu(); } - public Component[] convertComponents(Component comp) { + public @Override Component[] convertComponents(Component comp) { + if (comp instanceof JMenuItem) { + JMenuItem item = (JMenuItem) comp; + if (Boolean.TRUE.equals(item.getClientProperty(DynamicMenuContent.HIDE_WHEN_DISABLED)) && !item.isEnabled()) { + return new Component[0]; + } + } if (comp instanceof DynamicMenuContent) { Component[] toRet = ((DynamicMenuContent)comp).getMenuPresenters(); boolean atLeastOne = false; diff --git a/openide.awt/src/org/openide/awt/DynamicMenuContent.java b/openide.awt/src/org/openide/awt/DynamicMenuContent.java --- a/openide.awt/src/org/openide/awt/DynamicMenuContent.java +++ b/openide.awt/src/org/openide/awt/DynamicMenuContent.java @@ -42,6 +42,7 @@ package org.openide.awt; import javax.swing.JComponent; +import org.openide.util.Utilities; /** * Dynamic result of a {@link org.openide.util.actions.Presenter.Menu} or {@link org.openide.util.actions.Presenter.Popup}. If the presenters return @@ -66,4 +67,17 @@ * @return a new set of items to show in menu. Can be either an updated old set of instances or a completely new one. */ public JComponent[] synchMenuPresenters(JComponent[] items); + + /** + * Marker for actions which should be hidden rather than merely disabled. + * {@link Utilities#actionsToPopup(Action[],Lookup)} will skip over any disabled + * actions which have this property set to true, unless they implement + * {@link org.openide.util.actions.Presenter.Popup}. + * This is a convenient way to make context menu items disappear when disabled; + * for more complex cases you still need to have a popup presenter with dynamic + * menu content. + * @since XXX + */ + String HIDE_WHEN_DISABLED = "hideWhenDisabled"; // NOI18N + } diff --git a/openide.util.lookup/src/org/openide/util/lookup/Lookups.java b/openide.util.lookup/src/org/openide/util/lookup/Lookups.java --- a/openide.util.lookup/src/org/openide/util/lookup/Lookups.java +++ b/openide.util.lookup/src/org/openide/util/lookup/Lookups.java @@ -214,7 +214,7 @@ *

* Read more about the usage of this method. * - * @param path the path identifying the lookup, e.g. Projects/Actions + * @param path the path identifying the lookup, e.g. Servers/J2EEWrapper * @return lookup associated with this path * @since 7.9 */ diff --git a/profiler/src/org/netbeans/modules/profiler/mf-layer.xml b/profiler/src/org/netbeans/modules/profiler/mf-layer.xml --- a/profiler/src/org/netbeans/modules/profiler/mf-layer.xml +++ b/profiler/src/org/netbeans/modules/profiler/mf-layer.xml @@ -44,9 +44,8 @@ - - - + + @@ -392,9 +391,6 @@ - - - @@ -426,6 +422,12 @@ + + + + + + diff --git a/projectui/src/org/netbeans/modules/project/ui/actions/Actions.java b/projectui/src/org/netbeans/modules/project/ui/actions/Actions.java --- a/projectui/src/org/netbeans/modules/project/ui/actions/Actions.java +++ b/projectui/src/org/netbeans/modules/project/ui/actions/Actions.java @@ -67,7 +67,6 @@ private static Action SET_AS_MAIN_PROJECT; private static Action CUSTOMIZE_PROJECT; - private static Action OPEN_SUBPROJECTS; private static Action CLOSE_PROJECT; private static Action NEW_FILE; private static Action COPY_PROJECT; @@ -89,10 +88,7 @@ } public synchronized Action openSubprojectsAction() { - if ( OPEN_SUBPROJECTS == null ) { - OPEN_SUBPROJECTS = new OpenSubprojects(); - } - return OPEN_SUBPROJECTS; + return SystemAction.get(OpenSubprojects.class); } public synchronized Action closeProjectAction() { @@ -103,11 +99,15 @@ } public synchronized Action newFileAction() { + return newFile(); + } + + public static Action newFile() { if ( NEW_FILE == null ) { NEW_FILE = new NewFile.WithSubMenu(); } return NEW_FILE; - } + } public Action deleteProjectAction() { return deleteProject(); @@ -154,16 +154,19 @@ public static Action javadocProject() { return new ProjectAction ( - "javadoc", // XXX Define standard - NbBundle.getMessage(Actions.class, "LBL_JavadocProjectAction_Name" ), // NOI18N + "javadoc", // XXX move to java.project and use JavaProjectConstants.COMMAND_JAVADOC + NbBundle.getMessage(Actions.class, "LBL_JavadocProjectAction_Name"), + NbBundle.getMessage(Actions.class, "LBL_JavadocProjectAction_Name_popup"), null, null ); } public static Action testProject() { Action a = new ProjectAction ( - "test", // XXX Define standard - NbBundle.getMessage(Actions.class, "LBL_TestProjectAction_Name" ),ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/testProject.png", false), //NOI18N + ActionProvider.COMMAND_TEST, + NbBundle.getMessage(Actions.class, "LBL_TestProjectAction_Name"), + NbBundle.getMessage(Actions.class, "LBL_TestProjectAction_Name_popup"), + ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/testProject.png", false), null ); a.putValue("iconBase","org/netbeans/modules/project/ui/resources/testProject.png"); //NOI18N a.putValue("noIconInMenu", Boolean.TRUE); //NOI18N @@ -174,7 +177,9 @@ public static Action buildProject() { Action a = new ProjectAction ( ActionProvider.COMMAND_BUILD, - NbBundle.getMessage(Actions.class, "LBL_BuildProjectAction_Name" ),ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/buildCurrentProject.gif", false), //NOI18N + NbBundle.getMessage(Actions.class, "LBL_BuildProjectAction_Name"), + NbBundle.getMessage(Actions.class, "LBL_BuildProjectAction_Name_popup"), + ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/buildCurrentProject.gif", false), null ); a.putValue("iconBase","org/netbeans/modules/project/ui/resources/buildCurrentProject.gif"); //NOI18N return a; @@ -183,7 +188,9 @@ public static Action cleanProject() { Action a = new ProjectAction( ActionProvider.COMMAND_CLEAN, - NbBundle.getMessage(Actions.class, "LBL_CleanProjectAction_Name" ),ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/cleanCurrentProject.gif", false), //NOI18N + NbBundle.getMessage(Actions.class, "LBL_CleanProjectAction_Name"), + NbBundle.getMessage(Actions.class, "LBL_CleanProjectAction_Name_popup"), + ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/cleanCurrentProject.gif", false), null ); a.putValue("iconBase","org/netbeans/modules/project/ui/resources/cleanCurrentProject.gif"); //NOI18N return a; @@ -192,7 +199,9 @@ public static Action rebuildProject() { Action a = new ProjectAction( ActionProvider.COMMAND_REBUILD, - NbBundle.getMessage(Actions.class, "LBL_RebuildProjectAction_Name"),ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/rebuildCurrentProject.gif", false), //NOI18N + NbBundle.getMessage(Actions.class, "LBL_RebuildProjectAction_Name"), + NbBundle.getMessage(Actions.class, "LBL_RebuildProjectAction_Name_popup"), + ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/rebuildCurrentProject.gif", false), null ); a.putValue("iconBase","org/netbeans/modules/project/ui/resources/rebuildCurrentProject.gif"); //NOI18N return a; @@ -201,7 +210,9 @@ public static Action runProject() { Action a = new ProjectAction( ActionProvider.COMMAND_RUN, - NbBundle.getMessage(Actions.class, "LBL_RunProjectAction_Name"),ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/runCurrentProject.gif", false), //NOI18N + NbBundle.getMessage(Actions.class, "LBL_RunProjectAction_Name"), + NbBundle.getMessage(Actions.class, "LBL_RunProjectAction_Name_popup"), + ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/runCurrentProject.gif", false), null ); a.putValue("iconBase","org/netbeans/modules/project/ui/resources/runCurrentProject.gif"); //NOI18N return a; diff --git a/projectui/src/org/netbeans/modules/project/ui/actions/Bundle.properties b/projectui/src/org/netbeans/modules/project/ui/actions/Bundle.properties --- a/projectui/src/org/netbeans/modules/project/ui/actions/Bundle.properties +++ b/projectui/src/org/netbeans/modules/project/ui/actions/Bundle.properties @@ -69,10 +69,17 @@ # {0} number of project # {1} the first project name LBL_BuildProjectAction_Name=Build {0,choice,0#Project|1#Project ({1})|1<{0} Projects} +LBL_BuildProjectAction_Name_popup=Build LBL_CleanProjectAction_Name=Clean {0,choice,0#Project|1#Project ({1})|1<{0} Projects} +LBL_CleanProjectAction_Name_popup=Clean LBL_RebuildProjectAction_Name=Clean and Build {0,choice,0#Project|1#Project ({1})|1<{0} Projects} +LBL_RebuildProjectAction_Name_popup=Clean and Build LBL_JavadocProjectAction_Name=&Generate Javadoc{0,choice,0#|1# ({1})|1< {0} Projects} +LBL_JavadocProjectAction_Name_popup=Generate Javadoc +LBL_RunProjectAction_Name=Run {0,choice,0#Project|1#"{1}" Project|1<{0} Projects} +LBL_RunProjectAction_Name_popup=Run LBL_TestProjectAction_Name=&Test {0,choice,0#Project|1#Project ({1})|1<{0} Projects} +LBL_TestProjectAction_Name_popup=Test LBL_CompileSingleAction_Name=Compi&le {0,choice,0#File|1#File|1 + + + @@ -65,7 +68,9 @@ - + + + @@ -138,8 +143,18 @@ - - + + + + + + + + + + + + diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/LogicalViewProvider.java b/projectuiapi/src/org/netbeans/spi/project/ui/LogicalViewProvider.java --- a/projectuiapi/src/org/netbeans/spi/project/ui/LogicalViewProvider.java +++ b/projectuiapi/src/org/netbeans/spi/project/ui/LogicalViewProvider.java @@ -41,6 +41,7 @@ package org.netbeans.spi.project.ui; +import org.netbeans.spi.project.ui.support.CommonProjectActions; import org.openide.nodes.Node; /** @@ -64,6 +65,7 @@ * As of org.netbeans.modules.projectuiapi/1 1.31 *

* @return a node displaying the contents of the project in an intuitive way + * @see CommonProjectActions#forType */ Node createLogicalView(); diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/support/CommonProjectActions.java b/projectuiapi/src/org/netbeans/spi/project/ui/support/CommonProjectActions.java --- a/projectuiapi/src/org/netbeans/spi/project/ui/support/CommonProjectActions.java +++ b/projectuiapi/src/org/netbeans/spi/project/ui/support/CommonProjectActions.java @@ -41,8 +41,10 @@ package org.netbeans.spi.project.ui.support; +import java.util.List; import javax.swing.Action; import org.netbeans.modules.project.uiapi.Utilities; +import org.netbeans.spi.project.ui.LogicalViewProvider; /** * Factory for commonly needed generic project actions. @@ -216,4 +218,19 @@ return Utilities.getActionsFactory().setProjectConfigurationAction(); } + /** + * Loads actions to be displayed in the context menu of {@link LogicalViewProvider#createLogicalView}. + * The current implementation simply loads actions from {@code Projects//Actions} + * but in the future it may merge in actions from another location as well. + *

The folder is recommended to contain a link to {@code Projects/Actions} at some position + * in order to pick up miscellaneous actions applicable to all project types. + * @param projectType a type token, such as {@code org-netbeans-modules-java-j2seproject} + * @return a list of actions + * @since org.netbeans.modules.projectuiapi/1 XXX + */ + public static Action[] forType(String projectType) { + List actions = org.openide.util.Utilities.actionsForPath("Projects/" + projectType + "/Actions"); + return actions.toArray(new Action[actions.size()]); + } + }