KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > beaninfo > editors > FileEditor


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.beaninfo.editors;
21
22 import java.awt.event.ActionEvent JavaDoc;
23 import java.awt.event.KeyEvent JavaDoc;
24 import java.awt.Component JavaDoc;
25 import java.awt.Container JavaDoc;
26 import java.awt.Dialog JavaDoc;
27 import java.awt.KeyboardFocusManager JavaDoc;
28 import java.beans.PropertyChangeEvent JavaDoc;
29 import java.beans.PropertyChangeListener JavaDoc;
30 import java.beans.PropertyEditorSupport JavaDoc;
31 import java.io.File JavaDoc;
32 import java.io.FilenameFilter JavaDoc;
33 import java.util.logging.Level JavaDoc;
34 import java.util.logging.Logger JavaDoc;
35 import javax.swing.AbstractAction JavaDoc;
36 import javax.swing.AbstractButton JavaDoc;
37 import javax.swing.Action JavaDoc;
38 import javax.swing.JComboBox JavaDoc;
39 import javax.swing.JComponent JavaDoc;
40 import javax.swing.JFileChooser JavaDoc;
41 import javax.swing.JScrollBar JavaDoc;
42 import javax.swing.KeyStroke JavaDoc;
43 import org.openide.nodes.Node;
44 import org.openide.explorer.propertysheet.ExPropertyEditor;
45 import org.openide.explorer.propertysheet.PropertyEnv;
46 import org.openide.util.HelpCtx;
47 import org.openide.util.NbBundle;
48
49 /**
50  * PropertyEditor for <code>java.io.File</code>.
51  *
52  * @author Jaroslav Tulach, David Strupl, Peter Zavadsky, Jesse Glick
53  */

54 public class FileEditor extends PropertyEditorSupport JavaDoc implements ExPropertyEditor, PropertyChangeListener JavaDoc {
55     
56     /** Name of the property obtained from the feature descriptor.*/
57     static final String JavaDoc PROPERTY_SHOW_DIRECTORIES = "directories"; //NOI18N
58

59     /** Name of the property obtained from the feature descriptor.*/
60     static final String JavaDoc PROPERTY_SHOW_FILES = "files"; //NOI18N
61

62     /** Name of the property obtained from the feature descriptor.*/
63     static final String JavaDoc PROPERTY_FILTER = "filter"; //NOI18N
64

65     /** Name of the property obtained from the feature descriptor.*/
66     static final String JavaDoc PROPERTY_CURRENT_DIR = "currentDir"; //NOI18N
67

68     /** Name of the property obtained from the feature descriptor. */
69     static final String JavaDoc PROPERTY_BASE_DIR = "baseDir"; // NOI18N
70

71     /** Name of the property obtained from the feature descriptor. */
72     static final String JavaDoc PROPERTY_FILE_HIDING = "file_hiding"; // NOI18N
73

74     /** Openning mode.*/
75     private int mode = JFileChooser.FILES_AND_DIRECTORIES;
76     
77     /** Flag indicating whether to choose directories. Default value is <code>true</code>. */
78     private boolean directories = true;
79     /** Flag indicating whether to choose files. Default value is <code>true</code>. */
80     private boolean files = true;
81     /** Flag indicating whether to hide files marked as hidden. Default value is <code>false</code>. */
82     private boolean fileHiding = false;
83     /** Filter for files to show. */
84     private javax.swing.filechooser.FileFilter JavaDoc fileFilter;
85     /** Current firectory. */
86     private File JavaDoc currentDirectory;
87     /** Base directory to which to show relative path, if is set. */
88     private File JavaDoc baseDirectory;
89
90     /** Caches last used directory. */
91     static File JavaDoc lastCurrentDir;
92
93     private PropertyEnv env;
94     
95     /** Cached chooser.
96      * If you don't cache it, MountIterator in core flickers and behaves weirdly,
97      * because apparently PropertyPanel will call getCustomEditor repeatedly and
98      * refresh the display each time.
99      * XXX MountIterator is dead so is this still necessary? -jglick
100      */

101     private JFileChooser JavaDoc chooser;
102     
103     /** whether the value can be edited -- default to true */
104     private boolean editable = true;
105     
106     /**
107      * This method is called by the IDE to pass
108      * the environment to the property editor.
109      * @param env Environment passed by the ide.
110      */

111     public void attachEnv(PropertyEnv env) {
112         this.env = env;
113
114         // clearing to defaults
115
directories = true;
116         files = true;
117         fileFilter = null;
118         fileHiding = false;
119
120         Object JavaDoc dirs = env.getFeatureDescriptor().getValue(PROPERTY_SHOW_DIRECTORIES);
121         if (dirs instanceof Boolean JavaDoc) {
122             directories = ((Boolean JavaDoc)dirs).booleanValue();
123         } // XXX else if != null, warn
124
Object JavaDoc fil = env.getFeatureDescriptor().getValue(PROPERTY_SHOW_FILES);
125         if (fil instanceof Boolean JavaDoc) {
126             files = ((Boolean JavaDoc)fil).booleanValue();
127         } // XXX else if != null, warn
128
Object JavaDoc filter = env.getFeatureDescriptor().getValue(PROPERTY_FILTER);
129         if (filter instanceof FilenameFilter JavaDoc) {
130             fileFilter = new DelegatingFilenameFilter((FilenameFilter JavaDoc)filter);
131         } else if (filter instanceof javax.swing.filechooser.FileFilter JavaDoc) {
132             fileFilter = (javax.swing.filechooser.FileFilter JavaDoc)filter;
133         } else if (filter instanceof java.io.FileFilter JavaDoc) {
134             fileFilter = new DelegatingFileFilter((java.io.FileFilter JavaDoc)filter);
135         } // XXX else if != null, warn
136

137         Object JavaDoc curDir = env.getFeatureDescriptor().getValue(PROPERTY_CURRENT_DIR);
138         if (curDir instanceof File JavaDoc) {
139             currentDirectory = (File JavaDoc)curDir;
140             if(! currentDirectory.isDirectory()) {
141                 Logger.getAnonymousLogger().warning("java.io.File will not accept currentDir=" + currentDirectory); // NOI18N
142
currentDirectory = null;
143             }
144         } // XXX else if != null, warn
145

146         Object JavaDoc baseDir = env.getFeatureDescriptor().getValue(PROPERTY_BASE_DIR);
147         if(baseDir instanceof File JavaDoc) {
148             baseDirectory = (File JavaDoc)baseDir;
149             // As baseDir accept only directories in their absolute form.
150
if(!baseDirectory.isDirectory() || !baseDirectory.isAbsolute()) {
151                 Logger.getAnonymousLogger().warning("java.io.File will not accept baseDir=" + baseDirectory); // NOI18N
152
baseDirectory = null;
153             }
154         } // XXX else if != null, warn
155
if (files) {
156             mode = directories ? JFileChooser.FILES_AND_DIRECTORIES :
157                 JFileChooser.FILES_ONLY;
158         } else {
159             mode = directories ? JFileChooser.DIRECTORIES_ONLY :
160                 JFileChooser.FILES_AND_DIRECTORIES; // both false, what now? XXX warn
161
}
162         
163         Object JavaDoc fileHide = env.getFeatureDescriptor().getValue(PROPERTY_FILE_HIDING);
164         if (fileHide instanceof Boolean JavaDoc) {
165             fileHiding = ((Boolean JavaDoc)fileHide).booleanValue();
166         }
167         
168         if (env.getFeatureDescriptor() instanceof Node.Property){
169             Node.Property prop = (Node.Property)env.getFeatureDescriptor();
170             editable = prop.canWrite();
171         }
172     }
173
174     /** Returns human readable form of the edited value.
175      * @return string reprezentation
176      */

177     public String JavaDoc getAsText() {
178         File JavaDoc file = (File JavaDoc)getValue();
179         if (file == null) {
180             return ""; // NOI18N
181
}
182         String JavaDoc path = file.getPath();
183         // Dot is more friendly to people though Java itself would prefer blank:
184
if ("".equals(path)) path = "."; // NOI18N
185
return path;
186     }
187     
188     /** Parses the given string and should create a new instance of the
189      * edited object.
190      * @param str string reprezentation of the file (used as a parameter for File).
191      * @throws IllegalArgumentException If the given string cannot be parsed
192      */

193     public void setAsText(String JavaDoc str) throws IllegalArgumentException JavaDoc {
194         if (str == null) {
195             throw new IllegalArgumentException JavaDoc("null"); // NOI18N
196
}
197         if ("".equals(str)) { // NOI18N
198
setValue(null);
199             return;
200         }
201         // See getAsText.
202
if (".".equals(str)) str = ""; // NOI18N
203
setValue(new File JavaDoc(str));
204     }
205
206     /** Custon editor.
207      * @return Returns custom editor component.
208      */

209     public Component JavaDoc getCustomEditor() {
210         if (!editable) {
211             String JavaDoc info = "";
212             Object JavaDoc curVal = getValue();
213             if (curVal instanceof java.io.File JavaDoc) {
214                 info = ((java.io.File JavaDoc)curVal).getAbsolutePath();
215             }
216             return new StringCustomEditor(info, false, true, null, this, env);
217         }
218         if (chooser == null) {
219             chooser = createHackedFileChooser();
220         
221             File JavaDoc originalFile = (File JavaDoc)getValue ();
222             if (originalFile != null && ! originalFile.isAbsolute() && baseDirectory != null) {
223                 originalFile = new File JavaDoc(baseDirectory, originalFile.getPath());
224             }
225             if (currentDirectory != null) {
226                 chooser.setCurrentDirectory (currentDirectory);
227             } else if (originalFile != null && originalFile.getParentFile() != null) {
228                 chooser.setCurrentDirectory (originalFile.getParentFile());
229                 chooser.setSelectedFile (originalFile);
230             } else if (lastCurrentDir != null) {
231                 chooser.setCurrentDirectory(lastCurrentDir);
232             }
233             chooser.setFileSelectionMode(mode);
234             if (fileFilter != null) {
235                 chooser.setFileFilter(fileFilter);
236             }
237             switch (mode) {
238                 case JFileChooser.FILES_AND_DIRECTORIES:
239                     chooser.setDialogTitle (getString ("CTL_DialogTitleFilesAndDirs"));
240                     break;
241                 case JFileChooser.FILES_ONLY:
242                     chooser.setDialogTitle (getString ("CTL_DialogTitleFiles"));
243                     break;
244                 case JFileChooser.DIRECTORIES_ONLY:
245                     chooser.setDialogTitle (getString ("CTL_DialogTitleDirs"));
246                     break;
247             }
248             chooser.setFileHidingEnabled(fileHiding);
249
250             chooser.setControlButtonsAreShown(false);
251
252             chooser.addPropertyChangeListener(
253                 JFileChooser.SELECTED_FILE_CHANGED_PROPERTY,
254                 this
255             );
256             
257             HelpCtx.setHelpIDString (chooser, getHelpCtx ().getHelpID ());
258         }
259
260         return chooser;
261     }
262     
263     /** Implements PropertyEditor method.
264      * @return Returns true.
265      */

266     public boolean supportsCustomEditor() {
267         return true;
268     }
269     
270     /** Should create a string insertable to the newly generated source code.
271      * @return initialization string
272      */

273     public String JavaDoc getJavaInitializationString() {
274         File JavaDoc value = (File JavaDoc) getValue ();
275         if (value == null) {
276             return "null"; // NOI18N
277
} else {
278             // [PENDING] not a full escape of filenames, but enough to at least
279
// handle normal Windows backslashes
280
if (baseDirectory != null && !value.isAbsolute()) {
281                 return "new java.io.File(" // NOI18N
282
+ stringify(baseDirectory.getPath())
283                     + ", " // NOI18N
284
+ stringify(value.getPath())
285                     + ")"; // NOI18N
286
} else {
287                 return "new java.io.File(" // NOI18N
288
+ stringify(value.getAbsolutePath())
289                     + ")"; // NOI18N
290
}
291         }
292     }
293     static String JavaDoc stringify(String JavaDoc in) {
294         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(in.length() * 2 + 2);
295         buf.append('"'); // NOI18N
296
for (int i = 0; i < in.length(); i++) {
297             char c = in.charAt(i);
298             if (c == '\\' || c == '"') { // NOI18N
299
buf.append('\\'); // NOI18N
300
}
301             buf.append(c);
302         }
303         buf.append('"'); // NOI18N
304
return buf.toString();
305     }
306
307     /** Gets help context. */
308     private HelpCtx getHelpCtx () {
309         return new HelpCtx (FileEditor.class);
310     }
311     
312     /** Gets localized string. Helper method. */
313     private static String JavaDoc getString(String JavaDoc key) {
314         return NbBundle.getBundle(FileEditor.class).getString(key);
315     }
316     
317     /** Gets relative path of file to specified directory only for case the file
318      * is in directory tree.
319      * @param baseDir base directory
320      * @param file file which relative path to <code>baseDir</code> is needed
321      * @return relative path or <code>null</code> can't be resolved
322      * or if the <code>file</code> is not under <code>baseDir</code> tree */

323     static String JavaDoc getChildRelativePath(File JavaDoc baseDir, File JavaDoc file) {
324         // Handle hypothetical weird situations where file is in baseDir
325
// but the prefixes do not match. E.g.:
326
// file=\foo\bar.txt (assumed to be on C:) baseDir=c:\foo
327
if (file.equals(baseDir)) {
328             // The empty pathname, not ".", is correct here I think...
329
// Try making new File(new File("/tmp", x)) for x in {".", ""}
330
return ""; // NOI18N
331
}
332         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(file.getPath().length());
333         buf.append(file.getName());
334         for (File JavaDoc parent = file.getParentFile(); parent != null; parent = parent.getParentFile()) {
335             if (parent.equals(baseDir)) {
336                 return buf.toString();
337             }
338             buf.insert(0, File.separatorChar);
339             buf.insert(0, parent.getName());
340         }
341         return null;
342     }
343     
344     /** Property change listaner attached to the JFileChooser chooser. */
345     public void propertyChange(PropertyChangeEvent JavaDoc e) {
346         JFileChooser JavaDoc chooser = (JFileChooser JavaDoc)e.getSource();
347         File JavaDoc f = chooser.getSelectedFile();
348         if (f == null) {
349             return;
350         }
351         if (!files && f.isFile ()) return;
352         if (!directories && f.isDirectory ()) return;
353
354         if (baseDirectory != null) {
355             String JavaDoc rel = getChildRelativePath(baseDirectory, f);
356             if (rel != null) {
357                 f = new File JavaDoc(rel);
358             }
359         }
360
361         // use to be setValue(f) - the next line is
362
// workaround for JDK bug 4533419
363
// it should be returned back to setValue(f) after the
364
// mentioned bug is fixed in JDK.
365
setValue(new File JavaDoc(f.getPath()));
366         
367         lastCurrentDir = chooser.getCurrentDirectory();
368     }
369     
370     // XXX #18270. Enter doesn't work when expecting folder change,
371
// Accessibility problem. We hack default behaviour here.
372
/** Creates hacked fileChooser, responding on Enter the way it
373      * performs folder change. */

374     public static JFileChooser JavaDoc createHackedFileChooser() {
375         JFileChooser JavaDoc chooser = new JFileChooser JavaDoc();
376         hackFileChooser(chooser);
377         return chooser;
378     }
379     
380     /** Hacks fileChooser, responding on Enter the way it
381      * performs folder change. */

382     public static void hackFileChooser(final JFileChooser JavaDoc chooser) {
383         chooser.getAccessibleContext().setAccessibleDescription( getString("ACSD_FileEditor") );
384         
385         //issue 31605 - make escape work properly
386
//Get the existing action key on ESCAPE
387
// XXX is this hack still necessary?
388
final Object JavaDoc key = chooser.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).get(
389             KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
390         
391         Action JavaDoc close = new AbstractAction JavaDoc() {
392             public void actionPerformed(ActionEvent JavaDoc ae) {
393                 Component JavaDoc comp = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
394                 if (key != null) {
395                     //if there was an action, do it first
396
Action JavaDoc a = chooser.getActionMap().get(key);
397                     if (a != null) {
398                         a.actionPerformed(ae);
399                     }
400                 }
401                 if (comp.getParent() == null) {
402                     //then we were editing a file name, and the editor
403
//was removed - we don't want to close the dialog
404
return;
405                 }
406                 
407                 Container JavaDoc c = chooser.getTopLevelAncestor();
408                 //The action *may* have already hidden the panel (works
409
//intermittently)
410
if (c instanceof Dialog JavaDoc) {
411                     if (((Dialog JavaDoc) c).isVisible()) {
412                         ((Dialog JavaDoc) c).setVisible (false);
413                         ((Dialog JavaDoc) c).dispose();
414                     }
415                 }
416             }
417         };
418         chooser.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
419             KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
420         chooser.getActionMap().put("close", close);
421     }
422
423     private static class ButtonHider implements PropertyChangeListener JavaDoc {
424         public void propertyChange (PropertyChangeEvent JavaDoc pce) {
425             if (JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY.equals(pce.getPropertyName())) {
426                 JFileChooser JavaDoc jfc = (JFileChooser JavaDoc) pce.getSource();
427                 try {
428                     hideShowButtons(jfc, Boolean.TRUE.equals(pce.getNewValue()));
429                 } catch (Exception JavaDoc e) {
430                     Logger.getLogger(FileEditor.class.getName()).log(Level.WARNING, null, e);
431                 }
432             }
433         }
434         
435         private void hideShowButtons (Container JavaDoc cont, boolean val) {
436             if (cont instanceof JComboBox JavaDoc || cont instanceof JScrollBar JavaDoc) {
437                 return;
438             }
439             Component JavaDoc[] c = cont.getComponents();
440             for (int i=0; i < c.length; i++) {
441                 if (c[i] instanceof Container JavaDoc) {
442                     hideShowButtons ((Container JavaDoc) c[i], val);
443                 }
444                 if (c[i] instanceof AbstractButton JavaDoc) {
445                     c[i].setVisible(val);
446                 }
447             }
448         }
449     }
450     
451     /** Wraps java.io.FileFilter to javax.swing.filechooser.FileFilter. */
452     static class DelegatingFileFilter extends javax.swing.filechooser.FileFilter JavaDoc {
453         private java.io.FileFilter JavaDoc filter;
454         
455         public DelegatingFileFilter(java.io.FileFilter JavaDoc f) {
456             this.filter = f;
457         }
458         
459         public boolean accept(File JavaDoc f) {
460             return filter.accept(f);
461         }
462         
463         public String JavaDoc getDescription() {
464             // [PENDING] what should we return?
465
return null;
466         }
467         
468     } // End of class DelegatingFileFilter.
469

470     
471     /** Wraps FilenameFilter to javax.swing.filechooser.FileFilter. */
472     static class DelegatingFilenameFilter extends javax.swing.filechooser.FileFilter JavaDoc {
473         private FilenameFilter JavaDoc filter;
474         
475         public DelegatingFilenameFilter(FilenameFilter JavaDoc f) {
476             this.filter = f;
477         }
478         /** Calls the filenameFilter's accept method with arguments
479          * created from the original object f.
480          */

481         public boolean accept(File JavaDoc f) {
482             return filter.accept(f.getParentFile(), f.getName());
483         }
484         
485         public String JavaDoc getDescription() {
486             // [PENDING] what should we return?
487
return null;
488         }
489     } // End of class DelegatingFilenameFilter.
490

491 }
492
Popular Tags