libs/flake

KoCreatePathTool.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org>
00004  * Copyright (C) 2008-2009 Jan Hambrecht <jaham@gmx.net>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public License
00017  * along with this library; see the file COPYING.LIB.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  */
00021 
00022 #include "KoCreatePathTool.h"
00023 #include "KoSnapGuide.h"
00024 #include "SnapGuideConfigWidget.h"
00025 #include "KoSnapStrategy.h"
00026 
00027 #include "KoPathShape.h"
00028 #include "KoPathPoint.h"
00029 #include "KoPathPointData.h"
00030 #include "KoPointerEvent.h"
00031 #include "KoLineBorder.h"
00032 #include "KoCanvasBase.h"
00033 #include "KoShapeManager.h"
00034 #include "KoSelection.h"
00035 #include "KoShapeController.h"
00036 #include "KoCanvasResourceProvider.h"
00037 #include "KoParameterShape.h"
00038 #include "commands/KoPathPointMergeCommand.h"
00039 
00040 #include <KNumInput>
00041 
00042 #include <QtGui/QPainter>
00043 #include <QtGui/QLabel>
00044 
00045 qreal squareDistance( const QPointF &p1, const QPointF &p2)
00046 {
00047     qreal dx = p1.x()-p2.x();
00048     qreal dy = p1.y()-p2.y();
00049     return dx*dx + dy*dy;
00050 }
00051 
00052 class KoCreatePathTool::AngleSnapStrategy : public KoSnapStrategy
00053 {
00054 public:
00055     AngleSnapStrategy( qreal angleStep )
00056     : KoSnapStrategy(KoSnapStrategy::Custom), m_angleStep(angleStep), m_active(false)
00057     {
00058     }
00059 
00060     void setStartPoint(const QPointF &startPoint)
00061     {
00062         m_startPoint = startPoint;
00063         m_active = true;
00064     }
00065 
00066     void setAngleStep(qreal angleStep)
00067     {
00068         m_angleStep = qAbs(angleStep);
00069     }
00070 
00071     virtual bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
00072     {
00073         Q_UNUSED(proxy);
00074 
00075         if (!m_active)
00076             return false;
00077 
00078         QLineF line(m_startPoint, mousePosition);
00079         qreal currentAngle = line.angle();
00080         int prevStep = qAbs(currentAngle / m_angleStep);
00081         int nextStep = prevStep + 1;
00082         qreal prevAngle = prevStep*m_angleStep;
00083         qreal nextAngle = nextStep*m_angleStep;
00084 
00085         if (qAbs(currentAngle - prevAngle) <= qAbs(currentAngle - nextAngle)) {
00086             line.setAngle(prevAngle);
00087         } else {
00088             line.setAngle(nextAngle);
00089         }
00090 
00091         qreal maxSquareSnapDistance = maxSnapDistance*maxSnapDistance;
00092         qreal snapDistance = squareDistance(mousePosition, line.p2());
00093         if (snapDistance > maxSquareSnapDistance)
00094             return false;
00095 
00096         setSnappedPosition(line.p2());
00097         return true;
00098     }
00099 
00100     virtual QPainterPath decoration(const KoViewConverter &converter) const
00101     {
00102         Q_UNUSED(converter);
00103 
00104         QPainterPath decoration;
00105         decoration.moveTo(m_startPoint);
00106         decoration.lineTo(snappedPosition());
00107         return decoration;
00108     }
00109 
00110 private:
00111     QPointF m_startPoint;
00112     qreal m_angleStep;
00113     bool m_active;
00114 };
00115 
00116 KoCreatePathTool::KoCreatePathTool(KoCanvasBase * canvas)
00117         : KoTool(canvas)
00118         , m_shape(0)
00119         , m_activePoint(0)
00120         , m_firstPoint(0)
00121         , m_handleRadius(3)
00122         , m_mouseOverFirstPoint(false)
00123         , m_pointIsDragged(false)
00124         , m_existingStartPoint(0)
00125         , m_existingEndPoint(0)
00126         , m_hoveredPoint(0)
00127         , m_angleSnapStrategy(0)
00128         , m_angleSnappingDelta(15)
00129 {
00130 }
00131 
00132 KoCreatePathTool::~KoCreatePathTool()
00133 {
00134 }
00135 
00136 void KoCreatePathTool::paint(QPainter &painter, const KoViewConverter &converter)
00137 {
00138     if (m_shape) {
00139         painter.save();
00140         painter.setMatrix(m_shape->absoluteTransformation(&converter) * painter.matrix());
00141 
00142         painter.save();
00143         m_shape->paint(painter, converter);
00144         painter.restore();
00145         if (m_shape->border()) {
00146             painter.save();
00147             m_shape->border()->paintBorder(m_shape, painter, converter);
00148             painter.restore();
00149         }
00150 
00151         KoShape::applyConversion(painter, converter);
00152 
00153         painter.setPen(Qt::blue);
00154         painter.setBrush(Qt::white);   //TODO make configurable
00155 
00156         const bool firstPoint = (m_firstPoint == m_activePoint);
00157         if (m_pointIsDragged || firstPoint) {
00158             const bool onlyPaintActivePoints = false;
00159             KoPathPoint::KoPointTypes paintFlags = KoPathPoint::ControlPoint2;
00160             if (m_activePoint->activeControlPoint1())
00161                 paintFlags |= KoPathPoint::ControlPoint1;
00162             m_activePoint->paint(painter, m_handleRadius, paintFlags, onlyPaintActivePoints);
00163         }
00164 
00165         // paint the first point
00166 
00167         // check if we have to color the first point
00168         if (m_mouseOverFirstPoint)
00169             painter.setBrush(Qt::red);   // //TODO make configurable
00170         else
00171             painter.setBrush(Qt::white);   //TODO make configurable
00172 
00173         m_firstPoint->paint(painter, m_handleRadius, KoPathPoint::Node);
00174 
00175         painter.restore();
00176     }
00177 
00178     if (m_hoveredPoint) {
00179         painter.save();
00180         painter.setMatrix(m_hoveredPoint->parent()->absoluteTransformation(&converter), true);
00181         KoShape::applyConversion(painter, converter);
00182         painter.setPen(Qt::blue);
00183         painter.setBrush(Qt::white);   //TODO make configurable
00184         m_hoveredPoint->paint(painter, m_handleRadius, KoPathPoint::Node);
00185         painter.restore();
00186     }
00187     painter.save();
00188     KoShape::applyConversion(painter, converter);
00189     m_canvas->snapGuide()->paint(painter, converter);
00190     painter.restore();
00191 }
00192 
00193 void KoCreatePathTool::mousePressEvent(KoPointerEvent *event)
00194 {
00195     if ((event->buttons() & Qt::RightButton) && m_shape) {
00196         // repaint the shape before removing the last point
00197         m_canvas->updateCanvas(m_shape->boundingRect());
00198         m_shape->removePoint(m_shape->pathPointIndex(m_activePoint));
00199 
00200         addPathShape();
00201         return;
00202     }
00203 
00204     if (m_shape) {
00205         // the path shape gets closed by clicking on the first point
00206         if (handleGrabRect(m_firstPoint->point()).contains(event->point)) {
00207             m_activePoint->setPoint(m_firstPoint->point());
00208             m_shape->closeMerge();
00209             // we are closing the path, so reset the existing start path point
00210             m_existingStartPoint = 0;
00211             // finish path
00212             addPathShape();
00213         } else {
00214             m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00215 
00216             QPointF point = m_canvas->snapGuide()->snap(event->point, event->modifiers());
00217 
00218             // check whether we hit an start/end node of an existing path
00219             m_existingEndPoint = endPointAtPosition(point);
00220             if (m_existingEndPoint && m_existingEndPoint != m_existingStartPoint) {
00221                 point = m_existingEndPoint->parent()->shapeToDocument(m_existingEndPoint->point());
00222                 m_activePoint->setPoint(point);
00223                 // finish path
00224                 addPathShape();
00225             } else {
00226                 m_activePoint->setPoint(point);
00227                 m_canvas->updateCanvas(m_shape->boundingRect());
00228                 m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00229             }
00230         }
00231     } else {
00232         m_shape = new KoPathShape();
00233         m_shape->setShapeId(KoPathShapeId);
00234         KoLineBorder * border = new KoLineBorder(m_canvas->resourceProvider()->activeBorder());
00235         border->setColor(m_canvas->resourceProvider()->foregroundColor().toQColor());
00236         m_shape->setBorder(border);
00237         m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00238         QPointF point = m_canvas->snapGuide()->snap(event->point, event->modifiers());
00239 
00240         // check whether we hit an start/end node of an existing path
00241         m_existingStartPoint = endPointAtPosition(point);
00242         if (m_existingStartPoint) {
00243             point = m_existingStartPoint->parent()->shapeToDocument(m_existingStartPoint->point());
00244         }
00245         m_activePoint = m_shape->moveTo(point);
00246         // set the control points to be different from the default (0, 0)
00247         // to avoid a unnecessary big area being repainted
00248         m_activePoint->setControlPoint1(point);
00249         m_activePoint->setControlPoint2(point);
00250         // remove them immediately so we do not end up having control points on a line start point
00251         m_activePoint->removeControlPoint1();
00252         m_activePoint->removeControlPoint2();
00253         m_firstPoint = m_activePoint;
00254         m_canvas->updateCanvas(handlePaintRect(point));
00255         m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00256 
00257         m_canvas->snapGuide()->setEditedShape(m_shape);
00258 
00259         m_angleSnapStrategy = new AngleSnapStrategy(m_angleSnappingDelta);
00260         m_canvas->snapGuide()->addCustomSnapStrategy(m_angleSnapStrategy);
00261     }
00262 
00263     if (m_angleSnapStrategy)
00264         m_angleSnapStrategy->setStartPoint(m_activePoint->point());
00265 }
00266 
00267 void KoCreatePathTool::mouseDoubleClickEvent(KoPointerEvent *event)
00268 {
00269     Q_UNUSED(event);
00270 
00271     if (m_shape) {
00272         // the first click of the double click created a new point which has the be removed again
00273         m_shape->removePoint(m_shape->pathPointIndex(m_activePoint));
00274 
00275         addPathShape();
00276     }
00277 }
00278 
00279 void KoCreatePathTool::mouseMoveEvent(KoPointerEvent *event)
00280 {
00281     KoPathPoint * endPoint = endPointAtPosition(event->point);
00282     if (m_hoveredPoint != endPoint) {
00283         if (m_hoveredPoint) {
00284             QPointF nodePos = m_hoveredPoint->parent()->shapeToDocument(m_hoveredPoint->point());
00285             m_canvas->updateCanvas(handlePaintRect(nodePos));
00286         }
00287         m_hoveredPoint = endPoint;
00288         if (m_hoveredPoint) {
00289             QPointF nodePos = m_hoveredPoint->parent()->shapeToDocument(m_hoveredPoint->point());
00290             m_canvas->updateCanvas(handlePaintRect(nodePos));
00291         }
00292     }
00293 
00294     if (! m_shape) {
00295         m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00296         m_canvas->snapGuide()->snap(event->point, event->modifiers());
00297         m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00298 
00299         m_mouseOverFirstPoint = false;
00300         return;
00301     }
00302 
00303     m_mouseOverFirstPoint = handleGrabRect(m_firstPoint->point()).contains(event->point);
00304 
00305     m_canvas->updateCanvas(m_shape->boundingRect());
00306     m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00307     QPointF snappedPosition = m_canvas->snapGuide()->snap(event->point, event->modifiers());
00308 
00309     repaintActivePoint();
00310     if (event->buttons() & Qt::LeftButton) {
00311         m_pointIsDragged = true;
00312         QPointF offset = snappedPosition - m_activePoint->point();
00313         m_activePoint->setControlPoint2(m_activePoint->point() + offset);
00314         if ((event->modifiers() & Qt::AltModifier) == 0)
00315             m_activePoint->setControlPoint1(m_activePoint->point() - offset);
00316         repaintActivePoint();
00317     } else {
00318         m_activePoint->setPoint(snappedPosition);
00319     }
00320 
00321     m_canvas->updateCanvas(m_shape->boundingRect());
00322     m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00323 }
00324 
00325 void KoCreatePathTool::mouseReleaseEvent(KoPointerEvent *event)
00326 {
00327     if (! m_shape || (event->buttons() & Qt::RightButton))
00328         return;
00329 
00330     repaintActivePoint();
00331     m_pointIsDragged = false;
00332     KoPathPoint * lastActivePoint = m_activePoint;
00333     m_activePoint = m_shape->lineTo(event->point);
00334     // apply symmetric point property if applicable
00335     if (lastActivePoint->activeControlPoint1() && lastActivePoint->activeControlPoint2()) {
00336         QPointF diff1 = lastActivePoint->point() - lastActivePoint->controlPoint1();
00337         QPointF diff2 = lastActivePoint->controlPoint2() - lastActivePoint->point();
00338         if (qFuzzyCompare(diff1.x(), diff2.x()) && qFuzzyCompare(diff1.y(), diff2.y()))
00339             lastActivePoint->setProperty(KoPathPoint::IsSymmetric);
00340     }
00341     m_canvas->snapGuide()->setIgnoredPathPoints( (QList<KoPathPoint*>()<<m_activePoint) );
00342 }
00343 
00344 void KoCreatePathTool::keyPressEvent(QKeyEvent *event)
00345 {
00346     if (event->key() == Qt::Key_Escape)
00347         emit done();
00348     else
00349         event->ignore();
00350 }
00351 
00352 void KoCreatePathTool::activate(bool temporary)
00353 {
00354     Q_UNUSED(temporary);
00355     useCursor(Qt::ArrowCursor, true);
00356 
00357     // retrieve the actual global handle radius
00358     m_handleRadius = m_canvas->resourceProvider()->handleRadius();
00359 
00360     // reset snap guide
00361     m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00362     m_canvas->snapGuide()->reset();
00363 }
00364 
00365 void KoCreatePathTool::deactivate()
00366 {
00367     // reset snap guide
00368     m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00369     m_canvas->snapGuide()->reset();
00370 
00371     if (m_shape) {
00372         m_canvas->updateCanvas(handlePaintRect(m_firstPoint->point()));
00373         m_canvas->updateCanvas(m_shape->boundingRect());
00374         delete m_shape;
00375         m_shape = 0;
00376         m_firstPoint = 0;
00377         m_activePoint = 0;
00378         m_existingStartPoint = 0;
00379         m_existingEndPoint = 0;
00380         m_hoveredPoint = 0;
00381         m_angleSnapStrategy = 0;
00382     }
00383 }
00384 
00385 void KoCreatePathTool::resourceChanged(int key, const QVariant & res)
00386 {
00387     switch (key) {
00388     case KoCanvasResource::HandleRadius: {
00389         m_handleRadius = res.toUInt();
00390     }
00391     break;
00392     default:
00393         return;
00394     }
00395 }
00396 
00397 void KoCreatePathTool::addPathShape()
00398 {
00399     m_shape->normalize();
00400 
00401     // reset snap guide
00402     m_canvas->updateCanvas(m_canvas->snapGuide()->boundingRect());
00403     m_canvas->snapGuide()->reset();
00404     m_angleSnapStrategy = 0;
00405 
00406     // this is done so that nothing happens when the mouseReleaseEvent for the this event is received
00407     KoPathShape *pathShape = m_shape;
00408     m_shape = 0;
00409 
00410     KoPathShape * startShape = 0;
00411     KoPathShape * endShape = 0;
00412 
00413     if (connectPaths(pathShape, m_existingStartPoint, m_existingEndPoint)) {
00414         if (m_existingStartPoint)
00415             startShape = m_existingStartPoint->parent();
00416         if (m_existingEndPoint && m_existingEndPoint != m_existingStartPoint)
00417             endShape = m_existingEndPoint->parent();
00418     }
00419 
00420     QUndoCommand * cmd = m_canvas->shapeController()->addShape(pathShape);
00421     if (cmd) {
00422         KoSelection *selection = m_canvas->shapeManager()->selection();
00423         selection->deselectAll();
00424         selection->select(pathShape);
00425         if (startShape)
00426             m_canvas->shapeController()->removeShape(startShape, cmd);
00427         if (endShape && startShape != endShape)
00428             m_canvas->shapeController()->removeShape(endShape, cmd);
00429         m_canvas->addCommand(cmd);
00430     } else {
00431         m_canvas->updateCanvas(pathShape->boundingRect());
00432         delete pathShape;
00433     }
00434 
00435     m_existingStartPoint = 0;
00436     m_existingEndPoint = 0;
00437     m_hoveredPoint = 0;
00438 }
00439 
00440 void KoCreatePathTool::repaintActivePoint()
00441 {
00442     const bool isFirstPoint = (m_activePoint == m_firstPoint);
00443 
00444     if (!isFirstPoint && !m_pointIsDragged)
00445         return;
00446 
00447     QRectF rect = m_activePoint->boundingRect(false);
00448 
00449     // make sure that we have the second control point inside our
00450     // update rect, as KoPathPoint::boundingRect will not include
00451     // the second control point of the last path point if the path
00452     // is not closed
00453     const QPointF &point = m_activePoint->point();
00454     const QPointF &controlPoint = m_activePoint->controlPoint2();
00455     rect = rect.united(QRectF(point, controlPoint).normalized());
00456 
00457     // when paiting the fist point we want the
00458     // first control point to be painted as well
00459     if (isFirstPoint) {
00460         const QPointF &controlPoint = m_activePoint->controlPoint1();
00461         rect = rect.united(QRectF(point, controlPoint).normalized());
00462     }
00463 
00464     QPointF border = m_canvas->viewConverter()
00465                      ->viewToDocument(QPointF(m_handleRadius, m_handleRadius));
00466 
00467     rect.adjust(-border.x(), -border.y(), border.x(), border.y());
00468     m_canvas->updateCanvas(rect);
00469 }
00470 
00471 QMap<QString, QWidget *> KoCreatePathTool::createOptionWidgets()
00472 {
00473     QMap<QString, QWidget *> map;
00474     SnapGuideConfigWidget *widget = new SnapGuideConfigWidget(m_canvas->snapGuide());
00475     map.insert(i18n("Snapping"), widget);
00476 
00477     QWidget * angleWidget = new QWidget();
00478     angleWidget->setObjectName("Angle Constraints");
00479     QGridLayout * layout = new QGridLayout(angleWidget);
00480     layout->addWidget( new QLabel(i18n("Angle snapping delta"), angleWidget), 0, 0);
00481     KIntNumInput * angleEdit = new KIntNumInput(m_angleSnappingDelta, angleWidget);
00482     angleEdit->setRange(1, 360, 1);
00483     angleEdit->setSuffix(" °");
00484     layout->addWidget( angleEdit, 0, 1);
00485     map.insert(i18n("Angle Constraints"), angleWidget);
00486 
00487     connect(angleEdit, SIGNAL(valueChanged(int)), this, SLOT(angleDeltaChanged(int)));
00488 
00489     return map;
00490 }
00491 
00492 void KoCreatePathTool::angleDeltaChanged(int value)
00493 {
00494     m_angleSnappingDelta = value;
00495     if (m_angleSnapStrategy)
00496         m_angleSnapStrategy->setAngleStep(m_angleSnappingDelta);
00497 }
00498 
00499 KoPathPoint* KoCreatePathTool::endPointAtPosition( const QPointF &position )
00500 {
00501     QRectF roi = handleGrabRect(position);
00502     QList<KoShape *> shapes = m_canvas->shapeManager()->shapesAt(roi);
00503 
00504     KoPathPoint * nearestPoint = 0;
00505     qreal minDistance = HUGE_VAL;
00506     uint grabSensitivity = m_canvas->resourceProvider()->grabSensitivity();
00507     qreal maxDistance = m_canvas->viewConverter()->viewToDocumentX(grabSensitivity);
00508 
00509     foreach(KoShape *shape, shapes) {
00510         KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
00511         if (!path)
00512             continue;
00513         KoParameterShape *paramShape = dynamic_cast<KoParameterShape*>(shape);
00514         if (paramShape && paramShape->isParametricShape())
00515             continue;
00516 
00517         KoPathPoint * p = 0;
00518         uint subpathCount = path->subpathCount();
00519         for (uint i = 0; i < subpathCount; ++i) {
00520             if (path->isClosedSubpath(i))
00521                 continue;
00522             p = path->pointByIndex(KoPathPointIndex(i, 0));
00523             // check start of subpath
00524             qreal d = squareDistance(position, path->shapeToDocument(p->point()));
00525             if (d < minDistance && d < maxDistance) {
00526                 nearestPoint = p;
00527                 minDistance = d;
00528             }
00529             // check end of subpath
00530             p = path->pointByIndex(KoPathPointIndex(i, path->pointCountSubpath(i)-1));
00531             d = squareDistance(position, path->shapeToDocument(p->point()));
00532             if (d < minDistance && d < maxDistance) {
00533                 nearestPoint = p;
00534                 minDistance = d;
00535             }
00536         }
00537     }
00538 
00539     return nearestPoint;
00540 }
00541 
00542 bool KoCreatePathTool::connectPaths( KoPathShape *pathShape, KoPathPoint *pointAtStart, KoPathPoint *pointAtEnd )
00543 {
00544     // at least one point must be valid
00545     if (!pointAtStart && !pointAtEnd)
00546         return false;
00547     // do not allow connecting to the same point twice
00548     if (pointAtStart == pointAtEnd)
00549         pointAtEnd = 0;
00550 
00551     // we have hit an existing path point on start/finish
00552     // what we now do is:
00553     // 1. combine the new created path with the ones we hit on start/finish
00554     // 2. merge the endpoints of the corresponding subpaths
00555 
00556     uint newPointCount = pathShape->pointCountSubpath(0);
00557     KoPathPointIndex newStartPointIndex(0, 0);
00558     KoPathPointIndex newEndPointIndex(0, newPointCount-1);
00559     KoPathPoint * newStartPoint = pathShape->pointByIndex(newStartPointIndex);
00560     KoPathPoint * newEndPoint = pathShape->pointByIndex(newEndPointIndex);
00561 
00562     KoPathShape * startShape = pointAtStart ? pointAtStart->parent() : 0;
00563     KoPathShape * endShape = pointAtEnd ? pointAtEnd->parent() : 0;
00564 
00565     // combine with the path we hit on start
00566     KoPathPointIndex startIndex(-1,-1);
00567     if (pointAtStart) {
00568         startIndex = startShape->pathPointIndex(pointAtStart);
00569         pathShape->combine(startShape);
00570         pathShape->moveSubpath(0, pathShape->subpathCount()-1);
00571     }
00572     // combine with the path we hit on finish
00573     KoPathPointIndex endIndex(-1,-1);
00574     if (pointAtEnd) {
00575         endIndex = endShape->pathPointIndex(pointAtEnd);
00576         if (endShape != startShape) {
00577             endIndex.first += pathShape->subpathCount();
00578             pathShape->combine(endShape);
00579         }
00580     }
00581     // do we connect twice to a single subpath ?
00582     bool connectToSingleSubpath = (startShape == endShape && startIndex.first == endIndex.first);
00583 
00584     if (startIndex.second == 0 && !connectToSingleSubpath) {
00585         pathShape->reverseSubpath(startIndex.first);
00586         startIndex.second = pathShape->pointCountSubpath(startIndex.first)-1;
00587     }
00588     if (endIndex.second > 0 && !connectToSingleSubpath) {
00589         pathShape->reverseSubpath(endIndex.first);
00590         endIndex.second = 0;
00591     }
00592 
00593     // after combining we have a path where with the subpaths in the following
00594     // order:
00595     // 1. the subpaths of the pathshape we started the new path at
00596     // 2. the subpath we just created
00597     // 3. the subpaths of the pathshape we finished the new path at
00598 
00599     // get the path points we want to merge, as these are not going to
00600     // change while merging
00601     KoPathPoint * existingStartPoint = pathShape->pointByIndex(startIndex);
00602     KoPathPoint * existingEndPoint = pathShape->pointByIndex(endIndex);
00603 
00604     // merge first two points
00605     if (existingStartPoint) {
00606         KoPathPointData pd1(pathShape, pathShape->pathPointIndex(existingStartPoint));
00607         KoPathPointData pd2(pathShape, pathShape->pathPointIndex(newStartPoint));
00608         KoPathPointMergeCommand cmd1(pd1, pd2);
00609         cmd1.redo();
00610     }
00611     // merge last two points
00612     if (existingEndPoint) {
00613         KoPathPointData pd3(pathShape, pathShape->pathPointIndex(newEndPoint));
00614         KoPathPointData pd4(pathShape, pathShape->pathPointIndex(existingEndPoint));
00615         KoPathPointMergeCommand cmd2(pd3, pd4);
00616         cmd2.redo();
00617     }
00618 
00619     return true;
00620 }