File indexing completed on 2025-01-26 04:04:52

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2006, 2008 Jan Hambrecht <jaham@gmx.net>
0003  * SPDX-FileCopyrightText: 2006, 2007 Thorsten Zachmann <zachmann@kde.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KoPathPointInsertCommand.h"
0009 
0010 #include "KoPathPoint.h"
0011 #include <KoPathSegment.h>
0012 #include <klocalizedstring.h>
0013 
0014 class KoPathPointInsertCommandPrivate
0015 {
0016 public:
0017     KoPathPointInsertCommandPrivate() : deletePoints(true) { }
0018     ~KoPathPointInsertCommandPrivate() {
0019         if (deletePoints) {
0020             qDeleteAll(points);
0021         }
0022     }
0023     QList<KoPathPointData> pointDataList;
0024     QList<KoPathPoint*> points;
0025     QList<QPair<QPointF, QPointF> > controlPoints;
0026     bool deletePoints;
0027 };
0028 
0029 KoPathPointInsertCommand::KoPathPointInsertCommand(const QList<KoPathPointData> &pointDataList, qreal insertPosition, KUndo2Command *parent)
0030         : KUndo2Command(parent),
0031         d(new KoPathPointInsertCommandPrivate())
0032 {
0033     if (insertPosition < 0)
0034         insertPosition = 0;
0035     if (insertPosition > 1)
0036         insertPosition = 1;
0037 
0038     //TODO the list needs to be sorted
0039 
0040     QList<KoPathPointData>::const_iterator it(pointDataList.begin());
0041     for (; it != pointDataList.end(); ++it) {
0042         KoPathShape * pathShape = it->pathShape;
0043 
0044         KoPathSegment segment = pathShape->segmentByIndex(it->pointIndex);
0045 
0046         // should not happen but to be sure
0047         if (! segment.isValid())
0048             continue;
0049 
0050         d->pointDataList.append(*it);
0051 
0052         QPair<KoPathSegment, KoPathSegment> splitSegments = segment.splitAt(insertPosition);
0053 
0054         KoPathPoint * split1 = splitSegments.first.second();
0055         KoPathPoint * split2 = splitSegments.second.first();
0056         KoPathPoint * splitPoint = new KoPathPoint(pathShape, split1->point());
0057         if(split1->activeControlPoint1())
0058             splitPoint->setControlPoint1(split1->controlPoint1());
0059         if(split2->activeControlPoint2())
0060             splitPoint->setControlPoint2(split2->controlPoint2());
0061 
0062         d->points.append(splitPoint);
0063         QPointF cp1 = splitSegments.first.first()->controlPoint2();
0064         QPointF cp2 = splitSegments.second.second()->controlPoint1();
0065         d->controlPoints.append(QPair<QPointF, QPointF>(cp1, cp2));
0066     }
0067     setText(kundo2_i18n("Insert points"));
0068 }
0069 
0070 KoPathPointInsertCommand::~KoPathPointInsertCommand()
0071 {
0072     delete d;
0073 }
0074 
0075 void KoPathPointInsertCommand::redo()
0076 {
0077     KUndo2Command::redo();
0078     for (int i = d->pointDataList.size() - 1; i >= 0; --i) {
0079         KoPathPointData pointData = d->pointDataList.at(i);
0080         KoPathShape * pathShape = pointData.pathShape;
0081 
0082         KoPathSegment segment = pathShape->segmentByIndex(pointData.pointIndex);
0083 
0084         ++pointData.pointIndex.second;
0085 
0086         if (segment.first()->activeControlPoint2()) {
0087             QPointF controlPoint2 = segment.first()->controlPoint2();
0088             std::swap(controlPoint2, d->controlPoints[i].first);
0089             segment.first()->setControlPoint2(controlPoint2);
0090         }
0091 
0092         if (segment.second()->activeControlPoint1()) {
0093             QPointF controlPoint1 = segment.second()->controlPoint1();
0094             std::swap(controlPoint1, d->controlPoints[i].second);
0095             segment.second()->setControlPoint1(controlPoint1);
0096         }
0097 
0098         pathShape->insertPoint(d->points.at(i), pointData.pointIndex);
0099         pathShape->recommendPointSelectionChange({pointData.pointIndex});
0100         pathShape->update();
0101     }
0102     d->deletePoints = false;
0103 }
0104 
0105 void KoPathPointInsertCommand::undo()
0106 {
0107     KUndo2Command::undo();
0108     for (int i = 0; i < d->pointDataList.size(); ++i) {
0109         const KoPathPointData &pdBefore = d->pointDataList.at(i);
0110         KoPathShape * pathShape = pdBefore.pathShape;
0111         KoPathPointIndex piAfter = pdBefore.pointIndex;
0112         ++piAfter.second;
0113 
0114         KoPathPoint * before = pathShape->pointByIndex(pdBefore.pointIndex);
0115 
0116         d->points[i] = pathShape->removePoint(piAfter);
0117 
0118         if (d->points[i]->properties() & KoPathPoint::CloseSubpath) {
0119             piAfter.second = 0;
0120         }
0121 
0122         KoPathPoint * after = pathShape->pointByIndex(piAfter);
0123 
0124         if (before->activeControlPoint2()) {
0125             QPointF controlPoint2 = before->controlPoint2();
0126             std::swap(controlPoint2, d->controlPoints[i].first);
0127             before->setControlPoint2(controlPoint2);
0128         }
0129 
0130         if (after->activeControlPoint1()) {
0131             QPointF controlPoint1 = after->controlPoint1();
0132             std::swap(controlPoint1, d->controlPoints[i].second);
0133             after->setControlPoint1(controlPoint1);
0134         }
0135 
0136         QList<KoPathPointIndex> segmentPoints;
0137         segmentPoints << pdBefore.pointIndex;
0138 
0139         KoPathPointIndex nextPoint(pdBefore.pointIndex.first, pdBefore.pointIndex.second + 1);
0140         if (pathShape->pointByIndex(nextPoint)) {
0141             segmentPoints << nextPoint;
0142         }
0143 
0144         pathShape->recommendPointSelectionChange(segmentPoints);
0145         pathShape->update();
0146     }
0147     d->deletePoints = true;
0148 }
0149 
0150 QList<KoPathPoint*> KoPathPointInsertCommand::insertedPoints() const
0151 {
0152     return d->points;
0153 }