0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.uml.ui.products.ad.drawengines;
0043:
0044: import java.awt.Color;
0045: import java.awt.GradientPaint;
0046: import java.awt.event.ActionEvent;
0047: import java.util.Iterator;
0048: import org.netbeans.modules.uml.common.ETException;
0049: import org.netbeans.modules.uml.common.generics.ETPairT;
0050: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
0051: import org.netbeans.modules.uml.core.metamodel.core.foundation.IPresentationElement;
0052: import org.netbeans.modules.uml.core.metamodel.diagrams.ICoreRelationshipDiscovery;
0053: import org.netbeans.modules.uml.core.metamodel.diagrams.IGraphEventKind;
0054: import org.netbeans.modules.uml.core.metamodel.infrastructure.IPort;
0055: import org.netbeans.modules.uml.core.metamodel.structure.IComponent;
0056: import org.netbeans.modules.uml.core.preferenceframework.PreferenceAccessor;
0057: import org.netbeans.modules.uml.core.support.umlsupport.ETSize;
0058: import org.netbeans.modules.uml.core.support.umlsupport.IETRect;
0059: import org.netbeans.modules.uml.core.support.umlsupport.IETSize;
0060: import org.netbeans.modules.uml.core.support.umlutils.ETArrayList;
0061: import org.netbeans.modules.uml.core.support.umlutils.ETList;
0062: import org.netbeans.modules.uml.ui.products.ad.application.IMenuManager;
0063: import org.netbeans.modules.uml.ui.products.ad.application.action.ContextMenuActionClass;
0064: import org.netbeans.modules.uml.ui.products.ad.compartments.INameListCompartment;
0065: import org.netbeans.modules.uml.ui.products.ad.diagramengines.IADRelationshipDiscovery;
0066: import org.netbeans.modules.uml.ui.products.ad.drawEngineManagers.IADInterfaceEventManager;
0067: import org.netbeans.modules.uml.ui.support.PresentationReferenceHelper;
0068: import org.netbeans.modules.uml.ui.support.applicationmanager.INodePresentation;
0069: import org.netbeans.modules.uml.ui.support.applicationmanager.IProductGraphPresentation;
0070: import org.netbeans.modules.uml.ui.support.applicationmanager.MoveToFlags;
0071: import org.netbeans.modules.uml.ui.support.umltsconversions.RectConversions;
0072: import org.netbeans.modules.uml.ui.support.viewfactorysupport.GDISupport;
0073: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine;
0074: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawInfo;
0075: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IETGraphObject;
0076: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IETNode;
0077: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IEventManager;
0078: import org.netbeans.modules.uml.ui.support.viewfactorysupport.PresentationHelper;
0079: import org.netbeans.modules.uml.ui.support.viewfactorysupport.TypeConversions;
0080: import org.netbeans.modules.uml.ui.swing.drawingarea.IDiagramEngine;
0081: import org.netbeans.modules.uml.ui.swing.drawingarea.IDrawingAreaControl;
0082: import com.tomsawyer.editor.TSENode;
0083: import com.tomsawyer.editor.graphics.TSEGraphics;
0084: import org.netbeans.modules.uml.ui.support.TSSide;
0085: import com.tomsawyer.drawing.geometry.TSConstPoint;
0086: import com.tomsawyer.drawing.geometry.TSConstRect;
0087: import com.tomsawyer.drawing.geometry.TSPoint;
0088: import com.tomsawyer.drawing.geometry.TSRect;
0089: import com.tomsawyer.editor.TSTransform;
0090:
0091: public class ETComponentDrawEngine extends ETContainerDrawEngine
0092: implements IComponentDrawEngine {
0093:
0094: protected final int NODE_WIDTH = 180;
0095: protected final int NODE_HEIGHT = 100;
0096:
0097: private final static int s_PortOffset = 10;
0098: private final static int s_PortSize = 10;
0099:
0100: // Our original size before layout, restored after layout
0101: IETRect m_originalSize;
0102:
0103: ETNodeDrawEngine.ETHiddenNodeList m_HiddenNodes = null;
0104: ETList<PortLocations> m_PortLocations = new ETArrayList<PortLocations>();
0105:
0106: // Rect used for hiding and unhiding see comment in HideAllPorts
0107: IETRect m_additionalInvalidateRect;
0108:
0109: // Should we autoroute edges during graph events
0110: boolean m_autoRouteEdges;
0111:
0112: class PortLocations {
0113: public PortLocations() {
0114: }
0115:
0116: public TSPoint m_delta = new TSPoint();
0117: public TSENode m_node = null;
0118: public int m_closestSide; // TSSide
0119: };
0120:
0121: /* (non-Javadoc)
0122: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#getDrawEngineID()
0123: */
0124: public String getDrawEngineID() {
0125: return "ComponentDrawEngine";
0126: }
0127:
0128: /* (non-Javadoc)
0129: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#initCompartments()
0130: */
0131: public void initCompartments(IPresentationElement element) {
0132: if (null == element)
0133: throw new IllegalArgumentException();
0134:
0135: try {
0136: // We may get here with no compartments. This happens if we've been created
0137: // by the user. If we read from a file then the compartments have been pre-created and
0138: // we just need to initialize them.
0139: long numCompartments = getNumCompartments();
0140: if (numCompartments == 0) {
0141: createCompartments();
0142: }
0143:
0144: IElement modelElement = element.getFirstSubject();
0145: if (modelElement != null) {
0146: INameListCompartment nameCompartment = getCompartmentByKind(INameListCompartment.class);
0147: if (nameCompartment != null) {
0148: nameCompartment.attach(modelElement);
0149: }
0150: }
0151: } catch (ETException e) {
0152: e.printStackTrace();
0153: }
0154: }
0155:
0156: /* (non-Javadoc)
0157: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#createCompartments()
0158: */
0159: public void createCompartments() throws ETException {
0160: clearCompartments();
0161:
0162: createAndAddCompartment("ADNameListCompartment", 0);
0163:
0164: // Make sure we have a static text compartment showing the label <<datastore>>
0165: INameListCompartment pADNameListCompartment = getCompartmentByKind(INameListCompartment.class);
0166: if (pADNameListCompartment != null) {
0167: pADNameListCompartment.addStaticText("<<component>>");
0168: }
0169: }
0170:
0171: /* (non-Javadoc)
0172: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#sizeToContents()
0173: */
0174: public void sizeToContents() {
0175: ETList<IElement> allPorts = getPorts2();
0176: int count = (allPorts != null) ? allPorts.getCount() : 0;
0177:
0178: int nMinWidth = MIN_NODE_WIDTH;
0179: int nMinHeight = MIN_NODE_HEIGHT;
0180: if (count > 0) {
0181: // Increase some by the number of ports
0182: PortsPerSide pps = new PortsPerSide();
0183:
0184: if (nMinWidth < (((pps.m_nTop + 1) * s_PortSize) + ((pps.m_nTop + 1) * s_PortOffset))) {
0185: nMinWidth = (((pps.m_nTop + 1) * s_PortSize) + ((pps.m_nTop + 1) * s_PortOffset));
0186: }
0187: if (nMinWidth < (((pps.m_nBottom + 1) * s_PortSize) + ((pps.m_nBottom + 1) * s_PortOffset))) {
0188: nMinWidth = (((pps.m_nBottom + 1) * s_PortSize) + ((pps.m_nBottom + 1) * s_PortOffset));
0189: }
0190: if (nMinHeight < (((pps.m_nLeft + 1) * s_PortSize) + ((pps.m_nLeft + 1) * s_PortOffset))) {
0191: nMinHeight = (((pps.m_nLeft + 1) * s_PortSize) + ((pps.m_nLeft + 1) * s_PortOffset));
0192: }
0193: if (nMinHeight < (((pps.m_nRight + 1) * s_PortSize) + ((pps.m_nRight + 1) * s_PortOffset))) {
0194: nMinHeight = (((pps.m_nRight + 1) * s_PortSize) + ((pps.m_nRight + 1) * s_PortOffset));
0195: }
0196: }
0197:
0198: // Size but keep the current size if possible
0199: sizeToContentsWithMin(nMinWidth, nMinHeight, false, true);
0200: }
0201:
0202: /* (non-Javadoc)
0203: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#doDraw()
0204: */
0205: public void doDraw(IDrawInfo pDrawInfo) {
0206: TSEGraphics graphics = pDrawInfo.getTSEGraphics();
0207: IETRect deviceRect = pDrawInfo.getDeviceBounds();
0208: Color borderColor = getBorderBoundsColor();
0209: Color fillColor = getBkColor();
0210:
0211: // Draw a rectangle around the entire node
0212: //
0213: // --------------
0214: // | |
0215: // | |
0216: // | Name |
0217: // | |
0218: // --------------
0219: //
0220: float centerX = (float) deviceRect.getCenterX();
0221: GradientPaint paint = new GradientPaint(centerX, deviceRect
0222: .getBottom(), fillColor, centerX, deviceRect.getTop(),
0223: getLightGradientFillColor());
0224:
0225: GDISupport.drawRectangle(graphics, deviceRect.getRectangle(),
0226: borderColor, paint);
0227:
0228: // Draw each compartment now
0229: // handleNameListCompartmentDraw(pDrawInfo, deviceRect);
0230: handleNameListCompartmentDrawForContainers(pDrawInfo,
0231: deviceRect);
0232: super .doDraw(pDrawInfo);
0233: }
0234:
0235: /* (non-Javadoc)
0236: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#getElementType()
0237: */
0238: public String getElementType() {
0239: return new String("Component");
0240: }
0241:
0242: /* (non-Javadoc)
0243: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#initResources()
0244: */
0245: public void initResources() {
0246: setFillColor("componentfill", 255, 204, 0);
0247: setLightGradientFillColor("componentlightgradient", 254, 241,
0248: 187);
0249: setBorderColor("componentborder", Color.BLACK);
0250:
0251: super .initResources();
0252: }
0253:
0254: /* (non-Javadoc)
0255: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#onGraphEvent(int)
0256: */
0257: public void onGraphEvent(int nKind) {
0258: switch (nKind) {
0259: case IGraphEventKind.GEK_PRE_MOVE:
0260: this .selectAllPorts(true, true, true);
0261: break;
0262: case IGraphEventKind.GEK_PRE_DELETEGATHERSELECTED:
0263: // Select the ports connected to this component
0264: this .selectAllPorts(true, false, false);
0265: break;
0266: case IGraphEventKind.GEK_POST_MOVE:
0267: case IGraphEventKind.GEK_DELETECANCELED: {
0268: // Deselect the ports connected to this component
0269: ETPairT<IETRect, IETRect> bounds = getBoundingRectWithLollypops();
0270: if (bounds != null) {
0271: this .invalidateRect(bounds.getParamTwo());
0272: }
0273: selectAllPorts(false);
0274: break;
0275: }
0276: case IGraphEventKind.GEK_PRE_RESIZE:
0277: // Make the ports disappear and remember the positions
0278: rememberAllPortPositions();
0279: hideAllPorts(true);
0280: break;
0281: case IGraphEventKind.GEK_POST_RESIZE: {
0282: // Reposition the ports if necessary
0283: hideAllPorts(false);
0284: // Move the port to the nearest edge
0285: restoreAllPortPositions();
0286:
0287: ETPairT<IETRect, IETRect> bounds = getBoundingRectWithLollypops();
0288: if (bounds != null) {
0289: this .invalidateRect(bounds.getParamTwo());
0290: }
0291: break;
0292: }
0293: case IGraphEventKind.GEK_PRE_LAYOUT: {
0294: INodePresentation nodePE = getNodePresentation();
0295:
0296: if (nodePE != null) {
0297: // Resize us so we look bigger to the layout mechanism
0298: ETPairT<IETRect, IETRect> bounds = getBoundingRectWithLollypops();
0299:
0300: if (bounds != null) {
0301: m_originalSize = bounds.getParamOne();
0302: IETRect boundingRectWithEverything = bounds
0303: .getParamTwo();
0304:
0305: double width = m_originalSize.getWidth();
0306: double height = m_originalSize.getHeight();
0307:
0308: if (boundingRectWithEverything != null) {
0309: width = boundingRectWithEverything.getWidth();
0310: height = boundingRectWithEverything.getHeight();
0311: }
0312: nodePE.resize((long) width, (long) height, false);
0313: }
0314: }
0315:
0316: // Remember all port positions
0317: rememberAllPortPositions();
0318: hideAllPorts(true);
0319: }
0320: break;
0321: case IGraphEventKind.GEK_POST_LAYOUT: {
0322: INodePresentation nodePE = getNodePresentation();
0323:
0324: if (nodePE != null && m_originalSize != null) {
0325: double width = m_originalSize.getWidth();
0326: double height = m_originalSize.getHeight();
0327:
0328: nodePE.resize((long) width, (long) height, true);
0329: m_originalSize = null;
0330: }
0331:
0332: // Restore all port positions
0333: hideAllPorts(false);
0334: // Move the port to the nearest edge
0335: restoreAllPortPositions();
0336: // Distribute the ports and their attached lollypops
0337: distributeInterfacesOnAllPorts(false);
0338: }
0339: break;
0340: }
0341:
0342: super .onGraphEvent(nKind);
0343: }
0344:
0345: /*
0346: * (non-Javadoc)
0347: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#onContextMenu(org.netbeans.modules.uml.ui.products.ad.application.IMenuManager)
0348: */
0349: public void onContextMenu(IMenuManager manager) {
0350: // Add the context menu items dealing with ports
0351: addPortMenuItems(manager);
0352: super .onContextMenu(manager);
0353: }
0354:
0355: /*
0356: * (non-Javadoc)
0357: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#setSensitivityAndCheck(String,org.netbeans.modules.uml.ui.products.ad.application.action.ContextMenuActionClass)
0358: */
0359: public boolean setSensitivityAndCheck(String id,
0360: ContextMenuActionClass pClass) {
0361: boolean retVal = false;
0362: if (id.equals("MBK_COMPONENT_PORT_NAME")
0363: || id.equals("MBK_COMPONENT_PORT_NAME_END")) {
0364: // compute the index of the button kind into the ports list on the component
0365: int index = 0; //buttonKind - CADDrawEngineButtonHandler::MBK_COMPONENT_PORT_NAME;
0366:
0367: boolean isDisplayed = isDisplayed(index);
0368: pClass.setChecked(isDisplayed);
0369: } else {
0370: retVal = super .setSensitivityAndCheck(id, pClass);
0371: }
0372: return retVal;
0373: }
0374:
0375: /*
0376: * (non-Javadoc)
0377: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#onHandleButton(java.awt.event.ActionEvent,String)
0378: */
0379: public boolean onHandleButton(ActionEvent e, String id) {
0380: boolean handled = false;
0381: if (id.equals("MBK_COMPONENT_PORT_NAME")
0382: || id.equals("MBK_COMPONENT_PORT_NAME_END")) {
0383: // compute the index of the button kind into the ports list on the component
0384: int index = 0; //menuSelected - CADDrawEngineButtonHandler::MBK_COMPONENT_PORT_NAME;
0385:
0386: // Now we want to either show or hide this item
0387: boolean isDisplayed = isDisplayed(index);
0388:
0389: // Get the port at this index
0390: IPort port = getPortAtIndex(index);
0391:
0392: // Get the parent drawing area control
0393: IDrawingAreaControl control = getDrawingArea();
0394:
0395: if (control != null && port != null && isDisplayed) {
0396: // Whack this presentation element
0397: //
0398: // Go through the displayed ports, find it and then whack the presentation element
0399: ETList<IPresentationElement> displayedPorts = getPorts();
0400: if (displayedPorts != null) {
0401: // Go through the displayed ports looking for the port that corresponds to the
0402: // menu button port pMenuButtonPort.
0403: int count = displayedPorts.size();
0404: for (int i = 0; i < count; i++) {
0405: IPresentationElement this Port = displayedPorts
0406: .get(i);
0407: IElement pEle = TypeConversions
0408: .getElement(this Port);
0409: if (pEle != null) {
0410: boolean isSame = pEle.isSame(port);
0411: if (isSame
0412: && this Port instanceof INodePresentation) {
0413: control
0414: .postDeletePresentationElement(this Port);
0415: }
0416: }
0417: }
0418: }
0419: } else if (control != null && port != null) {
0420: IDiagramEngine pEngine = control.getDiagramEngine();
0421: if (pEngine != null) {
0422: ICoreRelationshipDiscovery pRD = pEngine
0423: .getRelationshipDiscovery();
0424: if (pRD != null
0425: && pRD instanceof IADRelationshipDiscovery) {
0426: IADRelationshipDiscovery pADRD = (IADRelationshipDiscovery) pRD;
0427: IPresentationElement compPE = getPresentationElement();
0428: if (compPE != null) {
0429: IPresentationElement presEle = pADRD
0430: .createPortPresentationElement(
0431: compPE, port);
0432: if (presEle != null) {
0433: repositionAllPorts();
0434: }
0435: }
0436: }
0437: }
0438: }
0439: } else {
0440: handled = super .onHandleButton(e, id);
0441: }
0442: return handled;
0443: }
0444:
0445: /* (non-Javadoc)
0446: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#calculateOptimumSize(org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawInfo, boolean)
0447: */
0448: public IETSize calculateOptimumSize(IDrawInfo pDrawInfo,
0449: boolean bAt100Pct) {
0450: // In Java in order to get an initial size to work properly we need to override this operation
0451: IETSize retVal = new ETSize(0, 0);
0452:
0453: IETSize tempSize = super .calculateOptimumSize(pDrawInfo, true);
0454:
0455: retVal.setWidth(Math.max(tempSize.getWidth(), NODE_WIDTH));
0456: retVal.setHeight(Math.max(tempSize.getHeight(), NODE_HEIGHT));
0457:
0458: TSTransform transform = pDrawInfo != null ? pDrawInfo
0459: .getTSTransform() : getTransform();
0460: return bAt100Pct || retVal == null ? retVal : scaleSize(retVal,
0461: transform);
0462: }
0463:
0464: /* (non-Javadoc)
0465: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#getBoundingRectWithLollypops()
0466: */
0467: public ETPairT<IETRect, IETRect> getBoundingRectWithLollypops() {
0468: TSENode componentNode = getOwnerNode();
0469:
0470: if (componentNode != null) {
0471: TSConstRect componentRect = componentNode.getBounds();
0472:
0473: IETRect currentBoundingRect = RectConversions
0474: .newETRect(componentRect);
0475:
0476: ETList<IPresentationElement> ports = getPorts();
0477:
0478: if (ports != null) {
0479: Iterator<IPresentationElement> portIter = ports
0480: .iterator();
0481: while (portIter.hasNext()) {
0482: IPresentationElement portPE = portIter.next();
0483:
0484: IProductGraphPresentation graphPE = null;
0485: if (portPE instanceof IProductGraphPresentation) {
0486: graphPE = (IProductGraphPresentation) portPE;
0487:
0488: IETRect portRect = graphPE.getBoundingRect();
0489:
0490: TSRect tsPortRect = RectConversions
0491: .etRectToTSRect(portRect);
0492:
0493: componentRect = tsPortRect != null ? componentRect
0494: .union(tsPortRect)
0495: : componentRect;
0496:
0497: TSENode portNode = TypeConversions
0498: .getOwnerNode(portPE);
0499:
0500: if (portNode != null) {
0501: ETList<IETGraphObject> interfaces = getLollypopInterfacesControlledByPort(portNode);
0502:
0503: if (interfaces != null) {
0504: Iterator<IETGraphObject> lollypopIter = interfaces
0505: .iterator();
0506: while (lollypopIter.hasNext()) {
0507: IETGraphObject anInterface = lollypopIter
0508: .next();
0509: IPresentationElement interfacePE = TypeConversions
0510: .getPresentationElement(anInterface);
0511: if (interfacePE instanceof IProductGraphPresentation) {
0512: IProductGraphPresentation interfaceGraphPE = (IProductGraphPresentation) interfacePE;
0513: IETRect interfaceRect = interfaceGraphPE
0514: .getBoundingRect();
0515: TSRect tsInterfaceRect = RectConversions
0516: .etRectToTSRect(interfaceRect);
0517: componentRect = tsInterfaceRect != null ? componentRect
0518: .union(tsInterfaceRect)
0519: : componentRect;
0520: }
0521: }
0522: }
0523: }
0524: }
0525: }
0526: }
0527: return new ETPairT<IETRect, IETRect>(currentBoundingRect,
0528: RectConversions.newETRect(componentRect));
0529: }
0530:
0531: return null;
0532: }
0533:
0534: // TODO, I (BDB) am not sure how java containment is processing these
0535: // // Virtual used by IADContainerDrawEngine to do the containment
0536: // STDMETHOD(ProcessContainment)( INodePresentation* pPreviousContainer,
0537: // IPresentationElement * pPresentationElement );
0538: //
0539: // /// Ends containment of a list of items
0540: // STDMETHOD(EndContainment)( /*[in]*/ IPresentationElements * pPresentationElements );
0541:
0542: /* (non-Javadoc)
0543: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#getPorts()
0544: */
0545: public ETList<IPresentationElement> getPorts() {
0546: IPresentationElement componentPE = getPresentationElement();
0547: if (componentPE != null) {
0548: return PresentationReferenceHelper
0549: .getAllReferredElements(componentPE);
0550: }
0551: return null;
0552: }
0553:
0554: public ETList<IElement> getPorts2() {
0555: ETList<IElement> foundElements = null;
0556:
0557: IPresentationElement componentPE = getPresentationElement();
0558: if (componentPE != null) {
0559: ETList<IElement> elements = PresentationReferenceHelper
0560: .getAllReferredSubjects(componentPE);
0561:
0562: // Now gather up all the ports
0563: foundElements = new ETArrayList<IElement>();
0564: if (foundElements != null) {
0565: int count = (elements != null) ? elements.getCount()
0566: : 0;
0567:
0568: for (int i = 0; i < count; i++) {
0569: IElement this Element = elements.item(i);
0570: if (this Element instanceof IPort) {
0571: IPort port = (IPort) this Element;
0572:
0573: foundElements.add(port);
0574: }
0575: }
0576: }
0577: }
0578:
0579: return foundElements;
0580: }
0581:
0582: /* (non-Javadoc)
0583: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#selectAllPorts(boolean)
0584: */
0585: public void selectAllPorts(boolean bSelect) {
0586: selectAllPorts(bSelect, false, false);
0587: }
0588:
0589: /* (non-Javadoc)
0590: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#selectAllPorts(boolean)
0591: */
0592: public void selectAllPorts(boolean bSelect,
0593: boolean firePreMoveEvent, boolean includeLollypopInterfaces) {
0594: ETList<IPresentationElement> ports = getPorts();
0595:
0596: if (ports != null && ports.getCount() > 0) {
0597: Iterator<IPresentationElement> iter = ports.iterator();
0598:
0599: while (iter.hasNext()) {
0600: IPresentationElement this Port = iter.next();
0601: TSENode portNode = TypeConversions
0602: .getOwnerNode(this Port);
0603: if (portNode != null) {
0604: portNode.setSelected(bSelect);
0605:
0606: if (includeLollypopInterfaces) {
0607: // Now make sure the interface lollypops are selected as well
0608: ETList<IETGraphObject> interfaces = getLollypopInterfacesControlledByPort(portNode);
0609:
0610: if (interfaces != null
0611: && interfaces.getCount() > 0) {
0612: Iterator<IETGraphObject> iterator = interfaces
0613: .iterator();
0614:
0615: while (iterator.hasNext()) {
0616: IETGraphObject etGraphObject = iterator
0617: .next();
0618:
0619: if (etGraphObject != null) {
0620: TSENode ownerNode = TypeConversions
0621: .getOwnerNode(etGraphObject);
0622:
0623: if (ownerNode != null) {
0624: etGraphObject.getEngine()
0625: .invalidate();
0626: ownerNode.setSelected(bSelect);
0627:
0628: if (firePreMoveEvent) {
0629: IETGraphObject interfaceGraphObject = TypeConversions
0630: .getETGraphObject(ownerNode);
0631: interfaceGraphObject
0632: .onGraphEvent(IGraphEventKind.GEK_PRE_MOVE);
0633: }
0634: }
0635: }
0636: }
0637: }
0638: }
0639: }
0640: }
0641: }
0642: }
0643:
0644: /* (non-Javadoc)
0645: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#hideAllPorts(boolean)
0646: */
0647: public void hideAllPorts(boolean bHide) {
0648: if (bHide) {
0649: ETList<IPresentationElement> ports = getPorts();
0650: if (ports == null)
0651: return;
0652: m_HiddenNodes = createHiddenList(ports);
0653: m_HiddenNodes.hide();
0654: } else if (m_HiddenNodes != null) {
0655: m_HiddenNodes.unHide();
0656: m_HiddenNodes = null;
0657: }
0658: }
0659:
0660: /* (non-Javadoc)
0661: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#repositionAllPorts()
0662: */
0663: public void repositionAllPorts() {
0664: ETList<IPresentationElement> ports = getPorts();
0665:
0666: if (ports == null)
0667: return;
0668:
0669: TSENode this Node = getOwnerNode();
0670:
0671: TSConstRect this Rect = this Node.getBounds();
0672:
0673: Iterator<IPresentationElement> iterator = ports.iterator();
0674:
0675: while (iterator.hasNext()) {
0676: IPresentationElement this Port = iterator.next();
0677:
0678: TSENode portNode = TypeConversions.getOwnerNode(this Port);
0679: if (portNode != null) {
0680: TSPoint centerPoint = new TSPoint(portNode.getCenter());
0681:
0682: if (centerPoint != null) {
0683: if (RectConversions.moveToNearestPoint(this Rect,
0684: centerPoint)) {
0685: portNode.assignCenter(centerPoint.getX(),
0686: centerPoint.getY());
0687:
0688: if (portNode instanceof IETNode) {
0689: IETNode portObject = (IETNode) portNode;
0690: portObject.getEngine().invalidate();
0691: portObject.invalidateEdges();
0692: }
0693: }
0694: }
0695: }
0696: }
0697: }
0698:
0699: /* (non-Javadoc)
0700: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#rememberAllPortPositions()
0701: */
0702: public void rememberAllPortPositions() {
0703: m_PortLocations.clear();
0704:
0705: ETList<IPresentationElement> ports = getPorts();
0706: TSENode this Node = getOwnerNode();
0707:
0708: if (ports != null) {
0709: if (ports.getCount() > 0 && this Node != null) {
0710: TSConstRect this Rect = this Node.getBounds();
0711:
0712: Iterator<IPresentationElement> iter = ports.iterator();
0713:
0714: while (iter.hasNext()) {
0715: IPresentationElement this Port = iter.next();
0716:
0717: TSENode portNode = TypeConversions
0718: .getOwnerNode(this Port);
0719:
0720: if (portNode != null) {
0721: PortLocations portLocation = new PortLocations();
0722: TSConstPoint componentCenter = this Node
0723: .getCenter();
0724: TSConstPoint portCenter = portNode.getCenter();
0725:
0726: if (componentCenter != null
0727: && portCenter != null) {
0728: portLocation.m_delta.setX(portCenter.getX()
0729: - componentCenter.getX());
0730: portLocation.m_delta.setY(portCenter.getY()
0731: - componentCenter.getY());
0732: portLocation.m_node = portNode;
0733: portLocation.m_closestSide = RectConversions
0734: .getClosestSide(this Rect,
0735: portCenter);
0736:
0737: m_PortLocations.add(portLocation);
0738: }
0739: }
0740: }
0741: }
0742: }
0743: }
0744:
0745: /* (non-Javadoc)
0746: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#restoreAllPortPositions()
0747: */
0748: public void restoreAllPortPositions() {
0749: TSENode this Node = getOwnerNode();
0750:
0751: TSConstRect this Rect = this Node.getBounds();
0752: TSPoint centerPoint = new TSPoint(this Rect.getCenter());
0753:
0754: IDrawingAreaControl control = getDrawingArea();
0755:
0756: if (this Node != null && control != null && centerPoint != null
0757: && this Rect != null) {
0758: Iterator<PortLocations> iterator = m_PortLocations
0759: .iterator();
0760:
0761: while (iterator.hasNext()) {
0762: PortLocations location = iterator.next();
0763: TSPoint newPoint = new TSPoint();
0764:
0765: newPoint.setX(centerPoint.getX()
0766: + location.m_delta.getX());
0767: newPoint.setY(centerPoint.getY()
0768: + location.m_delta.getY());
0769:
0770: if (location.m_closestSide == TSSide.TS_SIDE_RIGHT) {
0771: newPoint.setX(this Rect.getRight());
0772: } else if (location.m_closestSide == TSSide.TS_SIDE_TOP) {
0773: newPoint.setY(this Rect.getTop());
0774: } else if (location.m_closestSide == TSSide.TS_SIDE_LEFT) {
0775: newPoint.setX(this Rect.getLeft());
0776: } else if (location.m_closestSide == TSSide.TS_SIDE_BOTTOM) {
0777: newPoint.setY(this Rect.getBottom());
0778: }
0779:
0780: if (RectConversions.moveToNearestPoint(this Rect,
0781: newPoint)) {
0782: INodePresentation nodePresentation = TypeConversions
0783: .getNodePresentation(location.m_node);
0784: if (nodePresentation != null) {
0785: nodePresentation.invalidate();
0786: }
0787: location.m_node.assignCenter(newPoint.getX(),
0788: newPoint.getY());
0789: }
0790: }
0791: }
0792:
0793: m_PortLocations.clear();
0794:
0795: repositionAllPorts();
0796:
0797: //if (control != null)
0798: //control.refresh(true);
0799: }
0800:
0801: public ETList<IETGraphObject> getLollypopInterfacesControlledByPort(
0802: TSENode portNode) {
0803: if (portNode == null)
0804: return null;
0805:
0806: IETGraphObject portElement = TypeConversions
0807: .getETGraphObject(portNode);
0808:
0809: if (portElement != null) {
0810: PresentationHelper.LollypopsAndEdges result = PresentationHelper
0811: .getLollypopsWithOneControllingEdge(portElement);
0812:
0813: if (result != null)
0814: return result.getLollypops();
0815: }
0816: return null;
0817: }
0818:
0819: /* (non-Javadoc)
0820: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#distributeInterfacesOnAllPorts(boolean)
0821: */
0822: public void distributeInterfacesOnAllPorts(boolean bRedraw) {
0823: IDrawingAreaControl control = getDrawingArea();
0824: ETList<IPresentationElement> portPEs = getPorts();
0825:
0826: ETList<IPresentationElement> rightPorts = new ETArrayList<IPresentationElement>();
0827: ETList<IPresentationElement> topPorts = new ETArrayList<IPresentationElement>();
0828: ETList<IPresentationElement> leftPorts = new ETArrayList<IPresentationElement>();
0829: ETList<IPresentationElement> bottomPorts = new ETArrayList<IPresentationElement>();
0830:
0831: Iterator<IPresentationElement> iterator = portPEs.iterator();
0832: while (iterator.hasNext()) {
0833: IPresentationElement this Port = iterator.next();
0834:
0835: if (this Port != null) {
0836: IDrawEngine drawEngine = TypeConversions
0837: .getDrawEngine(this Port);
0838:
0839: if (drawEngine != null) {
0840: distributeAttachedInterfaces(drawEngine, bRedraw);
0841:
0842: IETRect boundingRect = drawEngine.getBoundingRect();
0843:
0844: int nSide = getPortSide(this Port);
0845:
0846: if (nSide == TSSide.TS_SIDE_RIGHT)
0847: rightPorts.add(this Port);
0848: else if (nSide == TSSide.TS_SIDE_TOP)
0849: topPorts.add(this Port);
0850: else if (nSide == TSSide.TS_SIDE_LEFT)
0851: leftPorts.add(this Port);
0852: else if (nSide == TSSide.TS_SIDE_BOTTOM)
0853: bottomPorts.add(this Port);
0854: }
0855: control.executeStackingCommand(this Port,
0856: IDrawingAreaControl.SOK_MOVETOFRONT, bRedraw);
0857: }
0858: }
0859:
0860: boolean foundRightIntersections = PresentationHelper
0861: .haveIntersections(rightPorts);
0862: boolean foundTopIntersections = PresentationHelper
0863: .haveIntersections(topPorts);
0864: boolean foundLeftIntersections = PresentationHelper
0865: .haveIntersections(leftPorts);
0866: boolean foundBottomIntersections = PresentationHelper
0867: .haveIntersections(bottomPorts);
0868:
0869: if (foundRightIntersections)
0870: movePortsToAvoidIntersections(QuadrantKindEnum.QK_RIGHT,
0871: rightPorts);
0872: if (foundTopIntersections)
0873: movePortsToAvoidIntersections(QuadrantKindEnum.QK_TOP,
0874: topPorts);
0875: if (foundLeftIntersections)
0876: movePortsToAvoidIntersections(QuadrantKindEnum.QK_LEFT,
0877: leftPorts);
0878: if (foundBottomIntersections)
0879: movePortsToAvoidIntersections(QuadrantKindEnum.QK_BOTTOM,
0880: bottomPorts);
0881:
0882: getDrawingArea().getGraphWindow().updateInvalidRegion();
0883: control.refresh(false);
0884: }
0885:
0886: /* (non-Javadoc)
0887: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#movePortsToAvoidIntersections(int)
0888: */
0889: public void movePortsToAvoidIntersections(int nSide,
0890: ETList<IPresentationElement> ports) {
0891: IETRect componentRect = getLogicalBoundingRect();
0892:
0893: if (componentRect != null) {
0894: long nLastPortPosition = 0;
0895: for (int index = 0; index < ports.getCount(); ++index) {
0896: IPresentationElement this PE = ports.item(index);
0897:
0898: if (this PE instanceof INodePresentation) {
0899: INodePresentation portNodePE = (INodePresentation) this PE;
0900:
0901: IDrawEngine portDE = TypeConversions
0902: .getDrawEngine(this PE);
0903:
0904: if (portDE != null) {
0905: IETRect portBoundingRect = portDE
0906: .getLogicalBoundingRect(false);
0907:
0908: if (portBoundingRect != null) {
0909: double nWidth = portBoundingRect.getWidth();
0910: double nHeight = Math.abs(portBoundingRect
0911: .getHeight());
0912: double nCenterX = 0;
0913: double nCenterY = 0;
0914:
0915: switch (nSide) {
0916: case QuadrantKindEnum.QK_RIGHT:
0917: case QuadrantKindEnum.QK_LEFT: {
0918: nWidth = s_PortSize;
0919: if (nSide == QuadrantKindEnum.QK_RIGHT) {
0920: nCenterX = componentRect.getRight();
0921: } else {
0922: nCenterX = componentRect.getLeft();
0923: }
0924:
0925: if (index == 0) {
0926: nLastPortPosition = Math.max(
0927: componentRect.getBottom(),
0928: componentRect.getTop());
0929: }
0930:
0931: // Compute the y pos which is the last port y - some slop - 1/2 height
0932: nCenterY = nLastPortPosition
0933: - s_PortOffset - nHeight / 2;
0934: nLastPortPosition = (long) (nCenterY - nHeight / 2);
0935:
0936: // Make sure we don't below the component
0937: if (nCenterY < Math.min(componentRect
0938: .getBottom(), componentRect
0939: .getTop())) {
0940: nCenterY = Math.min(componentRect
0941: .getBottom(), componentRect
0942: .getTop())
0943: + nHeight / 2;
0944: }
0945: }
0946: break;
0947: case QuadrantKindEnum.QK_TOP:
0948: case QuadrantKindEnum.QK_BOTTOM: {
0949: nHeight = s_PortSize;
0950: if (nSide == QuadrantKindEnum.QK_TOP) {
0951: nCenterY = Math.max(componentRect
0952: .getBottom(), componentRect
0953: .getTop());
0954: } else {
0955: nCenterY = Math.min(componentRect
0956: .getBottom(), componentRect
0957: .getTop());
0958: }
0959: if (index == 0) {
0960: nLastPortPosition = componentRect
0961: .getLeft();
0962: }
0963:
0964: // Compute the x pos which is the last port x + some slop + 1/2 width
0965: nCenterX = nLastPortPosition
0966: + s_PortOffset + nWidth / 2;
0967: nLastPortPosition = (long) (nCenterX + nWidth / 2);
0968:
0969: // Make sure we don't go right of the component
0970: if (nCenterX > componentRect.getRight()) {
0971: // move this guy back
0972: nCenterX = componentRect.getRight()
0973: - nWidth / 2;
0974: }
0975: }
0976: break;
0977: }
0978: TSPoint centerPoint = new TSPoint();
0979: centerPoint.setX(nCenterX);
0980: centerPoint.setY(nCenterY);
0981:
0982: portNodePE
0983: .moveTo(
0984: (int) nCenterX,
0985: (int) nCenterY,
0986: (MoveToFlags.MTF_MOVEX
0987: | MoveToFlags.MTF_MOVEY | MoveToFlags.MTF_LOGICALCOORD));
0988: portNodePE.resize((int) nWidth,
0989: (int) nHeight, false);
0990:
0991: IDrawEngine drawEngine = TypeConversions
0992: .getDrawEngine(portNodePE);
0993: if (drawEngine != null) {
0994: distributeAttachedInterfaces(
0995: drawEngine, true);
0996: }
0997: }
0998: }
0999: }
1000: }
1001: }
1002: }
1003:
1004: /* (non-Javadoc)
1005: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#movePortsToSide(int)
1006: */
1007: public void movePortsToSide(int nSide) {
1008: ETList<IPresentationElement> portPEs = getPorts();
1009: movePortsToSide(nSide, portPEs);
1010: }
1011:
1012: public void movePortsToSide(int nSide,
1013: ETList<IPresentationElement> portPEs) {
1014: if (portPEs != null) {
1015: movePortsToAvoidIntersections(nSide, portPEs);
1016: // Refresh the screen
1017: getDrawingArea().getGraphWindow().updateInvalidRegion();
1018: getDrawingArea().refresh(true);
1019: }
1020: }
1021:
1022: /* (non-Javadoc)
1023: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#getAllowAutoRouteEdges()
1024: */
1025: public boolean getAllowAutoRouteEdges() {
1026: return m_autoRouteEdges;
1027: }
1028:
1029: /* (non-Javadoc)
1030: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.IComponentDrawEngine#setAllowAutoRouteEdges(boolean)
1031: */
1032: public void setAllowAutoRouteEdges(boolean bAutoRouteEdges) {
1033: m_autoRouteEdges = bAutoRouteEdges;
1034: }
1035:
1036: /// Sends a graph event to all related ports
1037: // CLEAN this is no longer used by anybody STDMETHOD(SendGraphEventToPorts)(GraphEventKind nKind);
1038:
1039: // protected:
1040: /**
1041: * This class replaces the getPortsPerSide() from C++
1042: * Calculates the number of ports per side
1043: */
1044: protected class PortsPerSide {
1045: public int m_nLeft = 0;
1046: public int m_nRight = 0;
1047: public int m_nTop = 0;
1048: public int m_nBottom = 0;
1049: public int m_nNotAssigned = 0;
1050:
1051: public PortsPerSide() {
1052: ETList<IPresentationElement> allPorts = getPorts();
1053: int count = (allPorts != null) ? allPorts.getCount() : 0;
1054:
1055: for (int i = 0; i < count; i++) {
1056: IPresentationElement this Port = allPorts.item(i);
1057: if (this Port != null) {
1058: int nSide = getPortSide(this Port);
1059: switch (nSide) {
1060: case TSSide.TS_SIDE_RIGHT:
1061: m_nRight++;
1062: break;
1063: case TSSide.TS_SIDE_TOP:
1064: m_nTop++;
1065: break;
1066: case TSSide.TS_SIDE_LEFT:
1067: m_nLeft++;
1068: break;
1069: case TSSide.TS_SIDE_BOTTOM:
1070: m_nBottom++;
1071: break;
1072: case TSSide.TS_SIDE_UNDEFINED:
1073: m_nNotAssigned++;
1074: break;
1075: }
1076: }
1077: }
1078: }
1079: }
1080:
1081: /**
1082: * Returns the port at a specific index
1083: *
1084: * @return The port at index nIndex into the components list
1085: */
1086: protected IPort getPortAtIndex(int index) {
1087: IPort retObj = null;
1088: IComponent component = getComponent();
1089: if (component != null) {
1090: // Get the ports off the component
1091: ETList<IPort> ports = component.getExternalInterfaces();
1092: if (ports != null && ports.size() > index) {
1093: retObj = ports.get(index);
1094: }
1095: }
1096: return retObj;
1097: }
1098:
1099: /**
1100: * returns true if this port at this index is currently displayed
1101: *
1102: * @param nPortIndex [in] The port index to be queried
1103: * @return true if the port port is displayed on the diagram
1104: */
1105: protected boolean isDisplayed(int nPortIndex) {
1106: boolean bIsDisplayed = false;
1107:
1108: IPort this Port = getPortAtIndex(nPortIndex);
1109: if (this Port != null) {
1110: bIsDisplayed = isDisplayed(this Port);
1111: }
1112:
1113: return bIsDisplayed;
1114: }
1115:
1116: /**
1117: * returns true if this port is currently displayed
1118: *
1119: * @param port [in] The port to be queried
1120: * @return true if the port port is displayed on the diagram
1121: */
1122: protected boolean isDisplayed(IPort port) {
1123: boolean bIsDisplayed = false;
1124:
1125: ETList<IPort> ports;
1126: ETList<IElement> displayedPorts;
1127:
1128: // Get the component
1129: IComponent component = getComponent();
1130: if (component != null) {
1131: // Get the ports off the component
1132: ports = component.getExternalInterfaces();
1133:
1134: // Get the displayed ports
1135: displayedPorts = getPorts2();
1136:
1137: if ((ports != null) && (displayedPorts != null)) {
1138: // See if this port is in the displayed list
1139: if (port != null) {
1140: bIsDisplayed = displayedPorts.isInList(port);
1141: }
1142: }
1143: }
1144:
1145: return bIsDisplayed;
1146: }
1147:
1148: /**
1149: * returns the ICompoent for this draw engine
1150: *
1151: * @param component [out,retval] The component this DE represents
1152: */
1153: protected IComponent getComponent() {
1154: IComponent retObj = null;
1155: IElement this Ele = TypeConversions.getElement(this );
1156: if (this Ele != null && this Ele instanceof IComponent) {
1157: retObj = (IComponent) this Ele;
1158: }
1159: return retObj;
1160: }
1161:
1162: protected int getPortSide(IPresentationElement port) {
1163: int nSide = TSSide.TS_SIDE_BOTTOM;
1164:
1165: if (port != null) {
1166: TSENode this Node = getOwnerNode();
1167: if (this Node != null) {
1168: TSConstRect this Rect = this Node.getBounds();
1169:
1170: TSENode portNode = TypeConversions.getOwnerNode(port);
1171: if (portNode != null) {
1172: TSConstPoint portCenter = portNode.getCenter();
1173:
1174: if (portCenter != null) {
1175: nSide = RectConversions.getClosestSide(
1176: this Rect, portCenter);
1177: }
1178: }
1179: }
1180: }
1181: return nSide;
1182: }
1183:
1184: protected void distributeAttachedInterfaces(
1185: IDrawEngine portDrawEngine, boolean bRedraw) {
1186: IEventManager eventManager = portDrawEngine.getEventManager();
1187: IADInterfaceEventManager interfaceEM = null;
1188: if (eventManager instanceof IADInterfaceEventManager)
1189: interfaceEM = (IADInterfaceEventManager) eventManager;
1190:
1191: if (interfaceEM != null) {
1192: interfaceEM.distributeAttachedInterfaces(bRedraw);
1193: }
1194: }
1195:
1196: /**
1197: * Adds Port specific stuff.
1198: *
1199: * @param pDrawEngine [in] The draw engine we're over
1200: * @param pContextMenu [in] The context menu about to be displayed
1201: */
1202: protected void addPortMenuItems(IMenuManager manager) {
1203: IElement this Ele = TypeConversions.getElement(this );
1204: if (this Ele != null && this Ele instanceof IComponent) {
1205: IComponent component = (IComponent) this Ele;
1206: ETList<IPort> ports = component.getExternalInterfaces();
1207: if (ports != null) {
1208: int count = ports.size();
1209: if (count > 0) {
1210: IMenuManager subMenu = manager.createOrGetSubMenu(
1211: loadString("IDS_PORTS_TITLE"), "");
1212: if (subMenu != null) {
1213: // Go through the ports on the component and see if they are displayed
1214: for (int i = 0; i < count; i++) {
1215: IPort this Port = ports.get(i);
1216: String name = this Port.getName();
1217: if (name == null || name.length() == 0) {
1218: name = PreferenceAccessor.instance()
1219: .getDefaultElementName();
1220: }
1221: subMenu.add(createMenuAction(name,
1222: "MBK_COMPONENT_PORT_NAME" + i));
1223: }
1224: //manager.add(subMenu);
1225: }
1226: }
1227: }
1228: }
1229: }
1230: }
|