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: package org.openide.explorer.propertysheet;
042:
043: import org.openide.awt.Mnemonics;
044: import org.openide.explorer.ExplorerManager;
045: import org.openide.explorer.view.TreeTableView;
046: import org.openide.nodes.Node;
047: import org.openide.util.Lookup;
048: import org.openide.util.NbBundle;
049: import org.openide.util.actions.NodeAction;
050: import org.openide.util.actions.SystemAction;
051:
052: import java.awt.Component;
053:
054: import java.beans.*;
055:
056: import javax.swing.Action;
057: import javax.swing.JPanel;
058: import javax.swing.JScrollPane;
059: import javax.swing.Scrollable;
060: import javax.swing.UIManager;
061: import javax.swing.border.Border;
062:
063: /**
064: * Panel displaying indexed properties.
065: * @author dstrupl@netbeans.org
066: */
067: class IndexedEditorPanel extends javax.swing.JPanel implements
068: ExplorerManager.Provider, PropertyChangeListener,
069: Lookup.Provider {
070: private ExplorerManager em;
071:
072: /** lookup for move up and down actions */
073: private Lookup selectedLookup;
074: private Action moveUp;
075: private Action moveDown;
076: private Action newAction;
077: private boolean showingDetails = false;
078: private Node rootNode;
079: private Node.Property prop;
080: private JScrollPane jScrollPane1 = new JScrollPane();
081: private JPanel detailsPanel = new JPanel();
082:
083: // Variables declaration - do not modify//GEN-BEGIN:variables
084: private javax.swing.JButton deleteButton;
085: private javax.swing.JButton detailsButton;
086: private javax.swing.JButton downButton;
087: private javax.swing.JPanel jPanel1;
088: private javax.swing.JPanel jPanel2;
089: private javax.swing.JButton newButton;
090: private javax.swing.JLabel propertiesLabel;
091: private javax.swing.JButton upButton;
092: // End of variables declaration//GEN-END:variables
093: // XXX look into constructor
094: private TreeTableView treeTableView1;
095:
096: /** Creates new form IndexedEditorPanel */
097: public IndexedEditorPanel(Node node, Node.Property[] props) {
098: treeTableView1 = new TreeTableView();
099:
100: // install proper border
101: setBorder((Border) UIManager.get("Nb.ScrollPane.border")); // NOI18N
102: initComponents();
103: propertiesLabel.setLabelFor(treeTableView1);
104:
105: jPanel2.setLayout(new java.awt.BorderLayout());
106: jPanel2.add(treeTableView1);
107:
108: detailsPanel.setLayout(new java.awt.BorderLayout());
109: getExplorerManager().setRootContext(node);
110:
111: rootNode = node;
112: prop = props[0];
113: getExplorerManager().addPropertyChangeListener(this );
114: treeTableView1.setProperties(props);
115: treeTableView1.setRootVisible(false);
116: treeTableView1.setDefaultActionAllowed(false);
117: treeTableView1.setTreePreferredWidth(200);
118:
119: node.addPropertyChangeListener(this );
120:
121: try {
122: selectedLookup = org.openide.util.lookup.Lookups
123: .proxy(this );
124:
125: NodeAction globalMoveUp = SystemAction.get(Class.forName(
126: "org.openide.actions.MoveUpAction").asSubclass(
127: NodeAction.class)); // NOI18N
128: NodeAction globalMoveDown = SystemAction.get(Class.forName(
129: "org.openide.actions.MoveDownAction").asSubclass(
130: NodeAction.class)); // NOI18N
131: NodeAction globalNewAction = SystemAction.get(Class
132: .forName("org.openide.actions.NewAction")
133: .asSubclass(NodeAction.class)); // NOI18N
134:
135: // Get context aware instances.
136: moveUp = globalMoveUp
137: .createContextAwareInstance(selectedLookup);
138: moveDown = globalMoveDown
139: .createContextAwareInstance(selectedLookup);
140: newAction = globalNewAction
141: .createContextAwareInstance(selectedLookup);
142: } catch (ClassNotFoundException cnfe) {
143: }
144:
145: java.util.ResourceBundle bundle = NbBundle
146: .getBundle(IndexedEditorPanel.class);
147: treeTableView1.getAccessibleContext().setAccessibleDescription(
148: bundle.getString("ACSD_Properties"));
149: newButton.getAccessibleContext().setAccessibleDescription(
150: bundle.getString("ACSD_New"));
151: deleteButton.getAccessibleContext().setAccessibleDescription(
152: bundle.getString("ACSD_Delete"));
153: upButton.getAccessibleContext().setAccessibleDescription(
154: bundle.getString("ACSD_MoveUp"));
155: downButton.getAccessibleContext().setAccessibleDescription(
156: bundle.getString("ACSD_MoveDown"));
157: getAccessibleContext().setAccessibleDescription(
158: bundle.getString("ACSD_IndexedEditorPanel"));
159: }
160:
161: public void addNotify() {
162: super .addNotify();
163: updateButtonState();
164: }
165:
166: /** Returns the lookup of currently selected node.
167: */
168: public Lookup getLookup() {
169: Node[] arr = getExplorerManager().getSelectedNodes();
170:
171: return (arr.length == 1) ? arr[0].getLookup() : Lookup.EMPTY;
172: }
173:
174: /** This method is called from within the constructor to
175: * initialize the form.
176: * WARNING: Do NOT modify this code. The content of this method is
177: * always regenerated by the Form Editor.
178: */
179: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
180: private void initComponents() {
181: java.awt.GridBagConstraints gridBagConstraints;
182:
183: jPanel1 = new javax.swing.JPanel();
184: newButton = new javax.swing.JButton();
185: deleteButton = new javax.swing.JButton();
186: upButton = new javax.swing.JButton();
187: downButton = new javax.swing.JButton();
188: detailsButton = new javax.swing.JButton();
189: propertiesLabel = new javax.swing.JLabel();
190: jPanel2 = new javax.swing.JPanel();
191:
192: FormListener formListener = new FormListener();
193:
194: setLayout(new java.awt.GridBagLayout());
195:
196: setBorder(javax.swing.BorderFactory.createEmptyBorder(12, 12,
197: 0, 12));
198: jPanel1.setLayout(new java.awt.GridLayout(5, 1, 0, 5));
199:
200: org.openide.awt.Mnemonics.setLocalizedText(newButton,
201: org.openide.util.NbBundle.getBundle(
202: IndexedEditorPanel.class).getString("CTL_New"));
203: newButton.addActionListener(formListener);
204:
205: jPanel1.add(newButton);
206:
207: org.openide.awt.Mnemonics.setLocalizedText(deleteButton,
208: org.openide.util.NbBundle.getBundle(
209: IndexedEditorPanel.class).getString(
210: "CTL_Delete"));
211: deleteButton.addActionListener(formListener);
212:
213: jPanel1.add(deleteButton);
214:
215: org.openide.awt.Mnemonics.setLocalizedText(upButton,
216: org.openide.util.NbBundle.getBundle(
217: IndexedEditorPanel.class).getString(
218: "CTL_MoveUp"));
219: upButton.addActionListener(formListener);
220:
221: jPanel1.add(upButton);
222:
223: org.openide.awt.Mnemonics.setLocalizedText(downButton,
224: org.openide.util.NbBundle.getBundle(
225: IndexedEditorPanel.class).getString(
226: "CTL_MoveDown"));
227: downButton.addActionListener(formListener);
228:
229: jPanel1.add(downButton);
230:
231: org.openide.awt.Mnemonics.setLocalizedText(detailsButton,
232: org.openide.util.NbBundle.getBundle(
233: IndexedEditorPanel.class).getString(
234: "CTL_HideDetails"));
235: detailsButton.addActionListener(formListener);
236:
237: jPanel1.add(detailsButton);
238:
239: gridBagConstraints = new java.awt.GridBagConstraints();
240: gridBagConstraints.gridx = 1;
241: gridBagConstraints.gridy = 1;
242: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
243: gridBagConstraints.gridheight = java.awt.GridBagConstraints.RELATIVE;
244: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
245: gridBagConstraints.insets = new java.awt.Insets(0, 0, 11, 0);
246: add(jPanel1, gridBagConstraints);
247:
248: org.openide.awt.Mnemonics.setLocalizedText(propertiesLabel,
249: org.openide.util.NbBundle.getBundle(
250: IndexedEditorPanel.class).getString(
251: "CTL_Properties"));
252: gridBagConstraints = new java.awt.GridBagConstraints();
253: gridBagConstraints.gridx = 0;
254: gridBagConstraints.gridy = 0;
255: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
256: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
257: gridBagConstraints.insets = new java.awt.Insets(0, 0, 2, 11);
258: add(propertiesLabel, gridBagConstraints);
259:
260: gridBagConstraints = new java.awt.GridBagConstraints();
261: gridBagConstraints.gridx = 0;
262: gridBagConstraints.gridy = 1;
263: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
264: gridBagConstraints.weightx = 1.0;
265: gridBagConstraints.insets = new java.awt.Insets(0, 0, 11, 11);
266: add(jPanel2, gridBagConstraints);
267:
268: }
269:
270: // Code for dispatching events from components to event handlers.
271:
272: private class FormListener implements java.awt.event.ActionListener {
273: public void actionPerformed(java.awt.event.ActionEvent evt) {
274: if (evt.getSource() == newButton) {
275: IndexedEditorPanel.this .newButtonActionPerformed(evt);
276: } else if (evt.getSource() == deleteButton) {
277: IndexedEditorPanel.this
278: .deleteButtonActionPerformed(evt);
279: } else if (evt.getSource() == upButton) {
280: IndexedEditorPanel.this .upButtonActionPerformed(evt);
281: } else if (evt.getSource() == downButton) {
282: IndexedEditorPanel.this .downButtonActionPerformed(evt);
283: } else if (evt.getSource() == detailsButton) {
284: IndexedEditorPanel.this
285: .detailsButtonActionPerformed(evt);
286: }
287: }
288: }// </editor-fold>//GEN-END:initComponents
289:
290: private void detailsButtonActionPerformed(
291: java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detailsButtonActionPerformed
292: showingDetails = !showingDetails;
293:
294: if (showingDetails && !this .equals(detailsPanel.getParent())) {
295: initDetails();
296: }
297:
298: updateButtonState();
299: updateDetailsPanel();
300: }
301:
302: //GEN-LAST:event_detailsButtonActionPerformed
303:
304: private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed
305:
306: try {
307: getExplorerManager().setSelectedNodes(
308: new Node[] { rootNode });
309: } catch (PropertyVetoException pve) {
310: // this should be always possible --> if not, notify problem
311: PropertyDialogManager.notify(pve);
312: }
313:
314: if ((newAction != null) && (newAction.isEnabled())) {
315: newAction.actionPerformed(evt);
316: }
317: }
318:
319: //GEN-LAST:event_newButtonActionPerformed
320:
321: private void deleteButtonActionPerformed(
322: java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
323:
324: Node[] sn = getExplorerManager().getSelectedNodes();
325:
326: if ((sn == null) || (sn.length != 1) || (sn[0] == rootNode)) {
327: return;
328: }
329:
330: try {
331: sn[0].destroy();
332: } catch (java.io.IOException ioe) {
333: PropertyDialogManager.notify(ioe);
334: }
335:
336: rootNode = getExplorerManager().getRootContext();
337: }
338:
339: //GEN-LAST:event_deleteButtonActionPerformed
340:
341: private void downButtonActionPerformed(
342: java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downButtonActionPerformed
343:
344: Node[] sn = getExplorerManager().getSelectedNodes();
345:
346: if ((moveDown != null) && (moveDown.isEnabled())) {
347: moveDown.actionPerformed(evt);
348: }
349:
350: if ((sn == null) || (sn.length != 1) || (sn[0] == rootNode)) {
351: return;
352: }
353:
354: try {
355: getExplorerManager().setSelectedNodes(sn);
356: } catch (PropertyVetoException pve) {
357: }
358: }
359:
360: //GEN-LAST:event_downButtonActionPerformed
361:
362: private void upButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upButtonActionPerformed
363:
364: Node[] sn = getExplorerManager().getSelectedNodes();
365:
366: if ((moveUp != null) && (moveUp.isEnabled())) {
367: moveUp.actionPerformed(evt);
368: }
369:
370: if ((sn == null) || (sn.length != 1) || (sn[0] == rootNode)) {
371: return;
372: }
373:
374: try {
375: getExplorerManager().setSelectedNodes(sn);
376: } catch (PropertyVetoException pve) {
377: }
378: }
379:
380: //GEN-LAST:event_upButtonActionPerformed
381:
382: public synchronized ExplorerManager getExplorerManager() {
383: if (em == null) {
384: em = new ExplorerManager();
385: }
386:
387: return em;
388: }
389:
390: private void updateButtonState() {
391: // refresh the lookup
392: selectedLookup.lookup(Object.class);
393:
394: if (showingDetails) {
395: detailsButton.setText(NbBundle.getBundle(
396: IndexedEditorPanel.class).getString(
397: "CTL_HideDetails"));
398: } else {
399: detailsButton.setText(NbBundle.getBundle(
400: IndexedEditorPanel.class).getString(
401: "CTL_ShowDetails"));
402: }
403:
404: upButton.setEnabled((moveUp != null) && (moveUp.isEnabled()));
405: downButton.setEnabled((moveDown != null)
406: && (moveDown.isEnabled()));
407:
408: Node[] sn = getExplorerManager().getSelectedNodes();
409: deleteButton.setEnabled((sn != null) && (sn.length == 1)
410: && (sn[0] != rootNode));
411: detailsButton.setVisible((prop != null)
412: && (prop.getPropertyEditor() != null)
413: && (prop.getPropertyEditor().supportsCustomEditor()));
414:
415: if (detailsButton.isVisible()) {
416: if (showingDetails) {
417: Mnemonics.setLocalizedText(detailsButton, NbBundle
418: .getBundle(IndexedEditorPanel.class).getString(
419: "CTL_HideDetails"));
420: detailsButton.getAccessibleContext()
421: .setAccessibleDescription(
422: NbBundle.getBundle(
423: IndexedEditorPanel.class)
424: .getString("ACSD_HideDetails"));
425: } else {
426: Mnemonics.setLocalizedText(detailsButton, NbBundle
427: .getBundle(IndexedEditorPanel.class).getString(
428: "CTL_ShowDetails"));
429: detailsButton.getAccessibleContext()
430: .setAccessibleDescription(
431: NbBundle.getBundle(
432: IndexedEditorPanel.class)
433: .getString("ACSD_ShowDetails"));
434: }
435:
436: detailsButton.setEnabled((sn != null) && (sn.length == 1)
437: && (sn[0] != rootNode));
438: }
439: }
440:
441: private void updateDetailsPanel() {
442: detailsPanel.removeAll();
443:
444: if (!showingDetails) {
445: remove(detailsPanel);
446: revalidateDetailsPanel();
447:
448: return;
449: }
450:
451: Node[] selN = getExplorerManager().getSelectedNodes();
452:
453: if ((selN == null) || (selN.length == 0)) {
454: revalidateDetailsPanel();
455:
456: return;
457: }
458:
459: Node n = selN[0];
460:
461: if (n == rootNode) {
462: revalidateDetailsPanel();
463:
464: return;
465: }
466:
467: if (selN.length > 1) {
468: n = new ProxyNode(selN);
469: }
470:
471: // beware - this will function only if the DisplayIndexedNode has
472: // one property on the first sheet and the property is of type
473: // ValueProp
474: Node.Property prop = n.getPropertySets()[0].getProperties()[0];
475: PropertyPanel p = new PropertyPanel(prop);
476: p.setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
477:
478: if (isEditorScrollable(p)) {
479: detailsPanel.add(p, java.awt.BorderLayout.CENTER);
480: } else {
481: jScrollPane1.setViewportView(p);
482: detailsPanel
483: .add(jScrollPane1, java.awt.BorderLayout.CENTER);
484: }
485:
486: revalidateDetailsPanel();
487: }
488:
489: private void revalidateDetailsPanel() {
490: detailsPanel.invalidate();
491: repaint();
492:
493: if (detailsPanel.getParent() != null) {
494: detailsPanel.getParent().validate();
495: } else {
496: detailsPanel.validate();
497: }
498: }
499:
500: /**
501: * This method gets called when a bound property is changed.
502: * @param evt A PropertyChangeEvent object describing the event source
503: * and the property that has changed.
504: */
505: public void propertyChange(PropertyChangeEvent evt) {
506: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
507: .getPropertyName())) {
508: updateButtonState();
509: updateDetailsPanel();
510: }
511: }
512:
513: private void initDetails() {
514: java.awt.GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
515: gridBagConstraints.gridx = 0;
516: gridBagConstraints.gridy = 2;
517: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
518: gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
519: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
520: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
521: gridBagConstraints.weighty = 1.0;
522: add(detailsPanel, gridBagConstraints);
523: }
524:
525: private boolean isEditorScrollable(PropertyPanel p) {
526: Component[] comps = p.getComponents();
527:
528: for (int i = 0; i < comps.length; i++) {
529: if (comps[i] instanceof Scrollable
530: || isInstanceOfTopComponent(comps[i])) {
531: return true;
532: }
533: }
534:
535: return false;
536: }
537:
538: /** Checks whether an object is instanceof TopComponent
539: * @param obj the object
540: * @return true or false
541: */
542: private static boolean isInstanceOfTopComponent(Object obj) {
543: ClassLoader l = org.openide.util.Lookup.getDefault().lookup(
544: ClassLoader.class);
545:
546: if (l == null) {
547: l = IndexedEditorPanel.class.getClassLoader();
548: }
549:
550: try {
551: Class c = Class.forName("org.openide.windows.TopComponent",
552: true, l); // NOI18N
553:
554: return c.isInstance(obj);
555: } catch (Exception ex) {
556: return false;
557: }
558: }
559: }
|