File indexing completed on 2024-06-09 04:20:44
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 "KoPathPointRemoveCommand.h" 0009 #include "KoSubpathRemoveCommand.h" 0010 #include "KoShapeController.h" 0011 #include "KoPathPoint.h" 0012 #include <klocalizedstring.h> 0013 0014 class KoPathPointRemoveCommandPrivate 0015 { 0016 public: 0017 KoPathPointRemoveCommandPrivate() : deletePoints(false) { } 0018 ~KoPathPointRemoveCommandPrivate() { 0019 if (deletePoints) 0020 qDeleteAll(points); 0021 } 0022 QList<KoPathPointData> pointDataList; 0023 QList<KoPathPoint*> points; 0024 bool deletePoints; 0025 }; 0026 0027 KUndo2Command *KoPathPointRemoveCommand::createCommand( 0028 const QList<KoPathPointData> &pointDataList, 0029 KoShapeController *shapeController, 0030 KUndo2Command *parent) 0031 { 0032 /* 0033 * We want to decide if we have to: 0034 * 1. delete only some points of a path or 0035 * 2. delete one or more complete subpath or 0036 * 3. delete a complete path 0037 */ 0038 0039 QList<KoPathPointData> sortedPointData(pointDataList); 0040 std::sort(sortedPointData.begin(), sortedPointData.end()); 0041 0042 KoPathPointData last(0, KoPathPointIndex(-1, -1)); 0043 // add last at the end so that the point date before last will also be put in 0044 // the right places. 0045 sortedPointData.append(last); 0046 0047 QList<KoPathPointData> pointsOfSubpath; // points of current subpath 0048 QList<KoPathPointData> subpathsOfPath; // subpaths of current path 0049 QList<KoPathPointData> pointsToDelete; // single points to delete 0050 QList<KoPathPointData> subpathToDelete; // single subpaths to delete 0051 QList<KoShape*> shapesToDelete; // single paths to delete 0052 0053 last = sortedPointData.first(); 0054 0055 QList<KoPathPointData>::const_iterator it(sortedPointData.constBegin()); 0056 for (; it != sortedPointData.constEnd(); ++it) { 0057 // check if we have come to the next subpath of the same or another path 0058 if (last.pathShape != it->pathShape || last.pointIndex.first != it->pointIndex.first) { 0059 // check if all points of the last subpath should be deleted 0060 if (last.pathShape->subpathPointCount(last.pointIndex.first) == pointsOfSubpath.size()) { 0061 // all points of subpath to be deleted -> mark subpath as to be deleted 0062 subpathsOfPath.append(pointsOfSubpath.first()); 0063 } else { 0064 // not all points of subpath to be deleted -> add them to the delete point list 0065 pointsToDelete += pointsOfSubpath; 0066 } 0067 // clear the suboath point list 0068 pointsOfSubpath.clear(); 0069 } 0070 0071 // check if we have come to the next shape 0072 if (last.pathShape != it->pathShape) { 0073 // check if all subpath of the shape should be deleted 0074 if (last.pathShape->subpathCount() == subpathsOfPath.size()) { 0075 // all subpaths of path to be deleted -> add shape to delete shape list 0076 shapesToDelete.append(last.pathShape); 0077 } else { 0078 // not all subpaths of path to be deleted -> add them to delete subpath list 0079 subpathToDelete += subpathsOfPath; 0080 } 0081 subpathsOfPath.clear(); 0082 } 0083 if (! it->pathShape) 0084 continue; 0085 // keep reference to last point 0086 last = *it; 0087 // add this point to the current subpath point list 0088 pointsOfSubpath.append(*it); 0089 } 0090 0091 KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Remove points"), parent); 0092 0093 if (pointsToDelete.size() > 0) { 0094 new KoPathPointRemoveCommand(pointsToDelete, cmd); 0095 } 0096 Q_FOREACH (const KoPathPointData & pd, subpathToDelete) { 0097 new KoSubpathRemoveCommand(pd.pathShape, pd.pointIndex.first, cmd); 0098 } 0099 if (shapesToDelete.size() > 0) { 0100 shapeController->removeShapes(shapesToDelete, cmd); 0101 } 0102 0103 return cmd; 0104 } 0105 0106 KoPathPointRemoveCommand::KoPathPointRemoveCommand(const QList<KoPathPointData> & pointDataList, 0107 KUndo2Command *parent) 0108 : KUndo2Command(parent), 0109 d(new KoPathPointRemoveCommandPrivate()) 0110 { 0111 QList<KoPathPointData>::const_iterator it(pointDataList.begin()); 0112 for (; it != pointDataList.end(); ++it) { 0113 KoPathPoint *point = it->pathShape->pointByIndex(it->pointIndex); 0114 if (point) { 0115 d->pointDataList.append(*it); 0116 d->points.append(0); 0117 } 0118 } 0119 std::sort(d->pointDataList.begin(), d->pointDataList.end()); 0120 setText(kundo2_i18n("Remove points")); 0121 } 0122 0123 KoPathPointRemoveCommand::~KoPathPointRemoveCommand() 0124 { 0125 delete d; 0126 } 0127 0128 void KoPathPointRemoveCommand::redo() 0129 { 0130 KUndo2Command::redo(); 0131 KoPathShape * lastPathShape = 0; 0132 int updateBefore = d->pointDataList.size(); 0133 for (int i = d->pointDataList.size() - 1; i >= 0; --i) { 0134 const KoPathPointData &pd = d->pointDataList.at(i); 0135 pd.pathShape->update(); 0136 d->points[i] = pd.pathShape->removePoint(pd.pointIndex); 0137 0138 if (lastPathShape != pd.pathShape) { 0139 if (lastPathShape) { 0140 QPointF offset = lastPathShape->normalize(); 0141 0142 QTransform matrix; 0143 matrix.translate(-offset.x(), -offset.y()); 0144 for (int j = i + 1; j < updateBefore; ++j) { 0145 d->points.at(j)->map(matrix); 0146 } 0147 lastPathShape->update(); 0148 updateBefore = i + 1; 0149 } 0150 lastPathShape = pd.pathShape; 0151 } 0152 } 0153 0154 if (lastPathShape) { 0155 QPointF offset = lastPathShape->normalize(); 0156 0157 QTransform matrix; 0158 matrix.translate(-offset.x(), -offset.y()); 0159 for (int j = 0; j < updateBefore; ++j) { 0160 d->points.at(j)->map(matrix); 0161 } 0162 lastPathShape->update(); 0163 } 0164 0165 d->deletePoints = true; 0166 } 0167 0168 void KoPathPointRemoveCommand::undo() 0169 { 0170 KUndo2Command::undo(); 0171 KoPathShape * lastPathShape = 0; 0172 0173 QMap<KoPathShape *, QList<KoPathPointIndex>> pointsMap; 0174 0175 for (int i = 0; i < d->pointDataList.size(); ++i) { 0176 const KoPathPointData &pd = d->pointDataList.at(i); 0177 if (lastPathShape && lastPathShape != pd.pathShape) { 0178 lastPathShape->normalize(); 0179 lastPathShape->update(); 0180 } 0181 pd.pathShape->insertPoint(d->points[i], pd.pointIndex); 0182 lastPathShape = pd.pathShape; 0183 0184 pointsMap[pd.pathShape].append(pd.pointIndex); 0185 } 0186 0187 if (lastPathShape) { 0188 lastPathShape->normalize(); 0189 lastPathShape->update(); 0190 } 0191 0192 for (auto it = pointsMap.constBegin(); it != pointsMap.constEnd(); ++it) { 0193 it.key()->recommendPointSelectionChange(it.value()); 0194 } 0195 0196 d->deletePoints = false; 0197 }