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.products.ad.diagramengines.sequencediagram;
043:
044: import com.tomsawyer.drawing.geometry.TSConstPoint;
045: import java.util.List;
046: import java.util.Vector;
047: import org.netbeans.modules.uml.ui.support.archivesupport.IProductArchiveDefinitions;
048: import java.awt.Color;
049: import java.awt.Font;
050: import java.awt.Point;
051: import java.awt.event.MouseEvent;
052: import java.util.Iterator;
053: import java.util.ResourceBundle;
054:
055: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
056: import org.netbeans.modules.uml.core.metamodel.core.foundation.IPresentationElement;
057: import org.netbeans.modules.uml.core.metamodel.diagrams.IGraphEventKind;
058: import org.netbeans.modules.uml.core.metamodel.diagrams.IProxyDiagram;
059: import org.netbeans.modules.uml.core.metamodel.dynamics.IInteractionFragment;
060: import org.netbeans.modules.uml.core.metamodel.dynamics.IInteractionOccurrence;
061: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IBehavior;
062: import org.netbeans.modules.uml.core.support.umlsupport.ETDeviceRect;
063: import org.netbeans.modules.uml.core.support.umlsupport.ETPoint;
064: import org.netbeans.modules.uml.core.support.umlsupport.ETSize;
065: import org.netbeans.modules.uml.core.support.umlsupport.IETPoint;
066: import org.netbeans.modules.uml.core.support.umlsupport.IETRect;
067: import org.netbeans.modules.uml.core.support.umlsupport.IETSize;
068: import org.netbeans.modules.uml.core.support.umlutils.ETArrayList;
069: import org.netbeans.modules.uml.core.support.umlutils.ETList;
070: import org.netbeans.modules.uml.ui.controls.drawingarea.ITopographyChangeAction;
071: import org.netbeans.modules.uml.ui.products.ad.ADDrawEngines.ConvertRectToPercent;
072: import org.netbeans.modules.uml.ui.products.ad.compartments.IADCompartment;
073: import org.netbeans.modules.uml.ui.products.ad.compartments.IADEditableCompartment;
074: import org.netbeans.modules.uml.ui.products.ad.compartments.IADNameCompartment;
075: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.IConnectorsCompartment;
076: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.IGateCompartment;
077: import org.netbeans.modules.uml.ui.products.ad.drawengines.ContainmentTypeEnum;
078: import org.netbeans.modules.uml.ui.products.ad.drawengines.ETContainerDrawEngine;
079: import org.netbeans.modules.uml.ui.support.DiagramAndPresentationNavigator;
080: import org.netbeans.modules.uml.ui.support.IDiagramAndPresentationNavigator;
081: import org.netbeans.modules.uml.ui.support.applicationmanager.INodePresentation;
082: import org.netbeans.modules.uml.ui.support.archivesupport.IProductArchive;
083: import org.netbeans.modules.uml.ui.support.archivesupport.IProductArchiveElement;
084: import org.netbeans.modules.uml.ui.support.viewfactorysupport.DrawEngineLineKindEnum;
085: import org.netbeans.modules.uml.ui.support.viewfactorysupport.GDISupport;
086: import org.netbeans.modules.uml.ui.support.viewfactorysupport.ICompartment;
087: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine;
088: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawInfo;
089: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IETGraphObject;
090: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IMouseEvent;
091: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IStretchContext;
092: import org.netbeans.modules.uml.ui.support.viewfactorysupport.TypeConversions;
093: import org.netbeans.modules.uml.ui.swing.drawingarea.ADGraphWindow;
094: import org.netbeans.modules.uml.ui.swing.drawingarea.IDrawingAreaControl;
095: import com.tomsawyer.drawing.TSPolygonShape;
096: import com.tomsawyer.editor.TSENode;
097: import com.tomsawyer.editor.graphics.TSEGraphics; //import com.tomsawyer.util.TSTransform;
098: import com.tomsawyer.editor.TSTransform;
099:
100: /**
101: * @author brettb
102: *
103: */
104: public class InteractionFragmentDrawEngine extends
105: ETContainerDrawEngine implements IInteractionFragmentDrawEngine {
106: private final static long MIN_NODE_WIDTH = 5;
107: private final static long MIN_NODE_HEIGHT = 5;
108:
109: private static final String BUNDLE_NAME = "org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.Bundle"; //$NON-NLS-1$
110: private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
111: .getBundle(BUNDLE_NAME);
112:
113: /**
114: * Constructor
115: */
116: public InteractionFragmentDrawEngine() {
117: m_rectLabel = new ETDeviceRect();
118: m_rectText = new ETDeviceRect();
119: m_rectName = new ETDeviceRect();
120: m_nameLocation = _NameLocation.NL_OUTSIDE_LABEL;
121: m_bIsHollow = false;
122: m_nFontStringID = -1;
123:
124: // We are a container controlling the child's location
125: setContainmentType(ContainmentTypeEnum.CT_GRAPHICAL);
126:
127: m_maintainContainment = true;
128: }
129:
130: // IDrawEngine
131:
132: /**
133: * This is the name of the drawengine used when storing and reading from the product archive.
134: *
135: * @return A unique identifier for this draw engine. Used when persisting to the etlp file.
136: */
137: public String getDrawEngineID() {
138: return "InteractionFragmentDrawEngine";
139: }
140:
141: /**
142: * Notifies the node an event has been generated at the graph.
143: */
144: public void onGraphEvent(int /* IGraphEventKind */nKind) {
145: super .onGraphEvent(nKind);
146:
147: switch (nKind) {
148: case IGraphEventKind.GEK_POST_MOVE: {
149: IConnectorsCompartment connectorsCompartment = getCompartmentByKind(IConnectorsCompartment.class);
150: if (connectorsCompartment != null) {
151: connectorsCompartment.updateConnectors(null);
152: }
153: }
154: break;
155:
156: case IGraphEventKind.GEK_PRE_DELETEGATHERSELECTED:
157: // Fix 2895: Make sure any interactions are not deleted,
158: // by deselecting the presentation element.
159:
160: // UPDATE: The use may want to clear the entire diagram,
161: // so we should process this via affectModelElementDeletion()?
162:
163: if (getMetaTypeOfElement().equals("Interaction")) {
164: TSENode tseNode = getOwnerNode();
165: if (tseNode != null) {
166: IDrawingAreaControl control = getDrawingArea();
167: if (control != null) {
168: ADGraphWindow window = control.getGraphWindow();
169: if (window != null) {
170: window.deselectObject(tseNode, true);
171: }
172: }
173: }
174: }
175: break;
176:
177: default:
178: // do nothing
179: break;
180: }
181: }
182:
183: /**
184: * Tells the draw engine to write its data to the IProductArchive.
185: *
186: * @param pProductArchive[in] The archive we're saving to
187: * @param pParentElement[in] The current element, or parent for any new attributes or elements.
188: */
189: public long writeToArchive(IProductArchive productArchive,
190: IProductArchiveElement parentElement) {
191: if (null == productArchive)
192: throw new IllegalArgumentException();
193: if (null == parentElement)
194: throw new IllegalArgumentException();
195:
196: super .writeToArchive(productArchive, parentElement);
197:
198: IProductArchiveElement engineElement = parentElement
199: .getElement(IProductArchiveDefinitions.ENGINENAMEELEMENT_STRING);
200: if (engineElement != null) {
201: String strLabel = m_strLabelText;
202: engineElement.addAttributeString(
203: "INTERACTIONFRAGMENTENGINE_LABEL_STRING",
204: m_strLabelText);
205: engineElement.addAttributeLong(
206: "INTERACTIONFRAGMENTENGINE_NAMELOCATION_STRING",
207: m_nameLocation);
208: engineElement.addAttributeBool(
209: "INTERACTIONFRAGMENTENGINE_ISHOLLOW_STRING",
210: m_bIsHollow);
211: }
212:
213: return 0;
214: }
215:
216: /**
217: * Tells the draw engine to read its data to the IProductArchive.
218: *
219: * @param pProductArchive[in] The archive we're reading from
220: * @param pEngineElement[in] The element where this draw engine's information should exist.
221: */
222: public long readFromArchive(IProductArchive productArchive,
223: IProductArchiveElement parentElement) {
224: if (null == productArchive)
225: throw new IllegalArgumentException();
226: if (null == parentElement)
227: throw new IllegalArgumentException();
228:
229: super .readFromArchive(productArchive, parentElement);
230:
231: String strLabel = parentElement
232: .getAttributeString("INTERACTIONFRAGMENTENGINE_LABEL_STRING");
233: m_nameLocation = (int) parentElement
234: .getAttributeLong("INTERACTIONFRAGMENTENGINE_NAMELOCATION_STRING");
235: m_bIsHollow = parentElement
236: .getAttributeBool("INTERACTIONFRAGMENTENGINE_ISHOLLOW_STRING");
237:
238: if (strLabel.length() > 0) {
239: setLabelText(strLabel);
240: }
241:
242: return 0;
243: }
244:
245: public boolean handleLeftMouseButtonDoubleClick(
246: MouseEvent mouseEvent) {
247: // Allow the base class to try and handle the double-click,
248: // which passes it to all the compartments, e.g. allow the name compartment to be edited.
249: boolean bHandled = super
250: .handleLeftMouseButtonDoubleClick(mouseEvent);
251:
252: // Get the behavior off the interactionoccurrence
253: IBehavior behavior = null;
254: {
255: // When the model element is an interaction occurrence,
256: // the double-click will open the interaction occurrence's interaction's diagram
257: // or the activity diagram.
258:
259: IElement element = getFirstModelElement();
260: if (element instanceof IInteractionOccurrence) {
261: IInteractionOccurrence occurrence = (IInteractionOccurrence) element;
262: behavior = occurrence.getBehavior();
263: }
264: }
265:
266: // If not handled then bring up the diagram navigation dialog
267: if ((bHandled == false) && (behavior != null)) {
268: IDiagramAndPresentationNavigator navigator = new DiagramAndPresentationNavigator();
269: if (navigator != null) {
270: bHandled = navigator.handleNavigation(0, behavior,
271: false /*?*/);
272: }
273: }
274:
275: return bHandled;
276: }
277:
278: public void initResources() {
279: m_nFontStringID = m_ResourceUser.setResourceStringID(
280: m_nFontStringID, "interactionfragmentfont");
281: setBorderColor("interactionfragmentborder", Color.BLACK);
282: setFillColor("graphicfill", Color.WHITE);
283:
284: super .initResources();
285: }
286:
287: // TODO public void onContextMenu( IProductContextMenu contextMenu, long logicalX, long logicalY );
288:
289: /**
290: * Initializes our compartments.
291: */
292: public void initCompartments(IPresentationElement pe) {
293: if (null == pe)
294: throw new IllegalArgumentException();
295:
296: // We may get here with no compartments. This happens if we've been created
297: // by the user. If we read from a file then the compartments have been pre-created and
298: // we just need to initialize them.
299: long numCompartments = getNumCompartments();
300: if (numCompartments < 1) {
301: createCompartments();
302: numCompartments = getNumCompartments();
303: }
304:
305: IElement modelElement = pe.getFirstSubject();
306: if (modelElement != null) {
307: for (int nIndx = 0; nIndx < numCompartments; nIndx++) {
308: ICompartment compartment = getCompartment(nIndx);
309: if (compartment != null) {
310: compartment.addModelElement(modelElement, -1);
311: }
312: }
313:
314: // Make the name compartment the default compartment,
315: // so autotype will select the name compartment
316: IADNameCompartment nameCompartment = getCompartmentByKind(IADNameCompartment.class);
317: if (nameCompartment != null) {
318: setDefaultCompartment(nameCompartment);
319: }
320:
321: // Determine the draw engine settings based on the model element
322: String strLabelID = "IDS_IF_REFERENCE_LABEL";
323: if (modelElement instanceof IInteractionOccurrence) {
324: strLabelID = "IDS_IF_REFERENCE_LABEL";
325: m_nameLocation = _NameLocation.NL_OUTSIDE_LABEL;
326: m_bIsHollow = false;
327: m_isGraphicalContainer = false;
328: m_maintainContainment = false;
329: } else {
330: strLabelID = "IDS_IF_DIAGRAM_LABEL";
331: m_nameLocation = _NameLocation.NL_INSIDE_LABEL;
332: m_bIsHollow = true; // Fix W9665: need a hollow interaction boundary
333: m_isGraphicalContainer = true;
334: m_maintainContainment = true;
335: }
336:
337: final String strLabel = RESOURCE_BUNDLE
338: .getString(strLabelID);
339: setLabelText(strLabel);
340: }
341: }
342:
343: /**
344: * Create the compartments for this node..
345: */
346: public void createCompartments() {
347: clearCompartments();
348:
349: createAndAddCompartment("GateCompartment");
350: IADEditableCompartment nameCompartment = (IADEditableCompartment) createAndAddCompartment("ADNameCompartment");
351: if (nameCompartment != null) {
352: // Fix J1461: We need to ensure that the text is located on the left side of this compartment
353: nameCompartment.setHorizontalAlignment(IADCompartment.LEFT);
354: }
355: }
356:
357: /**
358: * Calculates the "best" size for this compartment. The calculation sets the member variable m_szCachedOptimumSize,
359: * which represents the "best" size of the compartment at 100%.
360: */
361: public IETSize calculateOptimumSize(IDrawInfo pDrawInfo,
362: boolean bAt100Pct) {
363: ETSize sizeReturn = new ETSize(0, 0);
364:
365: ETList<ICompartment> compartments = getCompartments();
366: if (compartments != null) {
367: final long lCnt = compartments.getCount();
368:
369: updatePreferedLabelSize(pDrawInfo, bAt100Pct);
370:
371: if (lCnt <= 2) {
372: sizeReturn.setWidth(Math.max(m_rectLabel.getRight(),
373: m_rectName.getRight()));
374: sizeReturn.setHeight(Math.max(m_rectLabel.getBottom(),
375: m_rectName.getBottom()));
376: } else {
377: // start at 1 to skip the label compartment
378: for (int nIndx = 1; nIndx < lCnt; nIndx++) {
379: ICompartment compartment = compartments.get(nIndx);
380: if (compartment != null) {
381: compartment.calculateOptimumSize(pDrawInfo,
382: bAt100Pct);
383: IETSize sizeCompartment = compartment
384: .getOptimumSize(bAt100Pct);
385:
386: // Keep the widest dimension, and sum the heights
387: if (sizeReturn.getWidth() < sizeCompartment
388: .getWidth()) {
389: sizeReturn.setWidth(sizeCompartment
390: .getWidth());
391: }
392: sizeReturn.setHeight(sizeReturn.getHeight()
393: + sizeCompartment.getHeight());
394: }
395: }
396: }
397:
398: // CLEAN setCalculatedOptimumSize( sizeReturn );
399: }
400:
401: return sizeReturn;
402: }
403:
404: /**
405: * Returns the optimum size for an item. This is used when an item is created from the toolbar.
406: */
407: public void sizeToContents() {
408: // Size but keep the current size if possible
409: sizeToContentsWithMin(MIN_NODE_WIDTH, MIN_NODE_HEIGHT, false,
410: true);
411: }
412:
413: /**
414: * Draws each of the individual compartments.
415: *
416: * @param drawInfo Information about the draw event (ie the DC, are we printing...)
417: */
418: public void doDraw(IDrawInfo drawInfo) {
419: if (null == drawInfo)
420: throw new IllegalArgumentException();
421:
422: // Retain the IETRect for use by the compartment draw calls
423: // Get the bounding rectangle of the node.
424: IETRect rectBounding = drawInfo.getDeviceBounds();
425: TSEGraphics graphics = drawInfo.getTSEGraphics();
426:
427: int numCompartments = getNumCompartments();
428:
429: if (!m_bIsHollow) {
430: GDISupport.fillRectangle(graphics.getGraphics(),
431: rectBounding, getBkColor());
432: }
433:
434: IGateCompartment gateCompartment = getCompartmentByKind(IGateCompartment.class);
435: if (gateCompartment != null) {
436: gateCompartment.draw(drawInfo, rectBounding);
437: }
438:
439: drawLabel(drawInfo, rectBounding);
440:
441: // Draw the name after the label, so the it is located properly
442: IADNameCompartment nameCompartment = getCompartmentByKind(IADNameCompartment.class);
443: if (nameCompartment != null) {
444: // calculate the rectangle for the name compartment
445: IETRect rectName = (IETRect) m_rectName.clone();
446: rectName.offsetRect(rectBounding.getTopLeft()); // necessary because java output is based in the client
447: if (_NameLocation.NL_OUTSIDE_LABEL == m_nameLocation) {
448: rectName.setRight(rectBounding.getRight());
449: rectName.setBottom(rectBounding.getBottom());
450: }
451:
452: nameCompartment.draw(drawInfo, rectName);
453: }
454:
455: // This call must come after the drawing of the compartments, because
456: // the shape is determined within the draw of the compartments.
457: if (m_bIsHollow && (isSettingShape() == false)) {
458: setDrawEngineShape();
459: }
460:
461: GDISupport.frameRectangle(graphics.getGraphics(), rectBounding,
462: DrawEngineLineKindEnum.DELK_SOLID, 1, getBorderColor());
463:
464: // Give the container a chance to draw
465: // super.doDraw(drawInfo);
466: }
467:
468: public boolean isDrawEngineValidForModelElement() {
469: boolean bIsValid = false;
470:
471: String currentMetaType = getMetaTypeOfElement();
472: if ((currentMetaType.equals("Interaction"))
473: || (currentMetaType.equals("InteractionOccurrence"))) {
474: bIsValid = true;
475: }
476:
477: return bIsValid;
478: }
479:
480: protected static final class _NameLocation {
481: public static final int NL_NONE = 0;
482: public static final int NL_OUTSIDE_LABEL = 1;
483: public static final int NL_INSIDE_LABEL = 2;
484: };
485:
486: /// Sets the location of the name
487: protected void setNameLocation(int /*_NameLocation*/nameLocation) {
488: m_nameLocation = nameLocation;
489: }
490:
491: /// Get the InteractionFragment from the parent product element
492: protected IInteractionFragment getInteractionFragment() {
493: IInteractionFragment interactionFragment = null;
494:
495: IElement element = getFirstModelElement();
496: if (element instanceof IInteractionFragment) {
497: interactionFragment = (IInteractionFragment) element;
498: }
499:
500: return interactionFragment;
501: }
502:
503: /// Determine the prefered size for the label in the upper left corner
504: protected final void updatePreferedLabelSize(IDrawInfo drawInfo,
505: boolean bAt100Pct) {
506: if (drawInfo != null) {
507: // Determine the size of the label we are about to draw
508: final String strLabel = m_strLabelText;
509: final String strReferenceLabel = strLabel;
510: final String strExtentTest = strReferenceLabel + " ";
511:
512: TSEGraphics graphics = drawInfo.getTSEGraphics();
513: TSTransform transform = graphics.getTSTransform();
514: Font fontCorner = m_ResourceUser.getZoomedFontForStringID(
515: m_nFontStringID, drawInfo.getFontScaleFactor());
516:
517: final IETSize sizeLabelExtent = GDISupport.getTextExtent(
518: graphics.getGraphics(), fontCorner, strExtentTest);
519:
520: // Calculate the rectangle used to display the label's text
521: m_rectText = new ETDeviceRect(new Point(0, 0),
522: sizeLabelExtent.asDimension());
523:
524: // Calculate the rectangle used to draw the outline of the label
525: m_rectLabel = (IETRect) m_rectText.clone();
526:
527: // Size the member rectangles based on the the location of the label
528: switch (m_nameLocation) {
529: case _NameLocation.NL_INSIDE_LABEL: {
530: // Add the size of the name compartment to the label size
531: IETSize sizeName = getNameCompartmentMinimumSize(
532: drawInfo, bAt100Pct);
533: m_rectLabel.setRight(m_rectLabel.getRight()
534: + sizeName.getWidth());
535:
536: // Fix J1461: For some reason we need to adjust this text in a different way from C++
537: final int dy = -2;
538:
539: // Place the name label inside the label to the right of the label's text
540: m_rectName = new ETDeviceRect(m_rectText.getRight(),
541: dy,
542: m_rectText.getRight() + sizeName.getWidth(),
543: m_rectLabel.getBottom() + dy);
544:
545: m_rectLabel.setRight((int) Math.round(m_rectLabel
546: .getRight()
547: + m_rectLabel.getHeight() / 2));
548: }
549: break;
550:
551: case _NameLocation.NL_OUTSIDE_LABEL: {
552: m_rectLabel.setRight((int) Math.round(m_rectLabel
553: .getRight()
554: + m_rectLabel.getHeight() / 2));
555:
556: // Place the name compartment to the right of the label
557: IETSize sizeName = getNameCompartmentMinimumSize(
558: drawInfo, bAt100Pct);
559:
560: m_rectName = new ETDeviceRect(m_rectText.getRight(), 0,
561: m_rectText.getRight() + sizeName.getWidth(),
562: m_rectLabel.getBottom());
563: }
564: break;
565:
566: default:
567: m_rectLabel.setRight((int) Math.round(m_rectLabel
568: .getRight()
569: + m_rectLabel.getHeight() / 2));
570: m_rectName.setRectEmpty();
571: break;
572: }
573: }
574: }
575:
576: /// Draws the reference label using the text from getLabelText()
577: protected void drawLabel(IDrawInfo drawInfo,
578: final IETRect rectBounding) {
579: // In C++ this passed in rectangle would be 0,0 relative to the upper left of the node
580: // However, in java we have to use device coordinates with 0,0 being the upper left of the
581: // client window.
582:
583: assert (m_strLabelText.length() > 0); // there should always be a label
584:
585: updatePreferedLabelSize(drawInfo, false);
586:
587: assert (!m_rectLabel.isZero());
588: assert (!m_rectText.isZero());
589:
590: if (drawInfo != null) {
591: TSEGraphics graphics = drawInfo.getTSEGraphics();
592: TSTransform transform = graphics.getTSTransform();
593: Font fontCorner = m_ResourceUser.getZoomedFontForStringID(
594: m_nFontStringID, drawInfo.getFontScaleFactor());
595:
596: // Determine the label's width height
597: final int iLabelWidth = Math.min(
598: rectBounding.getIntWidth(), m_rectLabel
599: .getIntWidth());
600: final int iLabelHeight = Math.min(rectBounding
601: .getIntHeight(), m_rectLabel.getIntHeight());
602:
603: final int dx = rectBounding.getLeft();
604: final int dy = rectBounding.getTop();
605:
606: int iLabelTop = m_rectLabel.getTop() + dy;
607: int iLabelBottom = m_rectLabel.getBottom() + dy;
608:
609: // Prepare the points for the label
610: m_aptLabel.clear();
611: m_aptLabel.add(new ETPoint(dx, iLabelTop));
612: m_aptLabel.add(new ETPoint(dx, iLabelBottom));
613: m_aptLabel.add(new ETPoint(dx
614: + Math.max(0, iLabelWidth - iLabelHeight / 2),
615: iLabelBottom));
616: m_aptLabel.add(new ETPoint(dx + iLabelWidth, iLabelTop
617: + iLabelHeight / 2));
618: m_aptLabel.add(new ETPoint(dx + iLabelWidth, iLabelTop));
619:
620: GDISupport.drawPolygon(graphics.getGraphics(), m_aptLabel,
621: getBorderColor(), 1, getFillColor());
622:
623: IETRect rectText = (IETRect) m_rectText.clone();
624: rectText.offsetRect(dx, dy);
625:
626: GDISupport.drawText(graphics.getGraphics(), fontCorner,
627: m_strLabelText, rectText);
628: }
629: }
630:
631: /// Sets the text that is displayed inside the label in the upper left corner
632: protected void setLabelText(final String strLabelText) {
633: m_strLabelText = strLabelText;
634:
635: // Clear the label size, so it will be recalculated in UpdatePreferedLabelSize()
636: m_rectLabel.setRectEmpty();
637: }
638:
639: /// Determines the minimum size of the name compartment
640: protected IETSize getNameCompartmentMinimumSize(IDrawInfo drawInfo,
641: boolean bAt100Pct) {
642: IETSize sizeName = null;
643:
644: // Add the name compartment's size to the right of the label
645: IADNameCompartment nameCompartment = getCompartmentByKind(IADNameCompartment.class);
646: if (nameCompartment != null) {
647: sizeName = nameCompartment.calculateOptimumSize(drawInfo,
648: bAt100Pct);
649: }
650:
651: return sizeName;
652: }
653:
654: private boolean m_SettingShape = false;
655:
656: protected synchronized boolean isSettingShape() {
657: return m_SettingShape;
658: }
659:
660: /// Tell Tom Sawyer the active shape for node selection
661: protected synchronized void setDrawEngineShape() {
662: m_SettingShape = true;
663: TSENode tseNode = getOwnerNode();
664: if (tseNode != null) {
665: // Here's our list of shapes that we're sending to tomsawyer
666: TSPolygonShape shape = new TSPolygonShape();
667:
668: List ptList = new Vector();
669: ptList.add(new TSConstPoint(0, 100));
670: ptList.add(new TSConstPoint(100, 100));
671: ptList.add(new TSConstPoint(100, 0));
672: ptList.add(new TSConstPoint(0, 0));
673: ptList.add(new TSConstPoint(0, 95));
674: ptList.add(new TSConstPoint(4, 95));
675: ptList.add(new TSConstPoint(4, 4));
676: ptList.add(new TSConstPoint(96, 4));
677: ptList.add(new TSConstPoint(96, 97));
678: ptList.add(new TSConstPoint(0, 97));
679: ptList.add(new TSConstPoint(0, 100));
680:
681: IETRect rectInner = getWinScaledOwnerRect();
682:
683: // Now convert the points to a -1000 to 1000 box.
684: // 0,0 . -1000,1000
685: // totalHeight . 1000
686: // totalWidth . 1000
687: // We also need to flip the y axis
688:
689: // Set up the coordinate conversion parameters
690: ConvertRectToPercent converter = new ConvertRectToPercent(
691: this );
692:
693: // make sure the label area is solid
694: getLabelShape(converter, shape);
695:
696: IADNameCompartment nameCompartment = getCompartmentByKind(IADNameCompartment.class);
697:
698: // Loop through all the compartments
699: final int iCompartmentCnt = getNumCompartments();
700: for (int iCompartmentIndx = 0; iCompartmentIndx < iCompartmentCnt; iCompartmentIndx++) {
701: ICompartment compartment = getCompartment(iCompartmentIndx);
702: if ((compartment != null)
703: && (compartment != nameCompartment)) // Don't process the name compartment
704: {
705: // Get the shape of the compartment
706: // The compartment should assume that the point before its list of points
707: // will be in the upper left corner of its bounding rect
708: ETList<IETPoint> pointList = compartment
709: .getCompartmentShape();
710:
711: // Process the list of points
712: if (pointList != null) {
713: int iPointsCnt = pointList.getCount();
714:
715: if (iPointsCnt > 0) {
716: // Convert each point from its bounding rect coordinates to percent
717: if (pointList != null) {
718: for (Iterator iterPoints = pointList
719: .iterator(); iterPoints
720: .hasNext();) {
721: IETPoint ptCompartment = (IETPoint) iterPoints
722: .next();
723:
724: Point point = converter
725: .ConvertToPercent(ptCompartment
726: .asPoint());
727: //shape.addPoint( point.x, point.y ); //jyothi
728: }
729: }
730: }
731: }
732: }
733: }
734:
735: // Give TS our new shape list
736: TSPolygonShape shape1 = new TSPolygonShape(ptList);
737: tseNode.setShape(shape1);
738: m_SettingShape = false;
739: }
740: }
741:
742: /// Returns the shape of the label
743: protected void getLabelShape(final ConvertRectToPercent converter,
744: TSPolygonShape shape) {
745: // Note the paths must be in clockwise order, to indicate a solid area
746:
747: // Loop around the name tag part of the compartment
748: appendPoint(shape, converter.ConvertToPercent(m_aptLabel.get(0)
749: .asPoint()));
750: appendPoint(shape, converter.ConvertToPercent(m_aptLabel.get(1)
751: .asPoint()));
752: appendPoint(shape, converter.ConvertToPercent(m_aptLabel.get(2)
753: .asPoint()));
754: appendPoint(shape, converter.ConvertToPercent(m_aptLabel.get(3)
755: .asPoint()));
756: appendPoint(shape, converter.ConvertToPercent(m_aptLabel.get(4)
757: .asPoint()));
758: appendPoint(shape, converter.ConvertToPercent(m_aptLabel.get(0)
759: .asPoint()));
760: }
761:
762: /**
763: * Used to clean up the code for appending a point to a list of points.
764: *
765: * @param pPointList[in,out] The list of points to which the point is being added
766: * @param ptPoint[in] The point to add to the list
767: */
768: protected void appendPoint(TSPolygonShape shape, final Point point) {
769: // jyothi shape.addPoint( point.getX(), point.getY() );
770: }
771:
772: private String m_strLabelText = "";
773: private ETList<IETPoint> m_aptLabel = new ETArrayList<IETPoint>(); // points used to define the label's shape
774: private IETRect m_rectLabel; /// The rectangle where the label is located
775: private IETRect m_rectText; /// The rectangle where the label's text is located
776: private IETRect m_rectName; /// The rectanble where the name is located, if displayed
777:
778: private int /*_NameLocation*/m_nameLocation;
779:
780: // When true, the user will be able to click on objects "under" the interaction fragment
781: private boolean m_bIsHollow;
782:
783: private int /*STRINGID*/m_nFontStringID = -1;
784: }
|