You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/linepath.cpp

958 lines
30 KiB

/***************************************************************************
* *
* 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 <tqcanvas.h>
#include <tqdatastream.h>
#include <tqdom.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(TQCanvas * canvas, int radius /* = 0 */)
: TQCanvasEllipse(radius * 2, radius * 2, canvas) {
}
void LinePath::Circle::setX(int x) {
TQCanvasItem::setX( (double) x );
}
void LinePath::Circle::setY(int y) {
TQCanvasItem::setY( (double) y );
}
void LinePath::Circle::setRadius(int radius) {
TQCanvasEllipse::setSize(radius * 2, radius * 2);
}
int LinePath::Circle::getRadius() const {
return (TQCanvasEllipse::height() / 2);
}
void LinePath::Circle::drawShape(TQPainter& 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, TQ_SIGNAL( sigColorChanged( Uml::IDType ) ), this, TQ_SLOT( slotLineColorChanged( Uml::IDType ) ) );
connect( view, TQ_SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, TQ_SLOT( slotLineWidthChanged( Uml::IDType ) ) );
}
TQPoint LinePath::getPoint( int pointIndex ) {
int count = m_LineList.count();
if( count == 0 || pointIndex > count || pointIndex < 0)
return TQPoint( -1, -1 );
if( pointIndex == count ) {
TQCanvasLine * line = m_LineList.last();
return line -> endPoint();
}
TQCanvasLine * line = m_LineList.at( pointIndex );
return line -> startPoint();
}
bool LinePath::setPoint( int pointIndex, const TQPoint &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) {
TQCanvasLine * line = m_LineList.last();
TQPoint p = line -> startPoint();
line -> setPoints( p.x(), p.y(), point.x(), point.y() );
moveSelected( pointIndex );
update();
return true;
}
if( pointIndex == 0 ) {
TQCanvasLine * line = m_LineList.first();
TQPoint p = line -> endPoint();
line -> setPoints( point.x(), point.y(), p.x(), p.y() );
moveSelected( pointIndex );
update();
return true;
}
TQCanvasLine * line = m_LineList.at( pointIndex );
TQPoint 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 TQPoint &point, unsigned short delta) {
int count = m_LineList.count();
if ( pointIndex >= count )
return false;
TQCanvasLine * 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 TQPoint &point ) {
int count = m_LineList.count();
if( count == 0 )
return false;
const bool bLoading = UMLApp::app()->getDocument()->loading();
if( count == 1 || pointIndex == 1) {
TQCanvasLine * first = m_LineList.first();
TQPoint sp = first -> startPoint();
TQPoint ep = first -> endPoint();
first -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
TQCanvasLine * line = new TQCanvasLine( 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 ) {
TQCanvasLine * before = m_LineList.last();
TQPoint sp = before -> startPoint();
TQPoint ep = before -> endPoint();
before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
TQCanvasLine * line = new TQCanvasLine( 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;
}
TQCanvasLine * before = m_LineList.at( pointIndex - 1 );
TQPoint sp = before -> startPoint();
TQPoint ep = before -> endPoint();
before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
TQCanvasLine * line = new TQCanvasLine(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 TQPoint &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 */
TQCanvasLine * 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 */
TQCanvasLine * next_line = m_LineList.at( pointIndex + 1 );
TQPoint startPoint = current_line -> startPoint();
TQPoint 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 */
TQCanvasLine * previous_line = m_LineList.at( pointIndex - 1 );
TQPoint startPoint = previous_line -> startPoint();
TQPoint 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 TQPoint &start, const TQPoint &end ) {
int count = m_LineList.count();
if( count == 0 ) {
TQCanvasLine * line = new TQCanvasLine(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 TQPoint &position ) {
TQCanvasItemList list = getCanvas() -> collisions( position );
int index = -1;
TQCanvasItemList::iterator end(list.end());
for(TQCanvasItemList::iterator item_it(list.begin()); item_it != end; ++item_it ) {
if( ( index = m_LineList.findRef( (TQCanvasLine*)*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 );
TQCanvasLine * 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 TQColor &color ) {
TQCanvasLine * line = 0;
uint linewidth = 0;
LineListIt it( m_LineList );
while( ( line = it.current() ) ) {
linewidth = line->pen().width();
line -> setPen( TQPen( color, linewidth ) );
++it;
}
LineListIt hit( m_HeadList );
while( ( line = hit.current() ) ) {
linewidth = line->pen().width();
line -> setPen( TQPen( color, linewidth ) );
++hit;
}
LineListIt pit( m_ParallelList );
while( ( line = pit.current() ) ) {
linewidth = line->pen().width();
line -> setPen( TQPen( color, linewidth ) );
++pit;
}
if( getAssocType() == Uml::at_Aggregation )
if (m_pClearPoly) m_pClearPoly -> setBrush( TQBrush( TQt::white ) );
else if( getAssocType() == Uml::at_Composition )
if (m_pClearPoly) m_pClearPoly -> setBrush( TQBrush( color ) );
if( m_pCircle ) {
linewidth = m_pCircle->pen().width();
m_pCircle->setPen( TQPen(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 ) {
TQCanvasLine * line = 0;
TQColor linecolor;
LineListIt it( m_LineList );
while( ( line = it.current() ) ) {
linecolor = line->pen().color();
line -> setPen( TQPen( linecolor, width ) );
++it;
}
LineListIt hit( m_HeadList );
while( ( line = hit.current() ) ) {
linecolor = line->pen().color();
line -> setPen( TQPen( linecolor, width ) );
++hit;
}
LineListIt pit( m_ParallelList );
while( ( line = pit.current() ) ) {
linecolor = line->pen().color();
line -> setPen( TQPen( linecolor, width ) );
++pit;
}
if( m_pCircle ) {
linecolor = m_pCircle->pen().color();
m_pCircle->setPen( TQPen(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();
TQCanvasRectangle * rect = 0;
TQCanvasLine * line = 0;
if( pointIndex == lineCount || lineCount == 1) {
line = m_LineList.last();
TQPoint p = line -> endPoint();
rect = m_RectList.last();
rect -> setX( p.x() );
rect -> setY( p.y() );
rect -> setZ( 4 );
return;
}
line = m_LineList.at( pointIndex );
TQPoint 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();
TQCanvasLine * line = 0;
LineListIt it( m_LineList );
while( ( line = it.current() ) ) {
TQPoint sp = line -> startPoint();
TQCanvasRectangle *rect = Widget_Utils::decoratePoint(sp);
m_RectList.append( rect );
++it;
}
//special case for last point
line = m_LineList.last();
TQPoint p = line -> endPoint();
TQCanvasRectangle *rect = Widget_Utils::decoratePoint(p);
m_RectList.append( rect );
update();
}
TQPen LinePath::getPen() {
Uml::Association_Type type = getAssocType();
if( type == Uml::at_Dependency || type == Uml::at_Realization || type == Uml::at_Anchor )
return TQPen( getLineColor(), getLineWidth(), TQt::DashLine );
return TQPen( getLineColor(), getLineWidth() );
}
void LinePath::calculateHead() {
uint size = m_LineList.count();
TQPoint 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 {
TQPoint 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();
TQCanvasLine * 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) {
TQPen pen( getLineColor(), getLineWidth() );
for (int i = 0; i < by; i++) {
TQCanvasLine * line = new TQCanvasLine( getCanvas() );
line -> setZ( 0 );
line -> setPen( pen );
line -> setVisible( true );
list.append( line );
}
}
void LinePath::createHeadLines() {
m_HeadList.clear();
TQCanvas * 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 TQCanvasPolygon( canvas );
m_pClearPoly -> setVisible( true );
m_pClearPoly -> setBrush( TQBrush( TQt::white ) );
m_pClearPoly -> setZ( -1 );
break;
case Uml::at_Composition:
case Uml::at_Aggregation:
growList(m_HeadList, 4);
m_pClearPoly = new TQCanvasPolygon( canvas );
m_pClearPoly -> setVisible( true );
if( getAssocType() == Uml::at_Aggregation )
m_pClearPoly -> setBrush( TQBrush( TQt::white ) );
else
m_pClearPoly -> setBrush( TQBrush( 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( TQPen( 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
TQPoint a = getPoint( midCount - 1 );
TQPoint 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;
TQPoint 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;
TQPoint 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 ] = TQPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
arrowSlope = angle - ATAN;
cosx = ( cos( arrowSlope ) ) * arrowDist;
siny = ( sin( arrowSlope ) ) * arrowDist;
m_ParallelLines[ 3 ] = TQPoint( 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;
TQCanvasLine * line = 0;
TQPoint common = m_ParallelLines.at( 0 );
TQPoint 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;
}
TQCanvas * 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;
}
TQColor LinePath::getLineColor() {
if( !m_pAssociation )
return TQt::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, TQ_SIGNAL( sigColorChanged( Uml::IDType ) ), this, TQ_SLOT( slotLineColorChanged( Uml::IDType ) ) );
disconnect( view, TQ_SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, TQ_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++ ) {
TQPoint point = getPoint( i );
kDebug()<<" * point x:"<<point.x()<<" y:"<<point.y()<<endl;
}
}
void LinePath::saveToXMI( TQDomDocument & qDoc, TQDomElement & qElement ) {
int count = m_LineList.count();
TQPoint point = getPoint( 0 );
TQDomElement lineElement = qDoc.createElement( "linepath" );
TQDomElement startElement = qDoc.createElement( "startpoint" );
startElement.setAttribute( "startx", point.x() );
startElement.setAttribute( "starty", point.y() );
lineElement.appendChild( startElement );
TQDomElement 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++ ) {
TQDomElement 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( TQDomElement & qElement ) {
TQDomNode node = qElement.firstChild();
TQDomElement startElement = node.toElement();
if( startElement.isNull() || startElement.tagName() != "startpoint" )
return false;
TQString x = startElement.attribute( "startx", "0" );
int nX = x.toInt();
TQString y = startElement.attribute( "starty", "0" );
int nY = y.toInt();
TQPoint startPoint( nX, nY );
node = startElement.nextSibling();
TQDomElement 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();
TQPoint endPoint( nX, nY );
setStartEndPoints( startPoint, endPoint );
TQPoint point;
node = endElement.nextSibling();
TQDomElement 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;
TQCanvas * canvas = getCanvas();
if (canvas == NULL)
return;
for (int i = 0; i < count ; i++) {
TQCanvasLine *line = m_LineList.at(i);
line -> setCanvas( canvas );
line -> setPen( getPen() );
}
}
#include "linepath.moc"