This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 102081
Collapse All | Expand All

(-)a/projectapi/src/org/netbeans/spi/project/ActionProvider.java (+6 lines)
Lines 46-51 Link Here
46
/**
46
/**
47
 * Ability for a project to have various actions (e.g. Build) invoked on it.
47
 * Ability for a project to have various actions (e.g. Build) invoked on it.
48
 * Should be registered in a project's lookup and will be used by UI infrastructure.
48
 * Should be registered in a project's lookup and will be used by UI infrastructure.
49
 * <p>
50
 * Implementations supporting single file commands (command constants ending with
51
 * {@code _SINGLE}) can also be registered in default lookup. If a provider in project
52
 * lookup does not enable the action for a given command on the selected file then
53
 * the first implementation found in default lookup that is enabled will be used.
54
 * </p>
49
 * @see org.netbeans.api.project.Project#getLookup
55
 * @see org.netbeans.api.project.Project#getLookup
50
 * @see <a href="@org-apache-tools-ant-module@/org/apache/tools/ant/module/api/support/ActionUtils.html"><code>ActionUtils</code></a>
56
 * @see <a href="@org-apache-tools-ant-module@/org/apache/tools/ant/module/api/support/ActionUtils.html"><code>ActionUtils</code></a>
51
 * @see <a href="@org-netbeans-modules-projectuiapi@/org/netbeans/spi/project/ui/support/ProjectSensitiveActions.html#projectCommandAction(java.lang.String,%20java.lang.String,%20javax.swing.Icon)"><code>ProjectSensitiveActions.projectCommandAction(...)</code></a>
57
 * @see <a href="@org-netbeans-modules-projectuiapi@/org/netbeans/spi/project/ui/support/ProjectSensitiveActions.html#projectCommandAction(java.lang.String,%20java.lang.String,%20javax.swing.Icon)"><code>ProjectSensitiveActions.projectCommandAction(...)</code></a>
(-)a/projectui/src/org/netbeans/modules/project/ui/actions/FileCommandAction.java (-2 / +26 lines)
Lines 41-52 Link Here
41
41
42
package org.netbeans.modules.project.ui.actions;
42
package org.netbeans.modules.project.ui.actions;
43
43
44
import java.util.Arrays;
45
import java.util.Collection;
44
import javax.swing.Action;
46
import javax.swing.Action;
45
import javax.swing.Icon;
47
import javax.swing.Icon;
46
import org.netbeans.api.project.Project;
48
import org.netbeans.api.project.Project;
47
import org.netbeans.spi.project.ActionProvider;
49
import org.netbeans.spi.project.ActionProvider;
48
import org.openide.awt.Actions;
50
import org.openide.awt.Actions;
49
import org.openide.filesystems.FileObject;
51
import org.openide.filesystems.FileObject;
52
import org.openide.loaders.DataObject;
50
import org.openide.util.ImageUtilities;
53
import org.openide.util.ImageUtilities;
51
import org.openide.util.Lookup;
54
import org.openide.util.Lookup;
52
55
Lines 73-80 Link Here
73
        Project[] projects = ActionsUtil.getProjectsFromLookup( context, getCommand() );
76
        Project[] projects = ActionsUtil.getProjectsFromLookup( context, getCommand() );
74
77
75
        if ( projects.length != 1 ) {
78
        if ( projects.length != 1 ) {
76
            setEnabled( false ); // Zero or more than one projects found or command not supported            
79
            if (projects.length == 0 && globalProvider(context) != null) {
77
            presenterName = ActionsUtil.formatName( getNamePattern(), 0, "" );            
80
                setEnabled(true);
81
                Collection<? extends DataObject> files = context.lookupAll(DataObject.class);
82
                presenterName = ActionsUtil.formatName(getNamePattern(), files.size(),
83
                        files.isEmpty() ? "" : files.iterator().next().getPrimaryFile().getNameExt()); // NOI18N
84
            } else {
85
                setEnabled(false); // Zero or more than one projects found or command not supported
86
                presenterName = ActionsUtil.formatName(getNamePattern(), 0, "");
87
            }
78
        }
88
        }
79
        else {
89
        else {
80
            FileObject[] files = ActionsUtil.getFilesFromLookup( context, projects[0] );
90
            FileObject[] files = ActionsUtil.getFilesFromLookup( context, projects[0] );
Lines 93-100 Link Here
93
        if ( projects.length == 1 ) {            
103
        if ( projects.length == 1 ) {            
94
            ActionProvider ap = projects[0].getLookup().lookup(ActionProvider.class);
104
            ActionProvider ap = projects[0].getLookup().lookup(ActionProvider.class);
95
            ap.invokeAction( getCommand(), context );
105
            ap.invokeAction( getCommand(), context );
106
            return;
96
        }
107
        }
97
        
108
        
109
        ActionProvider provider = globalProvider(context);
110
        if (provider != null) {
111
            provider.invokeAction(getCommand(), context);
112
        }
98
    }
113
    }
99
114
100
    @Override
115
    @Override
Lines 102-105 Link Here
102
        return new FileCommandAction( getCommand(), getNamePattern(), (Icon)getValue( SMALL_ICON ), actionContext );
117
        return new FileCommandAction( getCommand(), getNamePattern(), (Icon)getValue( SMALL_ICON ), actionContext );
103
    }
118
    }
104
119
120
    private ActionProvider globalProvider(Lookup context) {
121
        for (ActionProvider ap : Lookup.getDefault().lookupAll(ActionProvider.class)) {
122
            if (Arrays.asList(ap.getSupportedActions()).contains(getCommand()) && ap.isActionEnabled(getCommand(), context)) {
123
                return ap;
124
            }
125
        }
126
        return null;
127
    }
128
105
}
129
}
(-)a/projectui/test/unit/src/org/netbeans/modules/project/ui/actions/FileCommandActionTest.java (+33 lines)
Lines 45-50 Link Here
45
import java.util.Collection;
45
import java.util.Collection;
46
import java.util.Iterator;
46
import java.util.Iterator;
47
import java.util.List;
47
import java.util.List;
48
import java.util.concurrent.atomic.AtomicInteger;
49
import javax.swing.Action;
48
import javax.swing.Icon;
50
import javax.swing.Icon;
49
import org.netbeans.api.project.Project;
51
import org.netbeans.api.project.Project;
50
import org.netbeans.api.project.ProjectManager;
52
import org.netbeans.api.project.ProjectManager;
Lines 52-63 Link Here
52
import org.netbeans.junit.NbTestCase;
54
import org.netbeans.junit.NbTestCase;
53
import org.netbeans.modules.project.ui.actions.ProjectActionTest.ActionCreator;
55
import org.netbeans.modules.project.ui.actions.ProjectActionTest.ActionCreator;
54
import org.netbeans.spi.project.ActionProvider;
56
import org.netbeans.spi.project.ActionProvider;
57
import org.netbeans.spi.project.ui.support.FileSensitiveActions;
55
import org.netbeans.spi.project.ui.support.ProjectActionPerformer;
58
import org.netbeans.spi.project.ui.support.ProjectActionPerformer;
56
import org.openide.filesystems.FileObject;
59
import org.openide.filesystems.FileObject;
57
import org.openide.filesystems.FileUtil;
60
import org.openide.filesystems.FileUtil;
58
import org.openide.loaders.DataObject;
61
import org.openide.loaders.DataObject;
62
import org.openide.util.ContextAwareAction;
59
import org.openide.util.Lookup;
63
import org.openide.util.Lookup;
60
import org.openide.util.lookup.Lookups;
64
import org.openide.util.lookup.Lookups;
65
import org.openide.util.test.MockLookup;
61
66
62
public class FileCommandActionTest extends NbTestCase {
67
public class FileCommandActionTest extends NbTestCase {
63
    
68
    
Lines 132-137 Link Here
132
            }
137
            }
133
        }, true);
138
        }, true);
134
    }
139
    }
140
141
    public void testGlobalActions() throws Exception {
142
        final AtomicInteger runCount = new AtomicInteger();
143
        MockLookup.setInstances(new ActionProvider() {
144
            public String[] getSupportedActions() {
145
                return new String[] {"run"};
146
            }
147
            public boolean isActionEnabled(String command, Lookup context) throws IllegalArgumentException {
148
                DataObject d = context.lookup(DataObject.class);
149
                return d != null && d.getPrimaryFile().getName().equals("foo");
150
            }
151
            public void invokeAction(String command, Lookup context) throws IllegalArgumentException {
152
                runCount.incrementAndGet();
153
            }
154
        });
155
        ContextAwareAction global = (ContextAwareAction) FileSensitiveActions.fileCommandAction("run", "Run {0,choice,0#File|1#\"{1}\"|1<Files}", null);
156
        DataObject foo = DataObject.find(FileUtil.createMemoryFileSystem().getRoot().createData("foo"));
157
        DataObject bar = DataObject.find(FileUtil.createMemoryFileSystem().getRoot().createData("bar"));
158
        Action local = global.createContextAwareInstance(Lookups.fixed(foo));
159
        assertTrue(local.isEnabled());
160
        assertEquals("Run \"foo\"", local.getValue("menuText"));
161
        local.actionPerformed(null);
162
        assertEquals(1, runCount.get());
163
        local = global.createContextAwareInstance(Lookups.fixed(bar));
164
        assertFalse(local.isEnabled());
165
        assertEquals("Run File", local.getValue("menuText"));
166
        // XXX could test more complex interactions, e.g. >1 project responds, or file owned by project but project does not respond
167
    }
135
    
168
    
136
    private static class TestActionProvider implements ActionProvider {
169
    private static class TestActionProvider implements ActionProvider {
137
        
170
        
(-)a/projectuiapi/apichanges.xml (+17 lines)
Lines 104-109 Link Here
104
    <!-- ACTUAL CHANGES BEGIN HERE: -->
104
    <!-- ACTUAL CHANGES BEGIN HERE: -->
105
105
106
    <changes>
106
    <changes>
107
        <change id="ActionProvider.global">
108
            <api name="general"/>
109
            <summary>Globally registered <code>ActionProvider</code>s</summary>
110
            <version major="1" minor="37"/>
111
            <date day="23" month="7" year="2009"/>
112
            <author login="jglick"/>
113
            <compatibility semantic="compatible"/>
114
            <description>
115
                <p>
116
                  <code>ActionProvider</code>s may now be registered in global
117
                  lookup so as to enable certain file-sensitive actions on certain
118
                  selections without the support of any project.
119
                </p>
120
            </description>
121
            <class package="org.netbeans.spi.project.ui.support" name="FileSensitiveActions"/>
122
            <issue number="102081"/>
123
        </change>
107
        <change id="open-with-progress">
124
        <change id="open-with-progress">
108
            <api name="general"/>
125
            <api name="general"/>
109
            <summary>OpenProjects.open() supports visual progress</summary>
126
            <summary>OpenProjects.open() supports visual progress</summary>
(-)a/projectuiapi/nbproject/project.properties (-1 / +1 lines)
Lines 39-45 Link Here
39
39
40
javac.compilerargs=-Xlint -Xlint:-serial
40
javac.compilerargs=-Xlint -Xlint:-serial
41
javac.source=1.5
41
javac.source=1.5
42
spec.version.base=1.36.0
42
spec.version.base=1.37.0
43
is.autoload=true
43
is.autoload=true
44
javadoc.arch=${basedir}/arch.xml
44
javadoc.arch=${basedir}/arch.xml
45
javadoc.apichanges=${basedir}/apichanges.xml
45
javadoc.apichanges=${basedir}/apichanges.xml
(-)a/projectuiapi/src/org/netbeans/spi/project/ui/support/FileSensitiveActions.java (+4 lines)
Lines 60-65 Link Here
60
     * When performed the action will call the given command on the {@link ActionProvider} of
60
     * When performed the action will call the given command on the {@link ActionProvider} of
61
     * the selected project(s) and pass the proper context to it. Enablement of the
61
     * the selected project(s) and pass the proper context to it. Enablement of the
62
     * action depends on the behavior of the project's action provider.
62
     * action depends on the behavior of the project's action provider.
63
     * <p>As mentioned in {@link ActionProvider} Javadoc, the action may also be enabled
64
     * without the participation of any project in case some globally registered {@link ActionProvider}
65
     * can provide an implementation.
66
     * (This since {@code org.netbeans.modules.projectuiapi/1 1.37}.)
63
     * <p>Shortcuts for actions are shared according to command, i.e. actions based on the same command
67
     * <p>Shortcuts for actions are shared according to command, i.e. actions based on the same command
64
     * will have the same shortcut.
68
     * will have the same shortcut.
65
     * @param command the command which should be invoked when the action is
69
     * @param command the command which should be invoked when the action is

Return to bug 102081