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: package org.netbeans.modules.bpel.mapper.multiview;
020:
021: import java.awt.BorderLayout;
022: import java.awt.CardLayout;
023: import java.awt.Component;
024: import java.awt.Container;
025: import java.awt.Dimension;
026: import java.awt.EventQueue;
027: import java.awt.KeyboardFocusManager;
028: import java.beans.PropertyVetoException;
029: import java.io.IOException;
030: import java.io.ObjectInput;
031: import java.io.ObjectOutput;
032: import java.io.Serializable;
033: import java.util.Enumeration;
034: import javax.swing.JButton;
035: import javax.swing.JComboBox;
036: import javax.swing.JComponent;
037: import javax.swing.JEditorPane;
038: import javax.swing.JPanel;
039: import javax.swing.JToggleButton;
040: import javax.swing.JToolBar;
041: import javax.swing.JTree;
042: import javax.swing.SwingUtilities;
043: import javax.swing.text.JTextComponent;
044: import org.netbeans.core.spi.multiview.CloseOperationState;
045: import org.netbeans.core.spi.multiview.MultiViewElement;
046: import org.netbeans.core.spi.multiview.MultiViewElementCallback;
047: import org.netbeans.core.spi.multiview.MultiViewFactory;
048: import org.netbeans.modules.bpel.core.BPELDataEditorSupport;
049: import org.netbeans.modules.bpel.core.BPELDataObject;
050: import org.netbeans.modules.bpel.mapper.model.BpelMapperFactory;
051: import org.netbeans.modules.bpel.mapper.palette.Palette;
052: import org.netbeans.modules.bpel.mapper.tree.spi.MapperTcContext;
053: import org.netbeans.modules.soa.mappercore.Mapper;
054: import org.netbeans.modules.soa.mappercore.model.MapperModel;
055: import org.openide.awt.UndoRedo;
056: import org.openide.explorer.ExplorerManager;
057: import org.openide.explorer.ExplorerUtils;
058: import org.openide.nodes.Node;
059: import org.openide.util.Lookup;
060: import org.openide.util.NbBundle;
061: import org.openide.util.lookup.Lookups;
062: import org.openide.windows.CloneableTopComponent;
063: import org.openide.windows.TopComponent;
064:
065: /**
066: *
067: * @author Vitaly Bychkov
068: * @version 1.0
069: */
070: public abstract class MapperMultiviewElement extends TopComponent
071: implements MultiViewElement, Serializable, MapperTcContext,
072: ExplorerManager.Provider {
073:
074: // private static final long serialVersionUID = 1L;
075: public static final String MAPPER_PANEL_ID = "mapperPanelId"; // NOI18N
076: private transient JPanel myMapperPanel;
077: private transient Mapper myMapper;
078: private transient JEditorPane myErrorPanel;
079: private transient CardLayout myCardLayout;
080: private transient JComponent myToolBarPanel;
081: private transient MultiViewElementCallback myMultiViewObserver;
082: private BPELDataObject myDataObject;
083: private DesignContextChangeListener myContextChangeListener;
084: private DesignContextController myContextController;
085: private Boolean groupVisible;
086: private ActivatedNodesMediator myNodesMediator;
087: private CookieProxyLookup myCookieProxyLookup;
088: private ExplorerManager myExplorerManager;
089:
090: // for deexternalization
091: public MapperMultiviewElement() {
092: super ();
093: }
094:
095: public MapperMultiviewElement(BPELDataObject dObj) {
096: myDataObject = dObj;
097: initialize();
098: initializeUI();
099: }
100:
101: public JComponent getVisualRepresentation() {
102: return this ;
103: }
104:
105: public JComponent getToolbarRepresentation() {
106: if (myToolBarPanel == null) {
107: JToolBar toolbar = new JToolBar();
108: toolbar.setFloatable(false);
109: toolbar.setFocusable(false);
110: toolbar.addSeparator();
111:
112: int maxButtonHeight = 0;
113:
114: for (Component c : toolbar.getComponents()) {
115: if (c instanceof JButton || c instanceof JToggleButton) {
116: maxButtonHeight = Math.max(
117: c.getPreferredSize().height,
118: maxButtonHeight);
119: }
120: }
121:
122: for (Component c : toolbar.getComponents()) {
123: if (c instanceof JButton || c instanceof JToggleButton) {
124: Dimension size = c.getMaximumSize();
125: size.height = maxButtonHeight;
126: c.setMaximumSize(size);
127: c.setMinimumSize(c.getPreferredSize());
128: c.setFocusable(false);
129: } else if ((c instanceof JTextComponent)
130: || (c instanceof JComboBox)) {
131: c.setMaximumSize(c.getPreferredSize());
132: c.setMinimumSize(c.getPreferredSize());
133: } else {
134: c.setMinimumSize(c.getPreferredSize());
135: c.setFocusable(false);
136: }
137: }
138:
139: myToolBarPanel = toolbar;
140: }
141:
142: return myToolBarPanel;
143: }
144:
145: public void setMultiViewCallback(MultiViewElementCallback callback) {
146: myMultiViewObserver = callback;
147: }
148:
149: // TODO r | m
150: public DesignContextController getDesignContextController() {
151: return myContextController;
152: }
153:
154: // TODO r
155: public TopComponent getTopComponent() {
156: return this ;
157: }
158:
159: public CloseOperationState canCloseElement() {
160: //
161: // actually if there are any visual changed NOT committed to the model
162: // then we may need to flush something here or something
163: //
164: boolean lastView = isLastView();
165:
166: if (!lastView) {
167: return CloseOperationState.STATE_OK;
168: }
169:
170: BPELDataEditorSupport editorSupport = myDataObject
171: .getEditorSupport();
172: boolean modified = editorSupport.isModified();
173:
174: if (!modified) {
175: return CloseOperationState.STATE_OK;
176: } else {
177: return MultiViewFactory.createUnsafeCloseState(
178: "Data Object Modified", null, null); // NOI18N
179: }
180: }
181:
182: // TODO m
183: @Override
184: public void componentActivated() {
185: // System.out.println("mapperTC activated "+getClass());
186: super .componentActivated();
187:
188: boolean clearFocus = true;
189:
190: if (myMapper != null) {
191: if (!isFocusInside(myMapper)) {
192: Component focusable = getFocusableDescendant(myMapper);
193: if (focusable != null) {
194: focusable.requestFocusInWindow();
195: clearFocus = false;
196: }
197: }
198: }
199:
200: if (clearFocus) {
201: KeyboardFocusManager.getCurrentKeyboardFocusManager()
202: .clearGlobalFocusOwner();
203: }
204:
205: activateContextNode();
206: ExplorerUtils.activateActions(myExplorerManager, true);
207: }
208:
209: private boolean isFocusInside(Component container) {
210: Component focusOwner = KeyboardFocusManager
211: .getCurrentKeyboardFocusManager().getFocusOwner();
212: for (Component c = focusOwner; c != null; c = c.getParent()) {
213: if (c == container) {
214: return true;
215: }
216: }
217:
218: return false;
219: }
220:
221: private Component getFocusableDescendant(Component ancestor) {
222: if (ancestor instanceof JTree) {
223: return ancestor;
224: }
225:
226: Component result = null;
227:
228: if (ancestor instanceof Container) {
229: Container container = (Container) ancestor;
230: for (int i = container.getComponentCount() - 1; i >= 0; i--) {
231: result = getFocusableDescendant(container
232: .getComponent(i));
233: if (result != null)
234: break;
235: }
236: }
237:
238: return result;
239: }
240:
241: @Override
242: public void componentOpened() {
243: // System.out.println("mapperTC opened: "+getClass());
244: super .componentOpened();
245: }
246:
247: @Override
248: public void componentShowing() {
249: // System.out.println("mapperTC showing "+getClass());
250: super .componentShowing();
251: myContextController.showMapper();
252: }
253:
254: @Override
255: public void componentDeactivated() {
256: // System.out.println("mapperTC deactivated "+getClass());
257: super .componentDeactivated();
258: ExplorerUtils.activateActions(myExplorerManager, false);
259: }
260:
261: @Override
262: public void componentHidden() {
263: // System.out.println("mapperTC hidden "+getClass());
264: super .componentHidden();
265: myContextController.hideMapper();
266: }
267:
268: @Override
269: public void componentClosed() {
270: // System.out.println("mapperTC closed "+getClass());
271: super .componentClosed();
272: cleanup();
273: }
274:
275: private void cleanup() {
276: try {
277: myExplorerManager.setSelectedNodes(new Node[0]);
278: } catch (PropertyVetoException e) {
279: }
280: //// removePropertyChangeListener(myContextChangeListener);
281:
282: removePropertyChangeListener(
283: TopComponent.Registry.PROP_ACTIVATED_NODES,
284: myNodesMediator);
285: removePropertyChangeListener(
286: TopComponent.Registry.PROP_ACTIVATED_NODES,
287: myCookieProxyLookup);
288: myNodesMediator = null;
289: myCookieProxyLookup = null;
290:
291: //required to release all references to OM
292: // myMapper.closeView();
293: myContextController.cleanup();
294: myContextController = null;
295: myContextChangeListener = null;
296: myMapper = null;
297: removeAll();
298: }
299:
300: @Override
301: public UndoRedo getUndoRedo() {
302: return myDataObject.getEditorSupport().getUndoManager();
303: }
304:
305: /**
306: * Opens or closes the bpel_mapper_tcgroup TopComponentGroup.
307: *
308: * TODO: Figure out if it necessary to use a group here or using
309: * of topComp.open() or topComp.close is enough.
310: */
311: public void showMapperTcGroup(final boolean show) {
312: // TODO a & m
313: //////// // when active TopComponent changes, check if we should open or close
314: //////// // the BPEL editor group of windows
315: //////// WindowManager wm = WindowManager.getDefault();
316: //////// final TopComponentGroup group = wm.findTopComponentGroup("bpel_designer"); // NOI18N
317: //////// if (group == null) {
318: //////// return; // group not found (should not happen)
319: //////// }
320: //////// //
321: //////// boolean mapperSelected = false;
322: //////// Iterator it = wm.getModes().iterator();
323: //////// while (it.hasNext()) {
324: //////// Mode mode = (Mode) it.next();
325: //////// TopComponent selected = mode.getSelectedTopComponent();
326: //////// if (selected != null) {
327: //////// MultiViewHandler mvh = MultiViews.findMultiViewHandler(selected);
328: //////// if (mvh != null) {
329: //////// MultiViewPerspective mvp = mvh.getSelectedPerspective();
330: //////// if (mvp != null) {
331: //////// String id = mvp.preferredID();
332: //////// if (BpelMapperMultiviewElementDesc.PREFERED_ID.equals(id)) {
333: //////// mapperSelected = true;
334: //////// break;
335: //////// }
336: //////// }
337: //////// }
338: //////// }
339: //////// }
340: //////// //
341: //////// if (mapperSelected && !Boolean.TRUE.equals(groupVisible)) {
342: //////// group.open();
343: //////// } else if (!mapperSelected && !Boolean.FALSE.equals(groupVisible)) {
344: //////// group.close();
345: //////// }
346: //////// //
347: //////// groupVisible = mapperSelected ? Boolean.TRUE : Boolean.FALSE;
348: }
349:
350: public static String getTitleBase() {
351: return NbBundle.getMessage(MapperMultiviewElement.class,
352: "TITLE_MAPPER_WINDOW"); // NOI18N
353: }
354:
355: public ExplorerManager getExplorerManager() {
356: return myExplorerManager;
357: }
358:
359: //------------------------------------------------------------------------------
360: private boolean isLastView() {
361: boolean oneOrLess = true;
362: Enumeration en = ((CloneableTopComponent) myMultiViewObserver
363: .getTopComponent()).getReference().getComponents();
364: if (en.hasMoreElements()) {
365: en.nextElement();
366: if (en.hasMoreElements()) {
367: oneOrLess = false;
368: }
369: }
370:
371: return oneOrLess;
372: }
373:
374: protected abstract DesignContextController createDesignContextController();
375:
376: protected void initialize() {
377: ShowMapperCookie showCookie = new ShowMapperCookie() {
378: public void show(MapperModel mapperModel) {
379: MapperMultiviewElement.this .setMapperModel(mapperModel);
380: }
381:
382: public void show(String message) {
383: MapperMultiviewElement.this .setMessage(message);
384: }
385: };
386:
387: myExplorerManager = new ExplorerManager();
388: Node delegate = myDataObject.getNodeDelegate();
389: myNodesMediator = new ActivatedNodesMediator(delegate);
390: myNodesMediator.setExplorerManager(this );
391: myCookieProxyLookup = new CookieProxyLookup(new Lookup[] {
392: Lookups.fixed(new Object[] { showCookie,
393: // Need the data object registered in the lookup so that the
394: // projectui code will close our open editor windows when the
395: // project is closed.
396: myDataObject, }), myDataObject.getLookup(),// this lookup contain objects that are used in OM clients
397: Lookups.singleton(this ),
398:
399: myNodesMediator.getLookup(),
400: // The Node delegate Lookup must be the last one in the list
401: // for the CookieProxyLookup to work properly.
402: delegate.getLookup(), }, delegate);
403:
404: associateLookup(myCookieProxyLookup);
405: addPropertyChangeListener(
406: TopComponent.Registry.PROP_ACTIVATED_NODES,
407: myNodesMediator);
408: addPropertyChangeListener(
409: TopComponent.Registry.PROP_ACTIVATED_NODES,
410: myCookieProxyLookup);
411: myContextController = createDesignContextController();
412: // initListeneres();
413: }
414:
415: protected void initializeUI() {
416: // activate cur node
417: activateContextNode();
418: // create empty mapper;
419: myMapperPanel = new JPanel();
420: myMapperPanel.setLayout(new BorderLayout());
421: myMapper = BpelMapperFactory.createMapper(null);
422: myMapperPanel.add(myMapper, BorderLayout.CENTER);
423: myMapperPanel.add(new Palette(myMapper).getPanel(),
424: BorderLayout.NORTH);
425:
426: myErrorPanel = new MessagePanel(myMapper);
427: myErrorPanel.setText("<b>It is Error Panel !!!</b>"); // NOI18N
428:
429: myCardLayout = new CardLayout();
430: setLayout(myCardLayout);
431: add(myMapperPanel, MAPPER_PANEL_ID);
432: add(myErrorPanel, MessagePanel.MESSAGE_PANEL_ID);
433:
434: }
435:
436: private void activateContextNode() {
437: BpelDesignContext context = myContextController != null ? myContextController
438: .getContext()
439: : null;
440: Node aNode = null;
441: if (DesignContextUtil.isValidContext(context)) {
442: aNode = context == null ? null : context.getActivatedNode();
443: }
444:
445: Node[] tcANodes = getActivatedNodes();
446: Node tcANode = null;
447:
448: if (tcANodes != null && tcANodes.length > 0
449: && DesignContextUtil.isValidNode(tcANodes[0])) {
450: tcANode = tcANodes[0];
451: }
452:
453: if (tcANode == null || !tcANode.equals(aNode)) {
454: if (aNode != null) {
455: setActivatedNodes(new Node[] { aNode });
456: } else {
457: setActivatedNodes(new Node[0]);
458: }
459: }
460: }
461:
462: // TODO m
463: // protected void initListeneres( ) {
464: //
465: //// Check if the BPEL mapper is subscribed to changes of activated node
466: //// and subscribe if it does not.
467: // if (myContextChangeListener == null) {
468: //// myContextChangeListener = new DesignContextChangeListener(
469: //// myContextController);
470: //// myContextController.setContext(DesignContextChangeListener.getActivatedContext());
471: // } else {
472: //// TopComponent.getRegistry().
473: //// removePropertyChangeListener(myContextChangeListener);
474: // }
475: //
476: // //add TopComponent Active Node changes listener :
477: //// TopComponent.getRegistry().
478: //// addPropertyChangeListener(myContextChangeListener);
479: //
480: // }
481:
482: // private void showContextMapper() {
483: // Node[] nodes = TopComponent.getRegistry().getActivatedNodes();
484: // if (nodes != null && nodes.length > 0 && nodes[0] instanceof InstanceRef) {
485: // Object entity = ((InstanceRef) nodes[0]).getReference();
486: // if (entity instanceof BpelEntity) {
487: // BpelEntity bpelEntity = (BpelEntity)entity;
488: // setMapperModel(
489: //// BpelMapperModelFactory.getInstance().constructModel(
490: //// bpelEntity, nodes[0].getLookup()));
491: // BpelMapperModelFactory.getInstance().constructModel(
492: // myContextController.getContext()));
493: // }
494: //
495: // }
496: // }
497:
498: // TODO r
499: public void setMapper(final Mapper newMapper) {
500: assert true : "mapper shouldn't be changed in mapper tc";
501: //// if (!EventQueue.isDispatchThread()) {
502: //// SwingUtilities.invokeLater(new Runnable() {
503: //// public void run() {
504: //// MapperMultiviewElement.this.setMapperInAwt(newMapper);
505: //// }
506: //// });
507: //// } else {
508: //// setMapperInAwt(newMapper);
509: //// }
510: }
511:
512: private void setMapperInAwt(Mapper newMapper) {
513: assert EventQueue.isDispatchThread();
514:
515: //removeAll();
516:
517: if (newMapper != null) {
518: myCardLayout.show(this , MAPPER_PANEL_ID);
519: }
520: revalidate();
521: repaint();
522: }
523:
524: private void showMapper() {
525: assert EventQueue.isDispatchThread();
526: if (myMapper == null) {
527: return;
528: }
529:
530: myCardLayout.show(this , MAPPER_PANEL_ID);
531:
532: revalidate();
533: repaint();
534: }
535:
536: // TODO r
537: public Mapper getMapper() {
538: return myMapper;
539: }
540:
541: private void setMessage(final String message) {
542: if (!EventQueue.isDispatchThread()) {
543: SwingUtilities.invokeLater(new Runnable() {
544: public void run() {
545: MapperMultiviewElement.this
546: .setMessageInAwt(message);
547: // updateTitle();
548: }
549: });
550: } else {
551: setMessageInAwt(message);
552: // updateContextTitle();
553: }
554: }
555:
556: private void setMessageInAwt(String message) {
557: assert EventQueue.isDispatchThread();
558:
559: if (message != null) {
560: myErrorPanel.setText(message);
561: } else {
562: myErrorPanel
563: .setText(NbBundle.getMessage(
564: MapperMultiviewElement.class,
565: "LBL_CantShowMapper")); // NOI18N
566: }
567: myCardLayout.show(this , MessagePanel.MESSAGE_PANEL_ID);
568: }
569:
570: // TODO m
571: public void setMapperModel(final MapperModel mModel) {
572:
573: if (!EventQueue.isDispatchThread()) {
574: SwingUtilities.invokeLater(new Runnable() {
575: public void run() {
576: MapperMultiviewElement.this
577: .setMapperModelInAwt(mModel);
578: // updateContextTitle();
579: }
580: });
581: } else {
582: setMapperModelInAwt(mModel);
583: // updateContextTitle();
584: }
585: }
586:
587: private void setMapperModelInAwt(MapperModel mModel) {
588: assert EventQueue.isDispatchThread();
589:
590: if (myMapper != null) {
591: myMapper.setModel(mModel);
592:
593: //
594: // setMapper(myMapper);
595: showMapper();
596: }
597: //
598: // else {
599: // Mapper newMapper = createMapper(mModel);
600: // setMapper(newMapper);
601: // }
602: }
603:
604: protected abstract Mapper createMapper(MapperModel mModel);
605:
606: // private void updateContextTitle() {
607: // assert EventQueue.isDispatchThread();
608: //
609: // String activeNodeDisplayName = null;
610: // BpelDesignContext currentDesignContext = myContextController.getContext();
611: // if (currentDesignContext != null) {
612: // Node node = currentDesignContext.getActivatedNode();
613: // if (node != null) {
614: // activeNodeDisplayName = node.getDisplayName();
615: // }
616: // }
617: // if (activeNodeDisplayName != null && myContextTitle != null) {
618: // myContextTitle.setText("Context Entity: "+activeNodeDisplayName);
619: // //setDisplayName(getTitleBase() + " - " + activeNodeDisplayName); // NOI18N
620: //
621: // }
622: // }
623:
624: @Override
625: public void writeExternal(ObjectOutput out) throws IOException {
626: super .writeExternal(out);
627: out.writeObject(myDataObject);
628: }
629:
630: /**
631: * we are using Externalization semantics so that we can get a hook to call
632: * initialize() upon deserialization
633: */
634: @Override
635: public void readExternal(ObjectInput in) throws IOException,
636: ClassNotFoundException {
637: super .readExternal(in);
638:
639: myDataObject = (BPELDataObject) in.readObject();
640:
641: initialize();
642: // initializeLookup();
643: //
644: // FIX ME
645: //
646: initializeUI();
647: }
648:
649: }
|