001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: package org.netbeans.modules.xslt.tmap.multiview.tree;
021:
022: import java.awt.BorderLayout;
023: import java.awt.Component;
024: import java.awt.Dimension;
025: import java.awt.GridBagConstraints;
026: import java.awt.GridBagLayout;
027: import java.beans.PropertyChangeEvent;
028: import java.beans.PropertyChangeListener;
029: import java.beans.PropertyVetoException;
030: import java.io.IOException;
031: import java.io.ObjectInput;
032: import java.io.ObjectOutput;
033: import javax.swing.Box;
034: import javax.swing.JScrollPane;
035: import javax.swing.JToggleButton;
036: import org.netbeans.core.spi.multiview.CloseOperationState;
037: import org.netbeans.core.spi.multiview.MultiViewElement;
038: import org.netbeans.core.spi.multiview.MultiViewElementCallback;
039: import org.openide.windows.TopComponent;
040: import java.io.Serializable;
041: import java.util.Arrays;
042: import java.util.Collections;
043: import java.util.Enumeration;
044: import java.util.Iterator;
045: import javax.swing.ActionMap;
046: import javax.swing.JButton;
047:
048: import javax.swing.JComponent;
049: import javax.swing.JPanel;
050: import javax.swing.JSlider;
051: import javax.swing.JToolBar;
052: import javax.swing.SwingUtilities;
053: import javax.swing.text.DefaultEditorKit;
054: import javax.swing.text.JTextComponent;
055: import org.netbeans.core.api.multiview.MultiViewHandler;
056: import org.netbeans.core.api.multiview.MultiViewPerspective;
057: import org.netbeans.core.api.multiview.MultiViews;
058:
059: import org.netbeans.core.spi.multiview.MultiViewFactory;
060: import org.netbeans.modules.xml.xam.ui.multiview.ActivatedNodesMediator;
061: import org.netbeans.modules.xml.xam.ui.multiview.CookieProxyLookup;
062: import org.netbeans.modules.xml.xam.ui.undo.QuietUndoManager;
063: import org.netbeans.modules.xslt.tmap.TMapDataEditorSupport;
064: import org.netbeans.modules.xslt.tmap.TMapDataObject;
065: import org.netbeans.modules.xslt.tmap.model.api.TMapModel;
066: import org.netbeans.modules.xslt.tmap.navigator.TMapLogicalPanel;
067: import org.netbeans.modules.xslt.tmap.navigator.TMapNavigatorLookupHint;
068: import org.openide.awt.UndoRedo;
069: import org.openide.explorer.ExplorerManager;
070: import org.openide.explorer.ExplorerUtils;
071: import org.openide.loaders.DataNode;
072: import org.openide.util.Lookup;
073: import org.openide.util.lookup.ProxyLookup;
074: import org.openide.nodes.Node;
075: import org.openide.util.lookup.AbstractLookup;
076: import org.openide.util.lookup.InstanceContent;
077: import org.openide.util.lookup.Lookups;
078: import org.openide.windows.CloneableTopComponent;
079: import org.openide.windows.Mode;
080: import org.openide.windows.TopComponentGroup;
081: import org.openide.windows.WindowManager;
082:
083: /**
084: *
085: * @author Vitaly Bychkov
086: * @version 1.0
087: */
088: public class TreeMultiViewElement extends TopComponent implements
089: MultiViewElement, ExplorerManager.Provider, Serializable {
090:
091: private static final long serialVersionUID = 1L;
092: private static final String ACTIVATED_NODES = "activatedNodes"; // NOI18N
093: private transient MultiViewElementCallback myMultiViewObserver;
094: private transient TMapLogicalPanel myTreeView;
095:
096: private TMapDataObject myDataObject;
097: private transient JComponent myToolBarPanel;
098: private static Boolean groupVisible = null;
099: private transient InstanceContent nodesHack;
100: private ExplorerManager myExplorerManager;
101: private ActivatedNodesMediator myNodesMediator;
102: private CookieProxyLookup myCookieProxyLookup;
103:
104: // for deserialization
105: private TreeMultiViewElement() {
106: super ();
107: }
108:
109: /** Creates a new instance of DesignerMultiViewElement. This is the visual
110: * canvas 'Design' view in the multiview
111: */
112: public TreeMultiViewElement(TMapDataObject dataObject) {
113: myDataObject = dataObject;
114: initialize();
115: // initializeLookup();
116: initializeUI();
117: }
118:
119: // private void removeActiveNodeChangeListener() {
120: // if (myActiveNodeChangeListener != null) {
121: // removePropertyChangeListener(myActiveNodeChangeListener);
122: // }
123: // myActiveNodeChangeListener = null;
124: // }
125: //
126: // private void initActiveNodeChangeListener() {
127: // if (myActiveNodeChangeListener == null) {
128: // myActiveNodeChangeListener = new PropertyChangeListener() {
129: // /**
130: // * TODO: may not be needed at some point when parenting
131: // * MultiViewTopComponent delegates properly to its peer's
132: // * activatedNodes. see
133: // * http://www.netbeans.org/issues/show_bug.cgi?id=67257 note:
134: // * TopComponent.setActivatedNodes is final
135: // */
136: //
137: // public void propertyChange(PropertyChangeEvent event) {
138: // // no constant in TopComponent...lame
139: // if (event.getPropertyName().equals("activatedNodes")) { // NOI18N
140: //
141: // TopComponent tc = TopComponent.getRegistry().getActivated();
142: // /* Ignore event coming from my TC */
143: // // if(DEBUG)
144: // // Debug.verboseWithin(this,"propertyChange",getDataObject());
145: // nodesHack.set(Collections.EMPTY_LIST, null);
146: // nodesHack.set(Arrays.asList(getActivatedNodes()), null);
147: // }
148: // };
149: // };
150: // } else {
151: // removePropertyChangeListener(myActiveNodeChangeListener);
152: // }
153: //
154: // addPropertyChangeListener(myActiveNodeChangeListener);
155: // setActivatedNodes(new Node[0]);
156: // setActivatedNodes(new Node[] {getDataObject().getNodeDelegate()});
157: // }
158: //
159:
160: @Override
161: public void writeExternal(ObjectOutput out) throws IOException {
162: super .writeExternal(out);
163: out.writeObject(myDataObject);
164: }
165:
166: /**
167: * we are using Externalization semantics so that we can get a hook to call
168: * initialize() upon deserialization
169: */
170: @Override
171: public void readExternal(ObjectInput in) throws IOException,
172: ClassNotFoundException {
173: super .readExternal(in);
174: myDataObject = (TMapDataObject) in.readObject();
175: initialize();
176: initializeUI();
177: }
178:
179: private GridBagConstraints createGBConstraints() {
180: GridBagConstraints gc = new GridBagConstraints();
181: gc.fill = java.awt.GridBagConstraints.BOTH;
182: gc.insets = new java.awt.Insets(0, 0, 0, 0);
183: gc.weightx = 1.0;
184: gc.weighty = 1.0;
185: gc.anchor = GridBagConstraints.NORTHWEST;
186: return gc;
187: }
188:
189: ////////////////////////////////////////////////////////////////////////////
190: // MultiViewElement
191: ////////////////////////////////////////////////////////////////////////////
192: @Override
193: public int getPersistenceType() {
194: return TopComponent.PERSISTENCE_NEVER;
195: }
196:
197: public CloseOperationState canCloseElement() {
198: //
199: // actually if there are any visual changed NOT committed to the model
200: // then we may need to flush something here or something
201: //
202: boolean lastView = isLastView();
203:
204: if (!lastView) {
205: return CloseOperationState.STATE_OK;
206: }
207:
208: TMapDataEditorSupport editorSupport = myDataObject
209: .getEditorSupport();
210: boolean modified = editorSupport.isModified();
211:
212: if (!modified) {
213: return CloseOperationState.STATE_OK;
214: } else {
215: return MultiViewFactory.createUnsafeCloseState(
216: "Data Object Modified", null, null); // NOI18N
217: }
218: }
219:
220: @Override
221: public void componentActivated() {
222: super .componentActivated();
223: // not sure that we need to add undo manager each time when
224: // component is activated, but calling method addUndoManager() more
225: // than once is not a problem.
226: //// addUndoManager();
227: ExplorerUtils.activateActions(myExplorerManager, true);
228: // not sure that we need to add undo manager each time when
229: // component is activated, but calling method addUndoManager() more
230: // than once is not a problem.
231: // addUndoManager();
232: myTreeView.requestFocusInWindow();
233: }
234:
235: @Override
236: public void componentClosed() {
237: super .componentClosed();
238: cleanup();
239: }
240:
241: @Override
242: public void componentDeactivated() {
243: super .componentDeactivated();
244: ExplorerUtils.activateActions(myExplorerManager, false);
245: }
246:
247: @Override
248: public void componentHidden() {
249: super .componentHidden();
250: if (myTreeView != null) {
251: myTreeView.setVisible(false);
252: }
253: updateTMapTcGroupVisibility(false);
254: // removeActiveNodeChangeListener();
255: }
256:
257: @Override
258: public void componentOpened() {
259: super .componentOpened();
260: }
261:
262: @Override
263: public void componentShowing() {
264: super .componentShowing();
265: // Node[] curNodes = getActivatedNodes();
266: // if (curNodes != null) {
267: // curNodes = curNodes.clone();
268: // }
269:
270: if (myTreeView != null) {
271: myTreeView.setVisible(true);
272: }
273:
274: //// addUndoManager();
275: //
276: updateTMapTcGroupVisibility(true);
277: // initActiveNodeChangeListener();
278:
279: // showActivatedNodeStatus();
280:
281: // activate cur node
282: // if (myMultiViewObserver != null) {
283: // TopComponent thisTc = myMultiViewObserver.getTopComponent();
284: // if ( thisTc != null ) {
285: //
286: // // data node is the node associated with dataobject(BPELDataObject)
287: // if (curNodes == null || curNodes.length == 0 || curNodes[0] instanceof DataNode) {
288: // curNodes= myTreeView.getExplorerManager().getSelectedNodes();
289: // curNodes = curNodes != null
290: // ? curNodes.clone() : new Node[] {myDataObject.getNodeDelegate()};
291: // }
292: //
293: // if (curNodes != null && curNodes.length > 0) {
294: // thisTc.setActivatedNodes(new Node[0]);
295: // setActivatedNodes(new Node[0]);
296: //
297: //
298: // thisTc.setActivatedNodes(curNodes);
299: // setActivatedNodes(curNodes);
300: // }
301: // }
302: // }
303:
304: }
305:
306: // private void showActivatedNodeStatus() {
307: // if (myMultiViewObserver != null) {
308: // TopComponent thisTc = myMultiViewObserver.getTopComponent();
309: // if ( thisTc != null ) {
310: // Node[] tcActivatedNodes = thisTc.getActivatedNodes();
311: // System.out.println("design MVTC activated nodes: "+tcActivatedNodes);
312: // if (tcActivatedNodes != null) {
313: // for (int i = 0; i < tcActivatedNodes.length; i++) {
314: // Node node = tcActivatedNodes[i];
315: // System.out.println(i+") design tc activated node: "+node+"; displayName: "+node.getDisplayName());
316: // }
317: // } else {
318: // System.out.println("tcActivatedNodes is null");
319: // }
320: //
321: // Node[] designMvActivatedNodes = getActivatedNodes();
322: // if (designMvActivatedNodes != null) {
323: // for (int i = 0; i < designMvActivatedNodes.length; i++) {
324: // Node node = designMvActivatedNodes[i];
325: // System.out.println(i+") design mv activated node: "+node+"; displayName: "+node.getDisplayName());
326: // }
327: // } else {
328: // System.out.println("designMvActivatedNodes is null");
329: // }
330: //
331: // } else {
332: // System.out.println("this TC is null");
333: // }
334: // } else {
335: // System.out.println("myMultiViewObserver is null");
336: // }
337: //
338: ////// TopComponent regTcActive = TopComponent.getRegistry().getActivated();
339: ////// System.out.println("design tc : regTcActive: "+regTcActive);
340: //// Node[] regNodes = TopComponent.getRegistry().getActivatedNodes();
341: //// if (regNodes != null) {
342: //// for (int i = 0; i < regNodes.length; i++) {
343: //// Node node = regNodes[i];
344: //// System.out.println(i+") design tc registry activated node: "+node+"; displayName: "+node.getDisplayName());
345: //// }
346: //// } else {
347: //// System.out.println("regNodes is null");
348: //// }
349: //
350: // }
351:
352: public JComponent getToolbarRepresentation() {
353: if (myToolBarPanel == null) {
354: JToolBar toolbar = new JToolBar();
355: toolbar.setFloatable(false);
356: //TODO a toolbar.addSeparator();
357:
358: // toolbar.add(Box.createHorizontalStrut(1));
359: // TODO r
360: // toolbar.add(new JButton("testButton"));
361: // TODO a toolbar.addSeparator();
362: int maxButtonHeight = 0;
363:
364: for (Component c : toolbar.getComponents()) {
365: if (c instanceof JButton || c instanceof JToggleButton) {
366: maxButtonHeight = Math.max(
367: c.getPreferredSize().height,
368: maxButtonHeight);
369: }
370: }
371:
372: for (Component c : toolbar.getComponents()) {
373: if (c instanceof JButton || c instanceof JToggleButton) {
374: Dimension size = c.getMaximumSize();
375: size.height = maxButtonHeight;
376: c.setMaximumSize(size);
377: c.setMinimumSize(c.getPreferredSize());
378: } else if (c instanceof JTextComponent) {
379: c.setMaximumSize(c.getPreferredSize());
380: c.setMinimumSize(c.getPreferredSize());
381: } else if (c instanceof JSlider) {
382: Dimension size;
383: size = c.getMaximumSize();
384: size.width = 160;
385: c.setMaximumSize(size);
386:
387: size = c.getPreferredSize();
388: size.width = 160;
389: c.setPreferredSize(size);
390: } else {
391: c.setMinimumSize(c.getPreferredSize());
392: }
393: }
394: myToolBarPanel = toolbar;
395: }
396: return myToolBarPanel;
397: }
398:
399: @Override
400: public UndoRedo getUndoRedo() {
401: return myDataObject.getEditorSupport().getUndoManager();
402: }
403:
404: public JComponent getVisualRepresentation() {
405: return this ;
406: }
407:
408: public void setMultiViewCallback(MultiViewElementCallback callback) {
409: myMultiViewObserver = callback;
410: }
411:
412: @Override
413: public void requestVisible() {
414: if (myMultiViewObserver != null) {
415: myMultiViewObserver.requestVisible();
416: } else {
417: super .requestVisible();
418: }
419: }
420:
421: @Override
422: public void requestActive() {
423: if (myMultiViewObserver != null) {
424: myMultiViewObserver.requestActive();
425: } else {
426: super .requestActive();
427: }
428: }
429:
430: protected boolean closeLast() {
431: return true;
432: }
433:
434: private TMapLogicalPanel createTreeView() {
435: TMapLogicalPanel view = new TreeMultiViewVisualPanel();//TMapLogicalPanel();
436:
437: Lookup lookup = getLookup();
438: TMapModel model = lookup.lookup(TMapModel.class);
439: view.navigate(lookup, model);
440:
441: return view;
442: }
443:
444: private void initializeUI() {
445: setLayout(new GridBagLayout());
446:
447: myTreeView = createTreeView();
448: JScrollPane scroll = new JScrollPane(
449: /*new JPanel()*/myTreeView);
450: scroll.setBorder(null);
451: GridBagConstraints gc = createGBConstraints();
452: gc.gridx = 0;
453: gc.gridy = 0;
454: scroll.getVerticalScrollBar().setUnitIncrement(16);
455: scroll.getHorizontalScrollBar().setUnitIncrement(16);
456: add(scroll, gc);
457:
458: setVisible(true);
459: }
460:
461: /**
462: * Open or close the tmap_designer TopComponentGroup.
463: */
464: private static void updateTMapTcGroupVisibility(final boolean show) {
465: // when active TopComponent changes, check if we should open or close
466: // the TMap editor group of windows
467: WindowManager wm = WindowManager.getDefault();
468: final TopComponentGroup group = wm
469: .findTopComponentGroup("tmap_designer"); // NOI18N
470: if (group == null) {
471: return; // group not found (should not happen)
472: }
473: //
474: boolean designerSelected = false;
475: Iterator it = wm.getModes().iterator();
476: while (it.hasNext()) {
477: Mode mode = (Mode) it.next();
478: TopComponent selected = mode.getSelectedTopComponent();
479: if (selected != null) {
480: MultiViewHandler mvh = MultiViews
481: .findMultiViewHandler(selected);
482: if (mvh != null) {
483: MultiViewPerspective mvp = mvh
484: .getSelectedPerspective();
485: if (mvp != null) {
486: String id = mvp.preferredID();
487: if (TreeMultiViewElementDesc.PREFERRED_ID
488: .equals(id)) {
489: designerSelected = true;
490: break;
491: }
492: }
493: }
494: }
495: }
496: //
497: if (designerSelected && !Boolean.TRUE.equals(groupVisible)) {
498: group.open();
499: } else if (!designerSelected
500: && !Boolean.FALSE.equals(groupVisible)) {
501: group.close();
502: }
503: //
504: groupVisible = designerSelected ? Boolean.TRUE : Boolean.FALSE;
505: }
506:
507: public static String getMVEditorActivePanelPrefferedId() {
508: TopComponent activeTC = WindowManager.getDefault()
509: .getRegistry().getActivated();
510: MultiViewHandler mvh = MultiViews
511: .findMultiViewHandler(activeTC);
512: if (mvh == null) {
513: return null;
514: }
515:
516: MultiViewPerspective mvp = mvh.getSelectedPerspective();
517: if (mvp != null) {
518: return mvp.preferredID();
519: }
520:
521: return null;
522: }
523:
524: private boolean isLastView() {
525: boolean oneOrLess = true;
526: Enumeration en = ((CloneableTopComponent) myMultiViewObserver
527: .getTopComponent()).getReference().getComponents();
528: if (en.hasMoreElements()) {
529: en.nextElement();
530: if (en.hasMoreElements()) {
531: oneOrLess = false;
532: }
533: }
534:
535: return oneOrLess;
536: }
537:
538: private TMapDataObject getDataObject() {
539: return myDataObject;
540: }
541:
542: private void initialize() {
543: myExplorerManager = new ExplorerManager();
544:
545: ActionMap actionMap = getActionMap();
546: actionMap.put(DefaultEditorKit.copyAction, ExplorerUtils
547: .actionCopy(myExplorerManager));
548: actionMap.put(DefaultEditorKit.cutAction, ExplorerUtils
549: .actionCut(myExplorerManager));
550: actionMap.put(DefaultEditorKit.pasteAction, ExplorerUtils
551: .actionPaste(myExplorerManager));
552: actionMap.put("delete", ExplorerUtils.actionDelete(
553: myExplorerManager, false));
554:
555: Node delegate = myDataObject.getNodeDelegate();
556: myNodesMediator = new ActivatedNodesMediator(delegate);
557: myNodesMediator.setExplorerManager(this );
558:
559: Lookup proxyLookup = new ProxyLookup(new Lookup[] {
560: Lookups.fixed(new Object[] { TMapNavigatorLookupHint
561: .getInstance(),
562: // Need ActionMap in lookup so our actions are used.
563: // actionMap,
564: // Need the data object registered in the lookup so that the
565: // projectui code will close our open editor windows when the
566: // project is closed.
567: // myDataObject,
568: }), Lookups.singleton(myDataObject),
569: myDataObject.getLookup(),// this lookup contain objects that are used in OM clients
570: Lookups.singleton(this ),
571:
572: myNodesMediator.getLookup(),
573: // The Node delegate Lookup must be the last one in the list
574: // for the CookieProxyLookup to work properly.
575: delegate.getLookup(), });
576:
577: proxyLookup = Lookups.exclude(proxyLookup, ActionMap.class);
578:
579: myCookieProxyLookup = new CookieProxyLookup(
580: new Lookup[] { proxyLookup }, delegate);
581:
582: associateLookup(myCookieProxyLookup);
583: addPropertyChangeListener(ACTIVATED_NODES, myNodesMediator);
584: addPropertyChangeListener(ACTIVATED_NODES, myCookieProxyLookup);
585:
586: setLayout(new BorderLayout());
587: }
588:
589: private void cleanup() {
590: try {
591: myExplorerManager.setSelectedNodes(new Node[0]);
592: } catch (PropertyVetoException e) {
593: }
594: removePropertyChangeListener(ACTIVATED_NODES, myNodesMediator);
595: removePropertyChangeListener(ACTIVATED_NODES,
596: myCookieProxyLookup);
597: myNodesMediator = null;
598: myCookieProxyLookup = null;
599:
600: //required to release all references to OM
601: myTreeView = null;
602: removeAll();
603: }
604:
605: // private void initializeLookup() {
606: // associateLookup(createAssociateLookup());
607: // initActiveNodeChangeListener();
608: // }
609:
610: private Lookup createAssociateLookup() {
611: ActionMap actionMap = getActionMap();
612: actionMap.put(DefaultEditorKit.copyAction, null);
613: actionMap.put(DefaultEditorKit.cutAction, null);
614: actionMap.put(DefaultEditorKit.pasteAction, null);
615:
616: nodesHack = new InstanceContent();
617: //
618: // see http://www.netbeans.org/issues/show_bug.cgi?id=67257
619: //
620: return new ProxyLookup(new Lookup[] {
621: myDataObject.getLookup(), // this lookup contain objects that are used in OM clients
622: Lookups.fixed(actionMap),
623: new AbstractLookup(nodesHack),
624:
625: });
626: }
627:
628: public ExplorerManager getExplorerManager() {
629: return myExplorerManager;
630: }
631:
632: //// /**
633: //// * Adds the undo/redo manager to the bpel model as an undoable
634: //// * edit listener, so it receives the edits onto the queue.
635: //// */
636: //// private void addUndoManager() {
637: //// TMapDataEditorSupport support = myDataObject.getEditorSupport();
638: //// if ( support!= null ){
639: //// QuietUndoManager undo = support.getUndoManager();
640: //// support.addUndoManagerToModel( undo );
641: //// }
642: //// }
643: }
|