--- a/projectapi/src/org/netbeans/spi/project/ActionProvider.java +++ a/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(...) --- a/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java +++ a/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java @@ -41,9 +41,11 @@ package org.netbeans.modules.project.ui.actions; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import javax.swing.Action; import javax.swing.Icon; -import javax.swing.ImageIcon; import org.netbeans.api.project.Project; import org.netbeans.spi.project.ActionProvider; import org.openide.awt.Actions; @@ -56,6 +58,7 @@ public final class FileCommandAction extends ProjectAction { private String presenterName; + private Collection providers = new ArrayList(); public FileCommandAction( String command, String namePattern, String iconResource, Lookup lookup ) { this( command, namePattern, ImageUtilities.loadImageIcon(iconResource, false), lookup ); @@ -67,6 +70,13 @@ presenterName = ActionsUtil.formatName( getNamePattern(), 0, "" ); setDisplayName( presenterName ); putValue(SHORT_DESCRIPTION, Actions.cutAmpersand(presenterName)); + + Collection registeredProviders = Lookup.getDefault().lookupAll(ActionProvider.class); + for (ActionProvider p : registeredProviders) { + if (Arrays.asList(p.getSupportedActions()).contains(getCommand())) { + providers.add(p); + } + } } @Override @@ -74,8 +84,19 @@ 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, "" ); + boolean supportedByProvider = false; + for (ActionProvider provider : providers) { + if (provider.isActionEnabled(getCommand(), context)) { + setEnabled(true); + presenterName = ActionsUtil.formatName(getNamePattern(), 0, ""); + supportedByProvider = true; + break; + } + } + if (!supportedByProvider) { + 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] ); @@ -94,8 +115,15 @@ if ( projects.length == 1 ) { ActionProvider ap = (ActionProvider)projects[0].getLookup().lookup( ActionProvider.class ); ap.invokeAction( getCommand(), context ); + return; } + for (ActionProvider provider : providers) { + if (provider.isActionEnabled(getCommand(), context)) { + provider.invokeAction(getCommand(), context); + return; + } + } }