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.modules.project.libraries.ui;
043:
044: import java.awt.Dialog;
045: import java.awt.Dimension;
046: import java.awt.EventQueue;
047: import java.awt.GridBagConstraints;
048: import java.awt.GridBagLayout;
049: import java.awt.Image;
050: import java.awt.event.ActionEvent;
051: import java.awt.event.ActionListener;
052: import java.beans.Customizer;
053: import java.beans.PropertyChangeEvent;
054: import java.beans.PropertyChangeListener;
055: import java.beans.PropertyVetoException;
056: import java.beans.VetoableChangeListener;
057: import java.io.IOException;
058: import java.net.URL;
059: import java.text.Collator;
060: import java.util.ArrayList;
061: import java.util.Collection;
062: import java.util.Collections;
063: import java.util.Comparator;
064: import java.util.List;
065: import java.util.MissingResourceException;
066: import java.util.ResourceBundle;
067: import javax.swing.JComponent;
068: import javax.swing.JPanel;
069: import javax.swing.event.ChangeEvent;
070: import javax.swing.event.ChangeListener;
071: import org.netbeans.modules.project.libraries.LibraryTypeRegistry;
072: import org.netbeans.spi.project.libraries.LibraryImplementation;
073: import org.netbeans.spi.project.libraries.LibraryStorageArea;
074: import org.netbeans.spi.project.libraries.LibraryTypeProvider;
075: import org.openide.DialogDescriptor;
076: import org.openide.DialogDisplayer;
077: import org.openide.ErrorManager;
078: import org.openide.NotifyDescriptor;
079: import org.openide.explorer.ExplorerManager;
080: import org.openide.explorer.view.BeanTreeView;
081: import org.openide.filesystems.Repository;
082: import org.openide.loaders.DataFolder;
083: import org.openide.nodes.AbstractNode;
084: import org.openide.nodes.Children;
085: import org.openide.nodes.Node;
086: import org.openide.nodes.NodeNotFoundException;
087: import org.openide.nodes.NodeOp;
088: import org.openide.util.HelpCtx;
089: import org.openide.util.NbBundle;
090: import org.openide.util.Utilities;
091: import org.openide.util.lookup.Lookups;
092:
093: public final class LibrariesCustomizer extends JPanel implements
094: ExplorerManager.Provider, HelpCtx.Provider {
095:
096: private ExplorerManager manager;
097: private LibrariesModel model;
098: private BeanTreeView libraries;
099: private LibraryStorageArea libraryStorageArea;
100:
101: public LibrariesCustomizer(LibraryStorageArea libraryStorageArea) {
102: this .model = new LibrariesModel();
103: this .libraryStorageArea = (libraryStorageArea != null ? libraryStorageArea
104: : LibrariesModel.GLOBAL_AREA);
105: initComponents();
106: postInitComponents();
107: expandTree();
108: }
109:
110: private void expandTree() {
111: // get first library node
112: Node[] n = getExplorerManager().getRootContext().getChildren()
113: .getNodes()[0].getChildren().getNodes();
114: if (n.length != 0) {
115: try {
116: getExplorerManager().setSelectedNodes(
117: new Node[] { n[0] });
118: } catch (PropertyVetoException ex) {
119: // OK to ignore - it is just selection initialization
120: }
121: }
122: }
123:
124: public void setLibraryStorageArea(
125: LibraryStorageArea libraryStorageArea) {
126: this .libraryStorageArea = (libraryStorageArea != null ? libraryStorageArea
127: : LibrariesModel.GLOBAL_AREA);
128: forceTreeRecreation();
129: expandTree();
130: }
131:
132: public LibrariesModel getModel() {
133: return model;
134: }
135:
136: public void hideLibrariesList() {
137: libsPanel.setVisible(false);
138: jLabel2.setVisible(false);
139: createButton.setVisible(false);
140: deleteButton.setVisible(false);
141: }
142:
143: /**
144: * Force nodes recreation after LibrariesModel change. The nodes listen on
145: * model and eventually refresh themselves but usually it is too late.
146: * So forcing recreation makes sure that any subsequent call to
147: * NodeOp.findPath is successful and selects just created library node.
148: */
149: public void forceTreeRecreation() {
150: getExplorerManager().setRootContext(buildTree());
151: }
152:
153: public void setSelectedLibrary(LibraryImplementation library) {
154: if (library == null)
155: return;
156: ExplorerManager currentManager = this .getExplorerManager();
157: Node root = currentManager.getRootContext();
158: String[] path = { library.getType(), library.getName() };
159: try {
160: Node node = NodeOp.findPath(root, path);
161: if (node != null) {
162: currentManager.setSelectedNodes(new Node[] { node });
163: }
164: } catch (NodeNotFoundException e) {
165: //Ignore it
166: } catch (PropertyVetoException e) {
167: //Ignore it
168: }
169: }
170:
171: public HelpCtx getHelpCtx() {
172: return new HelpCtx(LibrariesCustomizer.class);
173: }
174:
175: public boolean apply() {
176: try {
177: this .model.apply();
178: return true;
179: } catch (IOException ioe) {
180: ErrorManager.getDefault().notify(ioe);
181: return false;
182: }
183: }
184:
185: public void addNotify() {
186: super .addNotify();
187: expandAllNodes(this .libraries, this .getExplorerManager()
188: .getRootContext());
189: //Select first library if nothing selected
190: if (this .getExplorerManager().getSelectedNodes().length == 0) {
191: SELECTED: for (Node areaNode : getExplorerManager()
192: .getRootContext().getChildren().getNodes(true)) {
193: for (Node typeNode : areaNode.getChildren().getNodes(
194: true)) {
195: for (Node libNode : typeNode.getChildren()
196: .getNodes(true)) {
197: try {
198: getExplorerManager().setSelectedNodes(
199: new Node[] { libNode });
200: } catch (PropertyVetoException e) {
201: //Ignore it
202: }
203: break SELECTED;
204: }
205: }
206: }
207: }
208: this .libraries.requestFocus();
209: }
210:
211: public ExplorerManager getExplorerManager() {
212: if (this .manager == null) {
213: this .manager = new ExplorerManager();
214: this .manager
215: .addPropertyChangeListener(new PropertyChangeListener() {
216: public void propertyChange(
217: PropertyChangeEvent event) {
218: if (ExplorerManager.PROP_SELECTED_NODES
219: .equals(event.getPropertyName())) {
220: Node[] nodes = (Node[]) event
221: .getNewValue();
222: selectLibrary(nodes);
223: libraries.requestFocus();
224: }
225: }
226: });
227: this .manager
228: .addVetoableChangeListener(new VetoableChangeListener() {
229: public void vetoableChange(
230: PropertyChangeEvent event)
231: throws PropertyVetoException {
232: if (ExplorerManager.PROP_SELECTED_NODES
233: .equals(event.getPropertyName())) {
234: Node[] nodes = (Node[]) event
235: .getNewValue();
236: if (nodes.length <= 1) {
237: return;
238: } else {
239: throw new PropertyVetoException(
240: "Invalid length", event); //NOI18N
241: }
242: }
243: }
244: });
245: manager.setRootContext(buildTree());
246: }
247: return this .manager;
248: }
249:
250: private void postInitComponents() {
251: this .libraries = new LibrariesView();
252: GridBagConstraints c = new GridBagConstraints();
253: c.gridx = GridBagConstraints.RELATIVE;
254: c.gridy = GridBagConstraints.RELATIVE;
255: c.gridwidth = GridBagConstraints.REMAINDER;
256: c.gridheight = GridBagConstraints.REMAINDER;
257: c.fill = GridBagConstraints.BOTH;
258: c.anchor = GridBagConstraints.NORTHWEST;
259: c.weightx = 1.0;
260: c.weighty = 1.0;
261: ((GridBagLayout) this .libsPanel.getLayout()).setConstraints(
262: this .libraries, c);
263: this .libsPanel.add(this .libraries);
264: this .libraries.setPreferredSize(new Dimension(200, 334));
265: this .libraryName.setColumns(25);
266: this .libraryName.setEnabled(false);
267: this .libraryName.addActionListener(new ActionListener() {
268: public void actionPerformed(ActionEvent e) {
269: nameChanged();
270: }
271: });
272: }
273:
274: private void nameChanged() {
275: Node[] nodes = this .getExplorerManager().getSelectedNodes();
276: if (nodes.length == 1) {
277: LibraryImplementation lib = nodes[0].getLookup().lookup(
278: LibraryImplementation.class);
279: if (lib == null) {
280: return;
281: }
282: String newName = this .libraryName.getText();
283: if (newName.equals(lib.getName())) {
284: return;
285: }
286: if (newName.length() == 0) {
287: DialogDisplayer.getDefault().notify(
288: new NotifyDescriptor.Message(NbBundle
289: .getMessage(LibrariesCustomizer.class,
290: "ERR_InvalidName"),
291: NotifyDescriptor.ERROR_MESSAGE));
292: } else if (isValidName(model, newName, model.getArea(lib))) {
293: lib.setName(newName);
294: } else {
295: DialogDisplayer.getDefault().notify(
296: new NotifyDescriptor.Message(NbBundle
297: .getMessage(LibrariesCustomizer.class,
298: "ERR_ExistingName", newName),
299: NotifyDescriptor.ERROR_MESSAGE));
300: }
301: }
302: }
303:
304: private void selectLibrary(Node[] nodes) {
305: int tabCount = this .properties.getTabCount();
306: for (int i = 0; i < tabCount; i++) {
307: this .properties.removeTabAt(0);
308: }
309: this .libraryName.setEnabled(false);
310: this .libraryName.setText(""); //NOI18N
311: this .jLabel1.setVisible(false);
312: this .libraryName.setVisible(false);
313: this .properties.setVisible(false);
314: this .deleteButton.setEnabled(false);
315: if (nodes.length != 1) {
316: return;
317: }
318: LibraryImplementation impl = nodes[0].getLookup().lookup(
319: LibraryImplementation.class);
320: if (impl == null) {
321: return;
322: }
323: this .jLabel1.setVisible(true);
324: this .libraryName.setVisible(true);
325: this .properties.setVisible(true);
326: boolean editable = model.isLibraryEditable(impl);
327: this .libraryName.setEnabled(editable);
328: this .deleteButton.setEnabled(editable);
329: this .libraryName.setText(getLocalizedString(impl
330: .getLocalizingBundle(), impl.getName()));
331: LibraryTypeProvider provider = nodes[0].getLookup().lookup(
332: LibraryTypeProvider.class);
333: if (provider == null)
334: return;
335: // a library customizer needs to know location of sharable library in order to
336: // relativize paths. that's why object implementing both LibraryImplementation
337: // and LibraryStorageArea is passed to JComponent here:
338: LibraryStorageArea area = nodes[0].getLookup().lookup(
339: LibraryStorageArea.class);
340: if (area != null && area != LibrariesModel.GLOBAL_AREA) {
341: impl = new LibraryImplementationWrapper(impl, area);
342: }
343:
344: String[] volumeTypes = provider.getSupportedVolumeTypes();
345: for (int i = 0; i < volumeTypes.length; i++) {
346: Customizer c = provider.getCustomizer(volumeTypes[i]);
347: if (c instanceof JComponent) {
348: c.setObject(impl);
349: JComponent component = (JComponent) c;
350: component.setEnabled(editable);
351: String tabName = component.getName();
352: if (tabName == null) {
353: tabName = volumeTypes[i];
354: }
355: this .properties.addTab(tabName, component);
356: }
357: }
358: }
359:
360: /** This method is called from within the constructor to
361: * initialize the form.
362: * WARNING: Do NOT modify this code. The content of this method is
363: * always regenerated by the Form Editor.
364: */
365: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
366: private void initComponents() {
367: java.awt.GridBagConstraints gridBagConstraints;
368:
369: jLabel1 = new javax.swing.JLabel();
370: libraryName = new javax.swing.JTextField();
371: jPanel1 = new javax.swing.JPanel();
372: properties = new javax.swing.JTabbedPane();
373: createButton = new javax.swing.JButton();
374: deleteButton = new javax.swing.JButton();
375: libsPanel = new javax.swing.JPanel();
376: jLabel2 = new javax.swing.JLabel();
377:
378: setMinimumSize(new java.awt.Dimension(642, 395));
379: setLayout(new java.awt.GridBagLayout());
380:
381: jLabel1.setLabelFor(libraryName);
382: java.util.ResourceBundle bundle = java.util.ResourceBundle
383: .getBundle("org/netbeans/modules/project/libraries/ui/Bundle"); // NOI18N
384: org.openide.awt.Mnemonics.setLocalizedText(jLabel1, bundle
385: .getString("CTL_CustomizerLibraryName")); // NOI18N
386: gridBagConstraints = new java.awt.GridBagConstraints();
387: gridBagConstraints.gridx = 3;
388: gridBagConstraints.gridy = 1;
389: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
390: gridBagConstraints.insets = new java.awt.Insets(0, 6, 12, 6);
391: add(jLabel1, gridBagConstraints);
392:
393: libraryName.setEditable(false);
394: gridBagConstraints = new java.awt.GridBagConstraints();
395: gridBagConstraints.gridx = 4;
396: gridBagConstraints.gridy = 1;
397: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
398: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
399: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
400: gridBagConstraints.weightx = 0.6;
401: gridBagConstraints.insets = new java.awt.Insets(0, 0, 12, 0);
402: add(libraryName, gridBagConstraints);
403: libraryName.getAccessibleContext().setAccessibleDescription(
404: bundle.getString("AD_LibraryName")); // NOI18N
405:
406: jPanel1.setLayout(new java.awt.BorderLayout());
407:
408: properties.setPreferredSize(new java.awt.Dimension(400, 300));
409: jPanel1.add(properties, java.awt.BorderLayout.CENTER);
410: properties.getAccessibleContext().setAccessibleName(
411: bundle.getString("AN_LibrariesCustomizerProperties")); // NOI18N
412: properties.getAccessibleContext().setAccessibleDescription(
413: bundle.getString("AD_LibrariesCustomizerProperties")); // NOI18N
414:
415: gridBagConstraints = new java.awt.GridBagConstraints();
416: gridBagConstraints.gridx = 3;
417: gridBagConstraints.gridy = 2;
418: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
419: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
420: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
421: gridBagConstraints.weightx = 1.0;
422: gridBagConstraints.weighty = 1.0;
423: gridBagConstraints.insets = new java.awt.Insets(0, 6, 12, 0);
424: add(jPanel1, gridBagConstraints);
425:
426: org.openide.awt.Mnemonics.setLocalizedText(createButton, bundle
427: .getString("CTL_NewLibrary")); // NOI18N
428: createButton
429: .addActionListener(new java.awt.event.ActionListener() {
430: public void actionPerformed(
431: java.awt.event.ActionEvent evt) {
432: createLibrary(evt);
433: }
434: });
435: gridBagConstraints = new java.awt.GridBagConstraints();
436: gridBagConstraints.gridx = 0;
437: gridBagConstraints.gridy = 3;
438: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
439: gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
440: add(createButton, gridBagConstraints);
441: createButton.getAccessibleContext().setAccessibleDescription(
442: bundle.getString("AD_NewLibrary")); // NOI18N
443:
444: org.openide.awt.Mnemonics.setLocalizedText(deleteButton, bundle
445: .getString("CTL_DeleteLibrary")); // NOI18N
446: deleteButton
447: .addActionListener(new java.awt.event.ActionListener() {
448: public void actionPerformed(
449: java.awt.event.ActionEvent evt) {
450: deleteLibrary(evt);
451: }
452: });
453: gridBagConstraints = new java.awt.GridBagConstraints();
454: gridBagConstraints.gridx = 1;
455: gridBagConstraints.gridy = 3;
456: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
457: gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
458: add(deleteButton, gridBagConstraints);
459: deleteButton.getAccessibleContext().setAccessibleDescription(
460: bundle.getString("AD_DeleteLibrary")); // NOI18N
461:
462: libsPanel.setBorder(javax.swing.BorderFactory
463: .createEtchedBorder());
464: libsPanel.setLayout(new java.awt.GridBagLayout());
465: gridBagConstraints = new java.awt.GridBagConstraints();
466: gridBagConstraints.gridx = 0;
467: gridBagConstraints.gridy = 1;
468: gridBagConstraints.gridwidth = 3;
469: gridBagConstraints.gridheight = 2;
470: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
471: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
472: gridBagConstraints.weighty = 1.0;
473: gridBagConstraints.insets = new java.awt.Insets(0, 0, 12, 6);
474: add(libsPanel, gridBagConstraints);
475: libsPanel.getAccessibleContext().setAccessibleDescription(
476: bundle.getString("AD_libsPanel")); // NOI18N
477:
478: jLabel2.setLabelFor(libsPanel);
479: org.openide.awt.Mnemonics.setLocalizedText(jLabel2, bundle
480: .getString("TXT_LibrariesPanel")); // NOI18N
481: gridBagConstraints = new java.awt.GridBagConstraints();
482: gridBagConstraints.gridx = 0;
483: gridBagConstraints.gridy = 0;
484: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
485: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
486: gridBagConstraints.insets = new java.awt.Insets(0, 0, 2, 12);
487: add(jLabel2, gridBagConstraints);
488:
489: getAccessibleContext().setAccessibleDescription(
490: bundle.getString("AD_LibrariesCustomizer")); // NOI18N
491: }// </editor-fold>//GEN-END:initComponents
492:
493: private void deleteLibrary(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteLibrary
494: Node[] nodes = this .getExplorerManager().getSelectedNodes();
495: if (nodes.length == 1) {
496: LibraryImplementation library = nodes[0].getLookup()
497: .lookup(LibraryImplementation.class);
498: if (library == null) {
499: return;
500: }
501: Node[] sib = nodes[0].getParentNode().getChildren()
502: .getNodes(true);
503: Node selNode = null;
504: for (int i = 0; i < sib.length; i++) {
505: if (nodes[0].equals(sib[i])) {
506: if (i > 0) {
507: selNode = sib[i - 1];
508: } else if (i < sib.length - 1) {
509: selNode = sib[i + 1];
510: }
511: }
512: }
513: model.removeLibrary(library);
514: try {
515: if (selNode != null) {
516: this .getExplorerManager().setSelectedNodes(
517: new Node[] { selNode });
518: }
519: } catch (PropertyVetoException e) {
520: //Ignore it
521: }
522: this .libraries.requestFocus();
523: }
524: }//GEN-LAST:event_deleteLibrary
525:
526: private void createLibrary(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createLibrary
527: Dialog dlg = null;
528: try {
529: String preselectedLibraryType = null;
530: LibraryStorageArea area = null;
531: Node[] preselectedNodes = this .getExplorerManager()
532: .getSelectedNodes();
533: if (preselectedNodes.length == 1) {
534: LibraryTypeProvider provider = preselectedNodes[0]
535: .getLookup().lookup(LibraryTypeProvider.class);
536: if (provider != null) {
537: preselectedLibraryType = provider.getLibraryType();
538: }
539: area = preselectedNodes[0].getLookup().lookup(
540: LibraryStorageArea.class);
541: }
542: if (area == null) {
543: area = LibrariesModel.GLOBAL_AREA;
544: }
545: NewLibraryPanel p = new NewLibraryPanel(model,
546: preselectedLibraryType, area);
547: DialogDescriptor dd = new DialogDescriptor(p, NbBundle
548: .getMessage(LibrariesCustomizer.class,
549: "CTL_CreateLibrary"), true,
550: DialogDescriptor.OK_CANCEL_OPTION, null, null);
551: p.setDialogDescriptor(dd);
552: dlg = DialogDisplayer.getDefault().createDialog(dd);
553: dlg.setVisible(true);
554: if (dd.getValue() == DialogDescriptor.OK_OPTION) {
555: String libraryType = p.getLibraryType();
556: String currentLibraryName = p.getLibraryName();
557: LibraryImplementation impl;
558: if (area != LibrariesModel.GLOBAL_AREA) {
559: impl = model.createArealLibrary(libraryType,
560: currentLibraryName, area);
561: } else {
562: LibraryTypeProvider provider = LibraryTypeRegistry
563: .getDefault().getLibraryTypeProvider(
564: libraryType);
565: if (provider == null) {
566: return;
567: }
568: impl = provider.createLibrary();
569: impl.setName(currentLibraryName);
570: }
571: model.addLibrary(impl);
572: forceTreeRecreation();
573: String[] path = { impl.getType(), impl.getName() };
574: ExplorerManager mgr = this .getExplorerManager();
575: try {
576: Node node = NodeOp.findPath(mgr.getRootContext(),
577: path);
578: if (node != null) {
579: mgr.setSelectedNodes(new Node[] { node });
580: }
581: } catch (PropertyVetoException e) {
582: //Ignore it
583: } catch (NodeNotFoundException e) {
584: //Ignore it
585: }
586: this .libraryName.requestFocus();
587: this .libraryName.selectAll();
588: } else {
589: this .libraries.requestFocus();
590: }
591: } finally {
592: if (dlg != null)
593: dlg.dispose();
594: }
595: }//GEN-LAST:event_createLibrary
596:
597: static boolean isValidName(LibrariesModel model, String name,
598: LibraryStorageArea area) {
599: for (LibraryImplementation lib : model.getLibraries()) {
600: if (lib.getName().equals(name)
601: && Utilities.compareObjects(model.getArea(lib),
602: area)) {
603: return false;
604: }
605: }
606: return true;
607: }
608:
609: static String getLocalizedString(String bundleResourceName,
610: String key) {
611: if (key == null) {
612: return null;
613: }
614: if (bundleResourceName == null) {
615: return key;
616: }
617: ResourceBundle bundle;
618: try {
619: bundle = NbBundle.getBundle(bundleResourceName);
620: } catch (MissingResourceException mre) {
621: // Bundle should have existed.
622: ErrorManager.getDefault().notify(
623: ErrorManager.INFORMATIONAL, mre);
624: return key;
625: }
626: try {
627: return bundle.getString(key);
628: } catch (MissingResourceException mre) {
629: // No problem, not specified.
630: return key;
631: }
632: }
633:
634: // Variables declaration - do not modify//GEN-BEGIN:variables
635: private javax.swing.JButton createButton;
636: private javax.swing.JButton deleteButton;
637: private javax.swing.JLabel jLabel1;
638: private javax.swing.JLabel jLabel2;
639: private javax.swing.JPanel jPanel1;
640: private javax.swing.JTextField libraryName;
641: private javax.swing.JPanel libsPanel;
642: private javax.swing.JTabbedPane properties;
643:
644: // End of variables declaration//GEN-END:variables
645:
646: private static void expandAllNodes(BeanTreeView btv, Node node) {
647: btv.expandNode(node);
648: Children ch = node.getChildren();
649: if (ch == Children.LEAF) {
650: return;
651: }
652: Node nodes[] = ch.getNodes(true);
653: for (int i = 0; i < nodes.length; i++) {
654: expandAllNodes(btv, nodes[i]);
655: }
656:
657: }
658:
659: private static class LibrariesView extends BeanTreeView {
660:
661: public LibrariesView() {
662: super ();
663: this .setRootVisible(false);
664: this .setPopupAllowed(false);
665: this .setDefaultActionAllowed(false);
666: this .tree.setEditable(false);
667: this .tree.setShowsRootHandles(false);
668: }
669:
670: }
671:
672: private class AreaChildren extends
673: Children.Keys<LibraryStorageArea> implements ChangeListener {
674:
675: @Override
676: protected void addNotify() {
677: super .addNotify();
678: model.addChangeListener(this );
679: computeKeys();
680: }
681:
682: @Override
683: protected void removeNotify() {
684: super .removeNotify();
685: model.removeChangeListener(this );
686: setKeys(Collections.<LibraryStorageArea> emptySet());
687: }
688:
689: private void computeKeys() {
690: setKeys(getSortedAreas(model));
691: }
692:
693: protected Node[] createNodes(LibraryStorageArea area) {
694: return new Node[] { new AreaNode(area) };
695: }
696:
697: public void stateChanged(ChangeEvent e) {
698: EventQueue.invokeLater(new Runnable() {
699: public void run() {
700: computeKeys();
701: }
702: });
703: }
704:
705: }
706:
707: static Collection<? extends LibraryStorageArea> getSortedAreas(
708: LibrariesModel model) {
709: List<LibraryStorageArea> areas = new ArrayList<LibraryStorageArea>(
710: model.getAreas());
711: Collections.sort(areas, new Comparator<LibraryStorageArea>() {
712: Collator COLL = Collator.getInstance();
713:
714: public int compare(LibraryStorageArea a1,
715: LibraryStorageArea a2) {
716: return COLL.compare(a1.getDisplayName(), a2
717: .getDisplayName());
718: }
719: });
720: areas.add(0, LibrariesModel.GLOBAL_AREA);
721: assert !areas.contains(null);
722: return areas;
723: }
724:
725: private final class AreaNode extends AbstractNode {
726:
727: private final LibraryStorageArea area;
728:
729: AreaNode(LibraryStorageArea area) {
730: super (new TypeChildren(area), Lookups.singleton(area));
731: this .area = area;
732: }
733:
734: @Override
735: public String getName() {
736: return getDisplayName();
737: }
738:
739: @Override
740: public String getDisplayName() {
741: return area.getDisplayName();
742: }
743:
744: private Node delegate() {
745: return DataFolder.findFolder(
746: Repository.getDefault().getDefaultFileSystem()
747: .getRoot()).getNodeDelegate();
748: }
749:
750: public Image getIcon(int type) {
751: return delegate().getIcon(type);
752: }
753:
754: public Image getOpenedIcon(int type) {
755: return delegate().getOpenedIcon(type);
756: }
757:
758: }
759:
760: private class TypeChildren extends
761: Children.Keys<LibraryTypeProvider> {
762:
763: private final LibraryStorageArea area;
764:
765: TypeChildren(LibraryStorageArea area) {
766: this .area = area;
767: }
768:
769: public void addNotify() {
770: // Could also filter by area (would then need to listen to model too)
771: this .setKeys(LibraryTypeRegistry.getDefault()
772: .getLibraryTypeProviders());
773: }
774:
775: public void removeNotify() {
776: this .setKeys(new LibraryTypeProvider[0]);
777: }
778:
779: protected Node[] createNodes(LibraryTypeProvider provider) {
780: return new Node[] { new CategoryNode(provider, area) };
781: }
782:
783: }
784:
785: private class CategoryNode extends AbstractNode {
786:
787: private LibraryTypeProvider provider;
788: private Node iconDelegate;
789:
790: public CategoryNode(LibraryTypeProvider provider,
791: LibraryStorageArea area) {
792: super (new CategoryChildren(provider, area), Lookups.fixed(
793: provider, area));
794: this .provider = provider;
795: this .iconDelegate = DataFolder.findFolder(
796: Repository.getDefault().getDefaultFileSystem()
797: .getRoot()).getNodeDelegate();
798: }
799:
800: public String getName() {
801: return provider.getLibraryType();
802: }
803:
804: public String getDisplayName() {
805: return this .provider.getDisplayName();
806: }
807:
808: public Image getIcon(int type) {
809: return this .iconDelegate.getIcon(type);
810: }
811:
812: public Image getOpenedIcon(int type) {
813: return this .iconDelegate.getOpenedIcon(type);
814: }
815:
816: }
817:
818: private class CategoryChildren extends
819: Children.Keys<LibraryImplementation> implements
820: ChangeListener {
821:
822: private LibraryTypeProvider provider;
823: private final LibraryStorageArea area;
824:
825: public CategoryChildren(LibraryTypeProvider provider,
826: LibraryStorageArea area) {
827: this .provider = provider;
828: this .area = area;
829: model.addChangeListener(this );
830: }
831:
832: public void addNotify() {
833: Collection<LibraryImplementation> keys = new ArrayList<LibraryImplementation>();
834: for (LibraryImplementation impl : model.getLibraries()) {
835: if (provider.getLibraryType().equals(impl.getType())
836: && model.getArea(impl).equals(area)) {
837: keys.add(impl);
838: }
839: }
840: this .setKeys(keys);
841: }
842:
843: public void removeNotify() {
844: this .setKeys(new LibraryImplementation[0]);
845: }
846:
847: protected Node[] createNodes(LibraryImplementation impl) {
848: return new Node[] { new LibraryNode(impl, provider, area) };
849: }
850:
851: public void stateChanged(ChangeEvent e) {
852: EventQueue.invokeLater(new Runnable() {
853: public void run() {
854: addNotify();
855: }
856: });
857: }
858:
859: }
860:
861: private static class LibraryNode extends AbstractNode {
862:
863: private static final String ICON = "org/netbeans/modules/project/libraries/resources/libraries.gif"; //NOI18N
864:
865: private LibraryImplementation lib;
866: private LibraryTypeProvider provider;
867:
868: public LibraryNode(LibraryImplementation lib,
869: LibraryTypeProvider provider, LibraryStorageArea area) {
870: super (Children.LEAF, Lookups.fixed(lib, provider, area));
871: this .lib = lib;
872: this .provider = provider;
873: this .setIconBaseWithExtension(ICON);
874: }
875:
876: public String getName() {
877: return this .lib.getName();
878: }
879:
880: public String getDisplayName() {
881: return getLocalizedString(this .lib.getLocalizingBundle(),
882: this .lib.getName());
883: }
884:
885: }
886:
887: private Node buildTree() {
888: return new AbstractNode(new TypeChildren(libraryStorageArea));
889: }
890:
891: private static class LibraryImplementationWrapper implements
892: LibraryImplementation, LibraryStorageArea {
893:
894: private LibraryImplementation lib;
895: private LibraryStorageArea area;
896:
897: public LibraryImplementationWrapper(LibraryImplementation lib,
898: LibraryStorageArea area) {
899: this .lib = lib;
900: this .area = area;
901: }
902:
903: public String getType() {
904: return lib.getType();
905: }
906:
907: public String getName() {
908: return lib.getName();
909: }
910:
911: public String getDescription() {
912: return lib.getDescription();
913: }
914:
915: public String getLocalizingBundle() {
916: return lib.getLocalizingBundle();
917: }
918:
919: public List<URL> getContent(String volumeType)
920: throws IllegalArgumentException {
921: return lib.getContent(volumeType);
922: }
923:
924: public void setName(String name) {
925: lib.setName(name);
926: }
927:
928: public void setDescription(String text) {
929: lib.setDescription(text);
930: }
931:
932: public void setLocalizingBundle(String resourceName) {
933: lib.setLocalizingBundle(resourceName);
934: }
935:
936: public void addPropertyChangeListener(PropertyChangeListener l) {
937: lib.addPropertyChangeListener(l);
938: }
939:
940: public void removePropertyChangeListener(
941: PropertyChangeListener l) {
942: lib.removePropertyChangeListener(l);
943: }
944:
945: public void setContent(String volumeType, List<URL> path)
946: throws IllegalArgumentException {
947: lib.setContent(volumeType, path);
948: }
949:
950: public URL getLocation() {
951: return area.getLocation();
952: }
953:
954: public String getDisplayName() {
955: return area.getDisplayName();
956: }
957: }
958:
959: }
|