001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.ui.swing.drawingarea;
043:
044: import java.util.Iterator;
045: import java.util.List;
046:
047: import org.netbeans.modules.uml.common.generics.IteratorT;
048: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
049: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamespace;
050: import org.netbeans.modules.uml.core.metamodel.core.foundation.IPresentationElement;
051: import org.netbeans.modules.uml.core.metamodel.diagrams.IDiagram;
052: import org.netbeans.modules.uml.core.metamodel.diagrams.IDiagramKind;
053: import org.netbeans.modules.uml.core.metamodel.diagrams.IGraphEventKind;
054: import org.netbeans.modules.uml.core.support.umlutils.ETArrayList;
055: import org.netbeans.modules.uml.core.support.umlutils.ETList;
056: import org.netbeans.modules.uml.ui.controls.drawingarea.DiagramAreaEnumerations;
057: import org.netbeans.modules.uml.ui.controls.drawingarea.ModelElementSetter;
058: import org.netbeans.modules.uml.ui.products.ad.graphobjects.ETEdge;
059: import org.netbeans.modules.uml.ui.products.ad.graphobjects.ETNode;
060: import org.netbeans.modules.uml.ui.support.applicationmanager.IPresentationTypesMgr;
061: import org.netbeans.modules.uml.ui.support.helpers.GUIBlocker;
062: import org.netbeans.modules.uml.ui.support.helpers.IGUIBlocker;
063: import org.netbeans.modules.uml.ui.support.helpers.IGUIBlocker.GBK;
064: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine;
065: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IETGraphObject;
066: import org.netbeans.modules.uml.ui.support.viewfactorysupport.TypeConversions;
067: import com.tomsawyer.drawing.TSLabel;
068: import com.tomsawyer.editor.TSEGraph;
069: import com.tomsawyer.editor.TSEObject;
070: import com.tomsawyer.graph.TSEdge;
071: import com.tomsawyer.graph.TSGraphObject;
072: import com.tomsawyer.graph.TSNode;
073: import com.tomsawyer.util.TSObject;
074:
075: /**
076: * @author sumitabhk
077: *
078: */
079: public class ETElementManager implements IGraphEventKind {
080: private IDrawingAreaControl m_Parent;
081:
082: /**
083: *
084: */
085: public ETElementManager(IDrawingAreaControl control) {
086: super ();
087: m_Parent = control;
088: }
089:
090: /**
091: * Notify the IETGraphObjects that a delete gather is about to happen
092: */
093: public void onPreDeleteGatherSelected() {
094: notifyETObjectsOfEvent(GEK_PRE_DELETEGATHERSELECTED);
095: }
096:
097: /**
098: * Fires the predelete to the IETGraphObjects
099: */
100: public void onPreDelete() {
101: notifyETObjectsOfEvent(GEK_PRE_DELETE);
102: }
103:
104: /**
105: * Notify the IETGraphObjects that a delete was canceled.
106: */
107: public void onDeleteCancelled() {
108: notifyETObjectsOfEvent(GEK_DELETECANCELED);
109: }
110:
111: /**
112: * Fires the preresize to the IETGraphObjects
113: */
114: public void onPreResize() {
115: notifyETObjectsOfEvent(GEK_PRE_RESIZE);
116: }
117:
118: /**
119: * Fires the postresize to the IETGraphObjects
120: */
121: public void onPostResize() {
122: notifyETObjectsOfEvent(GEK_POST_RESIZE);
123: }
124:
125: /**
126: * Notifies the IETGraphObjects objects that an event occured.
127: *
128: * @param kind On of the values in the IGraphEventKind interface.
129: * @see IGraphEventKind
130: */
131: protected void notifyETObjectsOfEvent(int kind) {
132: IDrawingAreaControl ctrl = getParent();
133: if (ctrl != null) {
134: dispatchToETGraphObjects(ctrl.getSelected(), kind);
135: }
136: }
137:
138: /**
139: *
140: * Called after an object has been added to the graph
141: *
142: * @param graphObject [in] The object added.
143: * @param bResize [in] VARIANT_TRUE to resize the new element to its contents
144: * @param handled [in] Did we handle this event?
145: *
146: */
147: public void handlePostAddObject(TSGraphObject graphObj,
148: boolean resize) {
149: IETGraphObject pETElement = TypeConversions
150: .getETGraphObject(graphObj);
151: IPresentationTypesMgr presMgr = m_Parent
152: .getPresentationTypesMgr();
153:
154: if (pETElement != null) {
155: // Get some details off our parent
156:
157: // Get the engine controlling where the element should be created (what namespace)
158: IDiagramEngine diaEng = m_Parent.getDiagramEngine();
159:
160: // Get the namespace from the parent
161: INamespace pNamespace = diaEng != null ? diaEng
162: .getNamespaceForCreatedElements() : null;
163:
164: // Get the type of the diagram
165: int diaKind = m_Parent.getDiagramKind();
166:
167: // Get the model element in case we need to attach
168: IElement modEle = m_Parent.getModelElement();
169:
170: // Get the correct init string. Labels have no initstring right now.
171: String initStr = pETElement.getETUI().getInitStringValue();
172:
173: // Set the drawing area backpointer
174: IDiagram pDia = m_Parent.getDiagram();
175: pETElement.setDiagram(pDia);
176: IElement createdModEle = null;
177:
178: // Construct or attach to an IElement
179: if (modEle != null) {
180: pETElement.attach(modEle, initStr);
181: } else {
182: createdModEle = pETElement.create(pNamespace, initStr);
183: }
184:
185: // Now verify that this graph object as created ok. To do that get the model element
186: // and presentation element. If they exist then assume everything is ok, otherwise
187: // post an event to remove the graph object
188: IPresentationElement pPE = pETElement
189: .getPresentationElement();
190: boolean isValid = false;
191: if (pPE != null) {
192: if (pPE.getFirstSubject() != null) {
193: isValid = true;
194: } else if (createdModEle != null) {
195: if (!createdModEle.isDeleted()) {
196: // At this point we could have an element that was unloaded. When unloaded
197: // the model element is moved to another xml file and the presentation element
198: // connections are lost. Normally we get an event and eventually call
199: // AxDrawingAreaControl::ReestablishPresentationElementOwnership to fix this, but
200: // we need to do this now, we can't wait for the event queue.
201: pPE.removeSubject(createdModEle);
202: pPE.addSubject(createdModEle);
203: isValid = true;
204: }
205: }
206: }
207:
208: // Verify that the draw engine is allowed on this diagram
209: if (presMgr != null) {
210: IDrawEngine pEng = TypeConversions
211: .getDrawEngine(pETElement);
212: if (pEng != null) {
213: if (!presMgr.isValidDrawEngine(diaKind, pEng
214: .getDrawEngineID())) {
215: isValid = false;
216: }
217: }
218: }
219:
220: if (isValid) {
221: // Update the track bar with the new object if it's a node that represents a lifeline.
222: // This update must be performed after the TS node is completely layed out.
223: // So, we put the call on the delayed action stack.
224: int kind = ((pETElement != null && pETElement.isNode()) && (IDiagramKind.DK_SEQUENCE_DIAGRAM == diaKind)) ? DiagramAreaEnumerations.SPAK_ADDTOTRACKBAR // Sizes the node to its content, and adds the car to the track bar.
225: : DiagramAreaEnumerations.SPAK_SIZETOCONTENTS; // Sizes the node to its content.
226:
227: // resize if told to do so or if SQD always resize
228: if (resize
229: || (diaKind == IDiagramKind.DK_SEQUENCE_DIAGRAM)) {
230: // Size the node view to the contents.
231: // Do it as a delayed action because TS will crash in certain callstacks.
232: IPresentationElement presEle = pETElement
233: .getPresentationElement();
234: if (presEle != null) {
235: m_Parent.postSimplePresentationDelayedAction(
236: presEle, kind);
237: }
238: }
239:
240: if (pETElement.isEdge()) {
241: TSEdge pEdge = (TSEdge) pETElement;
242: TSNode fromNode = pEdge.getSourceNode();
243: TSNode toNode = pEdge.getTargetNode();
244:
245: // Tell both nodes that a new edge has been added.
246: if (fromNode != null && toNode != null) {
247: IETGraphObject fromObj = TypeConversions
248: .getETGraphObject(fromNode);
249: IETGraphObject toObj = TypeConversions
250: .getETGraphObject(toNode);
251:
252: if (fromObj != null && toObj != null) {
253: // Notify these nodes that a new link has been attached.
254: fromObj.onPostAddLink(pETElement, true);
255: toObj.onPostAddLink(pETElement, false);
256: }
257: }
258: }
259:
260: // Tell the product element that we're done and it can initialize
261: pETElement
262: .onGraphEvent(IGraphEventKind.GEK_POST_CREATE);
263: } else {
264: IPresentationElement presEle = pETElement
265: .getPresentationElement();
266: if (presEle != null) {
267: m_Parent.postDeletePresentationElement(presEle);
268: } else {
269: m_Parent.postDeletePresentationElement(graphObj);
270: }
271: }
272:
273: // Make sure the scroll bars are updated
274: // TSEGraph editor = m_Parent.getCurrentGraph();
275: // if (editor != null)
276: // {
277: // editor.updateBounds();
278: // }
279: }
280: }
281:
282: //**************************************************
283: // Helper Methods
284: //**************************************************
285:
286: /**
287: * Retrieves the drawing area control that initialized the manager.
288: */
289: protected IDrawingAreaControl getParent() {
290: return m_Parent;
291: }
292:
293: protected void dispatchToETGraphObjects(
294: ETList<IPresentationElement> elements, int kind) {
295: if (elements != null) {
296: for (Iterator<IPresentationElement> iter = elements
297: .iterator(); iter.hasNext();) {
298: dispatchToETGraphObject(iter.next(), kind);
299: }
300: }
301: }
302:
303: protected void dispatchToETGraphObject(
304: IPresentationElement element, int kind) {
305: IETGraphObject obj = TypeConversions.getETGraphObject(element);
306: if (obj != null) {
307: obj.onGraphEvent(kind);
308: }
309: }
310:
311: public boolean onKeyDown(int nKeyCode, int nShift) {
312: boolean handled = false;
313: ETList<IETGraphObject> selectedObjs = m_Parent.getSelected3();
314: if (selectedObjs != null) {
315: int count = selectedObjs.size();
316: // Only pass the keydown if one product element is selected.
317: if (count == 1) {
318: IETGraphObject pObject = selectedObjs.get(0);
319: handled = pObject.onKeydown(nKeyCode, nShift);
320: }
321: }
322: return handled;
323: }
324:
325: public boolean onCharTyped(char ch) {
326: boolean handled = false;
327: ETList<IETGraphObject> selectedObjs = m_Parent.getSelected3();
328: if (selectedObjs != null) {
329: int count = selectedObjs.size();
330: // Only pass the keydown if one product element is selected.
331: if (count == 1) {
332: IETGraphObject pObject = selectedObjs.get(0);
333: handled = pObject.onCharTyped(ch);
334: }
335: }
336: return handled;
337: }
338:
339: /**
340: * Tells the IETGraphObject's about a PreCopy
341: */
342: public void onPreCopy() {
343: // Get all the selected product elements
344: ETList<IPresentationElement> pSelectedObjects = m_Parent
345: .getSelected();
346:
347: dispatchToETGraphObjects(pSelectedObjects,
348: IGraphEventKind.GEK_PRE_COPY);
349:
350: }
351:
352: /**
353: * Tells the IETGraphObject's about a PostCopy
354: */
355: public void onPostCopy() {
356: // Get all the selected product elements
357: ETList<IPresentationElement> pSelectedObjects = m_Parent
358: .getSelected();
359:
360: dispatchToETGraphObjects(pSelectedObjects,
361: IGraphEventKind.GEK_POST_COPY);
362: }
363:
364: /**
365: * Tells the IETGraphObject's about a PostPaste
366: */
367: public boolean onPostPaste(List nodeList, List edgeList,
368: List nodeLabelList, List edgeLabelList) {
369: return handlePostPaste(nodeList, edgeList, nodeLabelList,
370: edgeLabelList);
371: }
372:
373: /**
374: * Handles post paste ( it used to handle duplicate as well until we deprecated that feature)
375: *
376: * @param nodeList [in] The nodes that were pasted
377: * @param edgeList [in] The nodes that were pasted
378: * @param labelList [in] The nodes that were pasted
379: */
380: public boolean handlePostPaste(List nodeList, List edgeList,
381: List nodeLabelList, List edgeLabelList) {
382: boolean bHandled = false;
383:
384: // During post paste/duplicate we need to change the presentation elements of the pasted items otherwise
385: // we'll have two tomsawyer objects pointing to the same presentation element. If any labels have
386: // been pasted then whack them.
387:
388: // We need to block containment or otherwise a contained element could query for its container
389: // before the container has been initialized.
390:
391: IGUIBlocker cpBlocker = null;
392: try {
393: cpBlocker = new GUIBlocker();
394: cpBlocker.setKind(GBK.DIAGRAM_CONTAINMENT);
395:
396: // A list of objects we need to send post paste events to
397: ETList<IETGraphObject> pETElements = new ETArrayList<IETGraphObject>();
398:
399: /// Node List
400: if (nodeList != null) {
401: for (IteratorT<IETGraphObject> iter = new IteratorT<IETGraphObject>(
402: nodeList); iter.hasNext();) {
403: IETGraphObject cpObject = iter.next();
404:
405: IElement pElement = TypeConversions
406: .getElement(cpObject);
407:
408: IETGraphObject pETElement = cpObject;
409:
410: if (pElement != null && pETElement != null) {
411: // The model element setter will make sure that the postaddobject event
412: // attaches the node/edge to this element rather then create a new one.
413: // It's a IETElement::Attach rather then an IETElement::Create.
414: ModelElementSetter modelElementSetter = new ModelElementSetter(
415: m_Parent, pElement);
416:
417: // Add to our list of guys to send post paste events to
418: pETElements.add(pETElement);
419:
420: // Send the event to the element so it can prepare for the paste
421: pETElement
422: .onGraphEvent(IGraphEventKind.GEK_POST_PASTE_VIEW);
423:
424: // call parent but don't resize
425: m_Parent.postAddObject(pETElement, false);
426:
427: m_Parent.setModelElement(null);
428:
429: }
430: }
431:
432: }
433:
434: // W2526 We don't allow pasting of links or labels. For links we'd need to figure out
435: // what nodes to attach to and then create a new relationship. Lots of work which we're not
436: // going to do.
437: // Edge List
438: if (edgeList != null) {
439:
440: for (IteratorT<IETGraphObject> iter = new IteratorT<IETGraphObject>(
441: edgeList); iter.hasNext();) {
442: IETGraphObject cpObject = iter.next();
443:
444: IElement pElement = TypeConversions
445: .getElement(cpObject);
446:
447: IETGraphObject pETElement = cpObject;
448:
449: if (pElement != null && pETElement != null) {
450: // The model element setter will make sure that the postaddobject event
451: // attaches the node/edge to this element rather then create a new one.
452: // It's a IETElement::Attach rather then an IETElement::Create.
453: ModelElementSetter modelElementSetter = new ModelElementSetter(
454: m_Parent, pElement);
455:
456: // Add to our list of guys to send post paste events to
457: pETElements.add(pETElement);
458:
459: // Send the event to the element so it can prepare for the paste
460: pETElement
461: .onGraphEvent(IGraphEventKind.GEK_POST_PASTE_VIEW);
462:
463: // call parent but don't resize
464: m_Parent.postAddObject(pETElement, false);
465: m_Parent.setModelElement(null);
466: }
467: }
468: }
469:
470: // Label List - these are not allowed to be pasted.
471: if (nodeLabelList != null) {
472: for (IteratorT<IETGraphObject> iter = new IteratorT<IETGraphObject>(
473: nodeLabelList); iter.hasNext();) {
474: IETGraphObject cpObject = iter.next();
475:
476: IElement pElement = TypeConversions
477: .getElement(cpObject);
478:
479: IETGraphObject pETElement = cpObject;
480:
481: if (pElement != null && pETElement != null) {
482: // The model element setter will make sure that the postaddobject event
483: // attaches the node/edge to this element rather then create a new one.
484: // It's a IETElement::Attach rather then an IETElement::Create.
485: ModelElementSetter modelElementSetter = new ModelElementSetter(
486: m_Parent, pElement);
487:
488: // Add to our list of guys to send post paste events to
489: pETElements.add(pETElement);
490:
491: // Send the event to the element so it can prepare for the paste
492: pETElement
493: .onGraphEvent(IGraphEventKind.GEK_POST_PASTE_VIEW);
494:
495: // call parent but don't resize
496: m_Parent.postAddObject(pETElement, false);
497: m_Parent.setModelElement(null);
498: }
499: }
500:
501: }
502: // Label List - these are not allowed to be pasted.
503: if (edgeLabelList != null) {
504: for (IteratorT<IETGraphObject> iter = new IteratorT<IETGraphObject>(
505: edgeLabelList); iter.hasNext();) {
506: IETGraphObject cpObject = iter.next();
507:
508: IElement pElement = TypeConversions
509: .getElement(cpObject);
510:
511: IETGraphObject pETElement = cpObject;
512:
513: if (pElement != null && pETElement != null) {
514: // The model element setter will make sure that the postaddobject event
515: // attaches the node/edge to this element rather then create a new one.
516: // It's a IETElement::Attach rather then an IETElement::Create.
517: ModelElementSetter modelElementSetter = new ModelElementSetter(
518: m_Parent, pElement);
519:
520: // Add to our list of guys to send post paste events to
521: pETElements.add(pETElement);
522:
523: // Send the event to the element so it can prepare for the paste
524: pETElement
525: .onGraphEvent(IGraphEventKind.GEK_POST_PASTE_VIEW);
526:
527: // call parent but don't resize
528: m_Parent.postAddObject(pETElement, false);
529: m_Parent.setModelElement(null);
530: }
531: }
532: }
533:
534: // Send out the events now that all the objects have been reattached
535:
536: for (IteratorT<IETGraphObject> iter = new IteratorT<IETGraphObject>(
537: pETElements); iter.hasNext();) {
538: IETGraphObject pETElement = iter.next();
539:
540: if (pETElement != null) {
541: pETElement
542: .onGraphEvent(IGraphEventKind.GEK_POST_PASTE_ALL);
543: }
544: }
545: } finally {
546: if (cpBlocker != null) {
547: cpBlocker.clearBlockers();
548: }
549: }
550:
551: return bHandled;
552: }
553:
554: /**
555: *
556: * Tells the IETGraphObject's about a PostMove
557: *
558: *
559: * @return
560: *
561: */
562: public void onPostMove(ETList<IPresentationElement> pSelectedList) {
563:
564: // Now tell each product element that the move has finished
565: dispatchToETGraphObjects(pSelectedList,
566: IGraphEventKind.GEK_POST_MOVE);
567:
568: }
569:
570: /**
571: *
572: * Tells the IETGraphObject's about a PreMove
573: *
574: *
575: * @return
576: *
577: */
578: public void onPreMove(ETList<IPresentationElement> pSelectedList) {
579:
580: // Now tell each product element that the move has finished
581: dispatchToETGraphObjects(pSelectedList,
582: IGraphEventKind.GEK_PRE_MOVE);
583:
584: }
585:
586: }
|