Issue 102081: make it possible to define single-file actions outside of any project context. diff --git a/projectapi/src/org/netbeans/spi/project/ActionProvider.java b/projectapi/src/org/netbeans/spi/project/ActionProvider.java --- a/projectapi/src/org/netbeans/spi/project/ActionProvider.java +++ b/projectapi/src/org/netbeans/spi/project/ActionProvider.java @@ -46,6 +46,12 @@ /** * Ability for a project to have various actions (e.g. Build) invoked on it. * Should be registered in a project's lookup and will be used by UI infrastructure. + *

+ * Implementations supporting single file commands (command constants ending with + * {@code _SINGLE}) can also be registered in default lookup. If a provider in project + * lookup does not enable the action for a given command on the selected file then + * the first implementation found in default lookup that is enabled will be used. + *

* @see org.netbeans.api.project.Project#getLookup * @see ActionUtils * @see ProjectSensitiveActions.projectCommandAction(...) diff --git a/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java b/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java --- a/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java +++ b/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java @@ -41,12 +41,15 @@ package org.netbeans.modules.project.ui.actions; +import java.util.Arrays; +import java.util.Collection; import javax.swing.Action; import javax.swing.Icon; import org.netbeans.api.project.Project; import org.netbeans.spi.project.ActionProvider; import org.openide.awt.Actions; import org.openide.filesystems.FileObject; +import org.openide.loaders.DataObject; import org.openide.util.ImageUtilities; import org.openide.util.Lookup; @@ -73,8 +76,15 @@ Project[] projects = ActionsUtil.getProjectsFromLookup( context, getCommand() ); if ( projects.length != 1 ) { - setEnabled( false ); // Zero or more than one projects found or command not supported - presenterName = ActionsUtil.formatName( getNamePattern(), 0, "" ); + if (projects.length == 0 && globalProvider(context) != null) { + setEnabled(true); + Collection files = context.lookupAll(DataObject.class); + presenterName = ActionsUtil.formatName(getNamePattern(), files.size(), + files.isEmpty() ? "" : files.iterator().next().getPrimaryFile().getNameExt()); // NOI18N + } else { + setEnabled(false); // Zero or more than one projects found or command not supported + presenterName = ActionsUtil.formatName(getNamePattern(), 0, ""); + } } else { FileObject[] files = ActionsUtil.getFilesFromLookup( context, projects[0] ); @@ -93,8 +103,13 @@ if ( projects.length == 1 ) { ActionProvider ap = projects[0].getLookup().lookup(ActionProvider.class); ap.invokeAction( getCommand(), context ); + return; } + ActionProvider provider = globalProvider(context); + if (provider != null) { + provider.invokeAction(getCommand(), context); + } } @Override @@ -102,4 +117,13 @@ return new FileCommandAction( getCommand(), getNamePattern(), (Icon)getValue( SMALL_ICON ), actionContext ); } + private ActionProvider globalProvider(Lookup context) { + for (ActionProvider ap : Lookup.getDefault().lookupAll(ActionProvider.class)) { + if (Arrays.asList(ap.getSupportedActions()).contains(getCommand()) && ap.isActionEnabled(getCommand(), context)) { + return ap; + } + } + return null; + } + } \ No newline at end of file