KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > actions > OptionsAction


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.core.actions;
21
22 import java.awt.Component JavaDoc;
23 import java.awt.Dialog JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.Font JavaDoc;
26 import java.awt.GridBagConstraints JavaDoc;
27 import java.awt.Toolkit JavaDoc;
28 import java.awt.event.ActionEvent JavaDoc;
29 import java.awt.event.ActionListener JavaDoc;
30 import java.awt.event.MouseEvent JavaDoc;
31 import java.awt.event.MouseListener JavaDoc;
32 import java.beans.PropertyChangeEvent JavaDoc;
33 import java.beans.PropertyChangeListener JavaDoc;
34 import java.io.ObjectStreamException JavaDoc;
35 import java.lang.ref.Reference JavaDoc;
36 import java.lang.ref.WeakReference JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.Collection JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.List JavaDoc;
41 import javax.swing.JButton JavaDoc;
42 import javax.swing.JComponent JavaDoc;
43 import javax.swing.JSplitPane JavaDoc;
44 import javax.swing.KeyStroke JavaDoc;
45 import javax.swing.SwingUtilities JavaDoc;
46 import javax.swing.UIManager JavaDoc;
47 import javax.swing.border.Border JavaDoc;
48 import javax.swing.table.JTableHeader JavaDoc;
49 import org.netbeans.core.NbMainExplorer;
50 import org.netbeans.core.NbPlaces;
51 import org.netbeans.core.NbTopManager;
52 import org.netbeans.core.projects.SettingChildren;
53 import org.netbeans.core.startup.layers.SessionManager;
54 import org.openide.DialogDescriptor;
55 import org.openide.DialogDisplayer;
56 import org.openide.awt.Mnemonics;
57 import org.openide.awt.StatusDisplayer;
58 import org.openide.cookies.InstanceCookie;
59 import org.openide.explorer.ExplorerManager;
60 import org.netbeans.beaninfo.ExplorerPanel;
61 import org.openide.explorer.propertysheet.PropertySheetView;
62 import org.openide.explorer.view.NodeTableModel;
63 import org.openide.explorer.view.TreeTableView;
64 import org.openide.explorer.view.TreeView;
65 import org.openide.loaders.DataObject;
66 import org.openide.loaders.DataShadow;
67 import org.openide.nodes.FilterNode;
68 import org.openide.nodes.Node;
69 import org.openide.nodes.PropertySupport;
70 import org.openide.util.HelpCtx;
71 import org.openide.util.Mutex;
72 import org.openide.util.NbBundle;
73 import org.openide.util.RequestProcessor;
74 import org.openide.util.WeakListeners;
75 import org.openide.util.actions.CallableSystemAction;
76 import org.openide.windows.TopComponent;
77
78 /** Action that opens explorer view which displays global
79 * options of the IDE.
80  *
81  * @author Dafe Simonek
82  */

83 public class OptionsAction extends CallableSystemAction {
84
85     public OptionsAction() {
86         putValue("noIconInMenu", Boolean.TRUE); //NOI18N
87
}
88     
89     private static final String JavaDoc HELP_ID = "org.netbeans.core.actions.OptionsAction"; // NOI18N
90

91     /** Weak reference to the dialog showing singleton options. */
92     private Reference JavaDoc<Dialog JavaDoc> dialogWRef = new WeakReference JavaDoc<Dialog JavaDoc>(null);
93     
94
95     public void performAction () {
96         final OptionsPanel optionPanel = OptionsPanel.singleton ();
97         
98         Mutex.EVENT.readAccess(new Runnable JavaDoc() {
99             public void run() {
100                 Dialog JavaDoc dialog = dialogWRef.get();
101
102                 if(dialog == null || !dialog.isShowing()) {
103                     JButton JavaDoc closeButton = new JButton JavaDoc();
104                     Mnemonics.setLocalizedText(closeButton, NbBundle.getMessage(OptionsAction.class, "CTL_close_button"));
105                     closeButton.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(OptionsAction.class, "ACSD_close_button"));
106                     String JavaDoc title = (String JavaDoc) OptionsAction.this.getValue
107                         ("optionsDialogTitle");
108                     DialogDescriptor dd = new DialogDescriptor(
109                         InitPanel.getDefault(optionPanel),
110                         title == null ? optionPanel.getName() : title,
111                         false,
112                         new Object JavaDoc[] {closeButton},
113                         closeButton,
114                         DialogDescriptor.DEFAULT_ALIGN,
115                         getHelpCtx (),
116                         null);
117                     
118                     // HACK: switch back to new options dialog hack
119
String JavaDoc name = (String JavaDoc) OptionsAction.this.getValue
120                         ("additionalActionName");
121                     if (name != null) {
122                         ActionListener JavaDoc actionListener = (ActionListener JavaDoc)
123                             OptionsAction.this.getValue ("additionalActionListener");
124                         JButton JavaDoc additionalButton = new JButton JavaDoc ();
125                         Mnemonics.setLocalizedText (additionalButton, name);
126                         additionalButton.addActionListener (new ActionListener JavaDoc () {
127                             public void actionPerformed (ActionEvent JavaDoc e) {
128                                 Dialog JavaDoc dialog = dialogWRef.get ();
129                                 dialog.setVisible (false);
130                             }
131                         });
132                         additionalButton.addActionListener (actionListener);
133                         dd.setAdditionalOptions (new Object JavaDoc[] {additionalButton});
134                     }
135                     // end of HACK
136

137                     // #37673
138
optionPanel.setDialogDescriptor(dd);
139                         
140                     dialog = DialogDisplayer.getDefault().createDialog(dd);
141                     dialog.setVisible(true);
142                     dialogWRef = new WeakReference JavaDoc<Dialog JavaDoc>(dialog);
143                 } else {
144                     dialog.toFront();
145                 }
146             }
147         }); // EQ.iL
148
}
149     
150     protected boolean asynchronous() {
151         return false;
152     }
153
154     public HelpCtx getHelpCtx() {
155         return new HelpCtx (HELP_ID);
156     }
157
158     public String JavaDoc getName() {
159         return NbBundle.getBundle(OptionsAction.class).getString("Options");
160     }
161
162     /** Options panel. Uses singleton pattern. */
163     public static final class OptionsPanel extends NbMainExplorer.ExplorerTab
164     implements PropertyChangeListener JavaDoc {
165         /** Name of mode in which options panel is docked by default */
166         public static final String JavaDoc MODE_NAME = "options";
167         /** Singleton instance of options panel */
168         private static OptionsPanel singleton;
169         
170         private static String JavaDoc TEMPLATES_DISPLAY_NAME = NbBundle.getBundle(OptionsAction.class).getString("CTL_Templates_name"); // NOI18N
171

172         /** list of nodes that should be expanded when the tree is shown */
173         private Collection JavaDoc<Node> toExpand;
174         private transient boolean expanded;
175         /** root node to use */
176         private transient Node rootNode;
177         
178         // XXX #37673
179
private transient Reference JavaDoc<DialogDescriptor> descriptorRef = new WeakReference JavaDoc<DialogDescriptor>(null);
180         
181
182         private OptionsPanel () {
183             validateRootContext ();
184             // show only name of top component is typical case
185
putClientProperty("NamingType", "BothOnlyCompName"); // NOI18N
186
// Show without tab when alone in container cell.
187
putClientProperty("TabPolicy", "HideWhenAlone"); // NOI18N
188

189             getExplorerManager().addPropertyChangeListener(this);
190         }
191         
192         /** Overriden to explicitely set persistence type of OptionsPanel
193          * to PERSISTENCE_ALWAYS */

194         public int getPersistenceType() {
195             return TopComponent.PERSISTENCE_ALWAYS;
196         }
197         
198         protected String JavaDoc preferredID () {
199             return "options"; //NOI18N
200
}
201         
202         // #37673 It was requested to update helpCtx according to node selection in explorer.
203
public void propertyChange(PropertyChangeEvent JavaDoc evt) {
204             if(ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName())) {
205                 DialogDescriptor dd = descriptorRef.get();
206                 if(dd != null) {
207                     dd.setHelpCtx(getHelpCtx());
208                 }
209             }
210         }
211         // #37673
212
public void setDialogDescriptor(DialogDescriptor dd) {
213             descriptorRef = new WeakReference JavaDoc<DialogDescriptor>(dd);
214         }
215         
216         public HelpCtx getHelpCtx () {
217             HelpCtx defaultHelp = new HelpCtx (HELP_ID);
218             HelpCtx help = org.openide.explorer.ExplorerUtils.getHelpCtx (
219                 getExplorerManager ().getSelectedNodes (),
220                 defaultHelp
221             );
222             // bugfix #23551, add help id to subnodes of Templates category
223
// this check prevents mixed help ids on more selected nodes
224
if (!defaultHelp.equals (help)) {
225                 // try if selected node isn't template
226
Node node = getExplorerManager ().getSelectedNodes ()[0];
227                 HelpCtx readHelpId = getHelpId (node);
228                 if (readHelpId != null) return readHelpId;
229                 
230                 // next bugfix #23551, children have same helpId as parent if no specific is declared
231
while (node != null && !TEMPLATES_DISPLAY_NAME.equals (node.getDisplayName ())) {
232                     readHelpId = getHelpId (node);
233                     if (readHelpId != null) return readHelpId;
234                     node = node.getParentNode ();
235                 }
236                 if (node != null && TEMPLATES_DISPLAY_NAME.equals (node.getDisplayName ())) {
237                     return new HelpCtx ("org.netbeans.core.actions.OptionsAction$TemplatesSubnode"); // NOI18N
238
}
239             }
240             return help;
241         }
242         
243         private HelpCtx getHelpId (Node node) {
244             // it's template, return specific help id
245
DataObject dataObj = (DataObject)node.getCookie (DataObject.class);
246             if (dataObj != null) {
247                 Object JavaDoc o = dataObj.getPrimaryFile ().getAttribute ("helpID"); // NOI18N
248
if (o != null) {
249                     return new HelpCtx (o.toString ());
250                 }
251             }
252             return null;
253         }
254
255         /** Accessor to the singleton instance */
256         static OptionsPanel singleton () {
257             if (singleton == null) {
258                 singleton = new OptionsPanel();
259             }
260             return singleton;
261         }
262         
263         private transient JSplitPane JavaDoc split=null;
264         protected TreeView initGui () {
265             TTW retVal = new TTW () ;
266             
267             
268             split = new JSplitPane JavaDoc (JSplitPane.HORIZONTAL_SPLIT);
269             PropertySheetView propertyView = new PropertySheetView();
270             
271             split.setLeftComponent(retVal);
272             split.setRightComponent(propertyView);
273             // install proper border for split pane
274
split.setBorder((Border JavaDoc)UIManager.get("Nb.ScrollPane.border")); // NOI18N
275

276             setLayout (new java.awt.GridBagLayout JavaDoc ());
277
278             GridBagConstraints JavaDoc gridBagConstraints = new GridBagConstraints JavaDoc ();
279             gridBagConstraints.fill = GridBagConstraints.BOTH;
280             gridBagConstraints.weightx = 1.0;
281             gridBagConstraints.weighty = 1.0;
282             gridBagConstraints.gridwidth = 2;
283             add (split, gridBagConstraints);
284
285             return retVal;
286         }
287         
288         /** Overridden to provide a larger preferred size if the default font
289          * is larger, for locales that require this. */

290         public Dimension JavaDoc getPreferredSize() {
291             //issue 34104, bad sizing/split location for Chinese locales that require
292
//a larger default font size
293
Dimension JavaDoc result = super.getPreferredSize();
294             Font JavaDoc treeFont = UIManager.getFont("Tree.font"); // NOI18N
295
int fontsize = treeFont != null ? treeFont.getSize() : 11;
296             if (fontsize > 11) {
297                 int factor = fontsize - 11;
298                 result.height += 15 * factor;
299                 result.width += 50 * factor;
300                 Dimension JavaDoc screen = Toolkit.getDefaultToolkit().getScreenSize();
301                 if (result.height > screen.height) {
302                     result.height = screen.height -30;
303                 }
304                 if (result.width > screen.width) {
305                     result.width = screen.width -30;
306                 }
307             } else {
308                 result.width += 20;
309                 result.height +=20;
310             }
311             
312             return result;
313         }
314
315         /** Called when the explored context changes.
316         * Overriden - we don't want title to chnage in this style.
317         */

318         protected void updateTitle () {
319             // empty to keep the title unchanged
320
}
321
322         boolean isPrepared () {
323             return toExpand != null;
324         }
325         
326         public void prepareNodes() {
327             if (toExpand == null) {
328                 List JavaDoc<Node> arr = new ArrayList JavaDoc<Node> (101);
329                 expandNodes(getRootContext (), 2, arr);
330                 toExpand = arr;
331             }
332         }
333
334
335         protected void componentShowing () {
336             super.componentShowing ();
337             if (!expanded) {
338                 ((TTW)view).expandTheseNodes (toExpand, getExplorerManager ().getRootContext ());
339                 expanded = true;
340             }
341             // initialize divider location
342
split.setDividerLocation(getPreferredSize().width / 2);
343         }
344         
345
346         protected void validateRootContext () {
347             Node n = initRC ();
348             setRootContext (n);
349         }
350         
351         /** Resolves to the singleton instance of options panel. */
352         public Object JavaDoc readResolve ()
353         throws ObjectStreamException JavaDoc {
354             if (singleton == null) {
355                 singleton = this;
356             }
357             singleton.scheduleValidation();
358             // set deserialized root node
359
rootNode = getRootContext ();
360             return singleton;
361         }
362         
363         private synchronized Node initRC () {
364             if (rootNode == null) {
365                 rootNode = new OptionsFilterNode ();
366             }
367             return rootNode;
368         }
369
370         /** Expands the node in explorer.
371          */

372         private static void expandNodes (Node n, final int depth, final Collection JavaDoc<Node> list) {
373             if (depth == 0) {
374                 return;
375             }
376             
377             DataObject obj = (DataObject)n.getCookie(DataObject.class);
378             if (obj instanceof DataShadow) {
379                 obj = ((DataShadow)obj).getOriginal();
380             }
381             
382             if (obj != null) {
383                 if (!obj.getPrimaryFile().getPath().startsWith ("UI/Services")) { // NOI18N
384
return;
385                 }
386
387                 InstanceCookie ic = (InstanceCookie)obj.getCookie (InstanceCookie.class);
388                 if (ic != null) {
389
390                     if (ic instanceof InstanceCookie.Of) {
391                         if (((InstanceCookie.Of)ic).instanceOf (Node.class)) {
392                             return;
393                         }
394                     }
395                 }
396             }
397             
398             // ok, expand this node
399
if (!list.contains (n)) {
400                 list.add (n);
401             }
402          
403             Node[] arr = n.getChildren().getNodes(true);
404             for (int i = 0; i < arr.length; i++) {
405                 final Node p = arr[i];
406                 expandNodes(p, depth - 1, list);
407             }
408         }
409         
410         //
411
// Model to implement the special handling of SettingChildren.* properties
412
//
413

414         /** Model that tries to extract properties from the node.getValue
415          * instead of creating its getPropertySets.
416          */

417         private static class NTM extends NodeTableModel {
418             public NTM () {
419                 super ();
420             }
421             
422             protected Node.Property getPropertyFor(Node node, Node.Property prop) {
423                 Object JavaDoc value = node.getValue (prop.getName());
424                 if (value instanceof Node.Property) {
425                     return (Node.Property)value;
426                 }
427                 
428                 return null;
429             }
430         }
431
432         private static class TTW extends TreeTableView implements MouseListener JavaDoc, PropertyChangeListener JavaDoc, java.awt.event.ActionListener JavaDoc {
433             /** Dummy property that can be expanded or collapsed. */
434             private final Node.Property indicator = new IndicatorProperty();
435             /** Session layer state indicator property */
436             private final Node.Property session = new SettingChildren.FileStateProperty (SettingChildren.PROP_LAYER_SESSION);
437             /** Modules layer state indicator property */
438             private final Node.Property modules = new SettingChildren.FileStateProperty (SettingChildren.PROP_LAYER_MODULES);
439             
440             /** Active set of properties (columns) */
441             private Node.Property active_set [] = null;
442             PropertyChangeListener JavaDoc weakL = null;
443             
444             public TTW () {
445                 super (new NTM ());
446                 
447                 refreshColumns (true);
448                 addMouseListener (this);
449                 weakL = WeakListeners.propertyChange(this, SessionManager.getDefault ());
450                 SessionManager.getDefault ().addPropertyChangeListener (weakL);
451                 
452                 registerKeyboardAction(
453                     this,
454                     KeyStroke.getKeyStroke('+'),
455                     JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
456                 );
457
458                 getAccessibleContext().setAccessibleName(NbBundle.getBundle(OptionsAction.class).getString("ACSN_optionsTree"));
459                 getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(OptionsAction.class).getString("ACSD_optionsTree"));
460             }
461             public void mouseExited (MouseEvent JavaDoc evt) {
462             }
463             public void mouseReleased (MouseEvent JavaDoc evt) {
464             }
465             public void mousePressed (MouseEvent JavaDoc evt) {
466             }
467             public void mouseClicked (MouseEvent JavaDoc evt) {
468                 Component JavaDoc c = evt.getComponent ();
469                 if (c instanceof JTableHeader JavaDoc) {
470                     JTableHeader JavaDoc h = (JTableHeader JavaDoc)c;
471                     
472                     // show/hide additional properties
473
if (1 == h.columnAtPoint (evt.getPoint ())) {
474                         refreshColumns (true);
475                     }
476                 }
477             }
478             public void mouseEntered (MouseEvent JavaDoc evt) {
479             }
480             public void propertyChange(PropertyChangeEvent JavaDoc evt) {
481                 if (SessionManager.PROP_OPEN.equals (evt.getPropertyName ())) {
482                     refreshColumns (false);
483                 }
484             }
485             private void refreshColumns (boolean changeSets) {
486                 Node.Property new_set [] = active_set;
487                 int length = active_set == null ? 0 : active_set.length;
488
489                 if ((changeSets && length == 1) || (!changeSets && length > 1)) {
490                     // build full_set
491
new_set = new Node.Property[] {indicator, session, modules};
492
493                     indicator.setDisplayName (
494                         NbBundle.getMessage(OptionsAction.class, "LBL_IndicatorProperty_Name_Expanded")); //NOI18N
495
indicator.setShortDescription (
496                         NbBundle.getMessage(OptionsAction.class, "LBL_IndicatorProperty_Description_Expanded")); //NOI18N
497
}
498                 else {
499                     if (changeSets) {
500                         new_set = new Node.Property[] {indicator};
501                         indicator.setDisplayName (
502                             NbBundle.getMessage(OptionsAction.class, "LBL_IndicatorProperty_Name")); //NOI18N
503
indicator.setShortDescription (
504                             NbBundle.getMessage(OptionsAction.class, "LBL_IndicatorProperty_Description")); //NOI18N
505
}
506                 }
507                 
508                 if (active_set != new_set) {
509                     // setup new columns
510
final Node.Property set [] = new_set;
511                     if (SwingUtilities.isEventDispatchThread()) {
512                         setNewSet(set);
513                     } else {
514                         SwingUtilities.invokeLater (new Runnable JavaDoc () {
515                             public void run () {
516                                 setNewSet(set);
517                             }
518                         });
519                     }
520                     // remeber the last set of columns
521
active_set = new_set;
522                 }
523             }
524             
525             private void setNewSet (Node.Property[] set) {
526                 // change columns
527
setProperties (set);
528                 // set preferred colunm sizes
529
setTreePreferredWidth(set.length == 1 ? 480 : 300);
530                 setTableColumnPreferredWidth (0, 20);
531                 for (int i = 1; i < set.length; i++) {
532                     setTableColumnPreferredWidth (i, 60);
533                 }
534             }
535             
536             public void actionPerformed(ActionEvent JavaDoc e) {
537                 refreshColumns(true);
538             }
539             
540             public void expandTheseNodes (Collection JavaDoc<Node> paths, Node root) {
541                 Iterator JavaDoc<Node> it = paths.iterator();
542                 
543                 Node first = null;
544                 while (it.hasNext()) {
545                     Node n = it.next();
546                     if (first == null) {
547                         first = n;
548                     }
549                     
550                     this.expandNode(n);
551                 }
552
553                 if (first != null) {
554                     collapseNode (first);
555                     expandNode (first);
556                 }
557                 
558                 // move to top
559
tree.scrollRowToVisible(0);
560             }
561
562             /** Dummy placeholder property. */
563             private static final class IndicatorProperty extends PropertySupport.ReadOnly<String JavaDoc> {
564
565                 public IndicatorProperty() {
566                     super("indicator", String JavaDoc.class, "", ""); // NOI18N
567
}
568
569                 public String JavaDoc getValue() {
570                     return ""; // NOI18N
571
}
572
573             }
574
575         }
576             
577        
578         private static class OptionsFilterNode extends FilterNode {
579             public OptionsFilterNode () {
580                 super (
581                     NbPlaces.getDefault().session(),
582                     new SettingChildren (NbPlaces.getDefault().session())
583                 );
584             }
585             public HelpCtx getHelpCtx () {
586                 return new HelpCtx (OptionsFilterNode.class);
587             }
588             
589             public Node.Handle getHandle () {
590                 return new H ();
591             }
592             
593             private static class H implements Node.Handle {
594                 H() {}
595                 
596                 private static final long serialVersionUID = -5158460093499159177L;
597                 
598                 public Node getNode () throws java.io.IOException JavaDoc {
599                     return new OptionsFilterNode ();
600                 }
601             }
602         }
603         
604     } // end of inner class OptionsPanel
605
}
606
Popular Tags