001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.beaninfo.editors;
043:
044: import java.awt.event.KeyEvent;
045: import java.io.IOException;
046: import java.lang.ref.*;
047: import java.util.Arrays;
048: import java.util.StringTokenizer;
049: import java.beans.*;
050: import java.io.File;
051:
052: import javax.swing.event.DocumentListener;
053: import javax.swing.event.ChangeListener;
054: import javax.swing.event.ChangeEvent;
055: import javax.swing.KeyStroke;
056: import javax.swing.SwingUtilities;
057: import org.openide.explorer.propertysheet.PropertyEnv;
058: import org.openide.loaders.*;
059: import org.openide.nodes.*;
060: import org.openide.explorer.ExplorerManager;
061: import org.openide.filesystems.*;
062: import org.openide.util.Exceptions;
063: import org.openide.util.HelpCtx;
064: import org.openide.util.NbCollections;
065: import org.openide.windows.TopComponent;
066:
067: /**
068: * A panel for selecting an existing data folder.
069: * @author Jaroslav Tulach, David Strupl
070: * @version
071: */
072: class DataFolderPanel extends TopComponent implements DocumentListener,
073: DataFilter, PropertyChangeListener, VetoableChangeListener {
074:
075: /** prefered dimmension of the panels */
076: static java.awt.Dimension PREF_DIM = new java.awt.Dimension(450,
077: 250);
078:
079: /** format to for default package */
080: /** listener to changes in the panel */
081: private ChangeListener listener;
082:
083: /** file system reference */
084: Reference<FileSystem> system = new WeakReference<FileSystem>(null);
085:
086: /** root node */
087: private Node rootNode;
088:
089: /** last DataFolder object that can be returned */
090: private DataFolder df;
091:
092: /** */
093: private DataFolderEditor editor;
094:
095: private static final String PATH_TOKEN_DELIMITER = "/"
096: + java.io.File.separatorChar; // NOI18N
097:
098: private String last_suggestion = "";
099:
100: public DataFolderPanel(DataFolderEditor ed) {
101: this ();
102: editor = ed;
103:
104: editor.env.setState(PropertyEnv.STATE_NEEDS_VALIDATION);
105: editor.env.addPropertyChangeListener(this );
106: }
107:
108: /** Creates new form DataFolderPanel */
109: public DataFolderPanel() {
110: initComponents();
111:
112: setName(getString("LAB_TargetLocationPanelName"));
113:
114: setBorder(new javax.swing.border.EmptyBorder(
115: new java.awt.Insets(12, 12, 0, 11)));
116: /*
117: packagesPanel.setBorder (new javax.swing.border.CompoundBorder(
118: new javax.swing.border.TitledBorder(getString("LAB_SelectPackageBorder")),
119: new javax.swing.border.EmptyBorder(new java.awt.Insets(8, 8, 8, 8)))
120: );
121: */
122:
123: rootNode = createPackagesNode();
124:
125: beanTreeView.setRootVisible(false);
126:
127: packagesPanel.getExplorerManager().setRootContext(rootNode);
128: packagesPanel.getExplorerManager().addPropertyChangeListener(
129: this );
130: packagesPanel.getExplorerManager().addVetoableChangeListener(
131: this );
132:
133: // registers itself to listen to changes in the content of document
134: packageName.getDocument().addDocumentListener(this );
135: packageName.unregisterKeyboardAction(KeyStroke.getKeyStroke(
136: KeyEvent.VK_ENTER, 0));
137:
138: beanTreeView.getAccessibleContext().setAccessibleDescription(
139: getString("ACSD_DataFolderTree"));
140: packageName.getAccessibleContext().setAccessibleDescription(
141: getString("ACSD_package"));
142: directoryName.getAccessibleContext().setAccessibleDescription(
143: getString("ACSD_directory"));
144: createButton.getAccessibleContext().setAccessibleDescription(
145: getString("ACSD_Create"));
146: getAccessibleContext().setAccessibleDescription(
147: getString("ACSD_DataFolderPanel"));
148: }
149:
150: /** Preffered size */
151: public java.awt.Dimension getPreferredSize() {
152: return PREF_DIM;
153: }
154:
155: /** Request focus.
156: */
157: public void requestFocus() {
158: // TODO: set the focus
159: // used to be :
160: // className.requestFocus();
161: // className.selectAll ();
162: }
163:
164: /** Creates node that displays all packages.
165: */
166: private Node createPackagesNode() {
167: Node topNode = RepositoryNodeFactory.getDefault().repository(
168: this );
169: Node[] nodes = topNode.getChildren().getNodes(true);
170: assert nodes != null && nodes.length == 1 : "Only one subnode "
171: + topNode + " found, but was " + Arrays.asList(nodes);
172: return nodes[0];
173: }
174:
175: /** This method is called from within the constructor to
176: * initialize the form.
177: * WARNING: Do NOT modify this code. The content of this method is
178: * always regenerated by the FormEditor.
179: */
180: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
181: private void initComponents() {
182: java.awt.GridBagConstraints gridBagConstraints;
183:
184: packagesPanel = new org.netbeans.beaninfo.ExplorerPanel();
185: beanTreeView = new org.openide.explorer.view.BeanTreeView();
186: descriptionLabel = new javax.swing.JLabel();
187: packageLabel = new javax.swing.JLabel();
188: packageName = new javax.swing.JTextField();
189: dirLabel = new javax.swing.JLabel();
190: directoryName = new javax.swing.JTextField();
191: createButton = new javax.swing.JButton();
192:
193: setLayout(new java.awt.BorderLayout());
194:
195: packagesPanel.setLayout(new java.awt.GridBagLayout());
196:
197: beanTreeView.setDefaultActionAllowed(false);
198: beanTreeView.setPopupAllowed(false);
199: gridBagConstraints = new java.awt.GridBagConstraints();
200: gridBagConstraints.gridx = 0;
201: gridBagConstraints.gridy = 1;
202: gridBagConstraints.gridwidth = 3;
203: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
204: gridBagConstraints.weightx = 1.0;
205: gridBagConstraints.weighty = 1.0;
206: gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
207: packagesPanel.add(beanTreeView, gridBagConstraints);
208:
209: descriptionLabel.setLabelFor(beanTreeView);
210: org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel,
211: org.openide.util.NbBundle.getBundle(
212: DataFolderPanel.class).getString(
213: "LAB_TargetLocationDescription")); // NOI18N
214: gridBagConstraints = new java.awt.GridBagConstraints();
215: gridBagConstraints.gridx = 0;
216: gridBagConstraints.gridy = 0;
217: gridBagConstraints.gridwidth = 3;
218: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
219: gridBagConstraints.insets = new java.awt.Insets(0, 0, 2, 0);
220: packagesPanel.add(descriptionLabel, gridBagConstraints);
221:
222: packageLabel.setLabelFor(packageName);
223: org.openide.awt.Mnemonics
224: .setLocalizedText(packageLabel,
225: org.openide.util.NbBundle.getBundle(
226: DataFolderPanel.class).getString(
227: "LAB_package")); // NOI18N
228: gridBagConstraints = new java.awt.GridBagConstraints();
229: gridBagConstraints.gridx = 0;
230: gridBagConstraints.gridy = 2;
231: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
232: gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 12);
233: packagesPanel.add(packageLabel, gridBagConstraints);
234: gridBagConstraints = new java.awt.GridBagConstraints();
235: gridBagConstraints.gridx = 1;
236: gridBagConstraints.gridy = 2;
237: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
238: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
239: gridBagConstraints.weightx = 1.0;
240: gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
241: packagesPanel.add(packageName, gridBagConstraints);
242:
243: org.openide.awt.Mnemonics.setLocalizedText(dirLabel,
244: org.openide.util.NbBundle.getBundle(
245: DataFolderPanel.class).getString(
246: "LAB_directory")); // NOI18N
247: gridBagConstraints = new java.awt.GridBagConstraints();
248: gridBagConstraints.gridx = 0;
249: gridBagConstraints.gridy = 3;
250: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
251: gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
252: packagesPanel.add(dirLabel, gridBagConstraints);
253:
254: directoryName.setEnabled(false);
255: gridBagConstraints = new java.awt.GridBagConstraints();
256: gridBagConstraints.gridx = 1;
257: gridBagConstraints.gridy = 3;
258: gridBagConstraints.gridwidth = 2;
259: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
260: packagesPanel.add(directoryName, gridBagConstraints);
261:
262: org.openide.awt.Mnemonics.setLocalizedText(createButton,
263: org.openide.util.NbBundle.getBundle(
264: DataFolderPanel.class).getString("CTL_Create")); // NOI18N
265: createButton.setEnabled(false);
266: createButton
267: .addActionListener(new java.awt.event.ActionListener() {
268: public void actionPerformed(
269: java.awt.event.ActionEvent evt) {
270: createButtonActionPerformed(evt);
271: }
272: });
273: gridBagConstraints = new java.awt.GridBagConstraints();
274: gridBagConstraints.gridx = 2;
275: gridBagConstraints.gridy = 2;
276: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
277: gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
278: packagesPanel.add(createButton, gridBagConstraints);
279:
280: add(packagesPanel, java.awt.BorderLayout.CENTER);
281: }// </editor-fold>//GEN-END:initComponents
282:
283: private void createButtonActionPerformed(
284: java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createButtonActionPerformed
285: try {
286: // create the folder
287: final DataFolder newDf = (DataFolder) getPropertyValue();
288: // TODO: this line does not work - because the Node is not there yet
289: setTargetFolder(newDf);
290: updateDirectory();
291: updatePropertyEditor();
292: enableCreateButton();
293: } catch (IllegalStateException ex) {
294: throw new RuntimeException(ex.getMessage());
295: }
296: }//GEN-LAST:event_createButtonActionPerformed
297:
298: // Variables declaration - do not modify//GEN-BEGIN:variables
299: private org.openide.explorer.view.BeanTreeView beanTreeView;
300: private javax.swing.JButton createButton;
301: private javax.swing.JLabel descriptionLabel;
302: private javax.swing.JLabel dirLabel;
303: private javax.swing.JTextField directoryName;
304: private javax.swing.JLabel packageLabel;
305: private javax.swing.JTextField packageName;
306: private org.netbeans.beaninfo.ExplorerPanel packagesPanel;
307:
308: // End of variables declaration//GEN-END:variables
309:
310: //
311: // Filter to accept only folders
312: //
313:
314: /** Should the data object be displayed or not?
315: * @param obj the data object
316: * @return <CODE>true</CODE> if the object should be displayed,
317: * <CODE>false</CODE> otherwise
318: */
319: public boolean acceptDataObject(DataObject obj) {
320: return obj instanceof DataFolder;
321: }
322:
323: /** Allow only simple selection.
324: */
325: public void vetoableChange(PropertyChangeEvent ev)
326: throws PropertyVetoException {
327: if (ExplorerManager.PROP_SELECTED_NODES.equals(ev
328: .getPropertyName())) {
329: Node[] arr = (Node[]) ev.getNewValue();
330:
331: if (arr.length > 1) {
332: throw new PropertyVetoException(
333: "Only single selection allowed", ev); // NOI18N
334: }
335: }
336: }
337:
338: /** Changes in selected node in packages.
339: */
340: public void propertyChange(PropertyChangeEvent ev) {
341: if (ExplorerManager.PROP_SELECTED_NODES.equals(ev
342: .getPropertyName())) {
343: Node[] arr = packagesPanel.getExplorerManager()
344: .getSelectedNodes();
345: if (!isVisible()) {
346: // in the case we are not shown don't update the panel's state
347: return;
348: }
349: if (arr.length == 1) {
350: if (!isValid()) {
351: setTargetFolder(null);
352: implSetDataFolder(null);
353: return;
354: }
355: DataFolder df = (DataFolder) arr[0]
356: .getCookie(DataFolder.class);
357: if (df != null) {
358: setTargetFolder(df);
359: updatePropertyEditor();
360: enableCreateButton();
361: return;
362: }
363: }
364: setTargetFolder(null);
365: implSetDataFolder(null);
366: }
367:
368: if (PropertyEnv.PROP_STATE.equals(ev.getPropertyName())
369: && ev.getNewValue() == PropertyEnv.STATE_VALID) {
370: editor.setValue(getPropertyValue());
371: }
372:
373: }
374:
375: /** Fires info to listener.
376: */
377: private void fireStateChanged() {
378: if (listener != null) {
379: listener.stateChanged(new ChangeEvent(this ));
380: }
381: }
382:
383: //
384: // Modification of package name
385: //
386:
387: public void changedUpdate(final javax.swing.event.DocumentEvent p1) {
388: if (p1.getDocument() == packageName.getDocument()) {
389: SwingUtilities.invokeLater(new Runnable() {
390: public void run() {
391: String text = packageName.getText();
392: if (text != null) {
393: if (isValid()) {
394: setTargetFolder(text, false);
395: updatePropertyEditor();
396: }
397: updateDirectory();
398: }
399: enableCreateButton();
400: }
401: });
402: return;
403: }
404: }
405:
406: public void removeUpdate(final javax.swing.event.DocumentEvent p1) {
407: // when deleted => do no looking for folder
408: // changedUpdate (p1);
409: if (p1.getDocument() == packageName.getDocument()) {
410: SwingUtilities.invokeLater(new Runnable() {
411: public void run() {
412: if (packageName.getText().length() == 0) {
413: FileSystem fs = system.get();
414: if (fs != null) {
415: DataFolder df = DataFolder.findFolder(fs
416: .getRoot());
417: setTargetFolder(df);
418: packageName.selectAll();
419: }
420: }
421: String text = packageName.getText();
422: if (text != null) {
423: if (isValid()) {
424: setTargetFolder(text, true);
425: updatePropertyEditor();
426: }
427: updateDirectory();
428: }
429: enableCreateButton();
430: }
431: });
432: }
433: }
434:
435: public void insertUpdate(final javax.swing.event.DocumentEvent p1) {
436: changedUpdate(p1);
437: }
438:
439: /** Help for this panel.
440: * @return the help or <code>null</code> if no help is supplied
441: */
442: public org.openide.util.HelpCtx getHelp() {
443: return new HelpCtx(DataFolderPanel.class);
444: }
445:
446: /** Test whether the panel is finished and it is safe to proceed to the next one.
447: * If the panel is valid, the "Next" (or "Finish") button will be enabled.
448: * @return <code>true</code> if the user has entered satisfactory information
449: */
450: public boolean isValid() {
451: String text = packageName.getText();
452: if (text.length() == 0) {
453: Node[] arr = packagesPanel.getExplorerManager()
454: .getSelectedNodes();
455: if (arr.length == 1 && arr[0] == rootNode) {
456: return false;
457: }
458: }
459:
460: return true;
461: }
462:
463: /** Add a listener to changes of the panel's validity.
464: * @param l the listener to add
465: * @see #isValid
466: */
467: public void addChangeListener(ChangeListener l) {
468: if (listener != null)
469: throw new IllegalStateException();
470:
471: listener = l;
472: }
473:
474: /** Remove a listener to changes of the panel's validity.
475: * @param l the listener to remove
476: */
477: public void removeChangeListener(ChangeListener l) {
478: listener = null;
479: }
480:
481: /** Computes a suggestion for a given prefix and
482: * a list of file objects.
483: *
484: * @param node the node to start with
485: * @param pref prefix
486: * @param first [0] is the first node that satisfies the suggestion
487: * @return the longest continuation string for all folders that
488: * starts with prefix
489: */
490: private static String computeSuggestion(Node node, String pref,
491: Node[] first) {
492: Node[] arr = node.getChildren().getNodes();
493:
494: String match = null;
495:
496: for (int i = 0; i < arr.length; i++) {
497: String name = arr[i].getName();
498: if (name.startsWith(pref)) {
499: // ok, has the right prefix
500: if (match == null) {
501: // first match
502: match = name;
503: if (first != null) {
504: first[0] = arr[i];
505: }
506: } else {
507: // find common part of the names
508: int indx = pref.length();
509: int end = Math.min(name.length(), match.length());
510: while (indx < end
511: && match.charAt(indx) == name.charAt(indx)) {
512: indx++;
513: }
514: match = match.substring(0, indx);
515: }
516: }
517: }
518:
519: if (match == null) { // why? || match.length () == pref.length ()) {
520: return null;
521: } else {
522: return match.substring(pref.length());
523: }
524: }
525:
526: /** Presets a target folder.
527: * @param f the folder
528: * @return true if succeeded
529: */
530: boolean setTargetFolder(final DataFolder f) {
531: boolean exact;
532: Node n = null;
533: String name;
534:
535: df = f;
536:
537: if (f != null) {
538: FileObject fo = f.getPrimaryFile();
539: name = fo.getPath();
540:
541: StringTokenizer st = new StringTokenizer(name,
542: PATH_TOKEN_DELIMITER);
543: try {
544: FileSystem fs = fo.getFileSystem();
545:
546: if (fo.isRoot()) {
547: // bugfix #31645, possibility create new folder under root
548: name = packageName.getText().trim();
549: // bugfix #32910, possibility create only for single folder
550: boolean withSubfolder = name
551: .indexOf(File.separatorChar) != -1;
552: if (fo.getFileObject(name) != null || withSubfolder) {
553: name = ""; // NOI18N
554: }
555: }
556:
557: system = new WeakReference<FileSystem>(fs);
558:
559: n = NodeOp.findPath(rootNode, NbCollections
560: .checkedEnumerationByFilter(st, String.class,
561: true));
562:
563: exact = true;
564:
565: } catch (FileStateInvalidException ex) {
566: // invalid state of file system => back to root
567: n = rootNode;
568: name = ""; // NOI18N
569: exact = false;
570: } catch (NodeNotFoundException ex) {
571: n = ex.getClosestNode();
572: DataFolder df = (DataFolder) n
573: .getCookie(DataFolder.class);
574: if (df != null) {
575: name = df.getPrimaryFile().getPath();
576: } else {
577: name = ""; // NO-I18N // NOI18N
578: }
579: exact = false;
580: }
581:
582: } else {
583: // null folder => use root
584: n = rootNode;
585: name = null;
586: exact = true;
587: }
588:
589: // remove listener + do change + add listener
590: ExplorerManager em = packagesPanel.getExplorerManager();
591: em.removePropertyChangeListener(this );
592: packageName.getDocument().removeDocumentListener(this );
593:
594: try {
595: em.setSelectedNodes(new Node[] { n });
596: } catch (PropertyVetoException ex) {
597: throw new InternalError();
598: }
599:
600: packageName.setText(name);
601: updateDirectory();
602:
603: packageName.getDocument().addDocumentListener(this );
604: em.addPropertyChangeListener(this );
605:
606: fireStateChanged();
607:
608: return exact;
609: }
610:
611: /** Getter for target folder. If the folder does not
612: * exists it is created at this point.
613: * @param create true if the target folder should be created.
614: * @return the target folder
615: * @exception IOException if the possible creation of the folder fails
616: */
617: private DataFolder getTargetFolder(boolean create)
618: throws IOException {
619: if (create && isValid()) {
620: FileSystem fs = system.get();
621: if (fs != null) {
622: DataFolder folder = DataFolder.findFolder(fs.getRoot());
623: String currentName = packageName.getText().replace(
624: '\\', '/');
625: if (currentName.length() > 0) {
626: folder = DataFolder.create(folder, currentName);
627: }
628: df = folder;
629: return folder;
630: }
631: }
632: return df;
633: }
634:
635: /** Presets a target folder.
636: * @param f the name of target folder
637: * @return true if succeeded
638: */
639: private boolean setTargetFolder(final String f, boolean afterDelete) {
640: Node n = null;
641: NodeNotFoundException closest = null;
642:
643: // first of all test the currently selected nod
644: // for location of closest
645: java.util.Collection<Node> selected = new java.util.HashSet<Node>();
646: Node[] nodes = packagesPanel.getExplorerManager()
647: .getSelectedNodes();
648: for (int i = 0; i < nodes.length; i++) {
649: Node n1 = nodes[i];
650: if (n1.getParentNode() == null) {
651: continue;
652: }
653: while (n1.getParentNode().getParentNode() != null)
654: n1 = n1.getParentNode();
655: selected.add(n1);
656: }
657:
658: StringTokenizer st = new StringTokenizer(f,
659: PATH_TOKEN_DELIMITER);
660:
661: try {
662: n = NodeOp
663: .findPath(rootNode, NbCollections
664: .checkedEnumerationByFilter(st,
665: String.class, true));
666: } catch (NodeNotFoundException ex) {
667: if (!st.hasMoreElements()) {
668: // a test for !hasMoreElements is here to be sure that
669: // all tokens has been read, so only the last item
670: // has not been found
671:
672: // check whether we can continue from the nod
673: final String sugg = computeSuggestion(ex
674: .getClosestNode(), ex.getMissingChildName(),
675: null);
676:
677: if (sugg != null) {
678: // if we can go on and there has been no suggestion o
679: // this is the current filesystem => go o
680: closest = ex;
681: }
682: }
683: }
684:
685: if (n != null) {
686: // closest node not used
687: closest = null;
688: } else {
689:
690: if (closest == null) {
691: // the node has not been even found
692: return false;
693: }
694:
695: // we will select the closest node found - old version
696: n = closest.getClosestNode();
697:
698: // new - try to build shadow nodes hierarchy
699:
700: }
701:
702: // remove listener + do change + add listener
703: ExplorerManager em = packagesPanel.getExplorerManager();
704: em.removePropertyChangeListener(this );
705:
706: // change the text if we want to add suggestion
707: if (closest != null) {
708: Node[] first = new Node[1];
709: String sugg = computeSuggestion(closest.getClosestNode(),
710: closest.getMissingChildName(), first);
711:
712: if (afterDelete && sugg != null
713: && sugg.equals(last_suggestion))
714: sugg = null;
715:
716: last_suggestion = sugg;
717: if (sugg != null) {
718: packageName.getDocument().removeDocumentListener(
719: DataFolderPanel.this );
720:
721: packageName.setText(f + sugg);
722: updateDirectory();
723:
724: javax.swing.text.Caret c = packageName.getCaret();
725: c.setDot(f.length() + sugg.length());
726: c.moveDot(f.length());
727:
728: packageName.getDocument().addDocumentListener(
729: DataFolderPanel.this );
730: }
731:
732: if (first[0] != null) {
733: // show the first node that fits
734: n = first[0];
735: }
736: }
737:
738: // change the node
739: try {
740: em.setSelectedNodes(new Node[] { n });
741: //beanTreeView.selectionChanged(new Node[] { n }, em);
742: } catch (PropertyVetoException ex) {
743: throw new InternalError();
744: }
745:
746: // change the selected filesystem
747: df = (DataFolder) n.getCookie(DataFolder.class);
748: if (df != null) {
749: try {
750: FileSystem fs = df.getPrimaryFile().getFileSystem();
751: system = new WeakReference<FileSystem>(fs);
752: } catch (FileStateInvalidException ex) {
753: }
754: }
755:
756: em.addPropertyChangeListener(this );
757:
758: fireStateChanged();
759:
760: return closest == null;
761: }
762:
763: /** Updates directory name
764: */
765: void updateDirectory() {
766: FileSystem fs = system.get();
767: if (fs == null) {
768: // No known directory?? Leave it blank.
769: directoryName.setText(""); // NOI18N
770: return;
771: }
772: String name = packageName.getText();
773: FileObject folder = fs.findResource(name);
774: if (folder != null) {
775: File f = FileUtil.toFile(folder);
776: if (f != null) {
777: // A folder is selected which exists on disk.
778: directoryName.setText(f.getAbsolutePath());
779: } else {
780: // A folder is selected which is nowhere on disk (e.g. in a JAR).
781: directoryName.setText(""); // NOI18N
782: }
783: } else {
784: FileObject fo = fs.getRoot();
785: assert fo != null : fs;
786: File f = FileUtil.toFile(fo);
787: if (f != null) {
788: // The folder does not really exist, but the FS root does
789: // exist on disk. Guess that the resulting file name will
790: // be derived simply from the folder of the root (not always
791: // true, note).
792: File f2 = new File(f, name.replace('/',
793: File.separatorChar)); // NOI18N
794: directoryName.setText(f2.getAbsolutePath());
795: } else {
796: // The folder has not been made, and even if it were, the FS
797: // root is not on disk anyway. Leave it blank.
798: directoryName.setText(""); // NOI18N
799: }
800: }
801: }
802:
803: // bugfix #29401, correct notify all changes in data folders
804: private void implSetDataFolder(DataFolder df) {
805: if (editor != null) {
806: if (!isValid()) {
807: editor.setDataFolder(null);
808: } else {
809: FileSystem fs = null;
810: if (system != null) {
811: fs = system.get();
812: }
813: if (df == null && fs != null) {
814: FileObject fo = fs.getRoot();
815: //issue 34896, for whatever reason the root is sometimes null
816: if (fo != null) {
817: df = DataFolder.findFolder(fo);
818: }
819: }
820: if (df != null) {
821: String name = df.getPrimaryFile().getPath();
822: if (name.equals(packageName.getText())) {
823: editor.setDataFolder(df);
824: } else {
825: editor.setDataFolder(null);
826: }
827: } else {
828: editor.setDataFolder(null);
829: }
830: }
831: }
832: }
833:
834: /** Updates associated editor by calling setDataFolder(...) . */
835: void updatePropertyEditor() {
836: try {
837: DataFolder newF = getTargetFolder(false);
838: //fix for issue 31434, DataFolder may be null if
839: //user used the search popup in the target folder tree
840: implSetDataFolder(newF);
841: } catch (IOException ex) {
842: Exceptions.printStackTrace(ex);
843: }
844: }
845:
846: /** Sets the state of the createButton */
847: void enableCreateButton() {
848: String name = null;
849: if (df != null) {
850: name = df.getPrimaryFile().getPath();
851: } else {
852: name = ""; // NOI18N
853: }
854: if (name.equals(packageName.getText())) {
855: // nothing to create
856: createButton.setEnabled(false);
857: } else {
858: createButton.setEnabled(isValid());
859: }
860: }
861:
862: /** Get the customized property value.
863: * @return the property value
864: * @exception InvalidStateException when the custom property editor does not contain a valid property value
865: * (and thus it should not be set)
866: */
867: private Object getPropertyValue() throws IllegalStateException {
868: if (isValid()) {
869: try {
870: df = getTargetFolder(true);
871: return df;
872: } catch (IOException x) {
873: Exceptions.printStackTrace(x);
874: throw new IllegalStateException();
875: }
876: } else {
877: throw new IllegalStateException();
878: }
879: }
880:
881: public static class ShadowDirNode extends AbstractNode {
882: public ShadowDirNode(Children children) {
883: super (children);
884: }
885: }
886:
887: public static class ShadowLeafNode extends AbstractNode {
888: public ShadowLeafNode() {
889: super (Children.LEAF);
890: }
891: }
892:
893: private static String getString(String s) {
894: return org.openide.util.NbBundle.getBundle(
895: DataFolderPanel.class).getString(s);
896: }
897: }
|