Lines 50-70
Link Here
|
50 |
import java.util.Map; |
50 |
import java.util.Map; |
51 |
import java.util.Set; |
51 |
import java.util.Set; |
52 |
import java.util.WeakHashMap; |
52 |
import java.util.WeakHashMap; |
53 |
import java.util.concurrent.Executor; |
|
|
54 |
import java.util.logging.Level; |
53 |
import java.util.logging.Level; |
55 |
import java.util.logging.LogRecord; |
54 |
import java.util.logging.LogRecord; |
56 |
import java.util.logging.Logger; |
55 |
import java.util.logging.Logger; |
|
|
56 |
import javax.swing.Icon; |
57 |
import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation; |
57 |
import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation; |
58 |
import org.netbeans.modules.projectapi.TimedWeakReference; |
58 |
import org.netbeans.modules.projectapi.TimedWeakReference; |
59 |
import org.netbeans.spi.project.FileOwnerQueryImplementation; |
59 |
import org.netbeans.spi.project.FileOwnerQueryImplementation; |
60 |
import org.netbeans.spi.project.ProjectFactory; |
60 |
import org.netbeans.spi.project.ProjectFactory; |
|
|
61 |
import org.netbeans.spi.project.ProjectFactory2; |
61 |
import org.netbeans.spi.project.ProjectState; |
62 |
import org.netbeans.spi.project.ProjectState; |
62 |
import org.openide.filesystems.FileChangeAdapter; |
63 |
import org.openide.filesystems.FileChangeAdapter; |
63 |
import org.openide.filesystems.FileChangeListener; |
64 |
import org.openide.filesystems.FileChangeListener; |
64 |
import org.openide.filesystems.FileEvent; |
65 |
import org.openide.filesystems.FileEvent; |
65 |
import org.openide.filesystems.FileObject; |
66 |
import org.openide.filesystems.FileObject; |
66 |
import org.openide.filesystems.FileSystem; |
|
|
67 |
import org.openide.filesystems.FileUtil; |
67 |
import org.openide.filesystems.FileUtil; |
|
|
68 |
import org.openide.util.ImageUtilities; |
68 |
import org.openide.util.Lookup; |
69 |
import org.openide.util.Lookup; |
69 |
import org.openide.util.LookupEvent; |
70 |
import org.openide.util.LookupEvent; |
70 |
import org.openide.util.LookupListener; |
71 |
import org.openide.util.LookupListener; |
Lines 388-393
Link Here
|
388 |
* @throws IllegalArgumentException if the supplied file object is null or not a folder |
389 |
* @throws IllegalArgumentException if the supplied file object is null or not a folder |
389 |
*/ |
390 |
*/ |
390 |
public boolean isProject(final FileObject projectDirectory) throws IllegalArgumentException { |
391 |
public boolean isProject(final FileObject projectDirectory) throws IllegalArgumentException { |
|
|
392 |
return isProject2(projectDirectory, false) != null; |
393 |
} |
394 |
|
395 |
/** |
396 |
* Check whether a given directory is likely to contain a project without |
397 |
* actually loading it. The returned {@link org.netbeans.api.project.ProjectManager.Result} object contains additional |
398 |
* information about the found project. |
399 |
* Should be faster and use less memory than {@link #findProject} when called |
400 |
* on a large number of directories. |
401 |
* <p>The result is not guaranteed to be accurate; there may be false positives |
402 |
* (directories for which <code>isProject</code> is true but {@link #findProject} |
403 |
* will return false), for example if there is trouble loading the project. |
404 |
* False negatives are possible only if there are bugs in the project factory.</p> |
405 |
* <p>Acquires read access.</p> |
406 |
* <p class="nonnormative"> |
407 |
* You do <em>not</em> need to call this method if you just plan to call {@link #findProject} |
408 |
* afterwards. It is intended for only those clients which would discard the |
409 |
* result of {@link #findProject} other than to check for null, and which |
410 |
* can also tolerate false positives. |
411 |
* </p> |
412 |
* @param projectDirectory a directory which may be some project's top directory |
413 |
* @return Result object if the directory is likely to contain a project according to |
414 |
* some registered {@link ProjectFactory}, or null if not a project folder. |
415 |
* @throws IllegalArgumentException if the supplied file object is null or not a folder |
416 |
* @since org.netbeans.modules.projectapi 1.22 |
417 |
*/ |
418 |
public Result isProject2(final FileObject projectDirectory) throws IllegalArgumentException { |
419 |
return isProject2(projectDirectory, true); |
420 |
} |
421 |
|
422 |
private Result isProject2(final FileObject projectDirectory, final boolean preferResult) throws IllegalArgumentException { |
391 |
if (projectDirectory == null) { |
423 |
if (projectDirectory == null) { |
392 |
throw new IllegalArgumentException("Attempted to pass a null directory to isProject"); // NOI18N |
424 |
throw new IllegalArgumentException("Attempted to pass a null directory to isProject"); // NOI18N |
393 |
} |
425 |
} |
Lines 397-407
Link Here
|
397 |
if (projectDirectory.isValid()) { |
429 |
if (projectDirectory.isValid()) { |
398 |
throw new IllegalArgumentException("Attempted to pass a non-directory to isProject: " + projectDirectory); // NOI18N |
430 |
throw new IllegalArgumentException("Attempted to pass a non-directory to isProject: " + projectDirectory); // NOI18N |
399 |
} else { |
431 |
} else { |
400 |
return false; |
432 |
return null; |
401 |
} |
433 |
} |
402 |
} |
434 |
} |
403 |
return mutex().readAccess(new Mutex.Action<Boolean>() { |
435 |
return mutex().readAccess(new Mutex.Action<Result>() { |
404 |
public Boolean run() { |
436 |
public Result run() { |
405 |
synchronized (dir2Proj) { |
437 |
synchronized (dir2Proj) { |
406 |
Union2<Reference<Project>,LoadStatus> o; |
438 |
Union2<Reference<Project>,LoadStatus> o; |
407 |
do { |
439 |
do { |
Lines 416-441
Link Here
|
416 |
} while (LoadStatus.LOADING_PROJECT.is(o)); |
448 |
} while (LoadStatus.LOADING_PROJECT.is(o)); |
417 |
assert !LoadStatus.LOADING_PROJECT.is(o); |
449 |
assert !LoadStatus.LOADING_PROJECT.is(o); |
418 |
if (LoadStatus.NO_SUCH_PROJECT.is(o)) { |
450 |
if (LoadStatus.NO_SUCH_PROJECT.is(o)) { |
419 |
return false; |
451 |
return null; |
420 |
} else if (o != null) { |
452 |
} else if (o != null) { |
421 |
// Reference<Project> or SOME_SUCH_PROJECT |
453 |
// Reference<Project> or SOME_SUCH_PROJECT |
422 |
return true; |
454 |
// rather check for result than load project and lookup projectInformation for icon. |
|
|
455 |
return checkForProject(projectDirectory, preferResult); |
423 |
} |
456 |
} |
424 |
// Not in cache. |
457 |
// Not in cache. |
425 |
dir2Proj.put(projectDirectory, LoadStatus.LOADING_PROJECT.wrap()); |
458 |
dir2Proj.put(projectDirectory, LoadStatus.LOADING_PROJECT.wrap()); |
426 |
} |
459 |
} |
427 |
boolean resetLP = false; |
460 |
boolean resetLP = false; |
428 |
try { |
461 |
try { |
429 |
boolean p = checkForProject(projectDirectory); |
462 |
Result p = checkForProject(projectDirectory, preferResult); |
430 |
synchronized (dir2Proj) { |
463 |
synchronized (dir2Proj) { |
431 |
resetLP = true; |
464 |
resetLP = true; |
432 |
dir2Proj.notifyAll(); |
465 |
dir2Proj.notifyAll(); |
433 |
if (p) { |
466 |
if (p != null) { |
434 |
dir2Proj.put(projectDirectory, LoadStatus.SOME_SUCH_PROJECT.wrap()); |
467 |
dir2Proj.put(projectDirectory, LoadStatus.SOME_SUCH_PROJECT.wrap()); |
435 |
return true; |
468 |
return p; |
436 |
} else { |
469 |
} else { |
437 |
dir2Proj.put(projectDirectory, LoadStatus.NO_SUCH_PROJECT.wrap()); |
470 |
dir2Proj.put(projectDirectory, LoadStatus.NO_SUCH_PROJECT.wrap()); |
438 |
return false; |
471 |
return null; |
439 |
} |
472 |
} |
440 |
} |
473 |
} |
441 |
} finally { |
474 |
} finally { |
Lines 448-466
Link Here
|
448 |
} |
481 |
} |
449 |
}); |
482 |
}); |
450 |
} |
483 |
} |
451 |
|
484 |
|
452 |
private boolean checkForProject(FileObject dir) { |
485 |
/** |
|
|
486 |
* |
487 |
* @param dir |
488 |
* @param preferResult, if false will not actually call the factory methods with populated Results, but |
489 |
* create dummy ones and use the Result as boolean flag only. |
490 |
* @return |
491 |
*/ |
492 |
private Result checkForProject(FileObject dir, boolean preferResult) { |
453 |
assert dir != null; |
493 |
assert dir != null; |
454 |
assert dir.isFolder() : dir; |
494 |
assert dir.isFolder() : dir; |
455 |
assert mutex().isReadAccess(); |
495 |
assert mutex().isReadAccess(); |
456 |
Iterator it = factories.allInstances().iterator(); |
496 |
Iterator<? extends ProjectFactory> it = factories.allInstances().iterator(); |
457 |
while (it.hasNext()) { |
497 |
while (it.hasNext()) { |
458 |
ProjectFactory factory = (ProjectFactory)it.next(); |
498 |
ProjectFactory factory = it.next(); |
459 |
if (factory.isProject(dir)) { |
499 |
if (factory instanceof ProjectFactory2 && preferResult) { |
460 |
return true; |
500 |
Result res = ((ProjectFactory2)factory).isProject2(dir); |
|
|
501 |
if (res != null) { |
502 |
return res; |
503 |
} |
504 |
} else { |
505 |
if (factory.isProject(dir)) { |
506 |
return new Result((Icon)null); |
507 |
} |
461 |
} |
508 |
} |
462 |
} |
509 |
} |
463 |
return false; |
510 |
return null; |
464 |
} |
511 |
} |
465 |
|
512 |
|
466 |
/** |
513 |
/** |
Lines 671-675
Link Here
|
671 |
} |
718 |
} |
672 |
|
719 |
|
673 |
} |
720 |
} |
|
|
721 |
|
722 |
/** |
723 |
* A result (immutable) object returned from {@link org.netbeans.api.project.ProjectManager#isProject2} method. |
724 |
* To be created by {@link org.netbeans.spi.project.ProjectFactory2} project factories. |
725 |
* @since org.netbeans.modules.projectapi 1.22 |
726 |
*/ |
727 |
public static final class Result { |
728 |
private Icon icon; |
729 |
|
730 |
|
731 |
public Result(Icon icon) { |
732 |
this.icon = icon; |
733 |
} |
734 |
|
735 |
/** |
736 |
* Get the project icon. |
737 |
* @return project type icon for the result or null if the icon cannot be found this way. |
738 |
*/ |
739 |
public Icon getIcon() { |
740 |
return icon; |
741 |
} |
742 |
} |
743 |
|
674 |
|
744 |
|
675 |
} |
745 |
} |