summaryrefslogtreecommitdiffstats
path: root/umbrello/umbrello/linepath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'umbrello/umbrello/linepath.cpp')
-rw-r--r--umbrello/umbrello/linepath.cpp957
1 files changed, 957 insertions, 0 deletions
diff --git a/umbrello/umbrello/linepath.cpp b/umbrello/umbrello/linepath.cpp
new file mode 100644
index 00000000..59cf105f
--- /dev/null
+++ b/umbrello/umbrello/linepath.cpp
@@ -0,0 +1,957 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "linepath.h"
+
+// system includes
+#include <cstdlib>
+#include <cmath>
+
+// qt includes
+#include <qcanvas.h>
+#include <qdatastream.h>
+#include <qdom.h>
+
+// kde includes
+#include <kdebug.h>
+
+// application includes
+#include "associationwidget.h"
+#include "activitywidget.h"
+#include "widget_utils.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+
+LinePath::Circle::Circle(QCanvas * canvas, int radius /* = 0 */)
+ : QCanvasEllipse(radius * 2, radius * 2, canvas) {
+}
+
+void LinePath::Circle::setX(int x) {
+ QCanvasItem::setX( (double) x );
+}
+
+void LinePath::Circle::setY(int y) {
+ QCanvasItem::setY( (double) y );
+}
+
+void LinePath::Circle::setRadius(int radius) {
+ QCanvasEllipse::setSize(radius * 2, radius * 2);
+}
+
+int LinePath::Circle::getRadius() const {
+ return (QCanvasEllipse::height() / 2);
+}
+
+void LinePath::Circle::drawShape(QPainter& p) {
+ int diameter = height();
+ int radius = diameter / 2;
+ p.drawEllipse( (int)x() - radius, (int)y() - radius, diameter, diameter);
+}
+
+LinePath::LinePath() {
+ m_RectList.setAutoDelete( true );
+ m_LineList.setAutoDelete( true );
+ m_HeadList.setAutoDelete( true );
+ m_ParallelList.setAutoDelete( true );
+ m_bSelected = false;
+ m_pClearPoly = 0;
+ m_pCircle = 0;
+ m_PointArray.resize( 4 );
+ m_ParallelLines.resize( 4 );
+ m_pAssociation = 0;
+ m_bHeadCreated = false;
+ m_bParallelLineCreated = false;
+ m_DockRegion = TopBottom;
+}
+
+LinePath::~LinePath() {}
+
+void LinePath::setAssociation(AssociationWidget * association ) {
+ if( !association )
+ return;
+ cleanup();
+ m_pAssociation = association;
+ createHeadLines();
+ if( getAssocType() == Uml::at_Coll_Message )
+ setupParallelLine();
+ UMLView * view = (UMLView *)m_pAssociation -> parent();
+ connect( view, SIGNAL( sigColorChanged( Uml::IDType ) ), this, SLOT( slotLineColorChanged( Uml::IDType ) ) );
+ connect( view, SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, SLOT( slotLineWidthChanged( Uml::IDType ) ) );
+}
+
+QPoint LinePath::getPoint( int pointIndex ) {
+ int count = m_LineList.count();
+ if( count == 0 || pointIndex > count || pointIndex < 0)
+ return QPoint( -1, -1 );
+
+ if( pointIndex == count ) {
+ QCanvasLine * line = m_LineList.last();
+ return line -> endPoint();
+ }
+ QCanvasLine * line = m_LineList.at( pointIndex );
+ return line -> startPoint();
+}
+
+bool LinePath::setPoint( int pointIndex, const QPoint &point ) {
+ int count = m_LineList.count();
+ if( count == 0 || pointIndex > count || pointIndex < 0)
+ return false;
+ if (point.x() == 0 && point.y() == 0) {
+ kError() << "LinePath::setPoint:ignoring request for (0,0)" << endl;
+ return false;
+ }
+
+ if( pointIndex == count) {
+ QCanvasLine * line = m_LineList.last();
+ QPoint p = line -> startPoint();
+ line -> setPoints( p.x(), p.y(), point.x(), point.y() );
+ moveSelected( pointIndex );
+ update();
+ return true;
+ }
+ if( pointIndex == 0 ) {
+ QCanvasLine * line = m_LineList.first();
+ QPoint p = line -> endPoint();
+ line -> setPoints( point.x(), point.y(), p.x(), p.y() );
+ moveSelected( pointIndex );
+ update();
+ return true;
+ }
+ QCanvasLine * line = m_LineList.at( pointIndex );
+ QPoint p = line -> endPoint();
+ line -> setPoints( point.x(), point.y(), p.x(), p.y() );
+ line = m_LineList.at( pointIndex - 1 );
+ p = line -> startPoint();
+ line -> setPoints( p.x(), p.y(), point.x(), point.y() );
+ moveSelected( pointIndex );
+ update();
+ return true;
+}
+
+bool LinePath::isPoint( int pointIndex, const QPoint &point, unsigned short delta) {
+ int count = m_LineList.count();
+ if ( pointIndex >= count )
+ return false;
+
+ QCanvasLine * line = m_LineList.at( pointIndex );
+
+ /* check if the given point is the start or end point of the line */
+ if ( (
+ abs( line -> endPoint().x() - point.x() ) <= delta
+ &&
+ abs( line -> endPoint().y() - point.y() ) <= delta
+ ) || (
+ abs( line -> startPoint().x() - point.x() ) <= delta
+ &&
+ abs( line -> startPoint().y() - point.y() ) <= delta
+ ) )
+ return true;
+
+ /* check if the given point is the start or end point of the line */
+ return false;
+}
+
+bool LinePath::insertPoint( int pointIndex, const QPoint &point ) {
+ int count = m_LineList.count();
+ if( count == 0 )
+ return false;
+ const bool bLoading = UMLApp::app()->getDocument()->loading();
+
+ if( count == 1 || pointIndex == 1) {
+ QCanvasLine * first = m_LineList.first();
+ QPoint sp = first -> startPoint();
+ QPoint ep = first -> endPoint();
+ first -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
+ QCanvasLine * line = new QCanvasLine( getCanvas() );
+ line -> setZ( -2 );
+ line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.insert( 1, line );
+ if (!bLoading)
+ setupSelected();
+ return true;
+ }
+ if( count + 1 == pointIndex ) {
+ QCanvasLine * before = m_LineList.last();
+ QPoint sp = before -> startPoint();
+ QPoint ep = before -> endPoint();
+ before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
+ QCanvasLine * line = new QCanvasLine( getCanvas() );
+ line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
+ line -> setZ( -2 );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.append( line );
+ if (!bLoading)
+ setupSelected();
+ return true;
+ }
+ QCanvasLine * before = m_LineList.at( pointIndex - 1 );
+ QPoint sp = before -> startPoint();
+ QPoint ep = before -> endPoint();
+ before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
+ QCanvasLine * line = new QCanvasLine(getCanvas() );
+ line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
+ line -> setZ( -2 );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.insert( pointIndex, line );
+ if (!bLoading)
+ setupSelected();
+ return true;
+}
+
+bool LinePath::removePoint( int pointIndex, const QPoint &point, unsigned short delta )
+{
+ /* get the number of line segments */
+ int count = m_LineList.count();
+ if ( pointIndex >= count )
+ return false;
+
+ /* we don't know if the user clicked on the start- or endpoint of a
+ * line segment */
+ QCanvasLine * current_line = m_LineList.at( pointIndex );
+ if (abs( current_line -> endPoint().x() - point.x() ) <= delta
+ &&
+ abs( current_line -> endPoint().y() - point.y() ) <= delta)
+ {
+ /* the user clicked on the end point of the line;
+ * we have to make sure that this isn't the last line segment */
+ if (pointIndex >= count - 1)
+ return false;
+
+ /* the next segment will get the starting point from the current one,
+ * which is going to be removed */
+ QCanvasLine * next_line = m_LineList.at( pointIndex + 1 );
+ QPoint startPoint = current_line -> startPoint();
+ QPoint endPoint = next_line -> endPoint();
+ next_line -> setPoints(startPoint.x(), startPoint.y(),
+ endPoint.x(), endPoint.y());
+
+ } else
+ if (abs( current_line -> startPoint().x() - point.x() ) <= delta
+ &&
+ abs( current_line -> startPoint().y() - point.y() ) <= delta)
+ {
+ /* the user clicked on the start point of the line;
+ * we have to make sure that this isn't the first line segment */
+ if (pointIndex < 1)
+ return false;
+
+ /* the previous segment will get the end point from the current one,
+ * which is going to be removed */
+ QCanvasLine * previous_line = m_LineList.at( pointIndex - 1 );
+ QPoint startPoint = previous_line -> startPoint();
+ QPoint endPoint = current_line -> endPoint();
+ previous_line -> setPoints(startPoint.x(), startPoint.y(),
+ endPoint.x(), endPoint.y());
+ } else {
+ /* the user clicked neither on the start- nor on the end point of
+ * the line; this really shouldn't happen, but just make sure */
+ return false;
+ }
+
+
+ /* remove the segment from the list */
+ m_LineList.remove( pointIndex );
+
+ return true;
+}
+
+bool LinePath::setStartEndPoints( const QPoint &start, const QPoint &end ) {
+ int count = m_LineList.count();
+
+ if( count == 0 ) {
+ QCanvasLine * line = new QCanvasLine(getCanvas() );
+ line -> setPoints( start.x(), start.y(), end.x(), end.y() );
+ line -> setZ( -2 );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.append( line );
+ return true;
+ }
+ bool status = setPoint( 0, start );
+ if( status)
+ return setPoint( count , end );
+ return false;
+}
+
+int LinePath::count() {
+ return m_LineList.count() + 1;
+}
+
+int LinePath::onLinePath( const QPoint &position ) {
+ QCanvasItemList list = getCanvas() -> collisions( position );
+ int index = -1;
+
+ QCanvasItemList::iterator end(list.end());
+ for(QCanvasItemList::iterator item_it(list.begin()); item_it != end; ++item_it ) {
+ if( ( index = m_LineList.findRef( (QCanvasLine*)*item_it ) ) != -1 )
+ break;
+ }//end for
+ return index;
+}
+
+void LinePath::setSelected( bool select ) {
+ if(select)
+ setupSelected();
+ else if( m_RectList.count() > 0 )
+ m_RectList.clear();
+}
+
+void LinePath::setAssocType( Uml::Association_Type type ) {
+ LineListIt it( m_LineList );
+ QCanvasLine * line = 0;
+ while( ( line = it.current() ) ) {
+ line -> setPen( getPen() );
+ ++it;
+ }
+ if( m_pClearPoly ) {
+ delete m_pClearPoly;
+ m_pClearPoly = 0;
+ }
+ if( type == Uml::at_Coll_Message )
+ setupParallelLine();
+ else
+ createHeadLines();
+ update();
+}
+
+void LinePath::update() {
+ if (getAssocType() == Uml::at_Coll_Message) {
+ if (m_bParallelLineCreated) {
+ calculateParallelLine();
+ updateParallelLine();
+ } else
+ setupParallelLine();
+ } else if (m_bHeadCreated) {
+ calculateHead();
+ updateHead();
+ } else {
+ createHeadLines();
+ }
+}
+
+void LinePath::slotLineColorChanged( Uml::IDType viewID ) {
+ if(m_pAssociation->getUMLView()->getID() != viewID) {
+ return;
+ }
+ setLineColor( m_pAssociation->getUMLView()->getLineColor() );
+}
+
+
+void LinePath::setLineColor( const QColor &color ) {
+ QCanvasLine * line = 0;
+ uint linewidth = 0;
+ LineListIt it( m_LineList );
+ while( ( line = it.current() ) ) {
+ linewidth = line->pen().width();
+ line -> setPen( QPen( color, linewidth ) );
+ ++it;
+ }
+ LineListIt hit( m_HeadList );
+ while( ( line = hit.current() ) ) {
+ linewidth = line->pen().width();
+ line -> setPen( QPen( color, linewidth ) );
+ ++hit;
+ }
+ LineListIt pit( m_ParallelList );
+ while( ( line = pit.current() ) ) {
+ linewidth = line->pen().width();
+ line -> setPen( QPen( color, linewidth ) );
+ ++pit;
+ }
+
+ if( getAssocType() == Uml::at_Aggregation )
+ if (m_pClearPoly) m_pClearPoly -> setBrush( QBrush( Qt::white ) );
+ else if( getAssocType() == Uml::at_Composition )
+ if (m_pClearPoly) m_pClearPoly -> setBrush( QBrush( color ) );
+
+ if( m_pCircle ) {
+ linewidth = m_pCircle->pen().width();
+ m_pCircle->setPen( QPen(color, linewidth) );
+ }
+}
+
+void LinePath::slotLineWidthChanged( Uml::IDType viewID ) {
+ if(m_pAssociation->getUMLView()->getID() != viewID) {
+ return;
+ }
+ setLineWidth( m_pAssociation->getUMLView()->getLineWidth() );
+}
+
+void LinePath::setLineWidth( uint width ) {
+ QCanvasLine * line = 0;
+ QColor linecolor;
+ LineListIt it( m_LineList );
+ while( ( line = it.current() ) ) {
+ linecolor = line->pen().color();
+ line -> setPen( QPen( linecolor, width ) );
+ ++it;
+ }
+ LineListIt hit( m_HeadList );
+ while( ( line = hit.current() ) ) {
+ linecolor = line->pen().color();
+ line -> setPen( QPen( linecolor, width ) );
+ ++hit;
+ }
+ LineListIt pit( m_ParallelList );
+ while( ( line = pit.current() ) ) {
+ linecolor = line->pen().color();
+ line -> setPen( QPen( linecolor, width ) );
+ ++pit;
+ }
+
+ if( m_pCircle ) {
+ linecolor = m_pCircle->pen().color();
+ m_pCircle->setPen( QPen(linecolor, width) );
+ }
+}
+
+void LinePath::moveSelected( int pointIndex ) {
+ int lineCount = m_LineList.count();
+ if( !m_bSelected ) {
+ m_RectList.clear();
+ return;
+ }
+ if( (int)m_RectList.count() + 1 != lineCount )
+ setupSelected();
+ QCanvasRectangle * rect = 0;
+ QCanvasLine * line = 0;
+ if( pointIndex == lineCount || lineCount == 1) {
+ line = m_LineList.last();
+ QPoint p = line -> endPoint();
+ rect = m_RectList.last();
+ rect -> setX( p.x() );
+ rect -> setY( p.y() );
+ rect -> setZ( 4 );
+ return;
+ }
+ line = m_LineList.at( pointIndex );
+ QPoint p = line -> startPoint();
+ rect = m_RectList.at( pointIndex );
+ rect -> setX( p.x() );
+ rect -> setY( p.y() );
+ rect -> setZ( 4 );
+}
+
+void LinePath::setupSelected() {
+ m_RectList.clear();
+ QCanvasLine * line = 0;
+ LineListIt it( m_LineList );
+ while( ( line = it.current() ) ) {
+ QPoint sp = line -> startPoint();
+ QCanvasRectangle *rect = Widget_Utils::decoratePoint(sp);
+ m_RectList.append( rect );
+ ++it;
+ }
+ //special case for last point
+ line = m_LineList.last();
+ QPoint p = line -> endPoint();
+ QCanvasRectangle *rect = Widget_Utils::decoratePoint(p);
+ m_RectList.append( rect );
+ update();
+}
+
+QPen LinePath::getPen() {
+ Uml::Association_Type type = getAssocType();
+ if( type == Uml::at_Dependency || type == Uml::at_Realization || type == Uml::at_Anchor )
+ return QPen( getLineColor(), getLineWidth(), Qt::DashLine );
+ return QPen( getLineColor(), getLineWidth() );
+}
+
+void LinePath::calculateHead() {
+ uint size = m_LineList.count();
+ QPoint farPoint;
+ int halfLength = 10;
+ double arrowAngle = 0.2618; // 0.5 * atan(sqrt(3.0) / 3.0) = 0.2618
+ Uml::Association_Type at = getAssocType();
+ bool diamond = (at == Uml::at_Aggregation || at == Uml::at_Composition);
+ if (diamond || at == Uml::at_Containment) {
+ farPoint = getPoint(1);
+ m_EgdePoint = getPoint(0);
+ if (diamond) {
+ arrowAngle *= 1.5; // wider
+ halfLength += 1; // longer
+ } else {
+ // Containment has a circle-plus symbol at the
+ // containing object. What we are tweaking here
+ // is the perpendicular line through the circle
+ // (i.e. the horizontal line of the plus sign if
+ // the objects are oriented north/south)
+ arrowAngle *= 2.5; // wider
+ halfLength -= 4; // shorter
+ }
+ } else {
+ farPoint = getPoint(size - 1);
+ m_EgdePoint = getPoint(size);
+ // We have an arrow.
+ arrowAngle *= 2.0; // wider
+ halfLength += 3; // longer
+ }
+ int xa = farPoint.x();
+ int ya = farPoint.y();
+ int xb = m_EgdePoint.x();
+ int yb = m_EgdePoint.y();
+ double deltaX = xb - xa;
+ double deltaY = yb - ya;
+ double hypotenuse = sqrt(deltaX*deltaX + deltaY*deltaY); // the length
+ double slope = atan2(deltaY, deltaX); //slope of line
+ double arrowSlope = slope + arrowAngle;
+ double cosx, siny;
+ if (hypotenuse < 1.0e-6) {
+ cosx = 1.0;
+ siny = 0.0;
+ } else {
+ cosx = halfLength * deltaX/hypotenuse;
+ siny = halfLength * deltaY/hypotenuse;
+ }
+
+ m_ArrowPointA.setX( (int)rint(xb - halfLength * cos(arrowSlope)) );
+ m_ArrowPointA.setY( (int)rint(yb - halfLength * sin(arrowSlope)) );
+ arrowSlope = slope - arrowAngle;
+ m_ArrowPointB.setX( (int)rint(xb - halfLength * cos(arrowSlope)) );
+ m_ArrowPointB.setY( (int)rint(yb - halfLength * sin(arrowSlope)) );
+
+ if(xa > xb)
+ cosx = cosx > 0 ? cosx : cosx * -1;
+ else
+ cosx = cosx > 0 ? cosx * -1: cosx;
+
+ if(ya > yb)
+ siny = siny > 0 ? siny : siny * -1;
+ else
+ siny = siny > 0 ? siny * -1 : siny;
+
+ m_MidPoint.setX( (int)rint(xb + cosx) );
+ m_MidPoint.setY( (int)rint(yb + siny) );
+
+ m_PointArray.setPoint(0, m_EgdePoint);
+ m_PointArray.setPoint(1, m_ArrowPointA);
+ if( getAssocType() == Uml::at_Realization ||
+ getAssocType() == Uml::at_Generalization ) {
+ m_PointArray.setPoint( 2, m_ArrowPointB );
+ m_PointArray.setPoint( 3, m_EgdePoint );
+ } else {
+ QPoint diamondFarPoint;
+ diamondFarPoint.setX( (int)rint(xb + cosx * 2) );
+ diamondFarPoint.setY( (int)rint(yb + siny * 2) );
+ m_PointArray.setPoint(2, diamondFarPoint);
+ m_PointArray.setPoint(3, m_ArrowPointB);
+ }
+
+}
+
+void LinePath::updateHead() {
+ int count = m_HeadList.count();
+ QCanvasLine * line = 0;
+
+ switch( getAssocType() ) {
+ case Uml::at_State:
+ case Uml::at_Activity:
+ case Uml::at_UniAssociation:
+ case Uml::at_Dependency:
+ if( count < 2)
+ return;
+ line = m_HeadList.at( 0 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointA.x(), m_ArrowPointA.y() );
+
+ line = m_HeadList.at( 1 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
+ break;
+
+ case Uml::at_Relationship:
+ if (count < 2) {
+ return;
+ }
+ {
+ int xoffset = 0;
+ int yoffset = 0;
+ if( m_DockRegion == TopBottom )
+ xoffset = 8;
+ else
+ yoffset = 8;
+ line = m_HeadList.at( 0 );
+ line->setPoints( m_PointArray[2].x(), m_PointArray[2].y(),
+ m_PointArray[0].x()-xoffset, m_PointArray[0].y()-yoffset );
+
+ line = m_HeadList.at( 1 );
+ line->setPoints( m_PointArray[2].x(), m_PointArray[2].y(),
+ m_PointArray[0].x()+xoffset, m_PointArray[0].y()+yoffset );
+ }
+
+ case Uml::at_Generalization:
+ case Uml::at_Realization:
+ if( count < 3)
+ return;
+ line = m_HeadList.at( 0 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointA.x(), m_ArrowPointA.y() );
+
+ line = m_HeadList.at( 1 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
+
+ line = m_HeadList.at( 2 );
+ line -> setPoints( m_ArrowPointA.x(), m_ArrowPointA.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
+ m_pClearPoly -> setPoints( m_PointArray );
+ break;
+
+ case Uml::at_Composition:
+ case Uml::at_Aggregation:
+ if( count < 4)
+ return;
+ line = m_HeadList.at( 0 );
+ line -> setPoints( m_PointArray[ 0 ].x(), m_PointArray[ 0 ].y(), m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y() );
+
+ line = m_HeadList.at( 1 );
+ line -> setPoints( m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y(), m_PointArray[ 2 ].x(), m_PointArray[ 2 ].y() );
+
+ line = m_HeadList.at( 2 );
+ line -> setPoints( m_PointArray[ 2 ].x(), m_PointArray[ 2 ].y(), m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y() );
+
+ line = m_HeadList.at( 3 );
+ line -> setPoints( m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y(), m_PointArray[ 0 ].x(), m_PointArray[ 0 ].y() );
+ m_pClearPoly -> setPoints( m_PointArray );
+ break;
+
+ case Uml::at_Containment:
+ if (count < 1)
+ return;
+ line = m_HeadList.at( 0 );
+ line->setPoints( m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y(),
+ m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y() );
+ m_pCircle -> setX( m_MidPoint.x() );
+ m_pCircle -> setY( m_MidPoint.y() );
+ break;
+ default:
+ break;
+ }
+}
+
+void LinePath::growList(LineList &list, int by) {
+ QPen pen( getLineColor(), getLineWidth() );
+ for (int i = 0; i < by; i++) {
+ QCanvasLine * line = new QCanvasLine( getCanvas() );
+ line -> setZ( 0 );
+ line -> setPen( pen );
+ line -> setVisible( true );
+ list.append( line );
+ }
+}
+
+void LinePath::createHeadLines() {
+ m_HeadList.clear();
+ QCanvas * canvas = getCanvas();
+ switch( getAssocType() ) {
+ case Uml::at_Activity:
+ case Uml::at_State:
+ case Uml::at_Dependency:
+ case Uml::at_UniAssociation:
+ case Uml::at_Relationship:
+ growList(m_HeadList, 2);
+ break;
+
+ case Uml::at_Generalization:
+ case Uml::at_Realization:
+ growList(m_HeadList, 3);
+ m_pClearPoly = new QCanvasPolygon( canvas );
+ m_pClearPoly -> setVisible( true );
+ m_pClearPoly -> setBrush( QBrush( Qt::white ) );
+ m_pClearPoly -> setZ( -1 );
+ break;
+
+ case Uml::at_Composition:
+ case Uml::at_Aggregation:
+ growList(m_HeadList, 4);
+ m_pClearPoly = new QCanvasPolygon( canvas );
+ m_pClearPoly -> setVisible( true );
+ if( getAssocType() == Uml::at_Aggregation )
+ m_pClearPoly -> setBrush( QBrush( Qt::white ) );
+ else
+ m_pClearPoly -> setBrush( QBrush( getLineColor() ) );
+ m_pClearPoly -> setZ( -1 );
+ break;
+
+ case Uml::at_Containment:
+ growList(m_HeadList, 1);
+ if (!m_pCircle) {
+ m_pCircle = new Circle( canvas, 6 );
+ m_pCircle->show();
+ m_pCircle->setPen( QPen( getLineColor(), getLineWidth() ) );
+ }
+ break;
+ default:
+ break;
+ }
+ m_bHeadCreated = true;
+}
+
+void LinePath::calculateParallelLine() {
+ int midCount = count() / 2;
+ double ATAN = atan(1.0);
+ int lineDist = 10;
+ //get 1/8(M) and 7/8(T) point
+ QPoint a = getPoint( midCount - 1 );
+ QPoint b = getPoint( midCount );
+ int mx = ( a.x() + b.x() ) / 2;
+ int my = ( a.y() + b.y() ) / 2;
+ int tx = ( mx + b.x() ) / 2;
+ int ty = ( my + b.y() ) / 2;
+ //find dist between M and T points
+ int distX = ( mx - tx );
+ distX *= distX;
+ int distY = ( my - ty );
+ distY *= distY;
+ double dist = sqrt( double(distX + distY) );
+ double angle = atan2( double(ty - my), double(tx - mx) ) + ( ATAN * 2 );
+ //find point from M to start line from.
+ double cosx = cos( angle ) * lineDist;
+ double siny = sin( angle ) * lineDist;
+ QPoint pointM( mx + (int)cosx, my + (int)siny );
+ //find dist between P(xb, yb)
+ distX = ( tx - b.x() );
+ distX *= distX;
+ distY = ( ty - b.y() );
+ distY *= distY;
+ dist = sqrt( double(distX + distY) );
+ //find point from T to end line
+ cosx = cos( angle ) * lineDist;
+ siny = sin( angle ) * lineDist;
+ QPoint pointT( tx + (int)cosx, ty + (int)siny );
+ m_ParallelLines[ 1 ] = pointM;
+ m_ParallelLines[ 0 ] = pointT;
+
+ int arrowDist = 5;
+ angle = atan2( double(pointT.y() - pointM.y()),
+ double(pointT.x() - pointM.x()) );
+ double arrowSlope = angle + ATAN;
+ cosx = ( cos( arrowSlope ) ) * arrowDist;
+ siny = ( sin( arrowSlope ) ) * arrowDist;
+ m_ParallelLines[ 2 ] = QPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
+ arrowSlope = angle - ATAN;
+ cosx = ( cos( arrowSlope ) ) * arrowDist;
+ siny = ( sin( arrowSlope ) ) * arrowDist;
+ m_ParallelLines[ 3 ] = QPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
+}
+
+void LinePath::setupParallelLine() {
+ m_ParallelList.clear();
+ growList(m_ParallelList, 3);
+ m_bParallelLineCreated = true;
+}
+
+void LinePath::updateParallelLine() {
+ if( !m_bParallelLineCreated )
+ return;
+ QCanvasLine * line = 0;
+ QPoint common = m_ParallelLines.at( 0 );
+ QPoint p = m_ParallelLines.at( 1 );
+ line = m_ParallelList.at( 0 );
+ line -> setPoints( common.x(), common.y(), p.x(), p.y() );
+
+ p = m_ParallelLines.at( 2 );
+ line = m_ParallelList.at( 1 );
+ line -> setPoints( common.x(), common.y(), p.x(), p.y() );
+
+ p = m_ParallelLines.at( 3 );
+ line = m_ParallelList.at( 2 );
+ line -> setPoints( common.x(), common.y(), p.x(), p.y() );
+}
+
+bool LinePath::operator==( LinePath & rhs ) {
+ if( this -> m_LineList.count() != rhs.m_LineList.count() )
+ return false;
+
+ //Check to see if all points at the same position
+ for( int i = 0; i< rhs.count() ; i++ ) {
+ if( this -> getPoint( i ) != rhs.getPoint( i ) )
+ return false;
+ }
+ return true;
+}
+
+LinePath & LinePath::operator=( LinePath & rhs ) {
+ if( this == &rhs )
+ return *this;
+ //clear out the old canvas objects
+ this -> m_LineList.clear();
+ this -> m_ParallelList.clear();
+ this -> m_RectList.clear();
+ this -> m_HeadList.clear();
+ int count = rhs.m_LineList.count();
+ //setup start end points
+ this -> setStartEndPoints( rhs.getPoint( 0 ), rhs.getPoint( count) );
+ //now insert the rest
+ for( int i = 1; i < count ; i++ ) {
+ this -> insertPoint( i, rhs.getPoint ( i ) );
+ }
+ this -> setAssocType( rhs.getAssocType() );
+
+ return *this;
+}
+
+QCanvas * LinePath::getCanvas() {
+ if( !m_pAssociation )
+ return 0;
+ const UMLView * view = m_pAssociation->getUMLView();
+ return view -> canvas();
+}
+
+Uml::Association_Type LinePath::getAssocType() {
+ if( m_pAssociation )
+ return m_pAssociation -> getAssocType();
+ return Uml::at_Association;
+}
+
+QColor LinePath::getLineColor() {
+ if( !m_pAssociation )
+ return Qt::black;
+ return m_pAssociation -> getLineColor();
+}
+
+uint LinePath::getLineWidth() {
+ if( !m_pAssociation )
+ return 0;
+ int viewLineWidth = m_pAssociation -> getLineWidth();
+ if ( viewLineWidth >= 0 && viewLineWidth <= 10 )
+ return viewLineWidth;
+ else {
+ kWarning() << "Ignore wrong LineWidth of " << viewLineWidth
+ << " in LinePath::getLineWidth" << endl;
+ return 0;
+ }
+}
+
+void LinePath::cleanup() {
+ if (m_pAssociation)
+ m_LineList.clear();
+ m_HeadList.clear();
+ m_RectList.clear();
+ m_ParallelList.clear();
+
+ if( m_pClearPoly )
+ delete m_pClearPoly;
+ if( m_pCircle )
+ delete m_pCircle;
+ m_pCircle = 0;
+ m_pClearPoly = 0;
+ m_bHeadCreated = m_bParallelLineCreated = false;
+ if( m_pAssociation ) {
+ UMLView * view = (UMLView *)m_pAssociation -> parent();
+ if(view) {
+ disconnect( view, SIGNAL( sigColorChanged( Uml::IDType ) ), this, SLOT( slotLineColorChanged( Uml::IDType ) ) );
+ disconnect( view, SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, SLOT( slotLineWidthChanged( Uml::IDType ) ) );
+ }
+ m_pAssociation = NULL;
+ }
+}
+
+void LinePath::setDockRegion( Region region ) {
+ m_DockRegion = region;
+}
+
+bool LinePath::hasPoints () {
+ int count = m_LineList.count();
+ if (count>1)
+ return true;
+ return false;
+}
+void LinePath::dumpPoints () {
+ int count = m_LineList.count();
+ for( int i = 1; i < count; i++ ) {
+ QPoint point = getPoint( i );
+ kDebug()<<" * point x:"<<point.x()<<" y:"<<point.y()<<endl;
+ }
+}
+
+void LinePath::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ int count = m_LineList.count();
+ QPoint point = getPoint( 0 );
+ QDomElement lineElement = qDoc.createElement( "linepath" );
+ QDomElement startElement = qDoc.createElement( "startpoint" );
+ startElement.setAttribute( "startx", point.x() );
+ startElement.setAttribute( "starty", point.y() );
+ lineElement.appendChild( startElement );
+ QDomElement endElement = qDoc.createElement( "endpoint" );
+ point = getPoint( count );
+ endElement.setAttribute( "endx", point.x() );
+ endElement.setAttribute( "endy", point.y() );
+ lineElement.appendChild( endElement );
+ for( int i = 1; i < count; i++ ) {
+ QDomElement pointElement = qDoc.createElement( "point" );
+ point = getPoint( i );
+ pointElement.setAttribute( "x", point.x() );
+ pointElement.setAttribute( "y", point.y() );
+ lineElement.appendChild( pointElement );
+ }
+ qElement.appendChild( lineElement );
+}
+
+bool LinePath::loadFromXMI( QDomElement & qElement ) {
+ QDomNode node = qElement.firstChild();
+ QDomElement startElement = node.toElement();
+ if( startElement.isNull() || startElement.tagName() != "startpoint" )
+ return false;
+ QString x = startElement.attribute( "startx", "0" );
+ int nX = x.toInt();
+ QString y = startElement.attribute( "starty", "0" );
+ int nY = y.toInt();
+ QPoint startPoint( nX, nY );
+
+ node = startElement.nextSibling();
+ QDomElement endElement = node.toElement();
+ if( endElement.isNull() || endElement.tagName() != "endpoint" )
+ return false;
+ x = endElement.attribute( "endx", "0" );
+ nX = x.toInt();
+ y = endElement.attribute( "endy", "0" );
+ nY = y.toInt();
+ QPoint endPoint( nX, nY );
+ setStartEndPoints( startPoint, endPoint );
+ QPoint point;
+ node = endElement.nextSibling();
+ QDomElement element = node.toElement();
+ int i = 1;
+ while( !element.isNull() ) {
+ if( element.tagName() == "point" ) {
+ x = element.attribute( "x", "0" );
+ y = element.attribute( "y", "0" );
+ point.setX( x.toInt() );
+ point.setY( y.toInt() );
+ insertPoint( i++, point );
+ }
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+ return true;
+}
+
+
+void LinePath::activate() {
+ int count = m_LineList.count();
+ if (count == 0)
+ return;
+ QCanvas * canvas = getCanvas();
+ if (canvas == NULL)
+ return;
+ for (int i = 0; i < count ; i++) {
+ QCanvasLine *line = m_LineList.at(i);
+ line -> setCanvas( canvas );
+ line -> setPen( getPen() );
+ }
+}
+
+
+
+#include "linepath.moc"