/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.transformation.ui.connection; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.draw2d.ChopboxAnchor; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.emf.ecore.EObject; import org.eclipse.swt.graphics.Font; import org.teiid.designer.diagram.ui.DiagramUiConstants; import org.teiid.designer.diagram.ui.actions.ScaledFont; import org.teiid.designer.diagram.ui.actions.ScaledFontManager; import org.teiid.designer.diagram.ui.connection.AbstractNodeConnectionModel; import org.teiid.designer.diagram.ui.connection.AnchorManager; import org.teiid.designer.diagram.ui.connection.BinaryAssociation; import org.teiid.designer.diagram.ui.connection.NodeConnectionAnchor; import org.teiid.designer.diagram.ui.figure.DiagramFigure; import org.teiid.designer.diagram.ui.figure.LabeledRectangleFigure; import org.teiid.designer.diagram.ui.model.AssociationLabelModelNode; import org.teiid.designer.diagram.ui.model.DiagramModelNode; import org.teiid.designer.diagram.ui.model.LabelModelNode; import org.teiid.designer.diagram.ui.part.DiagramEditPart; import org.teiid.designer.metamodels.diagram.DiagramLinkType; import org.teiid.designer.transformation.ui.model.TransformationNode; import org.teiid.designer.transformation.util.TransformationHelper; /** * DiagramAssociation * * @since 8.0 */ public class TransformationLink extends AbstractNodeConnectionModel { private static final String EMPTY_LABEL = " "; //$NON-NLS-1$ private DiagramModelNode sourceNode; private DiagramModelNode targetNode; private LabelModelNode suidLabelNode; private LabelModelNode aliasLabelNode; private String sName; private int ltCurrentLinkType = DiagramLinkType.DIRECTED; private static final int DELTA_X = 6; private static final int DELTA_Y = 4; private String sRouterStyle; /** * Construct an instance of TransformationLink * */ public TransformationLink(DiagramModelNode source, DiagramModelNode target ) { super(); setSourceNode(source); setTargetNode(target); init(); } /** * Construct an instance of TransformationLink. * */ public TransformationLink(DiagramModelNode source, DiagramModelNode target, String sName ) { super(); this.sName = sName; setSourceNode(source); setTargetNode(target); init(); } private void init() { // String suidText = getSuidText(); // if( suidText != null ) // suidLabelNode = new AssociationLabelModelNode( suidText, AssociationLabelModelNode.SOURCE_ROLE_NAME ); // // String aliasText = getAliasText(); // if( aliasText != null ) // aliasLabelNode = new AssociationLabelModelNode( aliasText, AssociationLabelModelNode.NAME ); } @Override public void updateLabels() { String suidText = getSuidText(); if( suidText != null ) { if( suidLabelNode == null ) { suidLabelNode = new AssociationLabelModelNode( suidText, AssociationLabelModelNode.SOURCE_ROLE_NAME ); } else suidLabelNode.setName(suidText); suidLabelNode.update(); } String aliasText = getAliasText(); if( aliasText != null ) { if( aliasLabelNode == null ) { aliasLabelNode = new AssociationLabelModelNode( aliasText, AssociationLabelModelNode.NAME ); } else aliasLabelNode.setName(aliasText); aliasLabelNode.update(); } } private String getSuidText() { String text = EMPTY_LABEL; if( getTargetNode() instanceof TransformationNode ) { // get the target for this transformation EObject targetTableEObject = TransformationHelper.getTransformationLinkTarget(((DiagramModelNode)getTargetNode()).getModelObject()); if( TransformationHelper.tableSupportsUpdate(targetTableEObject) ) { // We get the SUID status from the SqlTransformation object // Let's get the source node model object text = "s"; //$NON-NLS-1$ if( TransformationHelper.supportsUpdate(((DiagramModelNode)getTargetNode()).getModelObject(), ((DiagramModelNode)getSourceNode()).getModelObject() )) text = text + "u"; //$NON-NLS-1$ if( TransformationHelper.supportsInsert(((DiagramModelNode)getTargetNode()).getModelObject(), ((DiagramModelNode)getSourceNode()).getModelObject() )) text = text + "i"; //$NON-NLS-1$ if( TransformationHelper.supportsDelete(((DiagramModelNode)getTargetNode()).getModelObject(), ((DiagramModelNode)getSourceNode()).getModelObject() )) text = text + "d"; //$NON-NLS-1$ } } else if( org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isTable(((DiagramModelNode)getTargetNode()).getModelObject()) ) { EObject tableEObject = ((DiagramModelNode)getTargetNode()).getModelObject(); if( TransformationHelper.tableSupportsUpdate(tableEObject) ) text = "suid"; //$NON-NLS-1$ } return text; } private String getAliasText() { String text = EMPTY_LABEL; if( getTargetNode() instanceof TransformationNode ) { List aliases = TransformationHelper .getSqlAliasesForSource( ((DiagramModelNode)getTargetNode()).getModelObject(), ((DiagramModelNode)getSourceNode()).getModelObject()); if( aliases != null && !aliases.isEmpty() && aliases.size() > 1 ) { text = EMPTY_LABEL + aliases.size(); // Iterator iter = aliases.iterator(); // SqlAlias nextAlias = null; // int count = 0; // while( iter.hasNext() ) { // nextAlias = (SqlAlias)iter.next(); // if( ! nextAlias.getAlias().equals(getSourceNode().getName()) ) { // if( count == 0 ) // text = "AS: "; //$NON-NLS-1$ // if( count > 0 ) // text += ", "; //$NON-NLS-1$ // text += nextAlias.getAlias(); // count++; // } // } } } return text; } public void setSource(DiagramModelNode iSource) { sourceNode = iSource; } public void setTarget(DiagramModelNode iTarget) { targetNode = iTarget; } @Override public void setName( String sName ) { this.sName = sName; } /** * @param */ @Override public String getName() { return sName; } @Override public void layout() { // System.out.println( "[DiagramAssociation.layout 0 arg ] TOP, node name: " + getName() ); //$NON-NLS-1$ } @Override public void setRouterStyle( String sRouterStyle ) { if ( this.sRouterStyle == null || !this.sRouterStyle.equals( sRouterStyle ) ) { this.sRouterStyle = sRouterStyle; // refresh the label layout manager } } @Override public int getRouterStyle() { return DiagramUiConstants.LinkRouter.DIRECT; } /** * @return sourceNode */ @Override public Object getSourceNode() { return sourceNode; } /** * @return targetNode */ @Override public Object getTargetNode() { return targetNode; } /** * @param node */ @Override public void setSourceNode(Object node) { sourceNode = (DiagramModelNode)node; } /** * @param node */ @Override public void setTargetNode(Object node) { targetNode = (DiagramModelNode)node; } /** * @return */ public LabelModelNode getNameLabel() { return aliasLabelNode; } /** * @return */ public LabelModelNode getSuidLabel() { return suidLabelNode; } /** * @param node */ public void setName(LabelModelNode node) { aliasLabelNode = node; } /** * @param node */ public void setSuidLabel(LabelModelNode node) { suidLabelNode = node; } @Override public List getLabelNodes() { List currentLabels = new ArrayList(); if(suidLabelNode != null ) currentLabels.add(suidLabelNode); if(aliasLabelNode != null ) currentLabels.add(aliasLabelNode); if( currentLabels.isEmpty() ) return Collections.EMPTY_LIST; return currentLabels; } public void clearLabelNodes() { suidLabelNode = null; aliasLabelNode = null; } // ===================================================================== // Methods to support firing PropertyChangeEvents // ===================================================================== transient protected PropertyChangeSupport listeners = new PropertyChangeSupport(this); @Override public void addPropertyChangeListener(PropertyChangeListener l) { listeners.addPropertyChangeListener(l); } @Override public void removePropertyChangeListener(PropertyChangeListener l) { listeners.removePropertyChangeListener(l); } @Override public void firePropertyChange(String prop, Object old, Object newValue) { listeners.firePropertyChange(prop, old, newValue); } // Used to alert the Edit Part that the children have been modified // and a refreshChildren() is needed. public void fireStructureChange(String prop, Object child) { listeners.firePropertyChange(prop, null, child); } // ===================================================================== // Layout code (rewritten from DCAssocation (modeler 3.1)) // ===================================================================== public int getLinkType() { return ltCurrentLinkType; } private void updateFonts( DiagramEditPart adepParentEditPart ) { // always run this; it may have changed since the last time layout was called... Font fntNew = getLabelFont(); updateFontOnLabelFigure( adepParentEditPart, suidLabelNode, fntNew ); updateFontOnLabelFigure( adepParentEditPart, aliasLabelNode, fntNew ); } private void updateFontOnLabelFigure( DiagramEditPart adepParentEditPart, LabelModelNode lmnLabel, Font fntNew ) { if( lmnLabel != null ) { DiagramEditPart dep = (DiagramEditPart)adepParentEditPart.getParent(); DiagramEditPart depLabelled = dep.getEditPart( lmnLabel ); if( depLabelled != null ) { DiagramFigure df1 = depLabelled.getDiagramFigure(); if ( df1 instanceof LabeledRectangleFigure ) { ((LabeledRectangleFigure)df1).updateForFont( fntNew ); } } } } private Font getLabelFont() { return ScaledFontManager.getFont(ScaledFont.SMALLER_PLAIN_STYLE); // int iCurrGeneralFontSize = ScaledFontManager.getSize(); // int iNewLabelFontSize = 0; // // if ( ScaledFontManager.canDecrease( iCurrGeneralFontSize - 2 ) ) { // // we can decrease by 3 // iNewLabelFontSize = iCurrGeneralFontSize - 3; // } // else // if ( ScaledFontManager.canDecrease( iCurrGeneralFontSize - 1 ) ) { // // we can decrease by 2 // iNewLabelFontSize = iCurrGeneralFontSize - 2; // } // else // if ( ScaledFontManager.canDecrease( iCurrGeneralFontSize // ) ) { // // we can only decrease by 1 // iNewLabelFontSize = iCurrGeneralFontSize - 1; // } else { // // no room to decrease at all // iNewLabelFontSize = iCurrGeneralFontSize; // } // // // // construct the new font // Font fnt = new Font( null, // ScaledFontManager.getName(), // iNewLabelFontSize, // ScaledFontManager.getStyle() ); // // return fnt; } /** * Creates all the labels and icons for the link. */ @Override public void layout( ConnectionAnchor sourceAnchor, ConnectionAnchor targetAnchor, DiagramEditPart adepParentEditPart ) { boolean isTNode = (sourceAnchor instanceof ChopboxAnchor); if( isTNode ) { if( canShowSuid() ) { // We need to treat this differently. // Go ahead and place the suid at a point right justified above the arrow point. updateLabels(); // update the fonts of each label before any other calcs updateFonts( adepParentEditPart ); int arrowPtX = ((DiagramModelNode)getSourceNode()).getX(); int arrowPtY = ((DiagramModelNode)getSourceNode()).getY() + ((DiagramModelNode)getSourceNode()).getHeight()/2; double strHeight = suidLabelNode.getHeight(); double strWidth = suidLabelNode.getWidth(); int strX = arrowPtX - (int)strWidth - 4; int strY = arrowPtY - (int)strHeight - 4; suidLabelNode.setPosition(new Point( strX, strY )); } } else{ // Check here!!! because we don't want to process generic connection anchors... if( !(sourceAnchor instanceof NodeConnectionAnchor) ) return; // This is the hook to go back to model properties and get the SUID and Name values // layout is called from refreshAssociations() in the Node edit part. if( suidLabelNode == null ) { // If SUID was turned from false to true // this will update the label "name" and should fire a property change // and ultimately change the label figure text. updateLabels(); return; } updateLabels(); // update the fonts of each label before any other calcs updateFonts( adepParentEditPart ); Point pSourceAnchor = null; int sourceX = ((NodeConnectionAnchor)sourceAnchor).getOffsetH() + ((DiagramModelNode)getSourceNode()).getX(); int sourceY = ((NodeConnectionAnchor)sourceAnchor).getOffsetV() + ((DiagramModelNode)getSourceNode()).getY(); pSourceAnchor = new Point( sourceX, sourceY ); double deltaX = DELTA_X; double deltaY = DELTA_Y; int sourceSide = 0; // Get End Points (Intersections) Point sourceStartPt = pSourceAnchor; sourceSide = ((NodeConnectionAnchor)sourceAnchor).getDirection(); double sourceAngleInRadians = getSourceAngleInRadians( sourceSide ); int tmpPtX = 0; int tmpPtY = 0; double startX = 0; double startY = 0; double strHeight = 0; double strWidth = 0; double tmpAngle = 0; if( canShowSuid() ) { // LOCATE SOURCE SUID STRING strHeight = suidLabelNode.getHeight(); strWidth = suidLabelNode.getWidth(); startX = sourceStartPt.x; startY = sourceStartPt.y; if( getLinkType() == DiagramLinkType.ORTHOGONAL ) { tmpAngle = Math.toDegrees(sourceAngleInRadians); } else tmpAngle = 360.0 - Math.toDegrees(sourceAngleInRadians); switch( sourceSide ) { case AnchorManager.NORTH: { if( tmpAngle >= 60 && tmpAngle <= 120 ) { // Baseline. Place at upper left of intersection. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY - deltaY - strHeight); } else if( tmpAngle < 60 ) { // Baseline. Place at X of intersection left justified. tmpPtX = (int)(startX - strWidth); tmpPtY = (int)(startY - deltaY - strHeight); } else { // Baseline. Place at X of intersection right justified. tmpPtX = (int)(startX); tmpPtY = (int)(startY - deltaY - strHeight); } } break; case AnchorManager.SOUTH: { if( tmpAngle >= 240 && tmpAngle <= 300 ) { // Baseline. Place at lower left of intersection. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY + deltaY); } else if( tmpAngle < 240 ) { // Baseline. Place at X of intersection left right justified. tmpPtX = (int)(startX - strWidth); tmpPtY = (int)(startY + deltaY); } else { // Baseline. Place at X of intersection right justified. tmpPtX = (int)(startX); tmpPtY = (int)(startY + deltaY ); } } break; case AnchorManager.EAST: { if( tmpAngle <= 20 || tmpAngle >= 340 ) { // Baseline. Place at upper right of intersection. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY - deltaY - strHeight); } else if( tmpAngle > 20 && tmpAngle <= 91 ) { // Baseline. Place at Y of intersection left justified. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY); } else { // Baseline. Place at Y of intersection right justified. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY - strHeight); } } break; case AnchorManager.WEST: { if( tmpAngle <= 200 && tmpAngle >= 160 ) { // Baseline. Place at upper left of intersection. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY - deltaY - strHeight); } else if( tmpAngle > 89 && tmpAngle < 160 ) { // Baseline. Place at Y of intersection left justified. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY - strHeight); } else { // Baseline. Place at Y of intersection right justified. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY - strHeight); } } break; default: break; } suidLabelNode.setPosition(new Point( tmpPtX, tmpPtY )); } if( canShowAliasedValues() ) { // LOCATE SOURCE ALIAS STRING strHeight = aliasLabelNode.getHeight(); strWidth = aliasLabelNode.getWidth(); startX = sourceStartPt.x; startY = sourceStartPt.y; if( getLinkType() == DiagramLinkType.ORTHOGONAL ) { tmpAngle = Math.toDegrees(sourceAngleInRadians); } else tmpAngle = 360.0 - Math.toDegrees(sourceAngleInRadians); switch( sourceSide ) { case AnchorManager.NORTH: { if( tmpAngle >= 60 && tmpAngle <= 120 ) { // Baseline. Place at upper left of intersection. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY - deltaY - strHeight); } else if( tmpAngle < 60 ) { // Baseline. Place at X of intersection left justified. tmpPtX = (int)(startX - strWidth); tmpPtY = (int)(startY - deltaY - strHeight*2); } else { // Baseline. Place at X of intersection right justified. tmpPtX = (int)(startX); tmpPtY = (int)(startY - deltaY - strHeight*2); } } break; case AnchorManager.SOUTH: { if( tmpAngle >= 240 && tmpAngle <= 300 ) { // Baseline. Place at lower left of intersection. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY + deltaY); } else if( tmpAngle < 240 ) { // Baseline. Place at X of intersection left right justified. tmpPtX = (int)(startX ); tmpPtY = (int)(startY + deltaY + strHeight); } else { // Baseline. Place at X of intersection right justified. tmpPtX = (int)(startX - strWidth); tmpPtY = (int)(startY + deltaY + strHeight ); } } break; case AnchorManager.EAST: { if( tmpAngle <= 20 || tmpAngle >= 340 ) { // Baseline. Place at upper right of intersection. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY + deltaY); } else if( tmpAngle > 20 && tmpAngle <= 91 ) { // Baseline. Place at Y of intersection left justified. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY + strHeight); } else { // Baseline. Place at Y of intersection right justified. tmpPtX = (int)(startX + deltaX); tmpPtY = (int)(startY - strHeight*2); } } break; case AnchorManager.WEST: { if( tmpAngle <= 200 && tmpAngle >= 160 ) { // Baseline. Place at upper left of intersection. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY + deltaY); } else if( tmpAngle > 89 && tmpAngle < 160 ) { // Baseline. Place at Y of intersection left justified. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY + strHeight); } else { // Baseline. Place at Y of intersection right justified. tmpPtX = (int)(startX - deltaX - strWidth); tmpPtY = (int)(startY - strHeight*2); } } break; default: break; } aliasLabelNode.setPosition(new Point( tmpPtX, tmpPtY )); } } } @Override public void placeStereotypeAndName( int iSourceSide, int iTargetSide, PointList plConnectionPoints ) { } private double getSourceAngleInRadians( int iSourceSide ) { // Code for Source End Object double sourceAngleInRadians = 0.0; // calc angle if( getLinkType() == DiagramLinkType.ORTHOGONAL ) { if( iSourceSide == AnchorManager.WEST ) sourceAngleInRadians = Math.PI; else if( iSourceSide == AnchorManager.EAST ) sourceAngleInRadians = 0; else if( iSourceSide == AnchorManager.NORTH ) sourceAngleInRadians = Math.PI/2; else sourceAngleInRadians = 3*Math.PI/2; } else { // NO logic yet } return sourceAngleInRadians; } private boolean canShowSuid() { if( suidLabelNode != null && suidLabelNode.getName().length() > 0 ) { return true; } return false; } private boolean canShowAliasedValues() { if( aliasLabelNode != null && aliasLabelNode.getName().length() > 0 ) { return true; } return false; } @Override public String toString() { String suidText = null; if (suidLabelNode != null) suidText = suidLabelNode.getDisplayString(); String nameText = null; if (aliasLabelNode != null) nameText = aliasLabelNode.getDisplayString(); return new StringBuffer().append(" TransformationLink:") //$NON-NLS-1$ .append(" Source Node = ").append(sourceNode.getName()) //$NON-NLS-1$ .append(" Target Node = ").append(targetNode.getName()) //$NON-NLS-1$ .append(" SUID = ").append(suidText) //$NON-NLS-1$ .append(" Aliases = ").append(nameText) //$NON-NLS-1$ .toString(); } /* (non-Javadoc) * @See org.teiid.designer.diagram.ui.connection.NodeConnectionModel#getDecoratorId() */ @Override public int getTargetDecoratorId() { return BinaryAssociation.DECORATOR_NONE; } /* (non-Javadoc) * @See org.teiid.designer.diagram.ui.connection.NodeConnectionModel#getDecoratorId() */ @Override public int getSourceDecoratorId() { return BinaryAssociation.DECORATOR_NONE; } /* (non-Javadoc) * @See org.teiid.designer.diagram.ui.connection.NodeConnectionModel#getLineStyle() */ @Override public int getLineStyle() { return BinaryAssociation.LINE_SOLID; } /* (non-Javadoc) * @See org.teiid.designer.diagram.ui.connection.NodeConnectionModel#getToolTipString() */ @Override public List getToolTipStrings() { List newList = new ArrayList(1); newList.add(sName); return newList; } }