KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > ComponentInspector


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.modules.form;
21
22 import java.awt.event.*;
23 import java.beans.*;
24 import java.awt.datatransfer.*;
25 import javax.swing.text.DefaultEditorKit JavaDoc;
26
27 import org.openide.*;
28 import org.openide.actions.PasteAction;
29 import org.openide.nodes.*;
30 import org.openide.explorer.*;
31 import org.openide.awt.UndoRedo;
32 import org.openide.explorer.view.BeanTreeView;
33 import org.openide.windows.*;
34 import org.openide.util.*;
35 import org.openide.util.actions.SystemAction;
36 import org.openide.util.actions.ActionPerformer;
37 import org.openide.util.datatransfer.*;
38
39 import org.netbeans.modules.form.actions.TestAction;
40 import org.netbeans.modules.form.palette.PaletteUtils;
41
42 /**
43  * The ComponentInspector - special explorer for form editor.
44  *
45  * @author Tomas Pavek
46  */

47
48 public class ComponentInspector extends TopComponent
49                                 implements ExplorerManager.Provider
50 {
51     private ExplorerManager explorerManager;
52
53     private TestAction testAction = (TestAction)
54                 SystemAction.findObject(TestAction.class, true);
55
56     private PasteAction pasteAction = (PasteAction)
57                 SystemAction.findObject(PasteAction.class, true);
58
59     private CopyCutActionPerformer copyActionPerformer = new CopyCutActionPerformer(true);
60     private CopyCutActionPerformer cutActionPerformer = new CopyCutActionPerformer(false);
61     private DeleteActionPerformer deleteActionPerformer = new DeleteActionPerformer();
62
63     private ClipboardListener clipboardListener;
64
65     /** Currently focused form or null if no form is opened/focused */
66     private FormEditor focusedForm;
67
68     private EmptyInspectorNode emptyInspectorNode;
69     
70     private BeanTreeView treeView;
71
72     /** Default icon base for control panel. */
73     private static final String JavaDoc EMPTY_INSPECTOR_ICON_BASE =
74         "org/netbeans/modules/form/resources/emptyInspector"; // NOI18N
75

76     /** The icon for ComponentInspector */
77     private static final String JavaDoc iconURL =
78         "org/netbeans/modules/form/resources/inspector.png"; // NOI18N
79

80     private static ComponentInspector instance;
81
82     // ------------
83
// construction (ComponentInspector is a singleton)
84

85     /** Gets default instance. Don't use directly, it reserved for '.settings' file only,
86      * i.e. deserialization routines, otherwise you can get non-deserialized instance. */

87     public static synchronized ComponentInspector getDefault() {
88         if (instance == null)
89             instance = new ComponentInspector();
90         return instance;
91     }
92
93     /** Finds default instance. Use in client code instead of {@link #getDefault()}. */
94     public static synchronized ComponentInspector getInstance() {
95         if (instance == null) {
96             TopComponent tc = WindowManager.getDefault().findTopComponent("ComponentInspector"); // NOI18N
97
if (instance == null) {
98                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, new IllegalStateException JavaDoc(
99                     "Can not find ComponentInspector component for its ID. Returned " + tc)); // NOI18N
100
instance = new ComponentInspector();
101             }
102         }
103         return instance;
104     }
105
106     /** Overriden to explicitely set persistence type of ComponentInspector
107      * to PERSISTENCE_ALWAYS */

108     public int getPersistenceType() {
109         return TopComponent.PERSISTENCE_ALWAYS;
110     }
111
112     private ComponentInspector() {
113         explorerManager = new ExplorerManager();
114
115         associateLookup(
116             ExplorerUtils.createLookup(explorerManager, setupActionMap(getActionMap()))
117         );
118
119         emptyInspectorNode = new EmptyInspectorNode();
120         explorerManager.setRootContext(emptyInspectorNode);
121
122         explorerManager.addPropertyChangeListener(new NodeSelectionListener());
123
124         setLayout(new java.awt.BorderLayout JavaDoc());
125         createComponents();
126
127         setIcon(Utilities.loadImage(iconURL));
128         setName(FormUtils.getBundleString("CTL_InspectorTitle")); // NOI18N
129
setToolTipText(FormUtils.getBundleString("HINT_ComponentInspector")); // NOI18N
130
}
131
132     javax.swing.ActionMap JavaDoc setupActionMap(javax.swing.ActionMap JavaDoc map) {
133         map.put(DefaultEditorKit.copyAction, copyActionPerformer);
134         map.put(DefaultEditorKit.cutAction, cutActionPerformer);
135         //map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(explorerManager));
136
map.put("delete", deleteActionPerformer); // NOI18N
137

138         return map;
139     }
140
141     private void createComponents() {
142         treeView = new BeanTreeView();
143         treeView.setDragSource(true);
144         treeView.setDropTarget(true);
145         treeView.getAccessibleContext().setAccessibleName(
146             FormUtils.getBundleString("ACS_ComponentTree")); // NOI18N
147
treeView.getAccessibleContext().setAccessibleDescription(
148             FormUtils.getBundleString("ACSD_ComponentTree")); // NOI18N
149
add(java.awt.BorderLayout.CENTER, treeView);
150     }
151
152     // --------------
153
// overriding superclasses, implementing interfaces
154

155     // ExplorerManager.Provider
156
public ExplorerManager getExplorerManager() {
157         return explorerManager;
158     }
159
160     public UndoRedo getUndoRedo() {
161         UndoRedo ur = focusedForm != null ?
162                           focusedForm.getFormUndoRedoManager() : null;
163         return ur != null ? ur : super.getUndoRedo();
164     }
165
166     public HelpCtx getHelpCtx() {
167         return new HelpCtx("gui.component-inspector"); // NOI18N
168
}
169
170     /** Replaces this in object stream. */
171     public Object JavaDoc writeReplace() {
172         return new ResolvableHelper();
173     }
174
175     protected void componentActivated() {
176         attachActions();
177     }
178
179     protected void componentDeactivated() {
180         detachActions();
181     }
182
183     // ------------
184
// activating and focusing
185

186     synchronized void attachActions() {
187         ExplorerUtils.activateActions(explorerManager, true);
188         updatePasteAction();
189
190         Clipboard c = getClipboard();
191         if (c instanceof ExClipboard) {
192             ExClipboard clip = (ExClipboard) c;
193             if (clipboardListener == null)
194                 clipboardListener = new ClipboardChangesListener();
195             clip.addClipboardListener(clipboardListener);
196         }
197     }
198
199     synchronized void detachActions() {
200         ExplorerUtils.activateActions(explorerManager, false);
201
202         Clipboard c = getClipboard();
203         if (c instanceof ExClipboard) {
204             ExClipboard clip = (ExClipboard) c;
205             clip.removeClipboardListener(clipboardListener);
206         }
207     }
208
209     /** This method focuses the ComponentInspector on given form.
210      * @param form the form to focus on
211      */

212     public void focusForm(final FormEditor form) {
213         if (focusedForm != form)
214             focusFormInAwtThread(form, 0);
215     }
216
217     /** This method focuses the ComponentInspector on given form.
218      * @param form the form to focus on
219      * @param visible true to open inspector, false to close
220      */

221     public void focusForm(final FormEditor form, boolean visible) {
222         if (focusedForm != form)
223             focusFormInAwtThread(form, visible ? 1 : -1);
224     }
225
226     private void focusFormInAwtThread(final FormEditor form,
227                                       final int visibility) {
228         if (java.awt.EventQueue.isDispatchThread()) {
229             focusFormImpl(form, visibility);
230         }
231         else {
232             java.awt.EventQueue.invokeLater(new Runnable JavaDoc() {
233                 public void run() {
234                     focusFormImpl(form, visibility);
235                 }
236             });
237         }
238     }
239
240     private void focusFormImpl(FormEditor form, int visibility) {
241         focusedForm = form;
242
243         if ((form == null) || (form.getFormDesigner() == null)) {
244             testAction.setFormDesigner(null);
245             PaletteUtils.setContext(null);
246
247             // swing memory leak workaround
248
removeAll();
249             createComponents();
250             revalidate();
251
252             getExplorerManager().setRootContext(emptyInspectorNode);
253         }
254         else {
255             Node[] selectedNodes = form.getFormDesigner().getSelectedComponentNodes();
256
257             testAction.setFormDesigner(form.getFormDesigner());
258             PaletteUtils.setContext(form.getFormDataObject().getPrimaryFile());
259
260             Node formNode = form.getFormRootNode();
261             if (formNode == null) { // form not loaded yet, should not happen
262
System.err.println("Warning: FormEditorSupport.getFormRootNode() returns null"); // NOI18N
263
getExplorerManager().setRootContext(emptyInspectorNode);
264             }
265             else
266                 getExplorerManager().setRootContext(formNode);
267             
268             try {
269                 getExplorerManager().setSelectedNodes(selectedNodes);
270             } catch (PropertyVetoException ex) {
271                 ex.printStackTrace(); // should not happen
272
}
273                         
274         }
275
276         if (visibility > 0)
277             open();
278         else if (visibility < 0)
279             close();
280     }
281
282     public FormEditor getFocusedForm() {
283         return focusedForm;
284     }
285
286     /** Called to synchronize with FormDesigner. Invokes NodeSelectionListener.
287      */

288     void setSelectedNodes(Node[] nodes, FormEditor form)
289         throws PropertyVetoException
290     {
291         if (form == focusedForm)
292             getExplorerManager().setSelectedNodes(nodes);
293     }
294
295     Node[] getSelectedNodes() {
296         return getExplorerManager().getSelectedNodes();
297     }
298
299     // ---------------
300
// actions
301

302     // fix of issue 42082
303
private void updatePasteAction() {
304         if(java.awt.EventQueue.isDispatchThread()) {
305             updatePasteActionInAwtThread();
306         } else {
307             java.awt.EventQueue.invokeLater(new Runnable JavaDoc() {
308                 public void run() {
309                     updatePasteActionInAwtThread();
310                 }
311             });
312         }
313     }
314
315     private void updatePasteActionInAwtThread() {
316         Node[] selected = getExplorerManager().getSelectedNodes();
317         if (selected != null && selected.length == 1) {
318             // exactly one node must be selected
319
Clipboard clipboard = getClipboard();
320             Transferable trans = clipboard.getContents(this); // [this??]
321
if (trans != null) {
322                 Node node = selected[0];
323                 PasteType[] pasteTypes = node.getPasteTypes(trans);
324                 if (pasteTypes.length != 0) {
325                     // transfer accepted by the node, we are done
326
pasteAction.setPasteTypes(pasteTypes);
327                     return;
328                 }
329
330                 boolean multiFlavor = false;
331                 try {
332                     multiFlavor = trans.isDataFlavorSupported(
333                                     ExTransferable.multiFlavor);
334                 }
335                 catch (Exception JavaDoc e) {} // ignore, should not happen
336

337                 if (multiFlavor) {
338                     // The node did not accept whole multitransfer as is - try
339
// to break it into individual transfers and paste them in
340
// sequence instead.
341
try {
342                         MultiTransferObject mto = (MultiTransferObject)
343                             trans.getTransferData(ExTransferable.multiFlavor);
344
345                         int n = mto.getCount(), i;
346                         Transferable[] t = new Transferable[n];
347                         PasteType[] p = new PasteType[n];
348
349                         for (i=0; i < n; i++) {
350                             t[i] = mto.getTransferableAt(i);
351                             pasteTypes = node.getPasteTypes(t[i]);
352                             if (pasteTypes.length == 0)
353                                 break;
354
355                             p[i] = pasteTypes[0]; // ??
356
}
357
358                         if (i == n) { // all individual transfers accepted
359
pasteAction.setPasteTypes(
360                                 new PasteType[] { new MultiPasteType(t, p) });
361                             return;
362                         }
363                     }
364                     catch (Exception JavaDoc ex) {
365                         org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex);
366                     }
367                 }
368             }
369         }
370
371         pasteAction.setPasteTypes(null);
372     }
373
374     private Clipboard getClipboard() {
375         Clipboard c = (java.awt.datatransfer.Clipboard JavaDoc)
376             Lookup.getDefault().lookup(java.awt.datatransfer.Clipboard JavaDoc.class);
377         if (c == null)
378             c = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
379         return c;
380     }
381     
382     protected String JavaDoc preferredID() {
383         return getClass().getName();
384     }
385     
386     public boolean requestFocusInWindow() {
387         super.requestFocusInWindow();
388         return treeView.requestFocusInWindow();
389     }
390
391     // ---------------
392
// innerclasses
393

394     // listener on nodes selection (ExplorerManager)
395
private class NodeSelectionListener implements PropertyChangeListener,
396                                                    ActionListener, Runnable JavaDoc
397     {
398         private javax.swing.Timer JavaDoc timer;
399
400         NodeSelectionListener() {
401             timer = new javax.swing.Timer JavaDoc(150, this);
402             timer.setCoalesce(true);
403             timer.setRepeats(false);
404         }
405
406         public void propertyChange(PropertyChangeEvent evt) {
407             if (!ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName()))
408                 return;
409             
410             FormDesigner designer;
411             if (focusedForm == null
412                     || (designer = focusedForm.getFormDesigner()) == null)
413                 return;
414
415             Node[] selectedNodes = getExplorerManager().getSelectedNodes();
416
417             if (designer.getDesignerMode() == FormDesigner.MODE_CONNECT) {
418                 // specially handle node selection in connection mode
419
if (selectedNodes.length > 0) {
420                     RADComponentCookie cookie = (RADComponentCookie)
421                         selectedNodes[0].getCookie(RADComponentCookie.class);
422                     if (cookie != null
423                         && cookie.getRADComponent() == designer.getConnectionSource()
424                         && selectedNodes.length > 1)
425                     {
426                         cookie = (RADComponentCookie)
427                             selectedNodes[selectedNodes.length-1]
428                                 .getCookie(RADComponentCookie.class);
429                     }
430                     if (cookie != null)
431                         designer.connectBean(cookie.getRADComponent(), true);
432                 }
433             }
434             else if (evt.getSource() == ComponentInspector.this.getExplorerManager())
435             { // the change comes from ComponentInspector => synchronize FormDesigner
436
designer.clearSelectionImpl();
437                 for (int i=0; i < selectedNodes.length; i++) {
438                     FormCookie formCookie = (FormCookie)
439                         selectedNodes[i].getCookie(FormCookie.class);
440                     if (formCookie != null) {
441                         Node node = formCookie.getOriginalNode();
442                         if (node instanceof RADComponentNode)
443                             designer.addComponentToSelectionImpl(
444                                 ((RADComponentNode)node).getRADComponent());
445                     }
446                 }
447                 designer.repaintSelection();
448             }
449
450             // refresh nodes' lookup with current set of cookies
451
for (int i=0; i < selectedNodes.length; i++)
452                 ((FormNode)selectedNodes[i]).updateCookies();
453
454             // restart waiting for expensive part of the update
455
timer.restart();
456         }
457
458         public void actionPerformed(ActionEvent evt) { // invoked by Timer
459
java.awt.EventQueue.invokeLater(this); // replan to EventQueue thread
460
}
461
462         /** Updates activated nodes and actions. It is executed via timer
463          * restarted each time a new selection change appears - if they come
464          * quickly e.g. due to the user is holding a cursor key, this
465          * (relatively time expensive update) is done only at the end.
466          */

467         public void run() {
468             Node[] selectedNodes = getExplorerManager().getSelectedNodes();
469             setActivatedNodes(selectedNodes);
470             // set activated nodes also on FormDesigner - to keep it in sync
471
FormDesigner designer = focusedForm != null ?
472                                     focusedForm.getFormDesigner() : null;
473             if (designer != null)
474                 designer.setActivatedNodes(selectedNodes);
475
476             updatePasteAction();
477
478             timer.stop();
479         }
480     }
481
482     // listener on clipboard changes
483
private class ClipboardChangesListener implements ClipboardListener {
484         public void clipboardChanged(ClipboardEvent ev) {
485             if (!ev.isConsumed())
486                 updatePasteAction();
487         }
488     }
489
490     // performer for DeleteAction
491
private class DeleteActionPerformer extends javax.swing.AbstractAction JavaDoc
492                                         implements ActionPerformer, Mutex.Action
493     {
494         private Node[] nodesToDestroy;
495
496         public void actionPerformed(ActionEvent e) {
497             performAction(null);
498         }
499
500         public void performAction(SystemAction action) {
501             Node[] selected = getExplorerManager().getSelectedNodes();
502
503             if (selected == null || selected.length == 0)
504                 return;
505
506             for (int i=0; i < selected.length; i++)
507                 if (!selected[i].canDestroy())
508                     return;
509
510             try { // clear nodes selection first
511
getExplorerManager().setSelectedNodes(new Node[0]);
512             }
513             catch (PropertyVetoException e) {} // cannot be vetoed
514

515             nodesToDestroy = selected;
516             if (java.awt.EventQueue.isDispatchThread())
517                 doDelete();
518             else // reinvoke synchronously in AWT thread
519
Mutex.EVENT.readAccess(this);
520         }
521
522         public Object JavaDoc run() {
523             doDelete();
524             return null;
525         }
526
527         private void doDelete() {
528             if (nodesToDestroy != null) {
529                 for (int i=0; i < nodesToDestroy.length; i++) {
530                     try {
531                         nodesToDestroy[i].destroy();
532                     }
533                     catch (java.io.IOException JavaDoc ex) { // should not happen
534
ex.printStackTrace();
535                     }
536                 }
537                 nodesToDestroy = null;
538             }
539         }
540     }
541     
542     // performer for CopyAction and CutAction
543
private class CopyCutActionPerformer extends javax.swing.AbstractAction JavaDoc
544                                          implements ActionPerformer
545     {
546         private boolean copy;
547
548         public CopyCutActionPerformer(boolean copy) {
549             this.copy = copy;
550         }
551
552         public void actionPerformed(ActionEvent e) {
553             performAction(null);
554         }
555
556         public void performAction(SystemAction action) {
557             Transferable trans;
558             Node[] selected = getExplorerManager().getSelectedNodes();
559
560             if (selected == null || selected.length == 0)
561                 trans = null;
562             else if (selected.length == 1)
563                 trans = getTransferableOwner(selected[0]);
564             else {
565                 Transferable[] transArray = new Transferable[selected.length];
566                 for (int i=0; i < selected.length; i++)
567                     if ((transArray[i] = getTransferableOwner(selected[i]))
568                                                                      == null)
569                         return;
570
571                 trans = new ExTransferable.Multi(transArray);
572             }
573
574             if (trans != null) {
575                 Clipboard clipboard = getClipboard();
576                 clipboard.setContents(trans, new StringSelection("")); // NOI18N
577
}
578         }
579
580         private Transferable getTransferableOwner(Node node) {
581             try {
582                 return copy ? node.clipboardCopy() : node.clipboardCut();
583             }
584             catch (java.io.IOException JavaDoc e) {
585                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
586                 return null;
587             }
588         }
589     }
590
591     // paste type used for ExTransferable.Multi
592
private static class MultiPasteType extends PasteType
593                                  implements Mutex.ExceptionAction
594     {
595         private Transferable[] transIn;
596         private PasteType[] pasteTypes;
597
598         MultiPasteType(Transferable[] t, PasteType[] p) {
599             transIn = t;
600             pasteTypes = p;
601         }
602
603         // performs the paste action
604
public Transferable paste() throws java.io.IOException JavaDoc {
605             if (java.awt.EventQueue.isDispatchThread())
606                 return doPaste();
607             else { // reinvoke synchronously in AWT thread
608
try {
609                     return (Transferable) Mutex.EVENT.readAccess(this);
610                 }
611                 catch (MutexException ex) {
612                     Exception JavaDoc e = ex.getException();
613                     if (e instanceof java.io.IOException JavaDoc)
614                         throw (java.io.IOException JavaDoc) e;
615                     else { // should not happen, ignore
616
e.printStackTrace();
617                         return ExTransferable.EMPTY;
618                     }
619                 }
620             }
621         }
622
623         public Object JavaDoc run() throws Exception JavaDoc {
624             return doPaste();
625         }
626
627         private Transferable doPaste() throws java.io.IOException JavaDoc {
628             Transferable[] transOut = new Transferable[transIn.length];
629             for (int i=0; i < pasteTypes.length; i++) {
630                 Transferable newTrans = pasteTypes[i].paste();
631                 transOut[i] = newTrans != null ? newTrans : transIn[i];
632             }
633             return new ExTransferable.Multi(transOut);
634         }
635     }
636
637     // -----------
638

639     // node for empty ComponentInspector
640
private static class EmptyInspectorNode extends AbstractNode {
641         public EmptyInspectorNode() {
642             super(Children.LEAF);
643             setIconBase(EMPTY_INSPECTOR_ICON_BASE);
644         }
645         public boolean canRename() {
646             return false;
647         }
648     }
649
650     final public static class ResolvableHelper implements java.io.Serializable JavaDoc {
651         static final long serialVersionUID = 7424646018839457544L;
652         public Object JavaDoc readResolve() {
653             return ComponentInspector.getDefault();
654         }
655     }
656 }
657
Popular Tags