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 187657
Collapse All | Expand All

(-)a/projectui/src/org/netbeans/modules/project/ui/OpenProjectList.java (-148 / +220 lines)
Lines 77-82 Link Here
77
import java.util.concurrent.Future;
77
import java.util.concurrent.Future;
78
import java.util.concurrent.TimeUnit;
78
import java.util.concurrent.TimeUnit;
79
import java.util.concurrent.TimeoutException;
79
import java.util.concurrent.TimeoutException;
80
import java.util.concurrent.atomic.AtomicBoolean;
81
import java.util.concurrent.atomic.AtomicInteger;
80
import java.util.concurrent.locks.Condition;
82
import java.util.concurrent.locks.Condition;
81
import java.util.concurrent.locks.Lock;
83
import java.util.concurrent.locks.Lock;
82
import java.util.concurrent.locks.ReentrantLock;
84
import java.util.concurrent.locks.ReentrantLock;
Lines 223-238 Link Here
223
    // Implementation of the class ---------------------------------------------
225
    // Implementation of the class ---------------------------------------------
224
    
226
    
225
    public static OpenProjectList getDefault() {
227
    public static OpenProjectList getDefault() {
226
        synchronized ( OpenProjectList.class ) {
228
        return ProjectManager.mutex().writeAccess(new Mutex.Action<OpenProjectList>() {
227
            if ( INSTANCE == null ) {
229
            public @Override OpenProjectList run() {
228
                INSTANCE = new OpenProjectList();
230
                if (INSTANCE == null) {
229
                INSTANCE.openProjects = loadProjectList();
231
                    INSTANCE = new OpenProjectList();
230
                // Load recent project list
232
                    INSTANCE.openProjects = loadProjectList();
231
                INSTANCE.recentProjects.load();
233
                    // Load recent project list
232
                WindowManager.getDefault().invokeWhenUIReady(INSTANCE.LOAD);
234
                    INSTANCE.recentProjects.load();
235
                    WindowManager.getDefault().invokeWhenUIReady(INSTANCE.LOAD);
236
                }
237
                return INSTANCE;
233
            }
238
            }
234
        }
239
        });
235
        return INSTANCE;
236
    }
240
    }
237
    
241
    
238
    static void waitProjectsFullyOpen() {
242
    static void waitProjectsFullyOpen() {
Lines 264-274 Link Here
264
    }
268
    }
265
269
266
    /** Modifications to the recentTemplates variables shall be done only 
270
    /** Modifications to the recentTemplates variables shall be done only 
267
     * when hodling a lock.
271
     * when holding a lock.
268
     * @return the list
272
     * @return the list
269
     */
273
     */
270
    private List<String> getRecentTemplates() {
274
    private List<String> getRecentTemplates() {
271
        assert Thread.holdsLock(this);
275
        assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess();
272
        return recentTemplates;
276
        return recentTemplates;
273
    }
277
    }
274
    
278
    
Lines 341-348 Link Here
341
            }
345
            }
342
        }
346
        }
343
347
344
        final void preferredProject(Project lazyP) {
348
        final void preferredProject(final Project lazyP) {
345
            synchronized (toOpenProjects) {
349
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
350
                public @Override Void run() {
346
                for (Project p : toOpenProjects) {
351
                for (Project p : toOpenProjects) {
347
                    FileObject dir = p.getProjectDirectory();
352
                    FileObject dir = p.getProjectDirectory();
348
                    assert dir != null : "Project has real directory " + p;
353
                    assert dir != null : "Project has real directory " + p;
Lines 352-366 Link Here
352
                    if (dir.equals(lazyP.getProjectDirectory())) {
357
                    if (dir.equals(lazyP.getProjectDirectory())) {
353
                        toOpenProjects.remove(p);
358
                        toOpenProjects.remove(p);
354
                        toOpenProjects.addFirst(p);
359
                        toOpenProjects.addFirst(p);
355
                        return;
360
                        return null;
356
                    }
361
                    }
357
                }
362
                }
358
            }
363
                    return null;
364
                }
365
            });
359
        }
366
        }
360
367
361
        private void updateGlobalState() {
368
        private void updateGlobalState() {
362
            log(Level.FINER, "updateGlobalState"); // NOI18N
369
            log(Level.FINER, "updateGlobalState"); // NOI18N
363
            synchronized (INSTANCE) {
370
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
371
                public @Override Void run() {
364
                INSTANCE.openProjects = lazilyOpenedProjects;
372
                INSTANCE.openProjects = lazilyOpenedProjects;
365
                log(Level.FINER, "openProjects changed: {0}", lazilyOpenedProjects); // NOI18N
373
                log(Level.FINER, "openProjects changed: {0}", lazilyOpenedProjects); // NOI18N
366
                if (lazyMainProject != null) {
374
                if (lazyMainProject != null) {
Lines 369-375 Link Here
369
                INSTANCE.mainProject = unwrapProject(INSTANCE.mainProject);
377
                INSTANCE.mainProject = unwrapProject(INSTANCE.mainProject);
370
                INSTANCE.getRecentTemplates().addAll(recentTemplates);
378
                INSTANCE.getRecentTemplates().addAll(recentTemplates);
371
                log(Level.FINER, "updateGlobalState, applied"); // NOI18N
379
                log(Level.FINER, "updateGlobalState, applied"); // NOI18N
380
                return null;
372
            }
381
            }
382
            });
373
            
383
            
374
            INSTANCE.pchSupport.firePropertyChange(PROPERTY_OPEN_PROJECTS, new Project[0], lazilyOpenedProjects.toArray(new Project[0]));
384
            INSTANCE.pchSupport.firePropertyChange(PROPERTY_OPEN_PROJECTS, new Project[0], lazilyOpenedProjects.toArray(new Project[0]));
375
            INSTANCE.pchSupport.firePropertyChange(PROPERTY_MAIN_PROJECT, null, INSTANCE.mainProject);
385
            INSTANCE.pchSupport.firePropertyChange(PROPERTY_MAIN_PROJECT, null, INSTANCE.mainProject);
Lines 377-412 Link Here
377
            log(Level.FINER, "updateGlobalState, done, notified"); // NOI18N
387
            log(Level.FINER, "updateGlobalState, done, notified"); // NOI18N
378
        }
388
        }
379
389
380
        boolean closeBeforeOpen(Project[] arr) {
390
        boolean closeBeforeOpen(final Project[] arr) {
381
            NEXT: for (int i = 0; i < arr.length; i++) {
391
            return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean>() {
382
                FileObject dir = arr[i].getProjectDirectory();
392
                public @Override Boolean run() {
383
                synchronized (toOpenProjects) {
393
                    NEXT: for (Project p : arr) {
384
                    for (Iterator<Project> it = toOpenProjects.iterator(); it.hasNext();) {
394
                        FileObject dir = p.getProjectDirectory();
385
                        if (dir.equals(it.next().getProjectDirectory())) {
395
                        for (Iterator<Project> it = toOpenProjects.iterator(); it.hasNext();) {
386
                            it.remove();
396
                            if (dir.equals(it.next().getProjectDirectory())) {
387
                            continue NEXT;
397
                                it.remove();
398
                                continue NEXT;
399
                            }
388
                        }
400
                        }
401
                        return false;
389
                    }
402
                    }
390
                    return false;
403
                    return true;
391
                }
404
                }
392
            }
405
            });
393
            return true;
394
        }
406
        }
395
            
407
            
396
        private void loadOnBackground() {
408
        private void loadOnBackground() {
397
            lazilyOpenedProjects = new ArrayList<Project>();
409
            lazilyOpenedProjects = new ArrayList<Project>();
398
            List<URL> URLs = OpenProjectListSettings.getInstance().getOpenProjectsURLs();
410
            List<URL> URLs = OpenProjectListSettings.getInstance().getOpenProjectsURLs();
399
            Project[] inital;
411
            final List<Project> initial = new ArrayList<Project>();
400
            final LinkedList<Project> projects = URLs2Projects(URLs);
412
            final LinkedList<Project> projects = URLs2Projects(URLs);
401
            synchronized (toOpenProjects) {
413
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
402
                toOpenProjects.addAll(projects);
414
                public @Override Void run() {
403
                log(Level.FINER, "loadOnBackground {0}", toOpenProjects); // NOI18N
415
                    toOpenProjects.addAll(projects);
404
                inital = toOpenProjects.toArray(new Project[0]);
416
                    log(Level.FINER, "loadOnBackground {0}", toOpenProjects); // NOI18N
417
                    initial.addAll(toOpenProjects);
418
                    return null;
405
            }
419
            }
420
            });
406
            recentTemplates = new ArrayList<String>( OpenProjectListSettings.getInstance().getRecentTemplates() );
421
            recentTemplates = new ArrayList<String>( OpenProjectListSettings.getInstance().getRecentTemplates() );
407
            URL mainProjectURL = OpenProjectListSettings.getInstance().getMainProjectURL();
422
            final URL mainProjectURL = OpenProjectListSettings.getInstance().getMainProjectURL();
408
            int max;
423
            int max = ProjectManager.mutex().writeAccess(new Mutex.Action<Integer>() {
409
            synchronized (toOpenProjects) {
424
                public @Override Integer run() {
410
                for (Project p : toOpenProjects) {
425
                for (Project p : toOpenProjects) {
411
                    INSTANCE.addModuleInfo(p);
426
                    INSTANCE.addModuleInfo(p);
412
                    // Set main project
427
                    // Set main project
Lines 420-438 Link Here
420
                        // Not a main project
435
                        // Not a main project
421
                    }
436
                    }
422
                }
437
                }
423
                max = toOpenProjects.size();
438
                return toOpenProjects.size();
424
            }
439
                }
440
            });
425
            progress.switchToDeterminate(max);
441
            progress.switchToDeterminate(max);
426
            for (;;) {
442
            for (;;) {
427
                Project p;
443
                final AtomicInteger openPrjSize = new AtomicInteger();
428
                int openPrjSize;
444
                Project p = ProjectManager.mutex().writeAccess(new Mutex.Action<Project>() {
429
                synchronized (toOpenProjects) {
445
                    public @Override Project run() {
430
                    if (toOpenProjects.isEmpty()) {
446
                        if (toOpenProjects.isEmpty()) {
431
                        break;
447
                            return null;
448
                        }
449
                        Project p = toOpenProjects.remove();
450
                        log(Level.FINER, "after remove {0}", toOpenProjects); // NOI18N
451
                        openPrjSize.set(toOpenProjects.size());
452
                        return p;
432
                    }
453
                    }
433
                    p = toOpenProjects.remove();
454
                });
434
                    log(Level.FINER, "after remove {0}", toOpenProjects); // NOI18N
455
                if (p == null) {
435
                    openPrjSize = toOpenProjects.size();
456
                    break;
436
                }
457
                }
437
                log(Level.FINE, "about to open a project {0}", p); // NOI18N
458
                log(Level.FINE, "about to open a project {0}", p); // NOI18N
438
                if (notifyOpened(p)) {
459
                if (notifyOpened(p)) {
Lines 451-462 Link Here
451
                        lazyMainProject = null;
472
                        lazyMainProject = null;
452
                    }
473
                    }
453
                }
474
                }
454
                progress.progress(max - openPrjSize);
475
                progress.progress(max - openPrjSize.get());
455
            }
476
            }
456
477
457
            if (inital != null) {
478
            if (initial != null) {
458
                log(createRecord("UI_INIT_PROJECTS", inital),"org.netbeans.ui.projects");
479
                Project[] initialA = initial.toArray(new Project[initial.size()]);
459
                log(createRecordMetrics("USG_PROJECT_OPEN", inital),"org.netbeans.ui.metrics.projects");
480
                log(createRecord("UI_INIT_PROJECTS", initialA),"org.netbeans.ui.projects");
481
                log(createRecordMetrics("USG_PROJECT_OPEN", initialA),"org.netbeans.ui.metrics.projects");
460
            }
482
            }
461
483
462
        }
484
        }
Lines 687-695 Link Here
687
        
709
        
688
        final List<Project> oldprjs = new ArrayList<Project>();
710
        final List<Project> oldprjs = new ArrayList<Project>();
689
        final List<Project> newprjs = new ArrayList<Project>();
711
        final List<Project> newprjs = new ArrayList<Project>();
690
        synchronized (this) {
712
        ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
691
            oldprjs.addAll(openProjects);
713
            public @Override Void run() {
692
        }
714
                oldprjs.addAll(openProjects);
715
                return null;
716
            }
717
        });
693
        
718
        
694
        for (Project p: projectsToOpen) {
719
        for (Project p: projectsToOpen) {
695
            
720
            
Lines 707-720 Link Here
707
                handle.progress((int) currentWork);
732
                handle.progress((int) currentWork);
708
            }
733
            }
709
        }
734
        }
710
        
735
711
        synchronized ( this ) {
736
        final boolean _recentProjectsChanged = recentProjectsChanged;
712
            newprjs.addAll(openProjects);
737
        ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
713
            saveProjectList( openProjects );
738
            public @Override Void run() {
714
            if ( recentProjectsChanged ) {
739
                newprjs.addAll(openProjects);
715
                recentProjects.save();
740
                saveProjectList(openProjects);
741
                if (_recentProjectsChanged) {
742
                    recentProjects.save();
743
                }
744
                return null;
716
            }
745
            }
717
        }
746
        });
718
        
747
        
719
	if (handle != null) {
748
	if (handle != null) {
720
	    handle.finish();
749
	    handle.finish();
Lines 750-756 Link Here
750
            LOAD.waitFinished();
779
            LOAD.waitFinished();
751
        }
780
        }
752
        
781
        
753
        Project[] projects = new Project[someProjects.length];
782
        final Project[] projects = new Project[someProjects.length];
754
        for (int i = 0; i < someProjects.length; i++) {
783
        for (int i = 0; i < someProjects.length; i++) {
755
            projects[i] = unwrapProject(someProjects[i]);
784
            projects[i] = unwrapProject(someProjects[i]);
756
        }
785
        }
Lines 764-781 Link Here
764
            LOAD.enter();
793
            LOAD.enter();
765
            ProjectUtilities.WaitCursor.show();
794
            ProjectUtilities.WaitCursor.show();
766
            logProjects("close(): closing project: ", projects);
795
            logProjects("close(): closing project: ", projects);
767
            boolean mainClosed = false;
796
            final AtomicBoolean mainClosed = new AtomicBoolean();
768
            boolean someClosed = false;
797
            final AtomicBoolean someClosed = new AtomicBoolean();
769
            List<Project> oldprjs = new ArrayList<Project>();
798
            final List<Project> oldprjs = new ArrayList<Project>();
770
            List<Project> newprjs = new ArrayList<Project>();
799
            final List<Project> newprjs = new ArrayList<Project>();
771
            final List<Project> notifyList = new ArrayList<Project>();
800
            final List<Project> notifyList = new ArrayList<Project>();
772
            synchronized ( this ) {
801
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
802
                public @Override Void run() {
773
                oldprjs.addAll(openProjects);
803
                oldprjs.addAll(openProjects);
774
                for( int i = 0; i < projects.length; i++ ) {
804
                    for (Project p : projects) {
775
                    Iterator<Project> it = openProjects.iterator();
805
                    Iterator<Project> it = openProjects.iterator();
776
                    boolean found = false;
806
                    boolean found = false;
777
                    while (it.hasNext()) {
807
                    while (it.hasNext()) {
778
                        if (it.next().equals(projects[i])) {
808
                        if (it.next().equals(p)) {
779
                            found = true;
809
                            found = true;
780
                            break;
810
                            break;
781
                        }
811
                        }
Lines 783-810 Link Here
783
                    if (!found) {
813
                    if (!found) {
784
                        continue; // Nothing to remove
814
                        continue; // Nothing to remove
785
                    }
815
                    }
786
                    if ( !mainClosed ) {
816
                    if (!mainClosed.get()) {
787
                        mainClosed = isMainProject( projects[i] );
817
                        mainClosed.set(isMainProject(p));
788
                    }
818
                    }
789
                    // remove the project from openProjects
819
                    // remove the project from openProjects
790
                    it.remove();
820
                    it.remove();
791
                    removeModuleInfo(projects[i]);
821
                    removeModuleInfo(p);
792
822
793
                    projects[i].getProjectDirectory().removeFileChangeListener(deleteListener);
823
                    p.getProjectDirectory().removeFileChangeListener(deleteListener);
794
824
795
                    notifyList.add(projects[i]);
825
                    notifyList.add(p);
796
826
797
                    someClosed = true;
827
                    someClosed.set(true);
798
                }
828
                }
799
                if ( someClosed ) {
829
                if (someClosed.get()) {
800
                    newprjs.addAll(openProjects);
830
                    newprjs.addAll(openProjects);
801
                    saveProjectList(openProjects);
831
                    saveProjectList(openProjects);
802
                }
832
                }
803
                if ( mainClosed ) {
833
                if (mainClosed.get()) {
804
                    this.mainProject = null;
834
                    mainProject = null;
805
                    saveMainProject( mainProject );
835
                    saveMainProject( mainProject );
806
                }
836
                }
837
                return null;
807
            }
838
            }
839
            });
808
            if (!notifyList.isEmpty()) {
840
            if (!notifyList.isEmpty()) {
809
                for (Project p : notifyList) {
841
                for (Project p : notifyList) {
810
                    recentProjects.add(p); // #183681: call outside of lock
842
                    recentProjects.add(p); // #183681: call outside of lock
Lines 820-833 Link Here
820
                }
852
                }
821
            });
853
            });
822
            logProjects("close(): openProjects == ", openProjects.toArray(new Project[0])); // NOI18N
854
            logProjects("close(): openProjects == ", openProjects.toArray(new Project[0])); // NOI18N
823
            if ( someClosed ) {
855
            if (someClosed.get()) {
824
                pchSupport.firePropertyChange( PROPERTY_OPEN_PROJECTS,
856
                pchSupport.firePropertyChange( PROPERTY_OPEN_PROJECTS,
825
                                oldprjs.toArray(new Project[oldprjs.size()]), newprjs.toArray(new Project[newprjs.size()]) );
857
                                oldprjs.toArray(new Project[oldprjs.size()]), newprjs.toArray(new Project[newprjs.size()]) );
826
            }
858
            }
827
            if ( mainClosed ) {
859
            if (mainClosed.get()) {
828
                pchSupport.firePropertyChange( PROPERTY_MAIN_PROJECT, null, null );
860
                pchSupport.firePropertyChange( PROPERTY_MAIN_PROJECT, null, null );
829
            }
861
            }
830
            if ( someClosed ) {
862
            if (someClosed.get()) {
831
                pchSupport.firePropertyChange( PROPERTY_RECENT_PROJECTS, null, null );
863
                pchSupport.firePropertyChange( PROPERTY_RECENT_PROJECTS, null, null );
832
            }
864
            }
833
            if (doSave) {
865
            if (doSave) {
Lines 854-912 Link Here
854
        }
886
        }
855
    }
887
    }
856
        
888
        
857
    public synchronized Project[] getOpenProjects() {
889
    public Project[] getOpenProjects() {
858
        Project projects[] = new Project[ openProjects.size() ];
890
        return ProjectManager.mutex().readAccess(new Mutex.Action<Project[]>() {
859
        openProjects.toArray( projects );
891
            public @Override Project[] run() {
860
        return projects;
892
                return openProjects.toArray(new Project[openProjects.size()]);
893
            }
894
        });
861
    }
895
    }
862
    
896
    
863
    public synchronized boolean isOpen( Project p ) {
897
    public boolean isOpen(final Project p) {
864
        // XXX shouldn't this just use openProjects.contains(p)?
898
        // XXX shouldn't this just use openProjects.contains(p)?
865
        for(Project cp : openProjects) {
899
        return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean>() {
866
            if ( p.getProjectDirectory().equals( cp.getProjectDirectory() ) ) { 
900
            public @Override Boolean run() {
867
                return true;
901
                for (Project cp : openProjects) {
902
                    if (p.getProjectDirectory().equals(cp.getProjectDirectory())) {
903
                        return true;
904
                    }
905
                }
906
                return false;
868
            }
907
            }
869
        }
908
        });
870
        return false;
871
    }
909
    }
872
910
873
    public synchronized boolean isMainProject( Project p ) {
911
    public boolean isMainProject(final Project p) {
874
912
        return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean>() {
875
        if ( mainProject != null && p != null &&
913
            public @Override Boolean run() {
876
             mainProject.getProjectDirectory().equals( p.getProjectDirectory() ) ) {
914
                if (mainProject != null && p != null && mainProject.getProjectDirectory().equals(p.getProjectDirectory())) {
877
            return true;
915
                    return true;
878
        }
916
                } else {
879
        else {
917
                    return false;
880
            return false;
918
                }
881
        }
919
            }
882
        
920
        });
883
    }
921
    }
884
    
922
    
885
    public synchronized Project getMainProject() {
923
    public Project getMainProject() {
886
        return mainProject;
924
        return ProjectManager.mutex().readAccess(new Mutex.Action<Project>() {
925
            public @Override Project run() {
926
                return mainProject;
927
            }
928
        });
887
    }
929
    }
888
    
930
    
889
    public void setMainProject( Project mainProject ) {
931
    public void setMainProject( final Project mainProject ) {
890
        LOGGER.finer("Setting main project: " + mainProject); // NOI18N
932
        LOGGER.finer("Setting main project: " + mainProject); // NOI18N
891
        logProjects("setMainProject(): openProjects == ", openProjects.toArray(new Project[0])); // NOI18N
933
        logProjects("setMainProject(): openProjects == ", openProjects.toArray(new Project[0])); // NOI18N
892
        synchronized ( this ) {
934
        ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
893
            if (mainProject != null && !openProjects.contains(mainProject)) {
935
            public @Override Void run() {
936
            Project main = mainProject;
937
            if (main != null && !openProjects.contains(main)) {
894
                //#139965 the project passed in here can be different from the current one.
938
                //#139965 the project passed in here can be different from the current one.
895
                // eg when the ManProjectAction shows a list of opened projects, it lists the "non-loaded skeletons"
939
                // eg when the ManProjectAction shows a list of opened projects, it lists the "non-loaded skeletons"
896
                // but when the user eventually selects one, the openProjects list already might hold the 
940
                // but when the user eventually selects one, the openProjects list already might hold the 
897
                // correct loaded list.
941
                // correct loaded list.
898
                try {
942
                try {
899
                    mainProject = ProjectManager.getDefault().findProject(mainProject.getProjectDirectory());
943
                    main = ProjectManager.getDefault().findProject(main.getProjectDirectory());
900
                    if (mainProject != null) {
944
                    if (main != null) {
901
                        boolean fail = true;
945
                        boolean fail = true;
902
                        for (Project p : openProjects) {
946
                        for (Project p : openProjects) {
903
                            if (p.equals(mainProject)) {
947
                            if (p.equals(main)) {
904
                                fail = false;
948
                                fail = false;
905
                                break;
949
                                break;
906
                            }
950
                            }
907
                            if (p instanceof LazyProject) {
951
                            if (p instanceof LazyProject) {
908
                                if (p.getProjectDirectory().equals(mainProject.getProjectDirectory())) {
952
                                if (p.getProjectDirectory().equals(main.getProjectDirectory())) {
909
                                    mainProject = p;
953
                                    main = p;
910
                                    fail = false;
954
                                    fail = false;
911
                                    break;
955
                                    break;
912
                                }
956
                                }
Lines 922-939 Link Here
922
                }
966
                }
923
            }
967
            }
924
        
968
        
925
            this.mainProject = mainProject;
969
            OpenProjectList.this.mainProject = main;
926
            saveMainProject( mainProject );
970
            saveMainProject(main);
971
            return null;
927
        }
972
        }
973
        });
928
        pchSupport.firePropertyChange( PROPERTY_MAIN_PROJECT, null, null );
974
        pchSupport.firePropertyChange( PROPERTY_MAIN_PROJECT, null, null );
929
    }
975
    }
930
    
976
    
931
    public List<Project> getRecentProjects() {
977
    public List<Project> getRecentProjects() {
932
        return ProjectManager.mutex().readAccess(new Mutex.Action<List<Project>>() {
978
        return ProjectManager.mutex().readAccess(new Mutex.Action<List<Project>>() {
933
            public List<Project> run() {
979
            public List<Project> run() {
934
                synchronized (OpenProjectList.class) {
980
                return recentProjects.getProjects();
935
                    return recentProjects.getProjects();
936
                }
937
            }
981
            }
938
        });
982
        });
939
    }
983
    }
Lines 941-949 Link Here
941
    public boolean isRecentProjectsEmpty() {
985
    public boolean isRecentProjectsEmpty() {
942
        return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean>() {
986
        return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean>() {
943
            public Boolean run() {
987
            public Boolean run() {
944
                synchronized (OpenProjectList.class) {
988
                return recentProjects.isEmpty();
945
                    return recentProjects.isEmpty();
946
                }
947
            }
989
            }
948
        });         
990
        });         
949
    }
991
    }
Lines 951-959 Link Here
951
    public List<UnloadedProjectInformation> getRecentProjectsInformation() {
993
    public List<UnloadedProjectInformation> getRecentProjectsInformation() {
952
        return ProjectManager.mutex().readAccess(new Mutex.Action<List<UnloadedProjectInformation>>() {
994
        return ProjectManager.mutex().readAccess(new Mutex.Action<List<UnloadedProjectInformation>>() {
953
            public List<UnloadedProjectInformation> run() {
995
            public List<UnloadedProjectInformation> run() {
954
                synchronized (OpenProjectList.class) {
996
                return recentProjects.getRecentProjectsInfo();
955
                    return recentProjects.getRecentProjectsInfo();
956
                }
957
            }
997
            }
958
        });
998
        });
959
    }
999
    }
Lines 997-1003 Link Here
997
        
1037
        
998
    
1038
    
999
    // Used from NewFile action    
1039
    // Used from NewFile action    
1000
    public synchronized void updateTemplatesLRU( FileObject template ) {
1040
    public void updateTemplatesLRU(final FileObject template) {
1041
        ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
1042
            public @Override Void run() {
1001
        
1043
        
1002
        String templateName = template.getPath();
1044
        String templateName = template.getPath();
1003
        
1045
        
Lines 1011-1016 Link Here
1011
        }
1053
        }
1012
        
1054
        
1013
        OpenProjectListSettings.getInstance().setRecentTemplates( new ArrayList<String>( getRecentTemplates() )  );
1055
        OpenProjectListSettings.getInstance().setRecentTemplates( new ArrayList<String>( getRecentTemplates() )  );
1056
                return null;
1057
            }
1058
        });
1014
    }
1059
    }
1015
    
1060
    
1016
    
1061
    
Lines 1159-1167 Link Here
1159
    }
1204
    }
1160
1205
1161
    private boolean doOpenProject(final Project p) {
1206
    private boolean doOpenProject(final Project p) {
1162
        boolean recentProjectsChanged;
1163
        LOGGER.finer("doOpenProject(): opening project " + p.toString());
1207
        LOGGER.finer("doOpenProject(): opening project " + p.toString());
1164
        synchronized (this) {
1208
        boolean recentProjectsChanged = ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean>() {
1209
            public @Override Boolean run() {
1165
            log(Level.FINER, "already opened: {0} ", openProjects);
1210
            log(Level.FINER, "already opened: {0} ", openProjects);
1166
            for (Project existing : openProjects) {
1211
            for (Project existing : openProjects) {
1167
                if (p.equals(existing) || existing.equals(p)) {
1212
                if (p.equals(existing) || existing.equals(p)) {
Lines 1174-1181 Link Here
1174
            p.getProjectDirectory().addFileChangeListener(deleteListener);
1219
            p.getProjectDirectory().addFileChangeListener(deleteListener);
1175
            p.getProjectDirectory().addFileChangeListener(nbprojectDeleteListener);
1220
            p.getProjectDirectory().addFileChangeListener(nbprojectDeleteListener);
1176
            
1221
            
1177
            recentProjectsChanged = recentProjects.remove(p);
1222
            return recentProjects.remove(p);
1178
        }
1223
        }
1224
        });
1179
        logProjects("doOpenProject(): openProjects == ", openProjects.toArray(new Project[0])); // NOI18N
1225
        logProjects("doOpenProject(): openProjects == ", openProjects.toArray(new Project[0])); // NOI18N
1180
        // Notify projects opened
1226
        // Notify projects opened
1181
        notifyOpened(p);
1227
        notifyOpened(p);
Lines 1238-1261 Link Here
1238
        }
1284
        }
1239
    }
1285
    }
1240
        
1286
        
1241
    private ArrayList<FileObject> getTemplateNamesLRU( Project project, PrivilegedTemplates priv ) {
1287
    private ArrayList<FileObject> getTemplateNamesLRU( final Project project, PrivilegedTemplates priv ) {
1242
        // First take recently used templates and try to find those which
1288
        // First take recently used templates and try to find those which
1243
        // are supported by the project.
1289
        // are supported by the project.
1244
        
1290
        
1245
        ArrayList<FileObject> result = new ArrayList<FileObject>(NUM_TEMPLATES);        
1291
        final ArrayList<FileObject> result = new ArrayList<FileObject>(NUM_TEMPLATES);
1246
        
1292
        
1247
        RecommendedTemplates rt = project.getLookup().lookup( RecommendedTemplates.class );
1293
        RecommendedTemplates rt = project.getLookup().lookup( RecommendedTemplates.class );
1248
        String rtNames[] = rt == null ? new String[0] : rt.getRecommendedTypes();
1294
        String rtNames[] = rt == null ? new String[0] : rt.getRecommendedTypes();
1249
        PrivilegedTemplates pt = priv != null ? priv : project.getLookup().lookup( PrivilegedTemplates.class );
1295
        PrivilegedTemplates pt = priv != null ? priv : project.getLookup().lookup( PrivilegedTemplates.class );
1250
        String ptNames[] = pt == null ? null : pt.getPrivilegedTemplates();        
1296
        String ptNames[] = pt == null ? null : pt.getPrivilegedTemplates();        
1251
        ArrayList<String> privilegedTemplates = new ArrayList<String>( Arrays.asList( pt == null ? new String[0]: ptNames ) );
1297
        final ArrayList<String> privilegedTemplates = new ArrayList<String>( Arrays.asList( pt == null ? new String[0]: ptNames ) );
1252
        
1298
        
1253
        if (priv == null) {
1299
        if (priv == null) {
1254
            // when the privileged templates are part of the active lookup,
1300
            // when the privileged templates are part of the active lookup,
1255
            // do not mix them with the recent templates, but use only the privileged ones.
1301
            // do not mix them with the recent templates, but use only the privileged ones.
1256
            // eg. on Webservices node, one is not interested in a recent "jsp" file template..
1302
            // eg. on Webservices node, one is not interested in a recent "jsp" file template..
1257
            
1303
            
1258
            synchronized (this) {
1304
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
1305
                public @Override Void run() {
1259
                Iterator<String> it = getRecentTemplates().iterator();
1306
                Iterator<String> it = getRecentTemplates().iterator();
1260
                for( int i = 0; i < NUM_TEMPLATES && it.hasNext(); i++ ) {
1307
                for( int i = 0; i < NUM_TEMPLATES && it.hasNext(); i++ ) {
1261
                    String templateName = it.next();
1308
                    String templateName = it.next();
Lines 1271-1277 Link Here
1271
                        continue;
1318
                        continue;
1272
                    }
1319
                    }
1273
                }
1320
                }
1321
                return null;
1274
            }
1322
            }
1323
            });
1275
        }
1324
        }
1276
        
1325
        
1277
        // If necessary fill the list with the rest of privileged templates
1326
        // If necessary fill the list with the rest of privileged templates
Lines 1352-1359 Link Here
1352
            }
1401
            }
1353
        }
1402
        }
1354
        
1403
        
1355
        public void add(Project p) {
1404
        public void add(final Project p) {
1356
            UnloadedProjectInformation projectInfo;
1405
            final UnloadedProjectInformation projectInfo;
1357
            try { // #183681: call outside of lock
1406
            try { // #183681: call outside of lock
1358
                projectInfo = ProjectInfoAccessor.DEFAULT.getProjectInfo(
1407
                projectInfo = ProjectInfoAccessor.DEFAULT.getProjectInfo(
1359
                        ProjectUtils.getInformation(p).getDisplayName(),
1408
                        ProjectUtils.getInformation(p).getDisplayName(),
Lines 1363-1369 Link Here
1363
                ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
1412
                ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
1364
                return;
1413
                return;
1365
            }
1414
            }
1366
            synchronized (this) {
1415
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
1416
                public @Override Void run() {
1367
                int index = getIndex(p);
1417
                int index = getIndex(p);
1368
                if (index == -1) {
1418
                if (index == -1) {
1369
                    // Project not in list
1419
                    // Project not in list
Lines 1383-1392 Link Here
1383
                }
1433
                }
1384
                recentProjects.add(0, new ProjectReference(p));
1434
                recentProjects.add(0, new ProjectReference(p));
1385
                recentProjectsInfos.add(0, projectInfo);
1435
                recentProjectsInfos.add(0, projectInfo);
1436
                return null;
1386
            }
1437
            }
1438
            });
1387
        }
1439
        }
1388
        
1440
        
1389
        public synchronized boolean remove( Project p ) {
1441
        public boolean remove(final Project p) {
1442
            return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean>() {
1443
                public @Override Boolean run() {
1390
            int index = getIndex( p );
1444
            int index = getIndex( p );
1391
            if ( index != -1 ) {
1445
            if ( index != -1 ) {
1392
                LOGGER.log(Level.FINE, "remove recent project: {0} @{1}", new Object[] {p, index});
1446
                LOGGER.log(Level.FINE, "remove recent project: {0} @{1}", new Object[] {p, index});
Lines 1395-1406 Link Here
1395
                return true;
1449
                return true;
1396
            }
1450
            }
1397
            return false;
1451
            return false;
1452
                }
1453
            });
1398
        }
1454
        }
1399
1455
1400
        public void refresh() {
1456
        public void refresh() {
1401
            ProjectManager.mutex().readAccess(new Runnable() {
1457
            ProjectManager.mutex().writeAccess(new Runnable() {
1402
                public void run () {
1458
                public void run () {
1403
                    synchronized (RecentProjectList.this) {
1404
                        assert recentProjects.size() == recentProjectsInfos.size();
1459
                        assert recentProjects.size() == recentProjectsInfos.size();
1405
                        boolean refresh = false;
1460
                        boolean refresh = false;
1406
                        Iterator<ProjectReference> recentProjectsIter = recentProjects.iterator();
1461
                        Iterator<ProjectReference> recentProjectsIter = recentProjects.iterator();
Lines 1438-1444 Link Here
1438
                            pchSupport.firePropertyChange(PROPERTY_RECENT_PROJECTS, null, null);
1493
                            pchSupport.firePropertyChange(PROPERTY_RECENT_PROJECTS, null, null);
1439
                            save();
1494
                            save();
1440
                        }
1495
                        }
1441
                    }
1442
                }
1496
                }
1443
            });
1497
            });
1444
        }
1498
        }
Lines 1473-1479 Link Here
1473
            return empty;
1527
            return empty;
1474
        }
1528
        }
1475
        
1529
        
1476
        public synchronized void load() {
1530
        public void load() {
1531
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
1532
                public @Override Void run() {
1477
            List<URL> URLs = OpenProjectListSettings.getInstance().getRecentProjectsURLs();
1533
            List<URL> URLs = OpenProjectListSettings.getInstance().getRecentProjectsURLs();
1478
            List<String> names = OpenProjectListSettings.getInstance().getRecentProjectsDisplayNames();
1534
            List<String> names = OpenProjectListSettings.getInstance().getRecentProjectsDisplayNames();
1479
            List<ExtIcon> icons = OpenProjectListSettings.getInstance().getRecentProjectsIcons();
1535
            List<ExtIcon> icons = OpenProjectListSettings.getInstance().getRecentProjectsIcons();
Lines 1507-1512 Link Here
1507
                    assert p.getProjectDirectory() != null : "Project " + p + " has null project directory";
1563
                    assert p.getProjectDirectory() != null : "Project " + p + " has null project directory";
1508
                    p.getProjectDirectory().addFileChangeListener(nbprojectDeleteListener);
1564
                    p.getProjectDirectory().addFileChangeListener(nbprojectDeleteListener);
1509
                }
1565
                }
1566
            return null;
1567
        }
1568
        });
1510
        }
1569
        }
1511
        
1570
        
1512
        public void save() {
1571
        public void save() {
Lines 1561-1570 Link Here
1561
            return -1;
1620
            return -1;
1562
        }
1621
        }
1563
        
1622
        
1564
        private synchronized List<UnloadedProjectInformation> getRecentProjectsInfo() {
1623
        private List<UnloadedProjectInformation> getRecentProjectsInfo() {
1565
            // #166408: refreshing is too time expensive and we want to be fast, not correct
1624
            // #166408: refreshing is too time expensive and we want to be fast, not correct
1566
            //refresh();
1625
            //refresh();
1567
            return new ArrayList<UnloadedProjectInformation>(recentProjectsInfos);
1626
            return ProjectManager.mutex().readAccess(new Mutex.Action<List<UnloadedProjectInformation>>() {
1627
                public @Override List<UnloadedProjectInformation> run() {
1628
                    return new ArrayList<UnloadedProjectInformation>(recentProjectsInfos);
1629
                }
1630
            });
1568
        }
1631
        }
1569
        
1632
        
1570
        private class ProjectReference {
1633
        private class ProjectReference {
Lines 1701-1714 Link Here
1701
    }
1764
    }
1702
    
1765
    
1703
    /**
1766
    /**
1704
     * Closesdeleted projects.
1767
     * Closes deleted projects.
1705
     */
1768
     */
1706
    private final class ProjectDeletionListener extends FileChangeAdapter {
1769
    private final class ProjectDeletionListener extends FileChangeAdapter {
1707
        
1770
        
1708
        public ProjectDeletionListener() {}
1771
        public ProjectDeletionListener() {}
1709
1772
1710
        public @Override void fileDeleted(FileEvent fe) {
1773
        public @Override void fileDeleted(final FileEvent fe) {
1711
            synchronized (OpenProjectList.this) {
1774
            ProjectManager.mutex().readAccess(new Mutex.Action<Void>() {
1775
                public @Override Void run() {
1712
                Project toRemove = null;
1776
                Project toRemove = null;
1713
                for (Project prj : openProjects) {
1777
                for (Project prj : openProjects) {
1714
                    if (fe.getFile().equals(prj.getProjectDirectory())) {
1778
                    if (fe.getFile().equals(prj.getProjectDirectory())) {
Lines 1726-1732 Link Here
1726
                        }
1790
                        }
1727
                    });
1791
                    });
1728
                }
1792
                }
1729
            }
1793
                    return null;
1794
                }
1795
            });
1730
        }
1796
        }
1731
        
1797
        
1732
    }
1798
    }
Lines 1747-1763 Link Here
1747
        return info;
1813
        return info;
1748
    }
1814
    }
1749
    
1815
    
1750
    private void addModuleInfo(Project prj) {
1816
    private void addModuleInfo(final Project prj) {
1751
        ModuleInfo info = findModuleForProject(prj);
1817
        final ModuleInfo info = findModuleForProject(prj);
1752
        if (info != null) {
1818
        if (info != null) {
1753
            // is null in tests..
1819
            // is null in tests..
1754
            synchronized (openProjectsModuleInfos) {
1820
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
1821
                public @Override Void run() {
1755
                if (!openProjectsModuleInfos.containsKey(info)) {
1822
                if (!openProjectsModuleInfos.containsKey(info)) {
1756
                    openProjectsModuleInfos.put(info, new ArrayList<Project>());
1823
                    openProjectsModuleInfos.put(info, new ArrayList<Project>());
1757
                    info.addPropertyChangeListener(infoListener);
1824
                    info.addPropertyChangeListener(infoListener);
1758
                }
1825
                }
1759
                openProjectsModuleInfos.get(info).add(prj);
1826
                openProjectsModuleInfos.get(info).add(prj);
1827
                return null;
1760
            }
1828
            }
1829
            });
1761
        }
1830
        }
1762
    }
1831
    }
1763
    
1832
    
Lines 1766-1784 Link Here
1766
        removeModuleInfo(prj, info);
1835
        removeModuleInfo(prj, info);
1767
    }
1836
    }
1768
    
1837
    
1769
    private void removeModuleInfo(Project prj, ModuleInfo info) {
1838
    private void removeModuleInfo(final Project prj, final ModuleInfo info) {
1770
        // info can be null in case we are closing a project from disabled module
1839
        // info can be null in case we are closing a project from disabled module
1771
        if (info != null) {
1840
        if (info != null) {
1772
            synchronized (openProjectsModuleInfos) {
1841
            ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
1842
                public @Override Void run() {
1773
                List<Project> prjlist = openProjectsModuleInfos.get(info);
1843
                List<Project> prjlist = openProjectsModuleInfos.get(info);
1774
                if (prjlist != null) {
1844
                if (prjlist != null) {
1775
                    prjlist.remove(prj);
1845
                    prjlist.remove(prj);
1776
                    if (prjlist.size() == 0) {
1846
                    if (prjlist.isEmpty()) {
1777
                        info.removePropertyChangeListener(infoListener);
1847
                        info.removePropertyChangeListener(infoListener);
1778
                        openProjectsModuleInfos.remove(info);
1848
                        openProjectsModuleInfos.remove(info);
1779
                    }
1849
                    }
1780
                }
1850
                }
1851
                return null;
1781
            }
1852
            }
1853
            });
1782
        }
1854
        }
1783
    }
1855
    }
1784
1856

Return to bug 187657