umbrello API Documentation

linepath.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2002-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "linepath.h"
00014 
00015 // system includes
00016 #include <cstdlib>
00017 #include <cmath>
00018 
00019 // qt includes
00020 #include <qcanvas.h>
00021 #include <qdatastream.h>
00022 #include <qdom.h>
00023 
00024 // kde includes
00025 #include <kdebug.h>
00026 
00027 // application includes
00028 #include "associationwidget.h"
00029 #include "activitywidget.h"
00030 #include "widget_utils.h"
00031 #include "umlview.h"
00032 #include "umldoc.h"
00033 #include "uml.h"
00034 
00035 LinePath::Circle::Circle(QCanvas * canvas, int radius /* = 0 */)
00036         : QCanvasEllipse(radius * 2, radius * 2, canvas) {
00037 }
00038 
00039 void LinePath::Circle::setX(int x) {
00040     QCanvasItem::setX( (double) x );
00041 }
00042 
00043 void LinePath::Circle::setY(int y) {
00044     QCanvasItem::setY( (double) y );
00045 }
00046 
00047 void LinePath::Circle::setRadius(int radius) {
00048     QCanvasEllipse::setSize(radius * 2, radius * 2);
00049 }
00050 
00051 int LinePath::Circle::getRadius() const {
00052     return (QCanvasEllipse::height() / 2);
00053 }
00054 
00055 void LinePath::Circle::drawShape(QPainter& p) {
00056     int diameter = height();
00057     int radius = diameter / 2;
00058     p.drawEllipse( (int)x() - radius, (int)y() - radius, diameter, diameter);
00059 }
00060 
00061 LinePath::LinePath() {
00062     m_RectList.setAutoDelete( true );
00063     m_LineList.setAutoDelete( true );
00064     m_HeadList.setAutoDelete( true );
00065     m_ParallelList.setAutoDelete( true );
00066     m_bSelected = false;
00067     m_pClearPoly = 0;
00068     m_pCircle = 0;
00069     m_PointArray.resize( 4 );
00070     m_ParallelLines.resize( 4 );
00071     m_pAssociation = 0;
00072     m_bHeadCreated = false;
00073     m_bParallelLineCreated = false;
00074     m_DockRegion = TopBottom;
00075 }
00076 
00077 LinePath::~LinePath() {}
00078 
00079 void LinePath::setAssociation(AssociationWidget * association ) {
00080     if( !association )
00081         return;
00082     cleanup();
00083     m_pAssociation = association;
00084     createHeadLines();
00085     if( getAssocType() == Uml::at_Coll_Message )
00086         setupParallelLine();
00087     UMLView * view =  (UMLView *)m_pAssociation -> parent();
00088     connect( view, SIGNAL( sigColorChanged( Uml::IDType ) ), this, SLOT( slotLineColorChanged( Uml::IDType ) ) );
00089     connect( view, SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, SLOT( slotLineWidthChanged( Uml::IDType ) ) );
00090 }
00091 
00092 QPoint LinePath::getPoint( int pointIndex ) {
00093     int count = m_LineList.count();
00094     if( count == 0 || pointIndex > count  || pointIndex < 0)
00095         return QPoint( -1, -1 );
00096 
00097     if( pointIndex == count ) {
00098         QCanvasLine * line = m_LineList.last();
00099         return line -> endPoint();
00100     }
00101     QCanvasLine * line = m_LineList.at( pointIndex );
00102     return line -> startPoint();
00103 }
00104 
00105 bool LinePath::setPoint( int pointIndex, const QPoint &point ) {
00106     int count = m_LineList.count();
00107     if( count == 0 || pointIndex > count  || pointIndex < 0)
00108         return false;
00109 
00110     if( pointIndex == count) {
00111         QCanvasLine * line = m_LineList.last();
00112         QPoint p = line -> startPoint();
00113         line -> setPoints( p.x(), p.y(), point.x(), point.y() );
00114         moveSelected( pointIndex );
00115         update();
00116         return true;
00117     }
00118     if( pointIndex == 0 ) {
00119         QCanvasLine * line = m_LineList.first();
00120         QPoint p = line -> endPoint();
00121         line -> setPoints( point.x(), point.y(), p.x(), p.y() );
00122         moveSelected( pointIndex );
00123         update();
00124         return true;
00125     }
00126     QCanvasLine * line = m_LineList.at( pointIndex  );
00127     QPoint p = line -> endPoint();
00128     line -> setPoints( point.x(), point.y(), p.x(), p.y() );
00129     line = m_LineList.at( pointIndex - 1 );
00130     p = line -> startPoint();
00131     line -> setPoints( p.x(), p.y(), point.x(), point.y() );
00132     moveSelected( pointIndex );
00133     update();
00134     return true;
00135 }
00136 
00137 bool LinePath::isPoint( int pointIndex, const QPoint &point, unsigned short delta) {
00138     int count = m_LineList.count();
00139     if ( pointIndex >= count )
00140         return false;
00141 
00142     QCanvasLine * line = m_LineList.at( pointIndex );
00143 
00144     /* check if the given point is the start or end point of the line */
00145     if ( (
00146                 abs( line -> endPoint().x() - point.x() ) <= delta
00147                 &&
00148                 abs( line -> endPoint().y() - point.y() ) <= delta
00149             ) || (
00150                 abs( line -> startPoint().x() - point.x() ) <= delta
00151                 &&
00152                 abs( line -> startPoint().y() - point.y() ) <= delta
00153             ) )
00154         return true;
00155 
00156     /* check if the given point is the start or end point of the line */
00157     return false;
00158 }
00159 
00160 bool LinePath::insertPoint( int pointIndex, const QPoint &point ) {
00161     int count = m_LineList.count();
00162     if( count == 0 )
00163         return false;
00164     const bool bLoading = UMLApp::app()->getDocument()->loading();
00165 
00166     if( count == 1 || pointIndex == 1) {
00167         QCanvasLine * first = m_LineList.first();
00168         QPoint sp = first -> startPoint();
00169         QPoint ep = first -> endPoint();
00170         first -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
00171         QCanvasLine * line = new QCanvasLine( getCanvas() );
00172         line -> setZ( -2 );
00173         line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
00174         line -> setPen( getPen() );
00175         line -> setVisible( true );
00176         m_LineList.insert( 1, line );
00177         if (!bLoading)
00178             setupSelected();
00179         return true;
00180     }
00181     if( count + 1 == pointIndex ) {
00182         QCanvasLine * before = m_LineList.last();
00183         QPoint sp = before -> startPoint();
00184         QPoint ep = before -> endPoint();
00185         before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
00186         QCanvasLine * line = new QCanvasLine( getCanvas() );
00187         line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
00188         line -> setZ( -2 );
00189         line -> setPen( getPen() );
00190         line -> setVisible( true );
00191         m_LineList.append( line );
00192         if (!bLoading)
00193             setupSelected();
00194         return true;
00195     }
00196     QCanvasLine * before = m_LineList.at( pointIndex - 1 );
00197     QPoint sp = before -> startPoint();
00198     QPoint ep = before -> endPoint();
00199     before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
00200     QCanvasLine * line = new QCanvasLine(getCanvas() );
00201     line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
00202     line -> setZ( -2 );
00203     line -> setPen( getPen() );
00204     line -> setVisible( true );
00205     m_LineList.insert( pointIndex, line );
00206     if (!bLoading)
00207         setupSelected();
00208     return true;
00209 }
00210 
00211 bool LinePath::removePoint( int pointIndex, const QPoint &point, unsigned short delta )
00212 {
00213     /* get the number of line segments */
00214     int count = m_LineList.count();
00215     if ( pointIndex >= count )
00216         return false;
00217 
00218     /* we don't know if the user clicked on the start- or endpoint of a
00219      * line segment */
00220     QCanvasLine * current_line = m_LineList.at( pointIndex );
00221     if (abs( current_line -> endPoint().x() - point.x() ) <= delta
00222             &&
00223             abs( current_line -> endPoint().y() - point.y() ) <= delta)
00224     {
00225         /* the user clicked on the end point of the line;
00226          * we have to make sure that this isn't the last line segment */
00227         if (pointIndex >= count - 1)
00228             return false;
00229 
00230         /* the next segment will get the starting point from the current one,
00231          * which is going to be removed */
00232         QCanvasLine * next_line = m_LineList.at( pointIndex + 1 );
00233         QPoint startPoint = current_line -> startPoint();
00234         QPoint endPoint = next_line -> endPoint();
00235         next_line -> setPoints(startPoint.x(), startPoint.y(),
00236                                endPoint.x(), endPoint.y());
00237 
00238     } else
00239         if (abs( current_line -> startPoint().x() - point.x() ) <= delta
00240                 &&
00241                 abs( current_line -> startPoint().y() - point.y() ) <= delta)
00242         {
00243             /* the user clicked on the start point of the line;
00244              * we have to make sure that this isn't the first line segment */
00245             if (pointIndex < 1)
00246                 return false;
00247 
00248             /* the previous segment will get the end point from the current one,
00249              * which is going to be removed */
00250             QCanvasLine * previous_line = m_LineList.at( pointIndex - 1 );
00251             QPoint startPoint = previous_line -> startPoint();
00252             QPoint endPoint = current_line -> endPoint();
00253             previous_line -> setPoints(startPoint.x(), startPoint.y(),
00254                                        endPoint.x(), endPoint.y());
00255         } else {
00256             /* the user clicked neither on the start- nor on the end point of
00257              * the line; this really shouldn't happen, but just make sure */
00258             return false;
00259         }
00260 
00261 
00262     /* remove the segment from the list */
00263     m_LineList.remove( pointIndex );
00264 
00265     return true;
00266 }
00267 
00268 bool LinePath::setStartEndPoints( const QPoint &start, const QPoint &end ) {
00269     int count = m_LineList.count();
00270 
00271     if( count == 0 ) {
00272         QCanvasLine * line = new QCanvasLine(getCanvas() );
00273         line -> setPoints( start.x(), start.y(), end.x(), end.y() );
00274         line -> setZ( -2 );
00275         line -> setPen( getPen() );
00276         line -> setVisible( true );
00277         m_LineList.append( line );
00278         return true;
00279     }
00280     bool status = setPoint( 0, start );
00281     if( status)
00282         return setPoint( count , end );
00283     return false;
00284 }
00285 
00286 int LinePath::count() {
00287     return m_LineList.count() + 1;
00288 }
00289 
00290 int LinePath::onLinePath( const QPoint &position ) {
00291     QCanvasItemList list = getCanvas() -> collisions( position );
00292     int index = -1;
00293 
00294     QCanvasItemList::iterator end(list.end());
00295     for(QCanvasItemList::iterator item_it(list.begin()); item_it != end; ++item_it ) {
00296         if( ( index = m_LineList.findRef( (QCanvasLine*)*item_it ) ) != -1 )
00297             break;
00298     }//end for
00299     return index;
00300 }
00301 
00302 void LinePath::setSelected( bool select ) {
00303     if(select)
00304         setupSelected();
00305     else if( m_RectList.count() > 0 )
00306         m_RectList.clear();
00307 }
00308 
00309 void LinePath::setAssocType( Uml::Association_Type type ) {
00310     LineListIt it( m_LineList );
00311     QCanvasLine * line = 0;
00312     while( ( line = it.current() ) ) {
00313         line -> setPen( getPen() );
00314         ++it;
00315     }
00316     if( m_pClearPoly ) {
00317         delete m_pClearPoly;
00318         m_pClearPoly = 0;
00319     }
00320     if( type == Uml::at_Coll_Message )
00321         setupParallelLine();
00322     else
00323         createHeadLines();
00324     update();
00325 }
00326 
00327 void LinePath::update() {
00328     if (getAssocType() == Uml::at_Coll_Message) {
00329         if (m_bParallelLineCreated) {
00330             calculateParallelLine();
00331             updateParallelLine();
00332         } else
00333             setupParallelLine();
00334     } else if (m_bHeadCreated) {
00335         calculateHead();
00336         updateHead();
00337     } else {
00338         createHeadLines();
00339     }
00340 }
00341 
00342 void LinePath::slotLineColorChanged( Uml::IDType viewID ) {
00343     if(m_pAssociation->getUMLView()->getID() != viewID) {
00344         return;
00345     }
00346     setLineColor( m_pAssociation->getUMLView()->getLineColor() );
00347 }
00348 
00349 
00350 void LinePath::setLineColor( const QColor &color ) {
00351     QCanvasLine * line = 0;
00352     uint linewidth = 0;
00353     LineListIt it( m_LineList );
00354     while( ( line = it.current() ) ) {
00355         linewidth = line->pen().width();
00356         line -> setPen( QPen( color, linewidth ) );
00357         ++it;
00358     }
00359     LineListIt hit( m_HeadList );
00360     while( ( line = hit.current() ) ) {
00361         linewidth = line->pen().width();
00362         line -> setPen( QPen( color, linewidth ) );
00363         ++hit;
00364     }
00365     LineListIt pit( m_ParallelList );
00366     while( ( line = pit.current() ) ) {
00367         linewidth = line->pen().width();
00368         line -> setPen( QPen( color, linewidth ) );
00369         ++pit;
00370     }
00371 
00372     if( getAssocType() == Uml::at_Aggregation )
00373         if (m_pClearPoly) m_pClearPoly -> setBrush( QBrush( Qt::white ) );
00374         else if( getAssocType() == Uml::at_Composition )
00375             if (m_pClearPoly) m_pClearPoly -> setBrush( QBrush( color ) );
00376 
00377     if( m_pCircle ) {
00378         linewidth = m_pCircle->pen().width();
00379         m_pCircle->setPen( QPen(color, linewidth) );
00380     }
00381 }
00382 
00383 void LinePath::slotLineWidthChanged( Uml::IDType viewID ) {
00384     if(m_pAssociation->getUMLView()->getID() != viewID) {
00385         return;
00386     }
00387     setLineWidth( m_pAssociation->getUMLView()->getLineWidth() );
00388 }
00389 
00390 void LinePath::setLineWidth( uint width ) {
00391     QCanvasLine * line = 0;
00392     QColor linecolor;
00393     LineListIt it( m_LineList );
00394     while( ( line = it.current() ) ) {
00395         linecolor = line->pen().color();
00396         line -> setPen( QPen( linecolor, width ) );
00397         ++it;
00398     }
00399     LineListIt hit( m_HeadList );
00400     while( ( line = hit.current() ) ) {
00401         linecolor = line->pen().color();
00402         line -> setPen( QPen( linecolor, width ) );
00403         ++hit;
00404     }
00405     LineListIt pit( m_ParallelList );
00406     while( ( line = pit.current() ) ) {
00407         linecolor = line->pen().color();
00408         line -> setPen( QPen( linecolor, width ) );
00409         ++pit;
00410     }
00411 
00412     if( m_pCircle ) {
00413         linecolor = m_pCircle->pen().color();
00414         m_pCircle->setPen( QPen(linecolor, width) );
00415     }
00416 }
00417 
00418 void LinePath::moveSelected( int pointIndex ) {
00419     int lineCount = m_LineList.count();
00420     if( !m_bSelected ) {
00421         m_RectList.clear();
00422         return;
00423     }
00424     if( (int)m_RectList.count() + 1 != lineCount )
00425         setupSelected();
00426     QCanvasRectangle * rect = 0;
00427     QCanvasLine * line = 0;
00428     if( pointIndex == lineCount || lineCount == 1) {
00429         line = m_LineList.last();
00430         QPoint p = line -> endPoint();
00431         rect = m_RectList.last();
00432         rect -> setX( p.x() );
00433         rect -> setY( p.y() );
00434         rect -> setZ( 4 );
00435         return;
00436     }
00437     line = m_LineList.at( pointIndex );
00438     QPoint p = line -> startPoint();
00439     rect = m_RectList.at( pointIndex );
00440     rect -> setX( p.x() );
00441     rect -> setY( p.y() );
00442     rect -> setZ( 4 );
00443 }
00444 
00445 void LinePath::setupSelected() {
00446     m_RectList.clear();
00447     QCanvasLine * line = 0;
00448     LineListIt it( m_LineList );
00449     while( ( line = it.current() ) ) {
00450         QPoint sp = line -> startPoint();
00451         QCanvasRectangle *rect = Widget_Utils::decoratePoint(sp);
00452         m_RectList.append( rect );
00453         ++it;
00454     }
00455     //special case for last point
00456     line = m_LineList.last();
00457     QPoint p = line -> endPoint();
00458     QCanvasRectangle *rect = Widget_Utils::decoratePoint(p);
00459     m_RectList.append( rect );
00460     update();
00461 }
00462 
00463 QPen LinePath::getPen() {
00464     Uml::Association_Type type = getAssocType();
00465     if( type == Uml::at_Dependency || type == Uml::at_Realization || type == Uml::at_Anchor )
00466         return QPen( getLineColor(), getLineWidth(), Qt::DashLine );
00467     return QPen( getLineColor(), getLineWidth() );
00468 }
00469 
00470 void LinePath::calculateHead() {
00471     uint size = m_LineList.count();
00472     QPoint farPoint;
00473     int halfLength = 10;
00474     double arrowAngle = 0.2618;   // 0.5 * atan(sqrt(3.0) / 3.0) = 0.2618
00475     Uml::Association_Type at = getAssocType();
00476     bool diamond = (at == Uml::at_Aggregation || at == Uml::at_Composition);
00477     if (diamond || at == Uml::at_Containment) {
00478         farPoint = getPoint(1);
00479         m_EgdePoint = getPoint(0);
00480         if (diamond) {
00481             arrowAngle *= 1.5;  // wider
00482             halfLength += 1;    // longer
00483         } else {
00484             // Containment has a circle-plus symbol at the
00485             // containing object.  What we are tweaking here
00486             // is the perpendicular line through the circle
00487             // (i.e. the horizontal line of the plus sign if
00488             // the objects are oriented north/south)
00489             arrowAngle *= 2.5;  // wider
00490             halfLength -= 4;    // shorter
00491         }
00492     } else {
00493         farPoint = getPoint(size - 1);
00494         m_EgdePoint = getPoint(size);
00495         // We have an arrow.
00496         arrowAngle *= 2.0;      // wider
00497         halfLength += 3;        // longer
00498     }
00499     int xa = farPoint.x();
00500     int ya = farPoint.y();
00501     int xb = m_EgdePoint.x();
00502     int yb = m_EgdePoint.y();
00503     double deltaX = xb - xa;
00504     double deltaY = yb - ya;
00505     double hypotenuse = sqrt(deltaX*deltaX + deltaY*deltaY); // the length
00506     double slope = atan2(deltaY, deltaX);       //slope of line
00507     double arrowSlope = slope + arrowAngle;
00508     double cosx, siny;
00509     if (hypotenuse < 1.0e-6) {
00510         cosx = 1.0;
00511         siny = 0.0;
00512     } else {
00513         cosx = halfLength * deltaX/hypotenuse;
00514         siny = halfLength * deltaY/hypotenuse;
00515     }
00516 
00517     m_ArrowPointA.setX( (int)rint(xb - halfLength * cos(arrowSlope)) );
00518     m_ArrowPointA.setY( (int)rint(yb - halfLength * sin(arrowSlope)) );
00519     arrowSlope = slope - arrowAngle;
00520     m_ArrowPointB.setX( (int)rint(xb - halfLength * cos(arrowSlope)) );
00521     m_ArrowPointB.setY( (int)rint(yb - halfLength * sin(arrowSlope)) );
00522 
00523     if(xa > xb)
00524         cosx = cosx > 0 ? cosx : cosx * -1;
00525     else
00526         cosx = cosx > 0 ? cosx * -1: cosx;
00527 
00528     if(ya > yb)
00529         siny = siny > 0 ? siny : siny * -1;
00530     else
00531         siny = siny > 0 ? siny * -1 : siny;
00532 
00533     m_MidPoint.setX( (int)rint(xb + cosx) );
00534     m_MidPoint.setY( (int)rint(yb + siny) );
00535 
00536     m_PointArray.setPoint(0, m_EgdePoint);
00537     m_PointArray.setPoint(1, m_ArrowPointA);
00538     if( getAssocType() == Uml::at_Realization ||
00539             getAssocType() == Uml::at_Generalization ) {
00540         m_PointArray.setPoint( 2, m_ArrowPointB );
00541         m_PointArray.setPoint( 3, m_EgdePoint );
00542     } else {
00543         QPoint diamondFarPoint;
00544         diamondFarPoint.setX( (int)rint(xb + cosx * 2) );
00545         diamondFarPoint.setY( (int)rint(yb + siny * 2) );
00546         m_PointArray.setPoint(2, diamondFarPoint);
00547         m_PointArray.setPoint(3, m_ArrowPointB);
00548     }
00549 
00550 }
00551 
00552 void LinePath::updateHead() {
00553     int count = m_HeadList.count();
00554     QCanvasLine * line = 0;
00555 
00556     switch( getAssocType() ) {
00557     case Uml::at_State:
00558     case Uml::at_Activity:
00559     case Uml::at_UniAssociation:
00560     case Uml::at_Dependency:
00561         if( count < 2)
00562             return;
00563         line = m_HeadList.at( 0 );
00564         line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointA.x(), m_ArrowPointA.y() );
00565 
00566         line = m_HeadList.at( 1 );
00567         line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
00568         break;
00569 
00570     case Uml::at_Relationship:
00571         if (count < 2) {
00572             return;
00573         }
00574         {
00575             int xoffset = 0;
00576             int yoffset = 0;
00577             if( m_DockRegion == TopBottom )
00578                 xoffset = 8;
00579             else
00580                 yoffset = 8;
00581             line = m_HeadList.at( 0 );
00582             line->setPoints( m_PointArray[2].x(), m_PointArray[2].y(),
00583                              m_PointArray[0].x()-xoffset, m_PointArray[0].y()-yoffset );
00584 
00585             line = m_HeadList.at( 1 );
00586             line->setPoints( m_PointArray[2].x(), m_PointArray[2].y(),
00587                              m_PointArray[0].x()+xoffset, m_PointArray[0].y()+yoffset );
00588         }
00589 
00590     case Uml::at_Generalization:
00591     case Uml::at_Realization:
00592         if( count < 3)
00593             return;
00594         line = m_HeadList.at( 0 );
00595         line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointA.x(), m_ArrowPointA.y() );
00596 
00597         line = m_HeadList.at( 1 );
00598         line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
00599 
00600         line = m_HeadList.at( 2 );
00601         line -> setPoints( m_ArrowPointA.x(), m_ArrowPointA.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
00602         m_pClearPoly -> setPoints( m_PointArray );
00603         break;
00604 
00605     case Uml::at_Composition:
00606     case Uml::at_Aggregation:
00607         if( count < 4)
00608             return;
00609         line = m_HeadList.at( 0 );
00610         line -> setPoints( m_PointArray[ 0 ].x(), m_PointArray[ 0 ].y(), m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y() );
00611 
00612         line = m_HeadList.at( 1 );
00613         line -> setPoints( m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y(), m_PointArray[ 2 ].x(), m_PointArray[ 2 ].y() );
00614 
00615         line = m_HeadList.at( 2 );
00616         line -> setPoints( m_PointArray[ 2 ].x(), m_PointArray[ 2 ].y(), m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y() );
00617 
00618         line = m_HeadList.at( 3 );
00619         line -> setPoints( m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y(), m_PointArray[ 0 ].x(), m_PointArray[ 0 ].y() );
00620         m_pClearPoly -> setPoints( m_PointArray );
00621         break;
00622 
00623     case Uml::at_Containment:
00624         if (count < 1)
00625             return;
00626         line = m_HeadList.at( 0 );
00627         line->setPoints( m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y(),
00628                          m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y() );
00629         m_pCircle -> setX( m_MidPoint.x() );
00630         m_pCircle -> setY( m_MidPoint.y() );
00631         break;
00632     default:
00633         break;
00634     }
00635 }
00636 
00637 void LinePath::growList(LineList &list, int by) {
00638     QPen pen( getLineColor(), getLineWidth() );
00639     for (int i = 0; i < by; i++) {
00640         QCanvasLine * line = new QCanvasLine( getCanvas() );
00641         line -> setZ( 0 );
00642         line -> setPen( pen );
00643         line -> setVisible( true );
00644         list.append( line );
00645     }
00646 }
00647 
00648 void LinePath::createHeadLines() {
00649     m_HeadList.clear();
00650     QCanvas * canvas = getCanvas();
00651     switch( getAssocType() ) {
00652     case Uml::at_Activity:
00653     case Uml::at_State:
00654     case Uml::at_Dependency:
00655     case Uml::at_UniAssociation:
00656     case Uml::at_Relationship:
00657         growList(m_HeadList, 2);
00658         break;
00659 
00660     case Uml::at_Generalization:
00661     case Uml::at_Realization:
00662         growList(m_HeadList, 3);
00663         m_pClearPoly = new QCanvasPolygon( canvas );
00664         m_pClearPoly -> setVisible( true );
00665         m_pClearPoly -> setBrush( QBrush( Qt::white ) );
00666         m_pClearPoly -> setZ( -1 );
00667         break;
00668 
00669     case Uml::at_Composition:
00670     case Uml::at_Aggregation:
00671         growList(m_HeadList, 4);
00672         m_pClearPoly = new QCanvasPolygon( canvas );
00673         m_pClearPoly -> setVisible( true );
00674         if( getAssocType() == Uml::at_Aggregation )
00675             m_pClearPoly -> setBrush( QBrush( Qt::white ) );
00676         else
00677             m_pClearPoly -> setBrush( QBrush( getLineColor() ) );
00678         m_pClearPoly -> setZ( -1 );
00679         break;
00680 
00681     case Uml::at_Containment:
00682         growList(m_HeadList, 1);
00683         if (!m_pCircle) {
00684             m_pCircle = new Circle( canvas, 6 );
00685             m_pCircle->show();
00686             m_pCircle->setPen( QPen( getLineColor(), getLineWidth() ) );
00687         }
00688         break;
00689     default:
00690         break;
00691     }
00692     m_bHeadCreated = true;
00693 }
00694 
00695 void LinePath::calculateParallelLine() {
00696     int midCount = count() / 2;
00697     double ATAN = atan(1.0);
00698     int lineDist = 10;
00699     //get  1/8(M) and 7/8(T) point
00700     QPoint a = getPoint( midCount - 1 );
00701     QPoint b = getPoint( midCount );
00702     int mx = ( a.x() + b.x() ) / 2;
00703     int my = ( a.y() + b.y() ) / 2;
00704     int tx = ( mx + b.x() ) / 2;
00705     int ty = ( my + b.y() ) / 2;
00706     //find dist between M and T points
00707     int distX = ( mx - tx );
00708     distX *= distX;
00709     int distY = ( my - ty );
00710     distY *= distY;
00711     double dist = sqrt( double(distX + distY) );
00712     double angle = atan2( double(ty - my), double(tx - mx) ) + ( ATAN * 2 );
00713     //find point from M to start line from.
00714     double cosx = cos( angle ) * lineDist;
00715     double siny = sin( angle ) * lineDist;
00716     QPoint pointM( mx + (int)cosx, my + (int)siny );
00717     //find dist between P(xb, yb)
00718     distX = ( tx - b.x() );
00719     distX *= distX;
00720     distY = ( ty - b.y() );
00721     distY *= distY;
00722     dist = sqrt( double(distX + distY) );
00723     //find point from T to end line
00724     cosx = cos( angle ) * lineDist;
00725     siny = sin( angle ) * lineDist;
00726     QPoint pointT( tx + (int)cosx, ty + (int)siny );
00727     m_ParallelLines[ 1 ] = pointM;
00728     m_ParallelLines[ 0 ] = pointT;
00729 
00730     int arrowDist = 5;
00731     angle = atan2( double(pointT.y() - pointM.y()),
00732                    double(pointT.x() - pointM.x()) );
00733     double arrowSlope = angle + ATAN;
00734     cosx = ( cos( arrowSlope ) ) * arrowDist;
00735     siny = ( sin( arrowSlope ) ) * arrowDist;
00736     m_ParallelLines[ 2 ] = QPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
00737     arrowSlope = angle - ATAN;
00738     cosx = ( cos( arrowSlope )  ) * arrowDist;
00739     siny = ( sin( arrowSlope ) ) * arrowDist;
00740     m_ParallelLines[ 3 ] = QPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
00741 }
00742 
00743 void LinePath::setupParallelLine() {
00744     m_ParallelList.clear();
00745     growList(m_ParallelList, 3);
00746     m_bParallelLineCreated = true;
00747 }
00748 
00749 void LinePath::updateParallelLine() {
00750     if( !m_bParallelLineCreated )
00751         return;
00752     QCanvasLine * line = 0;
00753     QPoint common = m_ParallelLines.at( 0 );
00754     QPoint p = m_ParallelLines.at( 1 );
00755     line = m_ParallelList.at( 0 );
00756     line -> setPoints( common.x(), common.y(), p.x(), p.y() );
00757 
00758     p = m_ParallelLines.at( 2 );
00759     line = m_ParallelList.at( 1 );
00760     line -> setPoints( common.x(), common.y(), p.x(), p.y() );
00761 
00762     p = m_ParallelLines.at( 3 );
00763     line = m_ParallelList.at( 2 );
00764     line -> setPoints( common.x(), common.y(), p.x(), p.y() );
00765 }
00766 
00767 bool LinePath::operator==( LinePath & rhs ) {
00768     if( this -> m_LineList.count() != rhs.m_LineList.count() )
00769         return false;
00770 
00771     //Check to see if all points at the same position
00772     for( int i = 0; i< rhs.count() ; i++ ) {
00773         if( this -> getPoint( i ) != rhs.getPoint( i ) )
00774             return false;
00775     }
00776     return true;
00777 }
00778 
00779 LinePath & LinePath::operator=( LinePath & rhs ) {
00780     if( this == &rhs )
00781         return *this;
00782     //clear out the old canvas objects
00783     this -> m_LineList.clear();
00784     this -> m_ParallelList.clear();
00785     this -> m_RectList.clear();
00786     this -> m_HeadList.clear();
00787     int count = rhs.m_LineList.count();
00788     //setup start end points
00789     this -> setStartEndPoints( rhs.getPoint( 0 ), rhs.getPoint( count) );
00790     //now insert the rest
00791     for( int i = 1; i < count ; i++ ) {
00792         this -> insertPoint( i, rhs.getPoint ( i ) );
00793     }
00794     this -> setAssocType( rhs.getAssocType() );
00795 
00796     return *this;
00797 }
00798 
00799 QCanvas * LinePath::getCanvas() {
00800     if( !m_pAssociation )
00801         return 0;
00802     const UMLView * view =  m_pAssociation->getUMLView();
00803     return view -> canvas();
00804 }
00805 
00806 Uml::Association_Type LinePath::getAssocType() {
00807     if( m_pAssociation )
00808         return m_pAssociation -> getAssocType();
00809     return Uml::at_Association;
00810 }
00811 
00812 QColor LinePath::getLineColor() {
00813     if( !m_pAssociation )
00814         return Qt::black;
00815     return m_pAssociation -> getLineColor();
00816 }
00817 
00818 uint LinePath::getLineWidth() {
00819     if( !m_pAssociation )
00820         return 0;
00821     int viewLineWidth = m_pAssociation -> getLineWidth();
00822     if ( viewLineWidth >= 0 && viewLineWidth <= 10 )
00823         return viewLineWidth;
00824     else {
00825         kWarning() << "Ignore wrong LineWidth of " << viewLineWidth
00826         << " in LinePath::getLineWidth" << endl;
00827         return 0;
00828     }
00829 }
00830 
00831 void LinePath::cleanup() {
00832     if (m_pAssociation)
00833         m_LineList.clear();
00834     m_HeadList.clear();
00835     m_RectList.clear();
00836     m_ParallelList.clear();
00837 
00838     if( m_pClearPoly )
00839         delete m_pClearPoly;
00840     if( m_pCircle )
00841         delete m_pCircle;
00842     m_pCircle = 0;
00843     m_pClearPoly = 0;
00844     m_bHeadCreated = m_bParallelLineCreated = false;
00845     if( m_pAssociation ) {
00846         UMLView * view =  (UMLView *)m_pAssociation -> parent();
00847         if(view) {
00848             disconnect( view, SIGNAL( sigColorChanged( Uml::IDType ) ), this, SLOT( slotLineColorChanged( Uml::IDType ) ) );
00849             disconnect( view, SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, SLOT( slotLineWidthChanged( Uml::IDType ) ) );
00850         }
00851         m_pAssociation = NULL;
00852     }
00853 }
00854 
00855 void LinePath::setDockRegion( Region region ) {
00856     m_DockRegion = region;
00857 }
00858 
00859 bool LinePath::hasPoints () {
00860     int count = m_LineList.count();
00861     if (count>1)
00862         return true;
00863     return false;
00864 }
00865 void LinePath::dumpPoints () {
00866     int count = m_LineList.count();
00867     for( int i = 1; i < count; i++ ) {
00868         QPoint point = getPoint( i );
00869         kDebug()<<" * point x:"<<point.x()<<" y:"<<point.y()<<endl;
00870     }
00871 }
00872 
00873 void LinePath::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00874     int count = m_LineList.count();
00875     QPoint point = getPoint( 0 );
00876     QDomElement lineElement = qDoc.createElement( "linepath" );
00877     QDomElement startElement = qDoc.createElement( "startpoint" );
00878     startElement.setAttribute( "startx", point.x() );
00879     startElement.setAttribute( "starty", point.y() );
00880     lineElement.appendChild( startElement );
00881     QDomElement endElement = qDoc.createElement( "endpoint" );
00882     point = getPoint( count );
00883     endElement.setAttribute( "endx", point.x() );
00884     endElement.setAttribute( "endy", point.y() );
00885     lineElement.appendChild( endElement );
00886     for( int i = 1; i < count; i++ ) {
00887         QDomElement pointElement = qDoc.createElement( "point" );
00888         point = getPoint( i );
00889         pointElement.setAttribute( "x", point.x() );
00890         pointElement.setAttribute( "y", point.y() );
00891         lineElement.appendChild( pointElement );
00892     }
00893     qElement.appendChild( lineElement );
00894 }
00895 
00896 bool LinePath::loadFromXMI( QDomElement & qElement ) {
00897     QDomNode node = qElement.firstChild();
00898     QDomElement startElement = node.toElement();
00899     if( startElement.isNull() || startElement.tagName() != "startpoint" )
00900         return false;
00901     QString x = startElement.attribute( "startx", "0" );
00902     int nX = x.toInt();
00903     QString y = startElement.attribute( "starty", "0" );
00904     int nY = y.toInt();
00905     QPoint startPoint( nX, nY );
00906 
00907     node = startElement.nextSibling();
00908     QDomElement endElement = node.toElement();
00909     if( endElement.isNull() || endElement.tagName() != "endpoint" )
00910         return false;
00911     x = endElement.attribute( "endx", "0" );
00912     nX = x.toInt();
00913     y = endElement.attribute( "endy", "0" );
00914     nY = y.toInt();
00915     QPoint endPoint( nX, nY );
00916     setStartEndPoints( startPoint, endPoint );
00917     QPoint point;
00918     node = endElement.nextSibling();
00919     QDomElement element = node.toElement();
00920     int i = 1;
00921     while( !element.isNull() ) {
00922         if( element.tagName() == "point" ) {
00923             x = element.attribute( "x", "0" );
00924             y = element.attribute( "y", "0" );
00925             point.setX( x.toInt() );
00926             point.setY( y.toInt() );
00927             insertPoint( i++, point );
00928         }
00929         node = element.nextSibling();
00930         element = node.toElement();
00931     }
00932 
00933     return true;
00934 }
00935 
00936 
00937 void LinePath::activate() {
00938     int count = m_LineList.count();
00939     if (count == 0)
00940         return;
00941     QCanvas * canvas = getCanvas();
00942     if (canvas == NULL)
00943         return;
00944     for (int i = 0; i < count ; i++) {
00945         QCanvasLine *line = m_LineList.at(i);
00946         line -> setCanvas( canvas );
00947         line -> setPen( getPen() );
00948     }
00949 }
00950 
00951 
00952 
00953 #include "linepath.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:58 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003