KickJava   Java API By Example, From Geeks To Geeks.

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


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.Component JavaDoc;
23 import java.awt.Cursor JavaDoc;
24 import java.awt.event.ActionEvent JavaDoc;
25 import java.io.File JavaDoc;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.Set JavaDoc;
34 import java.util.SortedSet JavaDoc;
35 import java.util.TreeSet JavaDoc;
36 import javax.swing.Action JavaDoc;
37 import javax.swing.JFrame JavaDoc;
38 import javax.swing.SwingUtilities JavaDoc;
39 import org.netbeans.api.project.FileOwnerQuery;
40 import org.netbeans.api.project.Project;
41 import org.netbeans.api.project.ProjectUtils;
42 import org.netbeans.spi.project.AuxiliaryConfiguration;
43 import org.openide.ErrorManager;
44 import org.openide.cookies.EditCookie;
45 import org.openide.cookies.OpenCookie;
46 import org.openide.explorer.ExplorerManager;
47 import org.openide.filesystems.FileObject;
48 import org.openide.filesystems.FileStateInvalidException;
49 import org.openide.filesystems.URLMapper;
50 import org.openide.loaders.DataObject;
51 import org.openide.loaders.DataObjectNotFoundException;
52 import org.openide.nodes.Node;
53 import org.openide.util.ContextAwareAction;
54 import org.openide.util.Mutex;
55 import org.openide.util.NbBundle;
56 import org.openide.windows.CloneableTopComponent;
57 import org.openide.windows.TopComponent;
58 import org.openide.windows.WindowManager;
59 import org.openide.xml.XMLUtil;
60 import org.w3c.dom.Document JavaDoc;
61 import org.w3c.dom.Element JavaDoc;
62 import org.w3c.dom.NodeList JavaDoc;
63
64 /** The util methods for projectui module.
65  *
66  * @author Jiri Rechtacek
67  */

68 public class ProjectUtilities {
69     
70     static final String JavaDoc OPEN_FILES_NS = "http://www.netbeans.org/ns/projectui-open-files/1"; // NOI18N
71
static final String JavaDoc OPEN_FILES_ELEMENT = "open-files"; // NOI18N
72
static final String JavaDoc FILE_ELEMENT = "file"; // NOI18N
73

74     // support class for xtesting in OpenProjectListTest
75
static OpenCloseProjectDocument OPEN_CLOSE_PROJECT_DOCUMENT_IMPL = new OpenCloseProjectDocument () {
76         public boolean open (FileObject fo) {
77             DataObject dobj;
78             try {
79                 dobj = DataObject.find (fo);
80             } catch (DataObjectNotFoundException donfo) {
81                 assert false : "DataObject must exist for " + fo;
82                 return false;
83             }
84             EditCookie ec = dobj.getCookie(EditCookie.class);
85             OpenCookie oc = dobj.getCookie(OpenCookie.class);
86             if (ec != null) {
87                 ec.edit();
88             } else if (oc != null) {
89                 oc.open();
90             } else {
91                 if (ERR.isLoggable (ErrorManager.INFORMATIONAL)) ERR.log ("No EditCookie nor OpenCookie for " + dobj);
92                 return false;
93             }
94             return true;
95         }
96         
97         public Map JavaDoc<Project,SortedSet JavaDoc<String JavaDoc>> close(final Project[] projects,
98                                                     final boolean notifyUI) {
99             final Wrapper wr = new Wrapper();
100
101             wr.urls4project = new HashMap JavaDoc<Project,SortedSet JavaDoc<String JavaDoc>>();
102             if (SwingUtilities.isEventDispatchThread()) {
103                 doClose(projects, notifyUI, wr);
104             } else {
105                 try {
106                     SwingUtilities.invokeAndWait(new Runnable JavaDoc() {
107                          public void run() {
108                              doClose(projects, notifyUI, wr);
109                          }
110                      });
111                 }
112                 catch (Exception JavaDoc ex) {
113                     ERR.notify(ErrorManager.INFORMATIONAL, ex);
114                 }
115             }
116             return wr.urls4project;
117         }
118
119         private void doClose(Project[] projects, boolean notifyUI, Wrapper wr) {
120             List JavaDoc<Project> listOfProjects = Arrays.asList(projects);
121             Set JavaDoc<DataObject> openFiles = new HashSet JavaDoc<DataObject>();
122             final Set JavaDoc<TopComponent> tc2close = new HashSet JavaDoc<TopComponent>();
123             for (TopComponent tc : WindowManager.getDefault().getRegistry().getOpened()) {
124                 //#84546 - this condituon should allow us to close just editor related TCs that are in any imaginable mode.
125
if (! (tc instanceof CloneableTopComponent)) {
126                     continue;
127                 }
128                 // #57621: check if the closed top component isn't instance of ExplorerManager.Provider e.g. Projects/Files tab, if yes then do skip this loop
129
if (tc instanceof ExplorerManager.Provider) {
130                     continue;
131                 }
132                 DataObject dobj = tc.getLookup().lookup(DataObject.class);
133
134                 if (dobj != null) {
135                     FileObject fobj = dobj.getPrimaryFile();
136                     Project owner = FileOwnerQuery.getOwner(fobj);
137
138                     if (listOfProjects.contains(owner)) {
139                         if (notifyUI) {
140                             openFiles.add(dobj);
141                             tc2close.add(tc);
142                         } else if (!dobj.isModified()) {
143                             // when not called from UI, only include TCs that arenot modified
144
tc2close.add(tc);
145                         }
146                         if (!wr.urls4project.containsKey(owner)) {
147                             // add project
148
wr.urls4project.put(owner, new TreeSet JavaDoc<String JavaDoc>());
149                         }
150                         URL JavaDoc url = null;
151
152                         try {
153                             url = dobj.getPrimaryFile().getURL();
154                             wr.urls4project.get(owner).add(url.toExternalForm());
155                         }
156                         catch (FileStateInvalidException fsie) {
157                             assert false : "FileStateInvalidException in " +
158                                            dobj.getPrimaryFile();
159                         }
160                     }
161                 }
162             }
163             if (notifyUI) {
164                 for (DataObject dobj : DataObject.getRegistry().getModifiedSet()) {
165                     FileObject fobj = dobj.getPrimaryFile();
166                     Project owner = FileOwnerQuery.getOwner(fobj);
167
168                     if (listOfProjects.contains(owner) &&
169                         !openFiles.contains(dobj)) {
170                         openFiles.add(dobj);
171                     }
172                 }
173             }
174             if (!notifyUI ||
175                 (!openFiles.isEmpty() && ExitDialog.showDialog(openFiles))) {
176                 // close documents
177
for (TopComponent tc : tc2close) {
178                     tc.close();
179                 }
180             } else {
181                 // signal that close was vetoed
182
if (!openFiles.isEmpty()) {
183                     wr.urls4project = null;
184                 }
185             }
186         }
187     };
188     
189     private static class Wrapper {
190         Map JavaDoc<Project,SortedSet JavaDoc<String JavaDoc>> urls4project;
191     }
192     
193     private static final ErrorManager ERR = ErrorManager.getDefault().getInstance(ProjectUtilities.class.getName());
194     
195     private ProjectUtilities() {}
196     
197     public static void selectAndExpandProject( final Project p ) {
198         
199         // invoke later to select the being opened project if the focus is outside ProjectTab
200
SwingUtilities.invokeLater (new Runnable JavaDoc () {
201             
202             final ProjectTab ptLogial = ProjectTab.findDefault(ProjectTab.ID_LOGICAL);
203             
204             public void run () {
205                 Node root = ptLogial.getExplorerManager ().getRootContext ();
206                 // Node projNode = root.getChildren ().findChild( p.getProjectDirectory().getName () );
207
Node projNode = null;
208                 for (Node n : root.getChildren().getNodes()) {
209                     Project prj = n.getLookup().lookup(Project.class);
210                     if (prj != null && prj.getProjectDirectory().equals(p.getProjectDirectory())) {
211                         projNode = n;
212                         break;
213                     }
214                 }
215                 if (projNode == null) {
216                     // fallback..
217
projNode = root.getChildren ().findChild( ProjectUtils.getInformation( p ).getName() );
218                 }
219                 
220                 if ( projNode != null ) {
221                     try {
222                         ptLogial.getExplorerManager ().setSelectedNodes( new Node[] { projNode } );
223                         ptLogial.expandNode( projNode );
224                         // ptLogial.open ();
225
// ptLogial.requestActive ();
226
} catch (Exception JavaDoc ignore) {
227                         // may ignore it
228
}
229                 }
230             }
231         });
232         
233     }
234     
235     /** Invokes the preferred action on given object and tries to select it in
236      * corresponding view, e.g. in logical view if possible otherwise
237      * in physical project's view.
238      * Note: execution this methods can invokes new threads to assure the action
239      * is called in EQ.
240      *
241      * @param newDo new data object
242      */

243     public static void openAndSelectNewObject (final DataObject newDo) {
244         // call the preferred action on main class
245
Mutex.EVENT.writeAccess (new Runnable JavaDoc () {
246             public void run () {
247                 final Node node = newDo.getNodeDelegate ();
248                 Action JavaDoc a = node.getPreferredAction();
249                 if (a instanceof ContextAwareAction) {
250                     a = ((ContextAwareAction) a).createContextAwareInstance(node.getLookup ());
251                 }
252                 if (a != null) {
253                     a.actionPerformed(new ActionEvent JavaDoc(node, ActionEvent.ACTION_PERFORMED, "")); // NOI18N
254
}
255
256                 // next action -> expand && select main class in package view
257
final ProjectTab ptLogical = ProjectTab.findDefault(ProjectTab.ID_LOGICAL);
258                 final ProjectTab ptPhysical = ProjectTab.findDefault(ProjectTab.ID_PHYSICAL);
259                 // invoke later, Mutex.EVENT.writeAccess isn't suffice to
260
// select && expand if the focus is outside ProjectTab
261
SwingUtilities.invokeLater (new Runnable JavaDoc () {
262                     public void run () {
263                         boolean success = ptLogical.selectNode (newDo.getPrimaryFile ());
264                         if (!success) {
265                             ptPhysical.selectNode (newDo.getPrimaryFile ());
266                         }
267                     }
268                 });
269             }
270         });
271     }
272     
273     /** Makes the project tab visible
274      * @param requestFocus if set to true the project tab will not only become visible but also
275      * will gain focus
276      */

277     public static void makeProjectTabVisible( final boolean requestFocus ) {
278         final ProjectTab ptLogical = ProjectTab.findDefault (ProjectTab.ID_LOGICAL);
279         
280 // SwingUtilities.invokeLater (new Runnable () {
281
// public void run () {
282
ptLogical.open();
283                 if ( requestFocus ) {
284                     ptLogical.requestActive();
285                 }
286                 else {
287                     ptLogical.requestVisible();
288                 }
289 // }
290
// });
291

292     }
293     
294     
295     /** Checks if the given file name can be created in the target folder.
296      *
297      * @param targetFolder target folder (e.g. source group)
298      * @param folderName name of the folder relative to target folder (null or /-separated)
299      * @param newObjectName name of created file
300      * @param extension extension of created file
301      * @param allowFileSeparator if '/' (and possibly other file separator, see {@link FileUtil#createFolder FileUtil#createFolder})
302      * is allowed in the newObjectName
303      * @return localized error message or null if all right
304      */

305     public static String JavaDoc canUseFileName (FileObject targetFolder, String JavaDoc folderName, String JavaDoc newObjectName, String JavaDoc extension, boolean allowFileSeparator) {
306         assert newObjectName != null; // SimpleTargetChooserPanel.isValid returns false if it is... XXX should it use an error label instead?
307

308         boolean allowSlash = false;
309         boolean allowBackslash = false;
310         int errorVariant = 0;
311         
312         if (allowFileSeparator) {
313             if (File.separatorChar == '\\') {
314                 errorVariant = 3;
315                 allowSlash = allowBackslash = true;
316             } else {
317                 errorVariant = 1;
318                 allowSlash = true;
319             }
320         }
321         
322         if ((!allowSlash && newObjectName.indexOf('/') != -1) || (!allowBackslash && newObjectName.indexOf('\\') != -1)) {
323             //if errorVariant == 3, the test above should never be true:
324
assert errorVariant == 0 || errorVariant == 1 : "Invalid error variant: " + errorVariant;
325             
326             return NbBundle.getMessage(ProjectUtilities.class, "MSG_not_valid_filename", newObjectName, new Integer JavaDoc(errorVariant));
327         }
328         
329         // test whether the selected folder on selected filesystem already exists
330
if (targetFolder == null) {
331             return NbBundle.getMessage (ProjectUtilities.class, "MSG_fs_or_folder_does_not_exist"); // NOI18N
332
}
333         
334         // target filesystem should be writable
335
if (!targetFolder.canWrite ()) {
336             return NbBundle.getMessage (ProjectUtilities.class, "MSG_fs_is_readonly"); // NOI18N
337
}
338
339         // file should not already exist
340
StringBuffer JavaDoc relFileName = new StringBuffer JavaDoc();
341         if (folderName != null) {
342             if (!allowBackslash && folderName.indexOf('\\') != -1) {
343                 return NbBundle.getMessage(ProjectUtilities.class, "MSG_not_valid_folder", folderName, new Integer JavaDoc(1));
344             }
345             relFileName.append(folderName);
346             relFileName.append('/');
347         }
348         relFileName.append(newObjectName);
349         if (extension != null && extension.length() != 0) {
350             relFileName.append('.');
351             relFileName.append(extension);
352         }
353         if (targetFolder.getFileObject(relFileName.toString()) != null) {
354             return NbBundle.getMessage (ProjectUtilities.class, "MSG_file_already_exist", newObjectName); // NOI18N
355
}
356         
357         // all ok
358
return null;
359     }
360     
361     
362     public static class WaitCursor implements Runnable JavaDoc {
363         
364         private boolean show;
365         
366         private WaitCursor( boolean show ) {
367             this.show = show;
368         }
369        
370         public static void show() {
371             invoke( new WaitCursor( true ) );
372         }
373         
374         public static void hide() {
375             invoke( new WaitCursor( false ) );
376         }
377         
378         private static void invoke( WaitCursor wc ) {
379             if ( SwingUtilities.isEventDispatchThread() ) {
380                 wc.run();
381             }
382             else {
383                 SwingUtilities.invokeLater( wc );
384             }
385         }
386         
387         public void run() {
388             try {
389                 JFrame JavaDoc f = (JFrame JavaDoc)WindowManager.getDefault ().getMainWindow ();
390                 Component JavaDoc c = f.getGlassPane ();
391                 c.setVisible ( show );
392                 c.setCursor (show ? Cursor.getPredefinedCursor (Cursor.WAIT_CURSOR) : null);
393             }
394             catch (NullPointerException JavaDoc npe) {
395                 ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, npe);
396             }
397         }
398     }
399     
400     /** Closes all documents in editor area which are owned by one of given projects.
401      * If some documents are modified then an user is notified by Save/Discard/Cancel dialog.
402      * Dialog is showed only once for all project's documents together.
403      * URLs of closed documents are stored to <code>private.xml</code>.
404      *
405      * @param p project to close
406      * @return false if the user cancelled the Save/Discard/Cancel dialog, true otherwise
407      */

408     public static boolean closeAllDocuments(Project[] projects, boolean notifyUI) {
409         if (projects == null) {
410             throw new IllegalArgumentException JavaDoc ("No projects are specified."); // NOI18N
411
}
412         
413         if (projects.length == 0) {
414             // no projects to close, no documents will be closed
415
return true;
416         }
417         
418         Map JavaDoc<Project,SortedSet JavaDoc<String JavaDoc>> urls4project = OPEN_CLOSE_PROJECT_DOCUMENT_IMPL.close(projects, notifyUI);
419
420         if (urls4project != null) {
421             // store project's documents
422
// loop all project being closed
423
for (Map.Entry JavaDoc<Project,SortedSet JavaDoc<String JavaDoc>> entry : urls4project.entrySet()) {
424                 storeProjectOpenFiles(entry.getKey(), entry.getValue());
425             }
426         }
427         
428         return urls4project != null;
429     }
430     
431     static private void storeProjectOpenFiles (Project p, SortedSet JavaDoc<String JavaDoc> urls) {
432         AuxiliaryConfiguration aux = p.getLookup().lookup(AuxiliaryConfiguration.class);
433         if (aux != null) {
434             
435             aux.removeConfigurationFragment (OPEN_FILES_ELEMENT, OPEN_FILES_NS, false);
436
437             Document JavaDoc xml = XMLUtil.createDocument (OPEN_FILES_ELEMENT, OPEN_FILES_NS, null, null);
438             Element JavaDoc fileEl;
439             
440             Element JavaDoc openFiles = xml.createElementNS (OPEN_FILES_NS, OPEN_FILES_ELEMENT);
441             
442             // loop all open files of given project
443
for (String JavaDoc url : urls) {
444                 fileEl = openFiles.getOwnerDocument ().createElement (FILE_ELEMENT);
445                 fileEl.appendChild(fileEl.getOwnerDocument().createTextNode(url));
446                 openFiles.appendChild (fileEl);
447             }
448             
449             aux.putConfigurationFragment (openFiles, false);
450         }
451     }
452     
453     /** Opens the project's files read from the private <code>project.xml</code> file
454      *
455      * @param p project
456      */

457     public static void openProjectFiles (Project p) {
458         boolean dolog = ERR.isLoggable(ErrorManager.INFORMATIONAL);
459         if (dolog) ERR.log("Trying to open files from " + p + "...");
460         
461         AuxiliaryConfiguration aux = p.getLookup().lookup(AuxiliaryConfiguration.class);
462         
463         if (aux == null) {
464             if (dolog) ERR.log("No AuxiliaryConfiguration in " + p);
465             return ;
466         }
467         
468         Element JavaDoc openFiles = aux.getConfigurationFragment (OPEN_FILES_ELEMENT, OPEN_FILES_NS, false);
469         if (openFiles == null) {
470             if (dolog) ERR.log("No " + OPEN_FILES_ELEMENT + " in private.xml");
471             return;
472         }
473
474         NodeList JavaDoc list = openFiles.getElementsByTagName (FILE_ELEMENT);
475         if (list == null) {
476             if (dolog) ERR.log("No " + FILE_ELEMENT + " in " + OPEN_FILES_ELEMENT);
477             return ;
478         }
479         
480         for (int i = 0; i < list.getLength (); i++) {
481             String JavaDoc url = list.item (i).getChildNodes ().item (0).getNodeValue ();
482             if (dolog) ERR.log("Will try to open " + url);
483             FileObject fo;
484             try {
485                 fo = URLMapper.findFileObject (new URL JavaDoc (url));
486             } catch (MalformedURLException JavaDoc mue) {
487                 assert false : "MalformedURLException in " + url;
488                 continue;
489             }
490             if (fo == null) {
491                 if (dolog) ERR.log("Could not find " + url);
492                 continue;
493             }
494             
495             OPEN_CLOSE_PROJECT_DOCUMENT_IMPL.open (fo);
496         }
497         
498         // clean-up stored files
499
aux.removeConfigurationFragment (OPEN_FILES_ELEMENT, OPEN_FILES_NS, false);
500     }
501     
502     // interface for handling project's documents stored in project private.xml
503
// it serves for a unit test of OpenProjectList
504
interface OpenCloseProjectDocument {
505         
506         // opens stored document in the document area
507
boolean open(FileObject fo);
508         
509         // closes documents of given projects and returns mapped document's urls by project
510
// it's used as base for storing documents in project private.xml
511
Map JavaDoc<Project,SortedSet JavaDoc<String JavaDoc>> close(Project[] projects, boolean notifyUI);
512     }
513     
514 }
515
Popular Tags