diff --git a/utilities/nbproject/project.xml b/utilities/nbproject/project.xml --- a/utilities/nbproject/project.xml +++ b/utilities/nbproject/project.xml @@ -50,6 +50,15 @@ org.netbeans.modules.utilities + org.netbeans.modules.projectapi + + + + 1 + 1.49 + + + org.netbeans.modules.queries diff --git a/utilities/src/org/netbeans/modules/utilities/CopyPathToClipboardAction.java b/utilities/src/org/netbeans/modules/utilities/CopyPathToClipboardAction.java --- a/utilities/src/org/netbeans/modules/utilities/CopyPathToClipboardAction.java +++ b/utilities/src/org/netbeans/modules/utilities/CopyPathToClipboardAction.java @@ -53,6 +53,7 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import org.netbeans.api.project.Project; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -65,15 +66,14 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.datatransfer.ExClipboard; +import org.openide.windows.TopComponent; /** - * Copies the absolute path of selected {@link DataObject}s to the clipboard. + * Copies the absolute path of selected {@link DataObject}s or {@link Project}s to the clipboard. * Action is shown in context menu of tab. It support DataShadows, so the path * of items in the favorites window can be copied properly. It support items * within JAR-files. * - * Note: It does not support selected Projects. - * * @author markiewb */ @ActionID( @@ -90,18 +90,17 @@ "CTL_CopyPaths=Copy File Path(s)", "CTL_CopyPath=Copy File Path" }) -public final class CopyPathToClipboardAction implements ActionListener, +public class CopyPathToClipboardAction implements ActionListener, ClipboardOwner { - private final List context; - - public CopyPathToClipboardAction(List context) { - this.context = context; - } @Override public void actionPerformed(ActionEvent ev) { - Collection paths = getSelectedPaths(); + + Collection paths=new TreeSet(); + paths.addAll(getSelectedPathsForDataObjects(getSelectedDataObjects())); + paths.addAll(getSelectedPathsForProjects(getSelectedProjects())); + StringBuilder sb = new StringBuilder(); int items = 0; for (String path : paths) { @@ -120,11 +119,27 @@ } /** + * Can be overridden in test. + * @return selected {@link DataObject}s in current {@link TopComponent} + */ + Collection getSelectedDataObjects() { + return TopComponent.getRegistry().getActivated().getLookup().lookupAll(DataObject.class); + } + + /** + * Can be overridden in test. + * @return selected {@link Project}s in current {@link TopComponent} + */ + Collection getSelectedProjects() { + return TopComponent.getRegistry().getActivated().getLookup().lookupAll(Project.class); + } + + /** * Get paths of selected DataObjects. Prevent duplicates, see #219014. * * @return Sorted collection of unique paths. */ - Collection getSelectedPaths() { + Collection getSelectedPathsForDataObjects(Collection context) { Set paths = new TreeSet(); for (DataObject dataObject : context) { paths.add(getAbsolutePath(dataObject)); @@ -193,6 +208,36 @@ } return dataObject.getPrimaryFile(); } + + /** + * Get the project directory of the given project. + * @param project + * @return + */ + private String getProjectDirectory(final Project project) { + try { + FileObject projectDirectory = project.getProjectDirectory(); + return getNativePath(projectDirectory); + } catch (Exception e) { + //ignore the exception + return null; + } + } + /** + * Get paths of selected projects. Prevent duplicates, see #219014. + * + * @return Sorted collection of unique paths. + */ + Collection getSelectedPathsForProjects(Collection projects) { + Set paths = new TreeSet(); + for (Project project : projects) { + String projectDir = getProjectDirectory(project); + if (null != projectDir) { + paths.add(projectDir); + } + } + return paths; + } /** * Sets the clipboard context in textual-format. @@ -202,7 +247,7 @@ @Messages({ "# {0} - copied file path", "CTL_Status_CopyToClipboardSingle=Copy to Clipboard: {0}", - "# {0} - numer of copied paths", + "# {0} - number of copied paths", "CTL_Status_CopyToClipboardMulti={0} paths were copied to clipboard" }) private void setClipboardContents(String content, int items) { diff --git a/utilities/test/unit/src/org/netbeans/modules/utilities/CopyPathToClipboardActionTest.java b/utilities/test/unit/src/org/netbeans/modules/utilities/CopyPathToClipboardActionTest.java --- a/utilities/test/unit/src/org/netbeans/modules/utilities/CopyPathToClipboardActionTest.java +++ b/utilities/test/unit/src/org/netbeans/modules/utilities/CopyPathToClipboardActionTest.java @@ -45,18 +45,21 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.junit.Test; +import org.netbeans.api.project.Project; import org.netbeans.junit.NbTestCase; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataFolder; import org.openide.loaders.DataObject; import org.openide.loaders.DataShadow; +import org.openide.util.Lookup; /** * @@ -66,6 +69,7 @@ List dataObjects; CopyPathToClipboardAction action; + List projects = new ArrayList(); public CopyPathToClipboardActionTest(String name) { super(name); @@ -73,6 +77,11 @@ @Override public void setUp() throws IOException, PropertyVetoException { + + // create projects + projects.add(createProject("projectDir1")); + projects.add(createProject("projectDir2")); + List l = new LinkedList(); clearWorkDir(); FileObject root = FileUtil.toFileObject(getWorkDir()); @@ -99,7 +108,16 @@ // /testDataShadows/testShadowFile -> test2/data.txt l.add(shadowFile); dataObjects = l; - action = new CopyPathToClipboardAction(dataObjects); + action = new CopyPathToClipboardAction(){ + @Override + Collection getSelectedDataObjects() { + return dataObjects; + } + @Override + Collection getSelectedProjects() { + return projects; + } + }; } @Override @@ -133,6 +151,13 @@ assertTrue(action.getAbsolutePath(dataObjects.get(3)).matches( ".*test2[/\\\\]data\\.txt$")); // Shadow File for data.txt } + + @Test + public void testGetSelectedPathsForProjects() { + List paths = new ArrayList(action.getSelectedPathsForProjects(projects)); + assertTrue(paths.get(0).endsWith("projectDir1")); // path for project 1 + assertTrue(paths.get(1).endsWith("projectDir2")); // path for project 2 + } /** * Creates ZIP file archive.zip that contains three files, a.txt, b.txt and @@ -168,8 +193,8 @@ return testShadowFile; } - public void testGetSelectedPaths() { - Collection paths = action.getSelectedPaths(); + public void testGetSelectedDataObjectPaths() { + Collection paths = action.getSelectedPathsForDataObjects(dataObjects); assertEquals("Duplicate shadow file should be ignored", 3, paths.size()); String[] pathsArray = paths.toArray(new String[paths.size()]); @@ -178,4 +203,29 @@ assertTrue(pathsArray[1].contains("archive.zip")); //test2/archive.zip? assertTrue(pathsArray[2].contains("data.txt")); //test2/data.txt } + /** + * Creates a mocked {@link Project} with the given dir. + * @param projectDir + * @return + */ + private Project createProject(String projectDir) { + try { + FileObject root = FileUtil.toFileObject(getWorkDir()); + final FileObject dir = root.createFolder(projectDir); + return new Project() { + + @Override + public FileObject getProjectDirectory() { + return dir; + } + + @Override + public Lookup getLookup() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + }; + } catch (IOException ex) { + throw new IllegalArgumentException("should not happen in test"); + } + } }