1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 * Copyright (C) 2007 by Franz Schmid *
9 * franz.schmid@altmuehlnet.de *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
25 ****************************************************************************/
26
27 #include "pathfinder.h"
28
29 #include "pageitem_polygon.h"
30 #include "pathfinderdialog.h"
31 #include "selection.h"
32 #include "scribuscore.h"
33 #include "scribusview.h"
34 #include "sccolorengine.h"
35 #include "ui/propertiespalette.h"
36 #include "undomanager.h"
37 #include "undostate.h"
38 #include "util_color.h"
39 #include "util_math.h"
40
41 #include <QMessageBox>
42 #include <QPixmap>
43 #include <QScopedPointer>
44
pathfinder_getPluginAPIVersion()45 int pathfinder_getPluginAPIVersion()
46 {
47 return PLUGIN_API_VERSION;
48 }
49
pathfinder_getPlugin()50 ScPlugin* pathfinder_getPlugin()
51 {
52 PathFinderPlugin* plug = new PathFinderPlugin();
53 Q_CHECK_PTR(plug);
54 return plug;
55 }
56
pathfinder_freePlugin(ScPlugin * plugin)57 void pathfinder_freePlugin(ScPlugin* plugin)
58 {
59 PathFinderPlugin* plug = qobject_cast<PathFinderPlugin*>(plugin);
60 Q_ASSERT(plug);
61 delete plug;
62 }
63
PathFinderPlugin()64 PathFinderPlugin::PathFinderPlugin()
65 {
66 // Set action info in languageChange, so we only have to do
67 // it in one place.
68 languageChange();
69 }
70
~PathFinderPlugin()71 PathFinderPlugin::~PathFinderPlugin() {}
72
languageChange()73 void PathFinderPlugin::languageChange()
74 {
75 // Note that we leave the unused members unset. They'll be initialised
76 // with their default ctors during construction.
77 // Action name
78 m_actionInfo.name = "PathFinder";
79 // Action text for menu, including accel
80 m_actionInfo.text = tr("Path Operations...");
81 // Menu
82 m_actionInfo.menu = "ItemPathOps";
83 m_actionInfo.parentMenu = "Item";
84 m_actionInfo.subMenuName = tr("Path Tools");
85 // m_actionInfo.toolbar = "Vector";
86 // m_actionInfo.toolBarName = tr("Vector-Tools");
87 // m_actionInfo.iconPath1 = "pathintersection.png";
88 // m_actionInfo.iconPath2 = "pathintersection.png";
89 m_actionInfo.enabledOnStartup = false;
90 m_actionInfo.notSuitableFor.append(PageItem::Line);
91 m_actionInfo.notSuitableFor.append(PageItem::TextFrame);
92 m_actionInfo.notSuitableFor.append(PageItem::ImageFrame);
93 m_actionInfo.notSuitableFor.append(PageItem::PolyLine);
94 m_actionInfo.notSuitableFor.append(PageItem::PathText);
95 m_actionInfo.notSuitableFor.append(PageItem::LatexFrame);
96 m_actionInfo.notSuitableFor.append(PageItem::Symbol);
97 m_actionInfo.notSuitableFor.append(PageItem::RegularPolygon);
98 m_actionInfo.notSuitableFor.append(PageItem::Arc);
99 m_actionInfo.notSuitableFor.append(PageItem::Spiral);
100 m_actionInfo.needsNumObjects = 2;
101 }
102
fullTrName() const103 QString PathFinderPlugin::fullTrName() const
104 {
105 return QObject::tr("PathFinder");
106 }
107
getAboutData() const108 const ScActionPlugin::AboutData* PathFinderPlugin::getAboutData() const
109 {
110 AboutData* about = new AboutData;
111 Q_CHECK_PTR(about);
112 about->authors = QString::fromUtf8("Franz Schmid <Franz.Schmid@altmuehlnet.de>");
113 about->shortDescription = tr("Path Operations");
114 about->description = tr("Apply fancy boolean operations to paths.");
115 // about->version
116 // about->releaseDate
117 // about->copyright
118 about->license = "GPL";
119 return about;
120 }
121
deleteAboutData(const AboutData * about) const122 void PathFinderPlugin::deleteAboutData(const AboutData* about) const
123 {
124 Q_ASSERT(about);
125 delete about;
126 }
127
run(ScribusDoc * doc,const QString &)128 bool PathFinderPlugin::run(ScribusDoc* doc, const QString&)
129 {
130 ScribusDoc* currDoc = doc;
131 if (currDoc == nullptr)
132 currDoc = ScCore->primaryMainWindow()->doc;
133 if (currDoc->m_Selection->count() <= 1)
134 return true;
135
136 PageItem *Item1 = currDoc->m_Selection->itemAt(0);
137 PageItem *Item2 = currDoc->m_Selection->itemAt(1);
138 QScopedPointer<PathFinderDialog> dia(new PathFinderDialog(currDoc->scMW(), currDoc, Item1, Item2));
139 if (dia->exec() != QDialog::Accepted)
140 return true;
141
142 //<<#9046
143 UndoTransaction activeTransaction;
144 UndoManager* undoManager = UndoManager::instance();
145 if (UndoManager::undoEnabled())
146 activeTransaction = undoManager->beginTransaction(Um::SelectionGroup, Um::IDocument, Um::PathOperation, "", Um::IPolygon);
147 //>>#9046
148
149 int opMode = dia->opMode;
150 if (dia->keepItem1)
151 {
152 PageItem *newItem;
153 if (dia->swapped)
154 {
155 newItem = new PageItem_Polygon(*Item2);
156 newItem->setSelected(false);
157 currDoc->Items->insert(currDoc->Items->indexOf(Item2), newItem);
158 }
159 else
160 {
161 newItem = new PageItem_Polygon(*Item1);
162 newItem->setSelected(false);
163 currDoc->Items->insert(currDoc->Items->indexOf(Item1), newItem);
164 }
165 if (UndoManager::undoEnabled())
166 {
167 int targetIndex = (newItem->OwnPage >= 0) ? newItem->OwnPage : 0;
168 ScItemState<PageItem*> *is = new ScItemState<PageItem*>("Create PageItem");
169 is->set("CREATE_ITEM");
170 is->setItem(newItem);
171 UndoObject *target = currDoc->Pages->at(targetIndex);
172 undoManager->action(target, is);
173 }
174 }
175 if (dia->keepItem2)
176 {
177 PageItem *newItem;
178 if (dia->swapped)
179 {
180 newItem = new PageItem_Polygon(*Item1);
181 newItem->setSelected(false);
182 currDoc->Items->insert(currDoc->Items->indexOf(Item1), newItem);
183 }
184 else
185 {
186 newItem = new PageItem_Polygon(*Item2);
187 newItem->setSelected(false);
188 currDoc->Items->insert(currDoc->Items->indexOf(Item2), newItem);
189 }
190 if (UndoManager::undoEnabled())
191 {
192 int targetIndex = (newItem->OwnPage >= 0) ? newItem->OwnPage : 0;
193 ScItemState<PageItem*> *is = new ScItemState<PageItem*>("Create PageItem");
194 is->set("CREATE_ITEM");
195 is->setItem(newItem);
196 UndoObject *target = currDoc->Pages->at(targetIndex);
197 undoManager->action(target, is);
198 }
199 }
200 if (opMode != 4)
201 {
202 PageItem *currItem;
203 QPainterPath path;
204 FPointArray points;
205 if (dia->targetColor == 0)
206 {
207 currItem = Item1;
208 if (dia->swapped)
209 {
210 currItem = Item2;
211 currItem->setXYPos(Item1->xPos(), Item1->yPos());
212 currItem->setRotation(0.0);
213 }
214 }
215 else
216 {
217 if (dia->swapped)
218 currItem = Item1;
219 else
220 {
221 currItem = Item2;
222 currItem->setXYPos(Item1->xPos(), Item1->yPos());
223 currItem->setRotation(0.0);
224 }
225 }
226
227 path = dia->result;
228 points.fromQPainterPath(path);
229
230 //<<#9046
231 FPointArray oldPOLine = currItem->PoLine;
232 FPointArray oldContourLine = currItem->ContourLine;
233 ScItemState<QPair<QPair<FPointArray, FPointArray>, QPair<FPointArray, FPointArray> > >* state = nullptr;
234 if (UndoManager::undoEnabled())
235 {
236 state = new ScItemState<QPair<QPair<FPointArray, FPointArray>, QPair<FPointArray, FPointArray> > >(Um::PathOperation);
237 state->set("PATH_OPERATION");
238 state->set("PATH_OP_OLD_CLIPEDITED", currItem->ClipEdited);
239 state->set("PATH_OP_OLD_FRAMETYPE", currItem->FrameType);
240 state->set("PATH_OP_OLD_OLDB2", currItem->OldB2);
241 state->set("PATH_OP_OLD_OLDH2", currItem->OldH2);
242 state->set("PATH_OP_NEW_FRAME", false);
243 state->set("PATH_OP_NEW_CLIPEDITED", true);
244 state->set("PATH_OP_NEW_FRAMETYPE", 3);
245 }
246 //>>#9046
247
248 int oldRotMode = currDoc->rotationMode();
249 currItem->setRotation(0.0);
250 currItem->PoLine = points;
251 currItem->ClipEdited = true;
252 currItem->FrameType = 3;
253 currDoc->setRotationMode(0);
254 currDoc->adjustItemSize(currItem);
255 currDoc->setRotationMode(oldRotMode);
256 currItem->OldB2 = currItem->width();
257 currItem->OldH2 = currItem->height();
258 currItem->updateClip();
259 currItem->ContourLine = currItem->PoLine.copy();
260
261 //<<#9046
262 if (UndoManager::undoEnabled())
263 {
264 state->set("PATH_OP_NEW_OLDB2", currItem->OldB2);
265 state->set("PATH_OP_NEW_OLDH2", currItem->OldH2);
266 state->setItem(qMakePair(qMakePair(oldPOLine, oldContourLine), qMakePair(currItem->PoLine, currItem->ContourLine)));
267 undoManager->action(currItem, state);
268 }
269 //>>#9046
270
271 currDoc->m_Selection->removeItem(currItem);
272 currDoc->itemSelection_DeleteItem();
273 }
274 else
275 {
276 QPainterPath path;
277 FPointArray points;
278 PageItem *newItem;
279 double i1x = Item1->xPos();
280 double i1y = Item1->yPos();
281 path = dia->result;
282 if (!path.isEmpty())
283 {
284 points.fromQPainterPath(path);
285 //<<#9046
286 FPointArray oldPOLine = Item1->PoLine;
287 FPointArray oldContourLine = Item1->ContourLine;
288 ScItemState<QPair<QPair<FPointArray, FPointArray>, QPair<FPointArray, FPointArray> > >* state = nullptr;
289 if (UndoManager::undoEnabled())
290 {
291 state = new ScItemState<QPair<QPair<FPointArray, FPointArray>, QPair<FPointArray, FPointArray> > >(Um::PathOperation);
292 state->set("PATH_OPERATION");
293 state->set("PATH_OP_OLD_CLIPEDITED", Item1->ClipEdited);
294 state->set("PATH_OP_OLD_FRAMETYPE", Item1->FrameType);
295 state->set("PATH_OP_OLD_OLDB2", Item1->OldB2);
296 state->set("PATH_OP_OLD_OLDH2", Item1->OldH2);
297 state->set("PATH_OP_NEW_FRAME", false);
298 state->set("PATH_OP_NEW_CLIPEDITED", true);
299 state->set("PATH_OP_NEW_FRAMETYPE", 3);
300 }
301 //>>#9046
302
303 int oldRotMode = currDoc->rotationMode();
304 Item1->setRotation(0.0);
305 Item1->PoLine = points;
306 Item1->ClipEdited = true;
307 Item1->FrameType = 3;
308 currDoc->setRotationMode(0);
309 currDoc->adjustItemSize(Item1);
310 currDoc->setRotationMode(oldRotMode);
311 Item1->OldB2 = Item1->width();
312 Item1->OldH2 = Item1->height();
313 Item1->updateClip();
314 Item1->ContourLine = Item1->PoLine.copy();
315
316 //<<#9046
317 if (UndoManager::undoEnabled())
318 {
319 state->set("PATH_OP_NEW_OLDB2", Item1->OldB2);
320 state->set("PATH_OP_NEW_OLDH2", Item1->OldH2);
321 state->setItem(qMakePair(qMakePair(oldPOLine, oldContourLine), qMakePair(Item1->PoLine, Item1->ContourLine)));
322 undoManager->action(Item1, state);
323 }
324 //>>#9046
325 }
326
327 path = QPainterPath();
328 path = dia->result1;
329 if (!path.isEmpty())
330 {
331 points.fromQPainterPath(path);
332 //<<#9046
333 FPointArray oldPOLine = Item2->PoLine;
334 FPointArray oldContourLine = Item2->ContourLine;
335 ScItemState<QPair<QPair<FPointArray, FPointArray>, QPair<FPointArray, FPointArray> > >* state = nullptr;
336 if (UndoManager::undoEnabled())
337 {
338 state = new ScItemState<QPair<QPair<FPointArray, FPointArray>, QPair<FPointArray, FPointArray> > >(Um::PathOperation);
339 state->set("PATH_OPERATION");
340 state->set("PATH_OP_OLD_CLIPEDITED", Item2->ClipEdited);
341 state->set("PATH_OP_OLD_FRAMETYPE", Item2->FrameType);
342 state->set("PATH_OP_OLD_OLDB2", Item2->OldB2);
343 state->set("PATH_OP_OLD_OLDH2", Item2->OldH2);
344 state->set("PATH_OP_NEW_FRAME", false);
345 state->set("PATH_OP_NEW_CLIPEDITED", true);
346 state->set("PATH_OP_NEW_FRAMETYPE", 3);
347 }
348 //>>#9046
349
350 int oldRotMode = currDoc->rotationMode();
351 Item2->setXYPos(i1x, i1y);
352 Item2->setRotation(0.0);
353 Item2->PoLine = points;
354 Item2->ClipEdited = true;
355 Item2->FrameType = 3;
356 currDoc->setRotationMode(0);
357 currDoc->adjustItemSize(Item2);
358 currDoc->setRotationMode(oldRotMode);
359 Item2->OldB2 = Item2->width();
360 Item2->OldH2 = Item2->height();
361 Item2->updateClip();
362 Item2->ContourLine = Item2->PoLine.copy();
363
364 //<<#9046
365 if (UndoManager::undoEnabled())
366 {
367 state->set("PATH_OP_NEW_OLDB2", Item2->OldB2);
368 state->set("PATH_OP_NEW_OLDH2", Item2->OldH2);
369 state->setItem(qMakePair(qMakePair(oldPOLine, oldContourLine), qMakePair(Item2->PoLine, Item2->ContourLine)));
370 undoManager->action(Item2, state);
371 }
372 //>>#9046
373 }
374
375 path = QPainterPath();
376 path = dia->result2;
377 if (!path.isEmpty())
378 {
379 if (dia->targetColor == 0)
380 {
381 newItem = new PageItem_Polygon(*Item1);
382 newItem->setXYPos(i1x, i1y);
383 }
384 else
385 {
386 newItem = new PageItem_Polygon(*Item2);
387 newItem->setXYPos(i1x, i1y);
388 newItem->setRotation(0.0);
389 }
390 currDoc->Items->append(newItem);
391 newItem->setSelected(false);
392
393 points.fromQPainterPath(path);
394
395 int oldRotMode = currDoc->rotationMode();
396 newItem->PoLine = points;
397 newItem->ClipEdited = true;
398 newItem->FrameType = 3;
399 currDoc->setRotationMode(0);
400 currDoc->adjustItemSize(newItem);
401 currDoc->setRotationMode(oldRotMode);
402 newItem->OldB2 = newItem->width();
403 newItem->OldH2 = newItem->height();
404 newItem->updateClip();
405 newItem->ContourLine = newItem->PoLine.copy();
406
407 if (UndoManager::undoEnabled())
408 {
409 int targetIndex = (newItem->OwnPage >= 0) ? newItem->OwnPage : 0;
410 ScItemState<PageItem*> *is = new ScItemState<PageItem*>("Create PageItem");
411 is->set("CREATE_ITEM");
412 is->setItem(newItem);
413 UndoObject *target = currDoc->Pages->at(targetIndex);
414 undoManager->action(target, is);
415 }
416
417 if (dia->targetColor == 2)
418 {
419 QString fill = dia->getOtherFillColor();
420 if (fill == CommonStrings::tr_NoneColor)
421 fill = CommonStrings::None;
422 newItem->setFillColor(fill);
423 QString stroke = dia->getOtherLineColor();
424 if (stroke == CommonStrings::tr_NoneColor)
425 stroke = CommonStrings::None;
426 newItem->setLineColor(stroke);
427 }
428 }
429 currDoc->m_Selection->clear();
430 currDoc->view()->deselectItems(true);
431 }
432
433 currDoc->changed();
434 currDoc->view()->DrawNew();
435
436 //<<#9046
437 if (activeTransaction)
438 activeTransaction.commit();
439 //>>#9046
440
441 return true;
442 }
443