You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by lk...@apache.org on 2019/07/28 20:48:19 UTC
[netbeans] 01/01: [NETBEANS-1802] Basic infrastructure to load a
project with a Project Type.
This is an automated email from the ASF dual-hosted git repository.
lkishalmi pushed a commit to branch NETBEANS-1802_OpenProjectAs
in repository https://gitbox.apache.org/repos/asf/netbeans.git
commit f1bd0b190dc37ade7a1adca5a663cc5dcad2f7e3
Author: Laszlo Kishalmi <la...@gmail.com>
AuthorDate: Sun Jul 28 13:47:47 2019 -0700
[NETBEANS-1802] Basic infrastructure to load a project with a Project Type.
---
ide/projectapi.nb/nbproject/project.properties | 2 +-
.../modules/projectapi/nb/NbProjectManager.java | 409 ++++++++++-----------
.../org/netbeans/api/project/ProjectManager.java | 38 +-
.../spi/project/ProjectManagerImplementation2.java | 62 ++++
.../ui/actions/OpenProjectFolderAction.java | 8 +-
5 files changed, 305 insertions(+), 214 deletions(-)
diff --git a/ide/projectapi.nb/nbproject/project.properties b/ide/projectapi.nb/nbproject/project.properties
index 7f641b7..3b054ca 100644
--- a/ide/projectapi.nb/nbproject/project.properties
+++ b/ide/projectapi.nb/nbproject/project.properties
@@ -15,5 +15,5 @@
# specific language governing permissions and limitations
# under the License.
is.eager=true
-javac.source=1.6
+javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/ide/projectapi.nb/src/org/netbeans/modules/projectapi/nb/NbProjectManager.java b/ide/projectapi.nb/src/org/netbeans/modules/projectapi/nb/NbProjectManager.java
index 5997014..26e0fd2 100644
--- a/ide/projectapi.nb/src/org/netbeans/modules/projectapi/nb/NbProjectManager.java
+++ b/ide/projectapi.nb/src/org/netbeans/modules/projectapi/nb/NbProjectManager.java
@@ -23,10 +23,12 @@ import java.awt.EventQueue;
import java.io.IOException;
import java.lang.ref.Reference;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
@@ -42,6 +44,7 @@ import org.netbeans.api.project.ProjectManager.Result;
import org.netbeans.spi.project.ProjectFactory;
import org.netbeans.spi.project.ProjectFactory2;
import org.netbeans.spi.project.ProjectManagerImplementation;
+import org.netbeans.spi.project.ProjectManagerImplementation2;
import org.netbeans.spi.project.ProjectState;
import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileChangeListener;
@@ -51,7 +54,6 @@ import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileUtil;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
-import org.openide.util.LookupListener;
import org.openide.util.Mutex;
import org.openide.util.Mutex.ExceptionAction;
import org.openide.util.MutexException;
@@ -66,7 +68,7 @@ import org.openide.util.spi.MutexImplementation;
* @author Jesse Glick
*/
@ServiceProvider(service = ProjectManagerImplementation.class, position = 1000)
-public final class NbProjectManager implements ProjectManagerImplementation {
+public final class NbProjectManager implements ProjectManagerImplementation2 {
// XXX need to figure out how to convince the system that a Project object is modified
// so that Save All and the exit dialog work... could temporarily use a DataLoader
@@ -84,14 +86,11 @@ public final class NbProjectManager implements ProjectManagerImplementation {
Lookup.getDefault().lookupResult(ProjectFactory.class);
public NbProjectManager() {
- factories.addLookupListener(new LookupListener() {
- @Override
- public void resultChanged(LookupEvent e) {
- clearNonProjectCache();
- }
+ factories.addLookupListener((LookupEvent e) -> {
+ clearNonProjectCache();
});
}
-
+
private static enum LoadStatus {
/**
* Marker for a directory which is known to not be a project.
@@ -122,19 +121,19 @@ public final class NbProjectManager implements ProjectManagerImplementation {
* Cache of loaded projects (modified or not).
* Also caches a dir which is <em>not</em> a project.
*/
- private final Map<FileObject,Union2<Reference<Project>,LoadStatus>> dir2Proj = new WeakHashMap<FileObject,Union2<Reference<Project>,LoadStatus>>();
+ private final Map<FileObject,Union2<Reference<Project>,LoadStatus>> dir2Proj = new WeakHashMap<>();
/**
* Set of modified projects (subset of loaded projects).
*/
- private final Set<Project> modifiedProjects = new HashSet<Project>();
+ private final Set<Project> modifiedProjects = new HashSet<>();
- private final Set<Project> removedProjects = Collections.synchronizedSet(new WeakSet<Project>());
+ private final Set<Project> removedProjects = Collections.synchronizedSet(new WeakSet<>());
/**
* Mapping from projects to the factories that created them.
*/
- private final Map<Project,ProjectFactory> proj2Factory = Collections.synchronizedMap(new WeakHashMap<Project,ProjectFactory>());
+ private final Map<Project,ProjectFactory> proj2Factory = Collections.synchronizedMap(new WeakHashMap<>());
/**
* Checks for deleted projects.
@@ -144,7 +143,7 @@ public final class NbProjectManager implements ProjectManagerImplementation {
/**
* Whether this thread is currently loading a project.
*/
- private ThreadLocal<Set<FileObject>> loadingThread = new ThreadLocal<Set<FileObject>>();
+ private final ThreadLocal<Set<FileObject>> loadingThread = new ThreadLocal<>();
/**
* Callback to ProjectManager.
@@ -213,15 +212,66 @@ public final class NbProjectManager implements ProjectManagerImplementation {
*/
@Override
public Project findProject(final FileObject projectDirectory) throws IOException, IllegalArgumentException {
+ return findProject(projectDirectory, null);
+ }
+
+ /**
+ * Create a project from a given directory.
+ * @param dir the project dir
+ * @return a project made from it, or null if it is not recognized
+ * @throws IOException if there was a problem loading the project
+ */
+ private Project createProject(FileObject dir, String projectType) throws IOException {
+ assert dir != null;
+ assert dir.isFolder();
+ assert getMutex().isReadAccess();
+ ProjectStateImpl state = new ProjectStateImpl();
+ for (ProjectFactory factory : factories.allInstances()) {
+ Project p = null;
+ if (factory instanceof ProjectFactory2) {
+ Result res = ((ProjectFactory2) factory).isProject2(dir);
+ if (res != null) {
+ if (projectType != null) {
+ if (projectType.equals(res.getProjectType())) {
+ p = factory.loadProject(dir, state);
+ }
+ } else {
+ p = factory.loadProject(dir, state);
+ }
+ }
+ } else if (projectType == null) {
+ p = factory.loadProject(dir, state);
+ }
+ if (p != null) {
+ if (TIMERS.isLoggable(Level.FINE)) {
+ LogRecord rec = new LogRecord(Level.FINE, "Project"); // NOI18N
+ rec.setParameters(new Object[] { p });
+ TIMERS.log(rec);
+ }
+ proj2Factory.put(p, factory);
+ state.attach(p);
+ return p;
+ }
+ }
+ return null;
+ }
+
+
+ @Override
+ public Result isProject(final FileObject projectDirectory) throws IllegalArgumentException {
+ Result[] res = checkProject(projectDirectory);
+ return res.length > 0 ? res[0] : null;
+ }
+
+ @Override
+ public Project findProject(FileObject projectDirectory, String projectType) throws IOException, IllegalArgumentException {
Parameters.notNull("projectDirectory", projectDirectory); //NOI18N
try {
- return getMutex().readAccess(new Mutex.ExceptionAction<Project>() {
- @Override
- public Project run() throws IOException {
- // Read access, but still needs to synch on the cache since there
- // may be >1 reader.
- try {
- boolean wasSomeSuchProject;
+ return getMutex().readAccess((Mutex.ExceptionAction<Project>) () -> {
+ // Read access, but still needs to synch on the cache since there
+ // may be >1 reader.
+ try {
+ boolean wasSomeSuchProject;
synchronized (dir2Proj) {
Union2<Reference<Project>,LoadStatus> o;
do {
@@ -286,7 +336,7 @@ public final class NbProjectManager implements ProjectManagerImplementation {
}
boolean resetLP = false;
try {
- Project p = createProject(projectDirectory);
+ Project p = createProject(projectDirectory, projectType);
//Thread.dumpStack();
synchronized (dir2Proj) {
dir2Proj.notifyAll();
@@ -332,118 +382,80 @@ public final class NbProjectManager implements ProjectManagerImplementation {
}
}
}
- // Workaround for issue #51911:
- // Log project creation exception here otherwise it can get lost
- // in following scenario:
- // If project creation calls ProjectManager.postWriteRequest() (what for
- // example FreeformSources.initSources does) and then it throws an
- // exception then this exception can get lost because leaving read mutex
- // will immediately execute the runnable posted by
- // ProjectManager.postWriteRequest() and if this runnable fails (what
- // for FreeformSources.initSources will happen because
- // AntBasedProjectFactorySingleton.getProjectFor() will not find project in
- // its helperRef cache) then only this second fail is logged, but the cause -
- // the failure to create project - is never logged. So, better log it here:
- } catch (Error e) {
- LOG.log(Level.FINE, null, e);
- throw e;
- } catch (RuntimeException e) {
- LOG.log(Level.FINE, null, e);
- throw e;
- } catch (IOException e) {
- LOG.log(Level.FINE, null, e);
- throw e;
- }
+ // Workaround for issue #51911:
+ // Log project creation exception here otherwise it can get lost
+ // in following scenario:
+ // If project creation calls ProjectManager.postWriteRequest() (what for
+ // example FreeformSources.initSources does) and then it throws an
+ // exception then this exception can get lost because leaving read mutex
+ // will immediately execute the runnable posted by
+ // ProjectManager.postWriteRequest() and if this runnable fails (what
+ // for FreeformSources.initSources will happen because
+ // AntBasedProjectFactorySingleton.getProjectFor() will not find project in
+ // its helperRef cache) then only this second fail is logged, but the cause -
+ // the failure to create project - is never logged. So, better log it here:
+ } catch (Error | RuntimeException | IOException e) {
+ LOG.log(Level.FINE, null, e);
+ throw e;
}
});
} catch (MutexException e) {
throw (IOException)e.getException();
}
}
-
- /**
- * Create a project from a given directory.
- * @param dir the project dir
- * @return a project made from it, or null if it is not recognized
- * @throws IOException if there was a problem loading the project
- */
- private Project createProject(FileObject dir) throws IOException {
- assert dir != null;
- assert dir.isFolder();
- assert getMutex().isReadAccess();
- ProjectStateImpl state = new ProjectStateImpl();
- for (ProjectFactory factory : factories.allInstances()) {
- Project p = factory.loadProject(dir, state);
- if (p != null) {
- if (TIMERS.isLoggable(Level.FINE)) {
- LogRecord rec = new LogRecord(Level.FINE, "Project"); // NOI18N
- rec.setParameters(new Object[] { p });
- TIMERS.log(rec);
- }
- proj2Factory.put(p, factory);
- state.attach(p);
- return p;
- }
- }
- return null;
- }
-
@Override
- public Result isProject(final FileObject projectDirectory) throws IllegalArgumentException {
+ public Result[] checkProject(FileObject projectDirectory) throws IllegalArgumentException {
+ final Result[] EMPTY_RESULT = new Result[0];
Parameters.notNull("projectDirectory", projectDirectory);
- return getMutex().readAccess(new Mutex.Action<Result>() {
- @Override
- public Result run() {
- synchronized (dir2Proj) {
- Union2<Reference<Project>,LoadStatus> o;
- do {
- o = dir2Proj.get(projectDirectory);
- if (LoadStatus.LOADING_PROJECT.is(o)) {
- if (EventQueue.isDispatchThread()) {
- // #183192: permitted false positive; better than blocking EQ
- return new Result(null);
- }
- try {
- dir2Proj.wait();
- } catch (InterruptedException e) {
- LOG.log(Level.INFO, null, e);
- return null;
- }
+ return getMutex().readAccess((Mutex.Action<Result[]>) () -> {
+ synchronized (dir2Proj) {
+ Union2<Reference<Project>,LoadStatus> o;
+ do {
+ o = dir2Proj.get(projectDirectory);
+ if (LoadStatus.LOADING_PROJECT.is(o)) {
+ if (EventQueue.isDispatchThread()) {
+ // #183192: permitted false positive; better than blocking EQ
+ return new Result[] {new Result(null)};
+ }
+ try {
+ dir2Proj.wait();
+ } catch (InterruptedException e) {
+ LOG.log(Level.INFO, null, e);
+ return EMPTY_RESULT;
}
- } while (LoadStatus.LOADING_PROJECT.is(o));
- assert !LoadStatus.LOADING_PROJECT.is(o);
- if (LoadStatus.NO_SUCH_PROJECT.is(o)) {
- return null;
- } else if (o != null) {
- // Reference<Project> or SOME_SUCH_PROJECT
- // rather check for result than load project and lookup projectInformation for icon.
- return checkForProject(projectDirectory);
}
- // Not in cache.
- dir2Proj.put(projectDirectory, LoadStatus.LOADING_PROJECT.wrap());
+ } while (LoadStatus.LOADING_PROJECT.is(o));
+ assert !LoadStatus.LOADING_PROJECT.is(o);
+ if (LoadStatus.NO_SUCH_PROJECT.is(o)) {
+ return EMPTY_RESULT;
+ } else if (o != null) {
+ // Reference<Project> or SOME_SUCH_PROJECT
+ // rather check for result than load project and lookup projectInformation for icon.
+ return checkForProject(projectDirectory);
}
- boolean resetLP = false;
- try {
- Result p = checkForProject(projectDirectory);
- synchronized (dir2Proj) {
- resetLP = true;
- dir2Proj.notifyAll();
- if (p != null) {
- dir2Proj.put(projectDirectory, LoadStatus.SOME_SUCH_PROJECT.wrap());
- return p;
- } else {
- dir2Proj.put(projectDirectory, LoadStatus.NO_SUCH_PROJECT.wrap());
- return null;
- }
+ // Not in cache.
+ dir2Proj.put(projectDirectory, LoadStatus.LOADING_PROJECT.wrap());
+ }
+ boolean resetLP = false;
+ try {
+ Result[] ps = checkForProject(projectDirectory);
+ synchronized (dir2Proj) {
+ resetLP = true;
+ dir2Proj.notifyAll();
+ if (ps.length > 0) {
+ dir2Proj.put(projectDirectory, LoadStatus.SOME_SUCH_PROJECT.wrap());
+ } else {
+ dir2Proj.put(projectDirectory, LoadStatus.NO_SUCH_PROJECT.wrap());
}
- } finally {
- if (!resetLP) {
- // some runtime exception interrupted.
- synchronized (dir2Proj) {
- assert LoadStatus.LOADING_PROJECT.is(dir2Proj.get(projectDirectory));
- dir2Proj.remove(projectDirectory);
- }
+ return ps;
+ }
+ } finally {
+ if (!resetLP) {
+ // some runtime exception interrupted.
+ synchronized (dir2Proj) {
+ assert LoadStatus.LOADING_PROJECT.is(dir2Proj.get(projectDirectory));
+ dir2Proj.remove(projectDirectory);
}
}
}
@@ -453,29 +465,28 @@ public final class NbProjectManager implements ProjectManagerImplementation {
/**
*
* @param dir
- * @param preferResult, if false will not actually call the factory methods with populated Results, but
- * create dummy ones and use the Result as boolean flag only.
* @return
*/
- private Result checkForProject(FileObject dir) {
+ private Result[] checkForProject(FileObject dir) {
assert dir != null;
assert dir.isFolder() : dir;
assert getMutex().isReadAccess();
- Iterator<? extends ProjectFactory> it = factories.allInstances().iterator();
- while (it.hasNext()) {
- ProjectFactory factory = it.next();
+ List<Result> detectedProjectTypes = new ArrayList<>();
+ for (ProjectFactory factory : factories.allInstances()) {
if (factory instanceof ProjectFactory2) {
Result res = ((ProjectFactory2)factory).isProject2(dir);
if (res != null) {
- return res;
+ String type = res.getProjectType() != null ? res.getProjectType() : factory.getClass().getSimpleName();
+ String name = res.getDisplayName() != null ? res.getDisplayName() : dir.getName();
+ detectedProjectTypes.add(new Result(name, type, res.getIcon()));
}
} else {
if (factory.isProject(dir)) {
- return new Result((Icon)null);
+ detectedProjectTypes.add(new Result((Icon)null));
}
}
}
- return null;
+ return detectedProjectTypes.toArray(new Result[detectedProjectTypes.size()]);
}
/**
@@ -511,16 +522,13 @@ public final class NbProjectManager implements ProjectManagerImplementation {
public void markModified() {
assert p != null;
LOG.log(Level.FINE, "markModified({0})", p.getProjectDirectory());
- getMutex().writeAccess(new Mutex.Action<Void>() {
- @Override
- public Void run() {
- if (proj2Factory.containsKey(p)) {
- modifiedProjects.add(p);
- } else {
- LOG.log(Level.WARNING, "An attempt to call ProjectState.markModified on an unknown project: {0}", p.getProjectDirectory());
- }
- return null;
+ getMutex().writeAccess((Mutex.Action<Void>) () -> {
+ if (proj2Factory.containsKey(p)) {
+ modifiedProjects.add(p);
+ } else {
+ LOG.log(Level.WARNING, "An attempt to call ProjectState.markModified on an unknown project: {0}", p.getProjectDirectory());
}
+ return null;
});
}
@@ -529,26 +537,23 @@ public final class NbProjectManager implements ProjectManagerImplementation {
assert p != null;
final FileObject dir = p.getProjectDirectory();
LOG.log(Level.FINE, "notifyDeleted: {0}", dir);
- getMutex().writeAccess(new Mutex.Action<Void>() {
- @Override
- public Void run() {
- synchronized (dir2Proj) {
- Union2<Reference<Project>,LoadStatus> o = dir2Proj.get(dir);
- if (o != null && o.hasFirst() && o.first().get() == p) {
- dir2Proj.remove(dir);
- } else {
- // #194046: project folder was moved, so now points to new project
- LOG.log(Level.FINE, "notifyDeleted skipping dir2Proj update since {0} @{1} != {2}", new Object[] {p, p.hashCode(), o});
- }
- }
- proj2Factory.remove(p);
- modifiedProjects.remove(p);
- if (!removedProjects.add(p)) {
- LOG.log(Level.WARNING, "An attempt to call notifyDeleted more than once. Project: {0}", dir);
+ getMutex().writeAccess((Mutex.Action<Void>) () -> {
+ synchronized (dir2Proj) {
+ Union2<Reference<Project>,LoadStatus> o = dir2Proj.get(dir);
+ if (o != null && o.hasFirst() && o.first().get() == p) {
+ dir2Proj.remove(dir);
+ } else {
+ // #194046: project folder was moved, so now points to new project
+ LOG.log(Level.FINE, "notifyDeleted skipping dir2Proj update since {0} @{1} != {2}", new Object[] {p, p.hashCode(), o});
}
- callBack.notifyDeleted(p);
- return null;
}
+ proj2Factory.remove(p);
+ modifiedProjects.remove(p);
+ if (!removedProjects.add(p)) {
+ LOG.log(Level.WARNING, "An attempt to call notifyDeleted more than once. Project: {0}", dir);
+ }
+ callBack.notifyDeleted(p);
+ return null;
});
}
@@ -558,13 +563,9 @@ public final class NbProjectManager implements ProjectManagerImplementation {
* <p>Acquires read access.
* @return an immutable set of projects
*/
+ @Override
public Set<Project> getModifiedProjects() {
- return getMutex().readAccess(new Mutex.Action<Set<Project>>() {
- @Override
- public Set<Project> run() {
- return new HashSet<Project>(modifiedProjects);
- }
- });
+ return getMutex().readAccess((Mutex.Action<Set<Project>>) () -> new HashSet<Project>(modifiedProjects));
}
/**
@@ -573,17 +574,15 @@ public final class NbProjectManager implements ProjectManagerImplementation {
* @param p a project loaded by this manager
* @return true if it is modified, false if has been saved since the last modification
*/
+ @Override
public boolean isModified(final Project p) {
- return getMutex().readAccess(new Mutex.Action<Boolean>() {
- @Override
- public Boolean run() {
- synchronized (dir2Proj) {
- if (!proj2Factory.containsKey(p)) {
- LOG.log(Level.WARNING, "Project {0} was already deleted", p);
- }
+ return getMutex().readAccess((Mutex.Action<Boolean>) () -> {
+ synchronized (dir2Proj) {
+ if (!proj2Factory.containsKey(p)) {
+ LOG.log(Level.WARNING, "Project {0} was already deleted", p);
}
- return modifiedProjects.contains(p);
}
+ return modifiedProjects.contains(p);
});
}
@@ -603,27 +602,25 @@ public final class NbProjectManager implements ProjectManagerImplementation {
* @throws IOException if it cannot be saved
* @see ProjectFactory#saveProject
*/
+ @Override
public void saveProject(final Project p) throws IOException {
try {
- getMutex().writeAccess(new Mutex.ExceptionAction<Void>() {
- @Override
- public Void run() throws IOException {
- //removed projects are the ones that cannot be mapped to an existing project type anymore.
- if (removedProjects.contains(p)) {
- return null;
- }
- if (modifiedProjects.contains(p)) {
- ProjectFactory f = proj2Factory.get(p);
- if (f != null) {
- f.saveProject(p);
- LOG.log(Level.FINE, "saveProject({0})", p.getProjectDirectory());
- } else {
- LOG.log(Level.WARNING, "Project {0} was already deleted", p);
- }
- modifiedProjects.remove(p);
- }
+ getMutex().writeAccess((Mutex.ExceptionAction<Void>) () -> {
+ //removed projects are the ones that cannot be mapped to an existing project type anymore.
+ if (removedProjects.contains(p)) {
return null;
}
+ if (modifiedProjects.contains(p)) {
+ ProjectFactory f = proj2Factory.get(p);
+ if (f != null) {
+ f.saveProject(p);
+ LOG.log(Level.FINE, "saveProject({0})", p.getProjectDirectory());
+ } else {
+ LOG.log(Level.WARNING, "Project {0} was already deleted", p);
+ }
+ modifiedProjects.remove(p);
+ }
+ return null;
});
} catch (MutexException e) {
//##91398 have a more descriptive error message, in case of RO folders.
@@ -641,25 +638,23 @@ public final class NbProjectManager implements ProjectManagerImplementation {
* @throws IOException if any of them cannot be saved
* @see ProjectFactory#saveProject
*/
+ @Override
public void saveAllProjects() throws IOException {
try {
- getMutex().writeAccess(new Mutex.ExceptionAction<Void>() {
- @Override
- public Void run() throws IOException {
- Iterator<Project> it = modifiedProjects.iterator();
- while (it.hasNext()) {
- Project p = it.next();
- ProjectFactory f = proj2Factory.get(p);
- if (f != null) {
- f.saveProject(p);
- LOG.log(Level.FINE, "saveProject({0})", p.getProjectDirectory());
- } else {
- LOG.log(Level.WARNING, "Project {0} was already deleted", p);
- }
- it.remove();
+ getMutex().writeAccess((Mutex.ExceptionAction<Void>) () -> {
+ Iterator<Project> it = modifiedProjects.iterator();
+ while (it.hasNext()) {
+ Project p = it.next();
+ ProjectFactory f = proj2Factory.get(p);
+ if (f != null) {
+ f.saveProject(p);
+ LOG.log(Level.FINE, "saveProject({0})", p.getProjectDirectory());
+ } else {
+ LOG.log(Level.WARNING, "Project {0} was already deleted", p);
}
- return null;
+ it.remove();
}
+ return null;
});
} catch (MutexException e) {
throw (IOException)e.getException();
@@ -675,13 +670,11 @@ public final class NbProjectManager implements ProjectManagerImplementation {
* @param p a project
* @return true if the project is still valid, false if it has been deleted
*/
+ @Override
public boolean isValid(final Project p) {
- return getMutex().readAccess(new Mutex.Action<Boolean>() {
- @Override
- public Boolean run() {
- synchronized (dir2Proj) {
- return proj2Factory.containsKey(p);
- }
+ return getMutex().readAccess((Mutex.Action<Boolean>) () -> {
+ synchronized (dir2Proj) {
+ return proj2Factory.containsKey(p);
}
});
}
diff --git a/ide/projectapi/src/org/netbeans/api/project/ProjectManager.java b/ide/projectapi/src/org/netbeans/api/project/ProjectManager.java
index 81da1b4..998834f 100644
--- a/ide/projectapi/src/org/netbeans/api/project/ProjectManager.java
+++ b/ide/projectapi/src/org/netbeans/api/project/ProjectManager.java
@@ -32,6 +32,7 @@ import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation;
import org.netbeans.spi.project.FileOwnerQueryImplementation;
import org.netbeans.spi.project.ProjectFactory;
import org.netbeans.spi.project.ProjectManagerImplementation;
+import org.netbeans.spi.project.ProjectManagerImplementation2;
import org.openide.filesystems.FileObject;
import org.openide.util.Lookup;
import org.openide.util.Mutex;
@@ -207,7 +208,42 @@ public final class ProjectManager {
}
return impl.isProject(projectDirectory);
}
-
+
+ /**
+ * Returns all {@link ProjectManager.Result} that can be associated with
+ * the given folder. If the actual implementation does not support
+ * {@link ProjectManagerImplementation2} this method just fallback to
+ * {@link ProjectManagerImplementation#isProject(org.openide.filesystems.FileObject)} method.
+ *
+ * @since 1.73
+ * @param projectDirectory the folder for inspection
+ * @return {@link ProjectManager.Result} that can be associated with the
+ * folder or an empty array if none has found.
+ * @throws IllegalArgumentException
+ */
+ public Result[] checkProject(@NonNull final FileObject projectDirectory) throws IllegalArgumentException {
+ if (projectDirectory == null) {
+ throw new IllegalArgumentException("Attempted to pass a null directory to isProject"); // NOI18N
+ }
+ if (!projectDirectory.isFolder() ) {
+ //#78215 it can happen that a no longer existing folder is queried. throw
+ // exception only for real wrong usage..
+ if (projectDirectory.isValid()) {
+ throw new IllegalArgumentException("Attempted to pass a non-directory to isProject: " + projectDirectory); // NOI18N
+ } else {
+ return null;
+ }
+ }
+ Result[] ret = new Result[0];
+ if (impl instanceof ProjectManagerImplementation2) {
+ ret = ((ProjectManagerImplementation2) impl).checkProject(projectDirectory);
+ } else {
+ Result p = impl.isProject(projectDirectory);
+ ret = p != null ? new Result[] {p} : ret;
+ }
+ return ret;
+ }
+
/**
* Clear the cached list of folders thought <em>not</em> to be projects.
* This may be useful after creating project metadata in a folder, etc.
diff --git a/ide/projectapi/src/org/netbeans/spi/project/ProjectManagerImplementation2.java b/ide/projectapi/src/org/netbeans/spi/project/ProjectManagerImplementation2.java
new file mode 100644
index 0000000..663fdfc
--- /dev/null
+++ b/ide/projectapi/src/org/netbeans/spi/project/ProjectManagerImplementation2.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.spi.project;
+
+import java.io.IOException;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.openide.filesystems.FileObject;
+
+/**
+ * Trivial extension of {@link ProjectManagerImplementation} to support access
+ * to multiple project types per project directories.
+ *
+ * @since 1.73
+ * @author lkishalmi
+ */
+public interface ProjectManagerImplementation2 extends ProjectManagerImplementation {
+ /**
+ * Find a NetBeans {@link Project} for the given directory and project type.
+ *
+ * @param projectDirectory the project folder
+ * @param projectType the project type to load. This can be {@code null}, that
+ * case the first identified project shall be used and the call
+ * is equivalent with {@link #findProject(org.openide.filesystems.FileObject)}.
+ * @see ProjectManager.Result#getProjectType()
+ * @return a project with the requested type or {@code null}.
+ * @throws IOException
+ * @throws IllegalArgumentException
+ */
+ @CheckForNull
+ Project findProject(@NonNull FileObject projectDirectory, String projectType) throws IOException, IllegalArgumentException;
+
+ /**
+ * Returns all {@link ProjectManager.Result} that can be associated with
+ * the given folder.
+ *
+ * @since 1.73
+ * @param projectDirectory the folder for inspection
+ * @return {@link ProjectManager.Result} that can be associated with the
+ * folder or an empty array if none has found.
+ * @throws IllegalArgumentException
+ */
+ ProjectManager.Result[] checkProject(@NonNull FileObject projectDirectory) throws IllegalArgumentException;
+}
diff --git a/ide/projectui/src/org/netbeans/modules/project/ui/actions/OpenProjectFolderAction.java b/ide/projectui/src/org/netbeans/modules/project/ui/actions/OpenProjectFolderAction.java
index a5c862f..75dad87 100644
--- a/ide/projectui/src/org/netbeans/modules/project/ui/actions/OpenProjectFolderAction.java
+++ b/ide/projectui/src/org/netbeans/modules/project/ui/actions/OpenProjectFolderAction.java
@@ -76,14 +76,14 @@ public final class OpenProjectFolderAction extends AbstractAction implements Con
public ContextAction(Lookup context) {
super(OpenProjectFolderAction_LBL_action());
this.context = context;
- boolean foundProject = false;
+ ProjectManager.Result[] projects = new ProjectManager.Result[0];
for (DataFolder d : context.lookupAll(DataFolder.class)) {
- if (ProjectManager.getDefault().isProject(d.getPrimaryFile())) {
- foundProject = true;
+ projects = ProjectManager.getDefault().checkProject(d.getPrimaryFile());
+ if (projects.length > 0) {
break;
}
}
- if (!foundProject) {
+ if (projects.length != 1) {
putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
setEnabled(false);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists