KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > project > ui > OpenProjectList


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.project.ui;
21
22 import java.awt.Dimension JavaDoc;
23 import java.awt.EventQueue JavaDoc;
24 import java.awt.Frame JavaDoc;
25 import java.awt.Rectangle JavaDoc;
26 import java.beans.PropertyChangeEvent JavaDoc;
27 import java.beans.PropertyChangeListener JavaDoc;
28 import java.beans.PropertyChangeSupport JavaDoc;
29 import java.io.File JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.lang.ref.WeakReference JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.text.Collator JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Arrays JavaDoc;
36 import java.util.Collection JavaDoc;
37 import java.util.Collections JavaDoc;
38 import java.util.Comparator JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.LinkedHashSet JavaDoc;
42 import java.util.LinkedList JavaDoc;
43 import java.util.List JavaDoc;
44 import java.util.Map JavaDoc;
45 import java.util.Set JavaDoc;
46 import java.util.StringTokenizer JavaDoc;
47 import javax.swing.Icon JavaDoc;
48 import javax.swing.JDialog JavaDoc;
49 import javax.swing.SwingUtilities JavaDoc;
50 import org.netbeans.api.progress.ProgressHandle;
51 import org.netbeans.api.progress.ProgressHandleFactory;
52 import org.netbeans.api.project.Project;
53 import org.netbeans.api.project.ProjectManager;
54 import org.netbeans.api.project.ProjectUtils;
55 import org.netbeans.modules.project.ui.api.UnloadedProjectInformation;
56 import org.netbeans.modules.project.uiapi.ProjectOpenedTrampoline;
57 import org.netbeans.spi.project.SubprojectProvider;
58 import org.netbeans.spi.project.ui.PrivilegedTemplates;
59 import org.netbeans.spi.project.ui.ProjectOpenedHook;
60 import org.netbeans.spi.project.ui.RecommendedTemplates;
61 import org.openide.ErrorManager;
62 import org.openide.filesystems.FileChangeAdapter;
63 import org.openide.filesystems.FileEvent;
64 import org.openide.filesystems.FileObject;
65 import org.openide.filesystems.FileStateInvalidException;
66 import org.openide.filesystems.FileSystem;
67 import org.openide.filesystems.FileUtil;
68 import org.openide.filesystems.Repository;
69 import org.openide.filesystems.URLMapper;
70 import org.openide.loaders.DataObject;
71 import org.openide.loaders.DataObjectNotFoundException;
72 import org.openide.modules.ModuleInfo;
73 import org.openide.util.Lookup;
74 import org.openide.util.Mutex;
75 import org.openide.util.Mutex.Action;
76 import org.openide.util.NbBundle;
77 import org.openide.util.RequestProcessor;
78 import org.openide.windows.WindowManager;
79
80 /**
81  * List of projects open in the GUI.
82  * @author Petr Hrebejk
83  */

84 public final class OpenProjectList {
85     
86     public static final Comparator JavaDoc<Project> PROJECT_BY_DISPLAYNAME = new ProjectByDisplayNameComparator();
87     
88     // Property names
89
public static final String JavaDoc PROPERTY_OPEN_PROJECTS = "OpenProjects";
90     public static final String JavaDoc PROPERTY_MAIN_PROJECT = "MainProject";
91     public static final String JavaDoc PROPERTY_RECENT_PROJECTS = "RecentProjects";
92     
93     private static OpenProjectList INSTANCE;
94     
95     // number of templates in LRU list
96
private static final int NUM_TEMPLATES = 15;
97     
98     private static final ErrorManager ERR = ErrorManager.getDefault().getInstance(OpenProjectList.class.getName());
99     private static final RequestProcessor OPENING_RP = new RequestProcessor("Opening projects", 1);
100     
101     /** List which holds the open projects */
102     private List JavaDoc<Project> openProjects;
103     private HashMap JavaDoc<ModuleInfo, List JavaDoc<Project>> openProjectsModuleInfos;
104     
105     /** Main project */
106     private Project mainProject;
107     
108     /** List of recently closed projects */
109     private final RecentProjectList recentProjects;
110
111     /** LRU List of recently used templates */
112     private List JavaDoc<String JavaDoc> recentTemplates;
113     
114     /** Property change listeners */
115     private final PropertyChangeSupport JavaDoc pchSupport;
116     
117     private ProjectDeletionListener deleteListener = new ProjectDeletionListener();
118     
119     private PropertyChangeListener JavaDoc infoListener;
120     
121     OpenProjectList() {
122         openProjects = new ArrayList JavaDoc<Project>();
123         openProjectsModuleInfos = new HashMap JavaDoc<ModuleInfo, List JavaDoc<Project>>();
124         infoListener = new PropertyChangeListener JavaDoc() {
125             public void propertyChange(PropertyChangeEvent JavaDoc evn) {
126                 if (ModuleInfo.PROP_ENABLED.equals(evn.getPropertyName())) {
127                     checkModuleInfo((ModuleInfo)evn.getSource());
128                 }
129             }
130         };
131         pchSupport = new PropertyChangeSupport JavaDoc( this );
132         recentProjects = new RecentProjectList(10); // #47134
133
}
134     
135            
136     // Implementation of the class ---------------------------------------------
137

138     public static OpenProjectList getDefault() {
139         boolean needNotify = false;
140         
141         synchronized ( OpenProjectList.class ) {
142             if ( INSTANCE == null ) {
143                 needNotify = true;
144                 INSTANCE = new OpenProjectList();
145                 INSTANCE.openProjects = loadProjectList();
146                 INSTANCE.recentTemplates = new ArrayList JavaDoc<String JavaDoc>( OpenProjectListSettings.getInstance().getRecentTemplates() );
147                 URL JavaDoc mainProjectURL = OpenProjectListSettings.getInstance().getMainProjectURL();
148                 // Load recent project list
149
INSTANCE.recentProjects.load();
150                 for( Iterator JavaDoc it = INSTANCE.openProjects.iterator(); it.hasNext(); ) {
151                     Project p = (Project)it.next();
152                     INSTANCE.addModuleInfo(p);
153                     // Set main project
154
try {
155                         if ( mainProjectURL != null &&
156                              mainProjectURL.equals( p.getProjectDirectory().getURL() ) ) {
157                             INSTANCE.mainProject = p;
158                         }
159                     }
160                     catch( FileStateInvalidException e ) {
161                         // Not a main project
162
}
163                 }
164             }
165         }
166         if ( needNotify ) {
167             //#68738: a project may open other projects in its ProjectOpenedHook:
168
for(Project p: new ArrayList JavaDoc<Project>(INSTANCE.openProjects)) {
169                 notifyOpened(p);
170             }
171             
172         }
173         
174         return INSTANCE;
175     }
176     
177     public void open( Project p ) {
178         open( new Project[] {p}, false );
179     }
180
181     public void open (Project p, boolean openSubprojects ) {
182         open( new Project[] {p}, openSubprojects );
183     }
184
185     public void open( Project[] projects, boolean openSubprojects ) {
186     open(projects, openSubprojects, false);
187     }
188     
189     public void open(final Project[] projects, final boolean openSubprojects, final boolean asynchronously ) {
190         if (projects.length == 0) {
191             //nothing to do:
192
return ;
193         }
194         
195         long start = System.currentTimeMillis();
196         
197     if (asynchronously) {
198             if (!EventQueue.isDispatchThread()) { // #89935
199
EventQueue.invokeLater(new Runnable JavaDoc() {
200                     public void run() {
201                         open(projects, openSubprojects, asynchronously);
202                     }
203                 });
204                 return;
205             }
206         final ProgressHandle handle = ProgressHandleFactory.createHandle(NbBundle.getMessage(OpenProjectList.class, "CAP_Opening_Projects"));
207         final Frame JavaDoc mainWindow = WindowManager.getDefault().getMainWindow();
208         final JDialog JavaDoc dialog = new JDialog JavaDoc(mainWindow, NbBundle.getMessage(OpenProjectList.class, "LBL_Opening_Projects_Progress"), true);
209             final OpeningProjectPanel panel = new OpeningProjectPanel(handle);
210             
211         dialog.getContentPane().add(panel);
212         dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); //make sure the dialog is not closed during the project open
213
dialog.pack();
214         
215         Rectangle JavaDoc bounds = mainWindow.getBounds();
216         
217         int middleX = bounds.x + bounds.width / 2;
218         int middleY = bounds.y + bounds.height / 2;
219         
220         Dimension JavaDoc size = dialog.getPreferredSize();
221         
222         dialog.setBounds(middleX - size.width / 2, middleY - size.height / 2, size.width, size.height);
223         
224         OPENING_RP.post(new Runnable JavaDoc() {
225         public void run() {
226             try {
227             doOpen(projects, openSubprojects, handle, panel);
228             } finally {
229             SwingUtilities.invokeLater(new Runnable JavaDoc() {
230                 public void run() {
231                                 //fix for #67114:
232
try {
233                                     Thread.currentThread().sleep(50);
234                                 } catch (InterruptedException JavaDoc e) {
235                                     // ignored
236
}
237                                 dialog.setVisible(false);
238                                 dialog.dispose();
239                 }
240             });
241             }
242         }
243         });
244         
245         dialog.setVisible(true);
246     } else {
247         doOpen(projects, openSubprojects, null, null);
248     }
249         
250         long end = System.currentTimeMillis();
251         
252         if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
253             ERR.log(ErrorManager.INFORMATIONAL, "opening projects took: " + (end - start) + "ms");
254         }
255     }
256     
257     private void doOpen(Project[] projects, boolean openSubprojects, ProgressHandle handle, OpeningProjectPanel panel) {
258         assert !Arrays.asList(projects).contains(null) : "Projects can't be null";
259             
260         boolean recentProjectsChanged = false;
261         int maxWork = 1000;
262         int workForSubprojects = maxWork / 2;
263         double currentWork = 0;
264         Collection JavaDoc<Project> projectsToOpen = new LinkedHashSet JavaDoc<Project>();
265         
266     if (handle != null) {
267         handle.start(maxWork);
268         handle.progress(0);
269     }
270         
271         if (panel != null) {
272             assert projects.length > 0 : "at least one project to open";
273             
274             panel.setProjectName(ProjectUtils.getInformation(projects[0]).getDisplayName());
275         }
276         
277         Map JavaDoc<Project,Set JavaDoc<? extends Project>> subprojectsCache = new HashMap JavaDoc<Project,Set JavaDoc<? extends Project>>(); // #59098
278

279         List JavaDoc<Project> toHandle = new LinkedList JavaDoc<Project>(Arrays.asList(projects));
280         
281         while (!toHandle.isEmpty()) {
282             Project p = toHandle.remove(0);
283             Set JavaDoc<? extends Project> subprojects = openSubprojects ? subprojectsCache.get(p) : Collections.<Project>emptySet();
284             
285             if (subprojects == null) {
286                 SubprojectProvider spp = p.getLookup().lookup(SubprojectProvider.class);
287                 if (spp != null) {
288                     subprojects = spp.getSubprojects();
289                 } else {
290                     subprojects = Collections.emptySet();
291                 }
292                 subprojectsCache.put(p, subprojects);
293             }
294             
295             projectsToOpen.add(p);
296             
297             for (Project sub : subprojects) {
298                 if (!projectsToOpen.contains(sub) && !toHandle.contains(sub)) {
299                     toHandle.add(sub);
300                 }
301             }
302             
303             double workPerOneProject = (workForSubprojects - currentWork) / (toHandle.size() + 1);
304             int lastState = (int) currentWork;
305             
306             currentWork += workPerOneProject;
307             
308             if (handle != null && lastState < (int) currentWork) {
309                 handle.progress((int) currentWork);
310             }
311         }
312         
313         double workPerProject = (maxWork - workForSubprojects) / projectsToOpen.size();
314         
315         for (Project p: projectsToOpen) {
316             
317             if (panel != null) {
318                 panel.setProjectName(ProjectUtils.getInformation(p).getDisplayName());
319             }
320             
321             recentProjectsChanged |= doOpenProject(p);
322             
323             int lastState = (int) currentWork;
324             
325             currentWork += workPerProject;
326             
327             if (handle != null && lastState < (int) currentWork) {
328                 handle.progress((int) currentWork);
329             }
330         }
331         
332         synchronized ( this ) {
333             saveProjectList( openProjects );
334             if ( recentProjectsChanged ) {
335                 recentProjects.save();
336             }
337         }
338         
339     if (handle != null) {
340         handle.finish();
341     }
342         
343         final boolean recentProjectsChangedCopy = recentProjectsChanged;
344         
345         Mutex.EVENT.readAccess(new Action<Void JavaDoc>() {
346             public Void JavaDoc run() {
347                 pchSupport.firePropertyChange( PROPERTY_OPEN_PROJECTS, null, null );
348                 if ( recentProjectsChangedCopy ) {
349                     pchSupport.firePropertyChange( PROPERTY_RECENT_PROJECTS, null, null );
350                 }
351                 
352                 return null;
353             }
354         });
355     }
356        
357     public void close( Project projects[], boolean notifyUI ) {
358         if (!ProjectUtilities.closeAllDocuments (projects, notifyUI )) {
359             return;
360         }
361         
362         boolean mainClosed = false;
363         boolean someClosed = false;
364         synchronized ( this ) {
365             for( int i = 0; i < projects.length; i++ ) {
366                 if ( !openProjects.contains( projects[i] ) ) {
367                     continue; // Nothing to remove
368
}
369                 if ( !mainClosed ) {
370                     mainClosed = isMainProject( projects[i] );
371                 }
372                 openProjects.remove( projects[i] );
373                 removeModuleInfo(projects[i]);
374                 
375                 projects[i].getProjectDirectory().removeFileChangeListener(deleteListener);
376                 
377                 recentProjects.add( projects[i] );
378                 notifyClosed( projects[i] );
379                 someClosed = true;
380             }
381             if ( someClosed ) {
382                 saveProjectList( openProjects );
383             }
384             if ( mainClosed ) {
385                 this.mainProject = null;
386                 saveMainProject( mainProject );
387             }
388             if ( someClosed ) {
389                 recentProjects.save();
390             }
391         }
392         if ( someClosed ) {
393             pchSupport.firePropertyChange( PROPERTY_OPEN_PROJECTS, null, null );
394         }
395         if ( mainClosed ) {
396             pchSupport.firePropertyChange( PROPERTY_MAIN_PROJECT, null, null );
397         }
398         if ( someClosed ) {
399             pchSupport.firePropertyChange( PROPERTY_RECENT_PROJECTS, null, null );
400         }
401         // Noticed in #72006: save them, in case e.g. editor stored bookmarks when receiving PROPERTY_OPEN_PROJECTS.
402
for (int i = 0; i < projects.length; i++) {
403             try {
404                 ProjectManager.getDefault().saveProject(projects[i]);
405             } catch (IOException JavaDoc e) {
406                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
407             }
408         }
409     }
410         
411     public synchronized Project[] getOpenProjects() {
412         Project projects[] = new Project[ openProjects.size() ];
413         openProjects.toArray( projects );
414         return projects;
415     }
416     
417     public synchronized boolean isOpen( Project p ) {
418         // XXX shouldn't this just use openProjects.contains(p)?
419
for( Iterator JavaDoc it = openProjects.iterator(); it.hasNext(); ) {
420             Project cp = (Project)it.next();
421             if ( p.getProjectDirectory().equals( cp.getProjectDirectory() ) ) {
422                 return true;
423             }
424         }
425         return false;
426     }
427
428     public synchronized boolean isMainProject( Project p ) {
429
430         if ( mainProject != null && p != null &&
431              mainProject.getProjectDirectory().equals( p.getProjectDirectory() ) ) {
432             return true;
433         }
434         else {
435             return false;
436         }
437         
438     }
439     
440     public synchronized Project getMainProject() {
441         return mainProject;
442     }
443     
444     public void setMainProject( Project mainProject ) {
445         synchronized ( this ) {
446             if (mainProject != null && !openProjects.contains(mainProject)) {
447                 throw new IllegalArgumentException JavaDoc("Project " + ProjectUtils.getInformation(mainProject).getDisplayName() + " is not open and cannot be set as main.");
448             }
449         
450             this.mainProject = mainProject;
451             saveMainProject( mainProject );
452         }
453         pchSupport.firePropertyChange( PROPERTY_MAIN_PROJECT, null, null );
454     }
455     
456     public synchronized List JavaDoc/*<Project>*/ getRecentProjects() {
457         return recentProjects.getProjects();
458     }
459     
460     public synchronized boolean isRecentProjectsEmpty() {
461         return recentProjects.isEmpty();
462     }
463     
464     public synchronized List JavaDoc/*<UnloadedProjectInformation>*/ getRecentProjectsInformation() {
465         return recentProjects.getRecentProjectsInfo();
466     }
467     
468     /** As this class is singletnon, which is not GCed it is good idea to
469      *add WeakListeners or remove the listeners properly.
470      */

471     
472     public void addPropertyChangeListener( PropertyChangeListener JavaDoc l ) {
473         pchSupport.addPropertyChangeListener( l );
474     }
475     
476     public void removePropertyChangeListener( PropertyChangeListener JavaDoc l ) {
477         pchSupport.removePropertyChangeListener( l );
478     }
479
480                
481     // Used from NewFile action
482
public List JavaDoc<DataObject> getTemplatesLRU( Project project ) {
483         List JavaDoc<FileObject> pLRU = getTemplateNamesLRU( project );
484         List JavaDoc<DataObject> templates = new ArrayList JavaDoc<DataObject>();
485         FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
486         for( Iterator JavaDoc<FileObject> it = pLRU.iterator(); it.hasNext(); ) {
487             FileObject fo = it.next();
488             if ( fo != null ) {
489                 try {
490                     DataObject dobj = DataObject.find( fo );
491                     templates.add( dobj );
492                 }
493                 catch ( DataObjectNotFoundException e ) {
494                     it.remove();
495                     org.openide.ErrorManager.getDefault().notify( org.openide.ErrorManager.INFORMATIONAL, e );
496                 }
497             }
498             else {
499                 it.remove();
500             }
501         }
502         
503         return templates;
504     }
505         
506     
507     // Used from NewFile action
508
public void updateTemplatesLRU( FileObject template ) {
509         
510         String JavaDoc templateName = template.getPath();
511         
512         if ( recentTemplates.contains( templateName ) ) {
513             recentTemplates.remove( templateName );
514         }
515         recentTemplates.add( 0, templateName );
516         
517         if ( recentTemplates.size() > 100 ) {
518             recentTemplates.remove( 100 );
519         }
520         
521         OpenProjectListSettings.getInstance().setRecentTemplates( new ArrayList JavaDoc<String JavaDoc>( recentTemplates ) );
522     }
523     
524     
525     // Package private methods -------------------------------------------------
526

527     // Used from ProjectUiModule
528
static void shutdown() {
529         if (INSTANCE != null) {
530             Iterator JavaDoc it = INSTANCE.openProjects.iterator();
531             while (it.hasNext()) {
532                 Project p = (Project)it.next();
533                 notifyClosed(p);
534             }
535         }
536     }
537         
538     // Used from OpenProjectAction
539
public static Project fileToProject( File JavaDoc projectDir ) {
540         
541         try {
542             
543             FileObject fo = FileUtil.toFileObject(projectDir);
544             if (fo != null && /* #60518 */ fo.isFolder()) {
545                 return ProjectManager.getDefault().findProject(fo);
546             } else {
547                 return null;
548             }
549                         
550         }
551         catch ( IOException JavaDoc e ) {
552             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
553             return null;
554         }
555         
556     }
557     
558     
559     
560     // Private methods ---------------------------------------------------------
561

562     private static List JavaDoc<Project> URLs2Projects( Collection JavaDoc<URL JavaDoc> URLs ) {
563         ArrayList JavaDoc<Project> result = new ArrayList JavaDoc<Project>( URLs.size() );
564             
565         for(URL JavaDoc url: URLs) {
566             FileObject dir = URLMapper.findFileObject( url );
567             if ( dir != null && dir.isFolder() ) {
568                 try {
569                     Project p = ProjectManager.getDefault().findProject( dir );
570                     if ( p != null ) {
571                         result.add( p );
572                     }
573                 }
574                 catch ( Throwable JavaDoc t ) {
575                     //something bad happened during loading the project.
576
//log the problem, but allow the other projects to be load
577
//see issue #65900
578
if (t instanceof ThreadDeath JavaDoc) {
579                         throw (ThreadDeath JavaDoc) t;
580                     }
581                     
582                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
583                 }
584             }
585         }
586         
587         return result;
588     }
589     
590     private static List JavaDoc<URL JavaDoc> projects2URLs( Collection JavaDoc<Project> projects ) {
591         ArrayList JavaDoc<URL JavaDoc> URLs = new ArrayList JavaDoc<URL JavaDoc>( projects.size() );
592         for(Project p: projects) {
593             try {
594                 URL JavaDoc root = p.getProjectDirectory().getURL();
595                 if ( root != null ) {
596                     URLs.add( root );
597                 }
598             }
599             catch( FileStateInvalidException e ) {
600                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
601             }
602         }
603         
604         return URLs;
605     }
606     
607     
608     private static void notifyOpened(Project p) {
609         for (Iterator JavaDoc i = p.getLookup().lookupAll(ProjectOpenedHook.class).iterator(); i.hasNext(); ) {
610             ProjectOpenedHook hook = (ProjectOpenedHook) i.next();
611             
612             try {
613                 ProjectOpenedTrampoline.DEFAULT.projectOpened(hook);
614             } catch (RuntimeException JavaDoc e) {
615                 ErrorManager.getDefault().notify(e);
616                 // Do not try to call its close hook if its open hook already failed:
617
INSTANCE.openProjects.remove(p);
618                 INSTANCE.removeModuleInfo(p);
619             } catch (Error JavaDoc e) {
620                 ErrorManager.getDefault().notify(e);
621                 INSTANCE.openProjects.remove(p);
622                 INSTANCE.removeModuleInfo(p);
623             }
624         }
625     }
626     
627     private static void notifyClosed(Project p) {
628         for (Iterator JavaDoc i = p.getLookup().lookupAll(ProjectOpenedHook.class).iterator(); i.hasNext(); ) {
629             ProjectOpenedHook hook = (ProjectOpenedHook) i.next();
630             
631             try {
632                 ProjectOpenedTrampoline.DEFAULT.projectClosed(hook);
633             } catch (RuntimeException JavaDoc e) {
634                 ErrorManager.getDefault().notify(e);
635             } catch (Error JavaDoc e) {
636                 ErrorManager.getDefault().notify(e);
637             }
638         }
639     }
640     
641     private boolean doOpenProject(final Project p) {
642         boolean recentProjectsChanged;
643         
644         synchronized (this) {
645             if (openProjects.contains(p)) {
646                 return false;
647             }
648             openProjects.add(p);
649             addModuleInfo(p);
650             
651             p.getProjectDirectory().addFileChangeListener(deleteListener);
652             recentProjectsChanged = recentProjects.remove(p);
653         }
654         
655         // Notify projects opened
656
notifyOpened(p);
657         
658         Mutex.EVENT.readAccess(new Action<Void JavaDoc>() {
659             public Void JavaDoc run() {
660                 // Open project files
661
ProjectUtilities.openProjectFiles(p);
662                 
663                 return null;
664             }
665         });
666         
667         return recentProjectsChanged;
668     }
669     
670     private static List JavaDoc<Project> loadProjectList() {
671         List JavaDoc<URL JavaDoc> URLs = OpenProjectListSettings.getInstance().getOpenProjectsURLs();
672         List JavaDoc<Project> projects = URLs2Projects( URLs );
673         return projects;
674     }
675     
676   
677     private static void saveProjectList( List JavaDoc<Project> projects ) {
678         List JavaDoc<URL JavaDoc> URLs = projects2URLs( projects );
679         OpenProjectListSettings.getInstance().setOpenProjectsURLs( URLs );
680     }
681     
682     private static void saveMainProject( Project mainProject ) {
683         try {
684             URL JavaDoc mainRoot = mainProject == null ? null : mainProject.getProjectDirectory().getURL();
685             OpenProjectListSettings.getInstance().setMainProjectURL( mainRoot );
686         }
687         catch ( FileStateInvalidException e ) {
688             OpenProjectListSettings.getInstance().setMainProjectURL( null );
689         }
690     }
691         
692     private ArrayList JavaDoc<FileObject> getTemplateNamesLRU( Project project ) {
693         // First take recently used templates and try to find those which
694
// are supported by the project.
695

696         ArrayList JavaDoc<FileObject> result = new ArrayList JavaDoc<FileObject>(NUM_TEMPLATES);
697         
698         RecommendedTemplates rt = project.getLookup().lookup( RecommendedTemplates.class );
699         String JavaDoc rtNames[] = rt == null ? new String JavaDoc[0] : rt.getRecommendedTypes();
700         PrivilegedTemplates pt = project.getLookup().lookup( PrivilegedTemplates.class );
701         String JavaDoc ptNames[] = pt == null ? null : pt.getPrivilegedTemplates();
702         ArrayList JavaDoc<String JavaDoc> privilegedTemplates = new ArrayList JavaDoc<String JavaDoc>( Arrays.asList( pt == null ? new String JavaDoc[0]: ptNames ) );
703         FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
704                 
705         Iterator JavaDoc<String JavaDoc> it = recentTemplates.iterator();
706         for( int i = 0; i < NUM_TEMPLATES && it.hasNext(); i++ ) {
707             String JavaDoc templateName = it.next();
708             FileObject fo = sfs.findResource( templateName );
709             if ( fo == null ) {
710                 it.remove(); // Does not exists remove
711
}
712             else if ( isRecommended( project, fo ) ) {
713                 result.add( fo );
714                 privilegedTemplates.remove( templateName ); // Not to have it twice
715
}
716             else {
717                 continue;
718             }
719         }
720         
721         // If necessary fill the list with the rest of privileged templates
722
it = privilegedTemplates.iterator();
723         for( int i = result.size(); i < NUM_TEMPLATES && it.hasNext(); i++ ) {
724             String JavaDoc path = it.next();
725             FileObject fo = sfs.findResource( path );
726             if ( fo != null ) {
727                 result.add( fo );
728             }
729         }
730                 
731         return result;
732                
733     }
734     
735     static boolean isRecommended (Project p, FileObject primaryFile) {
736         if (getRecommendedTypes (p) == null || getRecommendedTypes (p).length == 0) {
737             // if no recommendedTypes are supported (i.e. freeform) -> disaply all templates
738
return true;
739         }
740         
741         Object JavaDoc o = primaryFile.getAttribute ("templateCategory"); // NOI18N
742
if (o != null) {
743             assert o instanceof String JavaDoc : primaryFile + " attr templateCategory = " + o;
744             Iterator JavaDoc categoriesIt = getCategories ((String JavaDoc)o).iterator ();
745             boolean ok = false;
746             while (categoriesIt.hasNext ()) {
747                 String JavaDoc category = (String JavaDoc)categoriesIt.next ();
748                 if (Arrays.asList (getRecommendedTypes (p)).contains (category)) {
749                     ok = true;
750                     break;
751                 }
752             }
753             return ok;
754         } else {
755             // issue 43958, if attr 'templateCategorized' is not set => all is ok
756
// no category set, ok display it
757
return true;
758         }
759     }
760
761     private static String JavaDoc[] getRecommendedTypes (Project project) {
762         RecommendedTemplates rt = project.getLookup().lookup(RecommendedTemplates.class);
763         return rt == null ? null :rt.getRecommendedTypes();
764     }
765     
766     private static List JavaDoc<String JavaDoc> getCategories (String JavaDoc source) {
767         ArrayList JavaDoc<String JavaDoc> categories = new ArrayList JavaDoc<String JavaDoc> ();
768         StringTokenizer JavaDoc cattok = new StringTokenizer JavaDoc (source, ","); // NOI18N
769
while (cattok.hasMoreTokens ()) {
770             categories.add (cattok.nextToken ().trim ());
771         }
772         return categories;
773     }
774     
775     // Private innerclasses ----------------------------------------------------
776

777     /** Maintains recent project list
778      */

779     private static class RecentProjectList {
780        
781         private List JavaDoc<ProjectReference> recentProjects;
782         private List JavaDoc<UnloadedProjectInformation> recentProjectsInfos;
783         
784         private int size;
785         
786         /**
787          *@size Max number of the project list.
788          */

789         public RecentProjectList( int size ) {
790             this.size = size;
791             recentProjects = new ArrayList JavaDoc<ProjectReference>( size );
792             recentProjectsInfos = new ArrayList JavaDoc<UnloadedProjectInformation>(size);
793             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
794                 ERR.log("created a RecentProjectList: size=" + size);
795             }
796         }
797         
798         public void add( Project p ) {
799             int index = getIndex( p );
800             
801             if ( index == -1 ) {
802                 // Project not in list
803
if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
804                     ERR.log("add new recent project: " + p);
805                 }
806                 if ( recentProjects.size() == size ) {
807                     // Need some space for the newly added project
808
recentProjects.remove( size - 1 );
809                     recentProjectsInfos.remove(size - 1);
810                 }
811                 recentProjects.add( 0, new ProjectReference( p ) );
812                 try {
813                     recentProjectsInfos.add(0, ProjectInfoAccessor.DEFAULT.getProjectInfo(
814                         ProjectUtils.getInformation(p).getDisplayName(),
815                         ProjectUtils.getInformation(p).getIcon(),
816                         p.getProjectDirectory().getURL()));
817                 } catch(FileStateInvalidException ex) {
818                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
819                 }
820             }
821             else {
822                 if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
823                     ERR.log("re-add recent project: " + p);
824                 }
825                 // Project is in list => just move it to first place
826
recentProjects.remove( index );
827                 recentProjects.add( 0, new ProjectReference( p ) );
828                 recentProjectsInfos.remove(index);
829                 try {
830                     recentProjectsInfos.add(0, ProjectInfoAccessor.DEFAULT.getProjectInfo(
831                         ProjectUtils.getInformation(p).getDisplayName(),
832                         ProjectUtils.getInformation(p).getIcon(),
833                         p.getProjectDirectory().getURL()));
834                 } catch(FileStateInvalidException ex) {
835                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
836                 }
837             }
838         }
839         
840         public boolean remove( Project p ) {
841             int index = getIndex( p );
842             if ( index != -1 ) {
843                 if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
844                     ERR.log("remove recent project: " + p);
845                 }
846                 recentProjects.remove( index );
847                 recentProjectsInfos.remove(index);
848                 return true;
849             }
850             return false;
851         }
852         
853         
854         public List JavaDoc<Project> getProjects() {
855             List JavaDoc<Project> result = new ArrayList JavaDoc<Project>( recentProjects.size() );
856             // Copy the list
857
List JavaDoc<ProjectReference> references = new ArrayList JavaDoc<ProjectReference>( recentProjects );
858             for ( Iterator JavaDoc<ProjectReference> it = references.iterator(); it.hasNext(); ) {
859                 ProjectReference pRef = it.next();
860                 Project p = pRef.getProject();
861                 if ( p == null || !p.getProjectDirectory().isValid() ) {
862                     remove( p ); // Folder does not exist any more => remove from
863
if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
864                         ERR.log("removing dead recent project: " + p);
865                     }
866                 }
867                 else {
868                     result.add( p );
869                 }
870             }
871             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
872                 ERR.log("recent projects: " + result);
873             }
874             return result;
875         }
876         
877         
878         public boolean isEmpty() {
879             boolean empty = recentProjects.isEmpty();
880             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
881                 ERR.log("recent projects empty? " + empty);
882             }
883             return empty;
884         }
885         
886         public void load() {
887             List JavaDoc<URL JavaDoc> URLs = OpenProjectListSettings.getInstance().getRecentProjectsURLs();
888             List JavaDoc<String JavaDoc> names = OpenProjectListSettings.getInstance().getRecentProjectsDisplayNames();
889             List JavaDoc<ExtIcon> icons = OpenProjectListSettings.getInstance().getRecentProjectsIcons();
890             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
891                 ERR.log("recent project list load: " + URLs);
892             }
893             recentProjects.clear();
894             for ( Iterator JavaDoc it = URLs.iterator(); it.hasNext(); ) {
895                 recentProjects.add( new ProjectReference( (URL JavaDoc)it.next() ) );
896             }
897             recentProjectsInfos.clear();
898             for (Iterator JavaDoc iterNames = names.iterator(), iterURLs = URLs.iterator(), iterIcons = icons.iterator();
899                     (iterNames.hasNext() && iterURLs.hasNext() && iterIcons.hasNext()); ) {
900                 String JavaDoc name = (String JavaDoc) iterNames.next();
901                 URL JavaDoc url = (URL JavaDoc) iterURLs.next();
902                 Icon JavaDoc icon = ((ExtIcon) iterIcons.next()).getIcon();
903                 recentProjectsInfos.add(ProjectInfoAccessor.DEFAULT.getProjectInfo(name, icon, url));
904             }
905             // if following is true then there was either some problem with serialization
906
// or user started new IDE on userdir with only partial information saved - only URLs
907
// then both list should be cleared - recent project information will be lost
908
if (recentProjects.size() != recentProjectsInfos.size()) {
909                 recentProjects.clear();
910                 recentProjectsInfos.clear();
911             }
912         }
913         
914         public void save() {
915             List JavaDoc<URL JavaDoc> URLs = new ArrayList JavaDoc<URL JavaDoc>( recentProjects.size() );
916             for (ProjectReference pRef: recentProjects) {
917                 URL JavaDoc pURL = pRef.getURL();
918                 if ( pURL != null ) {
919                     URLs.add( pURL );
920                 }
921             }
922             if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
923                 ERR.log("recent project list save: " + URLs);
924             }
925             OpenProjectListSettings.getInstance().setRecentProjectsURLs( URLs );
926             int listSize = recentProjectsInfos.size();
927             List JavaDoc<String JavaDoc> names = new ArrayList JavaDoc<String JavaDoc>(listSize);
928             List JavaDoc<ExtIcon> icons = new ArrayList JavaDoc<ExtIcon>(listSize);
929             for (Iterator JavaDoc it = recentProjectsInfos.iterator(); it.hasNext(); ) {
930                 UnloadedProjectInformation prjInfo = (UnloadedProjectInformation) it.next();
931                 names.add(prjInfo.getDisplayName());
932                 ExtIcon extIcon = new ExtIcon();
933                 extIcon.setIcon(prjInfo.getIcon());
934                 icons.add(extIcon);
935             }
936             OpenProjectListSettings.getInstance().setRecentProjectsDisplayNames(names);
937             OpenProjectListSettings.getInstance().setRecentProjectsIcons(icons);
938         }
939         
940         private int getIndex( Project p ) {
941             
942             URL JavaDoc pURL;
943             try {
944                 if ( p == null || p.getProjectDirectory() == null ) {
945                     return -1;
946                 }
947                 pURL = p.getProjectDirectory().getURL();
948             }
949             catch( FileStateInvalidException e ) {
950                 return -1;
951             }
952             
953             int i = 0;
954             
955             for( Iterator JavaDoc it = recentProjects.iterator(); it.hasNext(); i++) {
956                 URL JavaDoc p2URL = ((ProjectReference)it.next()).getURL();
957                 if ( pURL.equals( p2URL ) ) {
958                     return i;
959                 }
960             }
961             
962             return -1;
963         }
964         
965         private List JavaDoc/*<UnloadedProjectInformation>*/ getRecentProjectsInfo() {
966             return recentProjectsInfos;
967         }
968         
969         private static class ProjectReference {
970             
971             private WeakReference JavaDoc<Project> projectReference;
972             private URL JavaDoc projectURL;
973             
974             public ProjectReference( URL JavaDoc url ) {
975                 this.projectURL = url;
976             }
977             
978             public ProjectReference( Project p ) {
979                 this.projectReference = new WeakReference JavaDoc<Project>( p );
980                 try {
981                     projectURL = p.getProjectDirectory().getURL();
982                 }
983                 catch( FileStateInvalidException e ) {
984                     if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
985                         ERR.log("FSIE getting URL for project: " + p.getProjectDirectory());
986                     }
987                 }
988             }
989             
990             public Project getProject() {
991                 
992                 Project p = null;
993                 
994                 if ( projectReference != null ) { // Reference to project exists
995
p = projectReference.get();
996                     if ( p != null ) {
997                         // And refers to some project, check for validity:
998
if ( ProjectManager.getDefault().isValid( p ) )
999                             return p;
1000                        else
1001                            return null;
1002                    }
1003                }
1004                
1005                if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
1006                    ERR.log("no active project reference for " + projectURL);
1007                }
1008                if ( projectURL != null ) {
1009                    FileObject dir = URLMapper.findFileObject( projectURL );
1010                    if ( dir != null && dir.isFolder() ) {
1011                        try {
1012                            p = ProjectManager.getDefault().findProject( dir );
1013                            if ( p != null ) {
1014                                projectReference = new WeakReference JavaDoc<Project>( p );
1015                                if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
1016                                    ERR.log("found " + p);
1017                                }
1018                                return p;
1019                            }
1020                        }
1021                        catch ( IOException JavaDoc e ) {
1022                            // Ignore invalid folders
1023
if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
1024                                ERR.log("could not load recent project from " + projectURL);
1025                            }
1026                        }
1027                    }
1028                }
1029                
1030                if (ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
1031                    ERR.log("no recent project in " + projectURL);
1032                }
1033                return null; // Empty reference
1034
}
1035            
1036            public URL JavaDoc getURL() {
1037                return projectURL;
1038            }
1039            
1040        }
1041        
1042    }
1043    
1044    public static class ProjectByDisplayNameComparator implements Comparator JavaDoc<Project> {
1045        
1046    private static Comparator JavaDoc<Object JavaDoc> COLLATOR = Collator.getInstance();
1047        
1048        public int compare(Project p1, Project p2) {
1049// Uncoment to make the main project be the first one
1050
// but then needs to listen to main project change
1051
// if ( OpenProjectList.getDefault().isMainProject( p1 ) ) {
1052
// return -1;
1053
// }
1054
//
1055
// if ( OpenProjectList.getDefault().isMainProject( p2 ) ) {
1056
// return 1;
1057
// }
1058

1059            String JavaDoc n1 = ProjectUtils.getInformation(p1).getDisplayName();
1060            String JavaDoc n2 = ProjectUtils.getInformation(p2).getDisplayName();
1061            if (n1 != null && n2 != null) {
1062                return COLLATOR.compare(n1, n2);
1063            } else if (n1 == null && n2 != null) {
1064                ERR.log(ErrorManager.WARNING, p1 + ": ProjectInformation.getDisplayName() should not return null!");
1065                return -1;
1066            } else if (n1 != null && n2 == null) {
1067                ERR.log(ErrorManager.WARNING, p2 + ": ProjectInformation.getDisplayName() should not return null!");
1068                return 1;
1069            }
1070            return 0; // both null
1071

1072        }
1073        
1074    }
1075    
1076    /**
1077     * Closesdeleted projects.
1078     */

1079    private final class ProjectDeletionListener extends FileChangeAdapter {
1080        
1081        public ProjectDeletionListener() {}
1082
1083        public void fileDeleted(FileEvent fe) {
1084            synchronized (OpenProjectList.this) {
1085                Project toRemove = null;
1086                for (Project prj : openProjects) {
1087                    if (fe.getFile().equals(prj.getProjectDirectory())) {
1088                        toRemove = prj;
1089                        break;
1090                    }
1091                }
1092                if (toRemove != null) {
1093                    close(new Project[] {toRemove}, false);
1094                }
1095            }
1096        }
1097        
1098    }
1099    
1100    
1101    private static ModuleInfo findModuleForProject(Project prj) {
1102        Collection JavaDoc<? extends ModuleInfo> instances = Lookup.getDefault().lookupAll(ModuleInfo.class);
1103        ModuleInfo info = null;
1104        for (ModuleInfo cur : instances) {
1105            if (!cur.isEnabled()) {
1106                continue;
1107            }
1108            if (cur.getClassLoader() == prj.getClass().getClassLoader()) {
1109                info = cur;
1110                break;
1111            }
1112        }
1113        return info;
1114    }
1115    
1116    private void addModuleInfo(Project prj) {
1117        ModuleInfo info = findModuleForProject(prj);
1118        if (info != null) {
1119            // is null in tests..
1120
if (!openProjectsModuleInfos.containsKey(info)) {
1121                openProjectsModuleInfos.put(info, new ArrayList JavaDoc<Project>());
1122                info.addPropertyChangeListener(infoListener);
1123            }
1124            openProjectsModuleInfos.get(info).add(prj);
1125        }
1126    }
1127    
1128    private void removeModuleInfo(Project prj) {
1129        ModuleInfo info = findModuleForProject(prj);
1130        removeModuleInfo(prj, info);
1131    }
1132    
1133    private void removeModuleInfo(Project prj, ModuleInfo info) {
1134        // info can be null in case we are closing a project from disabled module
1135
if (info != null) {
1136            openProjectsModuleInfos.get(info).remove(prj);
1137            if (openProjectsModuleInfos.get(info).size() == 0) {
1138                info.removePropertyChangeListener(infoListener);
1139                openProjectsModuleInfos.remove(info);
1140            }
1141        }
1142    }
1143
1144    private void checkModuleInfo(ModuleInfo info) {
1145        if (info.isEnabled()) {
1146            return;
1147        }
1148        Collection JavaDoc<Project> toRemove = new ArrayList JavaDoc<Project>(openProjectsModuleInfos.get(info));
1149        if (toRemove != null && toRemove.size() > 0) {
1150            for (Project prj : toRemove) {
1151                removeModuleInfo(prj, info);
1152            }
1153            close(toRemove.toArray(new Project[toRemove.size()]), false);
1154        }
1155    }
1156    
1157}
Popular Tags