File indexing completed on 2024-04-28 04:31:55

0001 /*
0002  * Copyright (C) 2010-2015 by Stephen Allewell
0003  * steve.allewell@gmail.com
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2 of the License, or
0008  * (at your option) any later version.
0009  */
0010 
0011 #include "Commands.h"
0012 
0013 #include <QApplication>
0014 #include <QClipboard>
0015 #include <QMimeData>
0016 
0017 #include <KLocalizedString>
0018 
0019 #include "BackgroundImage.h"
0020 #include "Document.h"
0021 #include "Editor.h"
0022 #include "Floss.h"
0023 #include "FlossScheme.h"
0024 #include "MainWindow.h"
0025 #include "Palette.h"
0026 #include "Preview.h"
0027 #include "SchemeManager.h"
0028 #include "StitchData.h"
0029 
0030 FilePropertiesCommand::FilePropertiesCommand(Document *document)
0031     : QUndoCommand(i18n("File Properties"))
0032     , m_document(document)
0033 {
0034 }
0035 
0036 void FilePropertiesCommand::redo()
0037 {
0038     QUndoCommand::redo();
0039     m_document->editor()->readDocumentSettings();
0040     m_document->preview()->readDocumentSettings();
0041     m_document->palette()->update();
0042 }
0043 
0044 void FilePropertiesCommand::undo()
0045 {
0046     QUndoCommand::undo();
0047     m_document->editor()->readDocumentSettings();
0048     m_document->preview()->readDocumentSettings();
0049     m_document->palette()->update();
0050 }
0051 
0052 ImportImageCommand::ImportImageCommand(Document *document)
0053     : QUndoCommand(i18n("Import Image"))
0054     , m_document(document)
0055 {
0056 }
0057 
0058 void ImportImageCommand::redo()
0059 {
0060     QUndoCommand::redo();
0061     m_document->editor()->readDocumentSettings();
0062     m_document->preview()->readDocumentSettings();
0063     m_document->palette()->update();
0064 }
0065 
0066 void ImportImageCommand::undo()
0067 {
0068     QUndoCommand::undo();
0069     m_document->editor()->readDocumentSettings();
0070     m_document->preview()->readDocumentSettings();
0071     m_document->palette()->update();
0072 }
0073 
0074 PaintStitchesCommand::PaintStitchesCommand(Document *document)
0075     : QUndoCommand(i18n("Paint Stitches"))
0076     , m_document(document)
0077 {
0078 }
0079 
0080 void PaintStitchesCommand::redo()
0081 {
0082     QUndoCommand::redo();
0083     m_document->editor()->drawContents();
0084     m_document->preview()->drawContents();
0085 }
0086 
0087 void PaintStitchesCommand::undo()
0088 {
0089     QUndoCommand::undo();
0090     m_document->editor()->drawContents();
0091     m_document->preview()->drawContents();
0092 }
0093 
0094 PaintKnotsCommand::PaintKnotsCommand(Document *document)
0095     : QUndoCommand(i18n("Paint Knots"))
0096     , m_document(document)
0097 {
0098 }
0099 
0100 void PaintKnotsCommand::redo()
0101 {
0102     QUndoCommand::redo();
0103     m_document->editor()->drawContents();
0104     m_document->preview()->drawContents();
0105 }
0106 
0107 void PaintKnotsCommand::undo()
0108 {
0109     QUndoCommand::undo();
0110     m_document->editor()->drawContents();
0111     m_document->preview()->drawContents();
0112 }
0113 
0114 DrawLineCommand::DrawLineCommand(Document *document)
0115     : QUndoCommand(i18n("Draw Line"))
0116     , m_document(document)
0117 {
0118 }
0119 
0120 void DrawLineCommand::redo()
0121 {
0122     QUndoCommand::redo();
0123     m_document->editor()->drawContents();
0124     m_document->preview()->drawContents();
0125 }
0126 
0127 void DrawLineCommand::undo()
0128 {
0129     QUndoCommand::undo();
0130     m_document->editor()->drawContents();
0131     m_document->preview()->drawContents();
0132 }
0133 
0134 EraseStitchesCommand::EraseStitchesCommand(Document *document)
0135     : QUndoCommand(i18n("Erase Stitches"))
0136     , m_document(document)
0137 {
0138 }
0139 
0140 void EraseStitchesCommand::redo()
0141 {
0142     QUndoCommand::redo();
0143     m_document->editor()->drawContents();
0144     m_document->preview()->drawContents();
0145 }
0146 
0147 void EraseStitchesCommand::undo()
0148 {
0149     QUndoCommand::undo();
0150     m_document->editor()->drawContents();
0151     m_document->preview()->drawContents();
0152 }
0153 
0154 DrawRectangleCommand::DrawRectangleCommand(Document *document)
0155     : QUndoCommand(i18n("Draw Rectangle"))
0156     , m_document(document)
0157 {
0158 }
0159 
0160 void DrawRectangleCommand::redo()
0161 {
0162     QUndoCommand::redo();
0163     m_document->editor()->drawContents();
0164     m_document->preview()->drawContents();
0165 }
0166 
0167 void DrawRectangleCommand::undo()
0168 {
0169     QUndoCommand::undo();
0170     m_document->editor()->drawContents();
0171     m_document->preview()->drawContents();
0172 }
0173 
0174 FillRectangleCommand::FillRectangleCommand(Document *document)
0175     : QUndoCommand(i18n("Fill Rectangle"))
0176     , m_document(document)
0177 {
0178 }
0179 
0180 void FillRectangleCommand::redo()
0181 {
0182     QUndoCommand::redo();
0183     m_document->editor()->drawContents();
0184     m_document->preview()->drawContents();
0185 }
0186 
0187 void FillRectangleCommand::undo()
0188 {
0189     QUndoCommand::undo();
0190     m_document->editor()->drawContents();
0191     m_document->preview()->drawContents();
0192 }
0193 
0194 DrawEllipseCommand::DrawEllipseCommand(Document *document)
0195     : QUndoCommand(i18n("Draw Ellipse"))
0196     , m_document(document)
0197 {
0198 }
0199 
0200 void DrawEllipseCommand::redo()
0201 {
0202     QUndoCommand::redo();
0203     m_document->editor()->drawContents();
0204     m_document->preview()->drawContents();
0205 }
0206 
0207 void DrawEllipseCommand::undo()
0208 {
0209     QUndoCommand::undo();
0210     m_document->editor()->drawContents();
0211     m_document->preview()->drawContents();
0212 }
0213 
0214 FillEllipseCommand::FillEllipseCommand(Document *document)
0215     : QUndoCommand(i18n("Fill Ellipse"))
0216     , m_document(document)
0217 {
0218 }
0219 
0220 void FillEllipseCommand::redo()
0221 {
0222     QUndoCommand::redo();
0223     m_document->editor()->drawContents();
0224     m_document->preview()->drawContents();
0225 }
0226 
0227 void FillEllipseCommand::undo()
0228 {
0229     QUndoCommand::undo();
0230     m_document->editor()->drawContents();
0231     m_document->preview()->drawContents();
0232 }
0233 
0234 FillPolygonCommand::FillPolygonCommand(Document *document)
0235     : QUndoCommand(i18n("Fill Polygon"))
0236     , m_document(document)
0237 {
0238 }
0239 
0240 void FillPolygonCommand::redo()
0241 {
0242     QUndoCommand::redo();
0243     m_document->editor()->drawContents();
0244     m_document->preview()->drawContents();
0245 }
0246 
0247 void FillPolygonCommand::undo()
0248 {
0249     QUndoCommand::undo();
0250     m_document->editor()->drawContents();
0251     m_document->preview()->drawContents();
0252 }
0253 
0254 AddStitchCommand::AddStitchCommand(Document *document, const QPoint &location, Stitch::Type type, int colorIndex, QUndoCommand *parent)
0255     : QUndoCommand(i18n("Add Stitch"), parent)
0256     , m_document(document)
0257     , m_cell(location)
0258     , m_type(type)
0259     , m_colorIndex(colorIndex)
0260     , m_original(nullptr)
0261 {
0262 }
0263 
0264 AddStitchCommand::~AddStitchCommand()
0265 {
0266     delete m_original;
0267 }
0268 
0269 void AddStitchCommand::redo()
0270 {
0271     m_original = m_document->pattern()->stitches().stitchQueueAt(m_cell);
0272 
0273     if (m_original) {
0274         m_document->pattern()->stitches().replaceStitchQueueAt(m_cell, new StitchQueue(m_original));
0275     }
0276 
0277     m_document->pattern()->stitches().addStitch(m_cell, m_type, m_colorIndex);
0278 }
0279 
0280 void AddStitchCommand::undo()
0281 {
0282     delete m_document->pattern()->stitches().takeStitchQueueAt(m_cell);
0283 
0284     if (m_original) {
0285         m_document->pattern()->stitches().replaceStitchQueueAt(m_cell, m_original);
0286         m_original = nullptr;
0287     }
0288 }
0289 
0290 DeleteStitchCommand::DeleteStitchCommand(Document *document, const QPoint &cell, Stitch::Type type, int colorIndex, QUndoCommand *parent)
0291     : QUndoCommand(i18n("Delete Stitches"), parent)
0292     , m_document(document)
0293     , m_cell(cell)
0294     , m_type(type)
0295     , m_colorIndex(colorIndex)
0296     , m_original(nullptr)
0297 {
0298 }
0299 
0300 DeleteStitchCommand::~DeleteStitchCommand()
0301 {
0302     delete m_original;
0303 }
0304 
0305 void DeleteStitchCommand::redo()
0306 {
0307     m_original = m_document->pattern()->stitches().stitchQueueAt(m_cell);
0308 
0309     if (m_original) {
0310         m_original = m_document->pattern()->stitches().replaceStitchQueueAt(m_cell, new StitchQueue(m_original));
0311         m_document->pattern()->stitches().deleteStitch(m_cell, m_type, m_colorIndex);
0312     }
0313 }
0314 
0315 void DeleteStitchCommand::undo()
0316 {
0317     if (m_original) {
0318         delete m_document->pattern()->stitches().replaceStitchQueueAt(m_cell, m_original);
0319         m_original = nullptr;
0320     }
0321 }
0322 
0323 AddBackstitchCommand::AddBackstitchCommand(Document *document, const QPoint &start, const QPoint &end, int colorIndex)
0324     : QUndoCommand(i18n("Add Backstitch"))
0325     , m_document(document)
0326     , m_start(start)
0327     , m_end(end)
0328     , m_colorIndex(colorIndex)
0329 {
0330 }
0331 
0332 void AddBackstitchCommand::redo()
0333 {
0334     m_document->pattern()->stitches().addBackstitch(m_start, m_end, m_colorIndex);
0335     m_document->editor()->drawContents();
0336     m_document->preview()->drawContents();
0337 }
0338 
0339 void AddBackstitchCommand::undo()
0340 {
0341     delete m_document->pattern()->stitches().takeBackstitch(m_start, m_end, m_colorIndex);
0342     m_document->editor()->drawContents();
0343     m_document->preview()->drawContents();
0344 }
0345 
0346 DeleteBackstitchCommand::DeleteBackstitchCommand(Document *document, const QPoint &start, const QPoint &end, int colorIndex)
0347     : QUndoCommand(i18n("Delete Backstitch"))
0348     , m_document(document)
0349     , m_start(start)
0350     , m_end(end)
0351     , m_colorIndex(colorIndex)
0352     , m_backstitch(nullptr)
0353 {
0354 }
0355 
0356 DeleteBackstitchCommand::~DeleteBackstitchCommand()
0357 {
0358     delete m_backstitch;
0359 }
0360 
0361 void DeleteBackstitchCommand::redo()
0362 {
0363     m_backstitch = m_document->pattern()->stitches().takeBackstitch(m_start, m_end, m_colorIndex);
0364     m_document->editor()->drawContents();
0365     m_document->preview()->drawContents();
0366 }
0367 
0368 void DeleteBackstitchCommand::undo()
0369 {
0370     m_document->pattern()->stitches().addBackstitch(m_backstitch);
0371     m_backstitch = nullptr;
0372     m_document->editor()->drawContents();
0373     m_document->preview()->drawContents();
0374 }
0375 
0376 AddKnotCommand::AddKnotCommand(Document *document, const QPoint &snap, int colorIndex, QUndoCommand *parent)
0377     : QUndoCommand(i18n("Add Knot"), parent)
0378     , m_document(document)
0379     , m_snap(snap)
0380     , m_colorIndex(colorIndex)
0381 {
0382 }
0383 
0384 void AddKnotCommand::redo()
0385 {
0386     m_document->pattern()->stitches().addFrenchKnot(m_snap, m_colorIndex);
0387 }
0388 
0389 void AddKnotCommand::undo()
0390 {
0391     delete m_document->pattern()->stitches().takeFrenchKnot(m_snap, m_colorIndex);
0392 }
0393 
0394 DeleteKnotCommand::DeleteKnotCommand(Document *document, const QPoint &snap, int colorIndex, QUndoCommand *parent)
0395     : QUndoCommand(i18n("Delete Knots"), parent)
0396     , m_document(document)
0397     , m_snap(snap)
0398     , m_colorIndex(colorIndex)
0399     , m_knot(nullptr)
0400 {
0401 }
0402 
0403 DeleteKnotCommand::~DeleteKnotCommand()
0404 {
0405     delete m_knot;
0406 }
0407 
0408 void DeleteKnotCommand::redo()
0409 {
0410     m_knot = m_document->pattern()->stitches().takeFrenchKnot(m_snap, m_colorIndex);
0411 }
0412 
0413 void DeleteKnotCommand::undo()
0414 {
0415     m_document->pattern()->stitches().addFrenchKnot(m_knot);
0416     m_knot = nullptr;
0417 }
0418 
0419 SetPropertyCommand::SetPropertyCommand(Document *document, const QString &name, const QVariant &value, QUndoCommand *parent)
0420     : QUndoCommand(i18n("Set Property"), parent)
0421     , m_document(document)
0422     , m_name(name)
0423     , m_value(value)
0424 {
0425 }
0426 
0427 void SetPropertyCommand::redo()
0428 {
0429     m_oldValue = m_document->property(m_name);
0430     m_document->setProperty(m_name, m_value);
0431 }
0432 
0433 void SetPropertyCommand::undo()
0434 {
0435     m_document->setProperty(m_name, m_oldValue);
0436 }
0437 
0438 AddBackgroundImageCommand::AddBackgroundImageCommand(Document *document, QSharedPointer<BackgroundImage> backgroundImage, MainWindow *mainWindow)
0439     : QUndoCommand(i18n("Add Background Image"))
0440     , m_document(document)
0441     , m_backgroundImage(backgroundImage)
0442     , m_mainWindow(mainWindow)
0443 {
0444 }
0445 
0446 void AddBackgroundImageCommand::redo()
0447 {
0448     m_document->backgroundImages().addBackgroundImage(m_backgroundImage);
0449     m_mainWindow->updateBackgroundImageActionLists();
0450     m_document->editor()->drawContents();
0451 }
0452 
0453 void AddBackgroundImageCommand::undo()
0454 {
0455     m_document->backgroundImages().removeBackgroundImage(m_backgroundImage);
0456     m_mainWindow->updateBackgroundImageActionLists();
0457     m_document->editor()->drawContents();
0458 }
0459 
0460 FitBackgroundImageCommand::FitBackgroundImageCommand(Document *document, QSharedPointer<BackgroundImage> backgroundImage, const QRect &rect)
0461     : QUndoCommand(i18n("Fit Background to Selection"))
0462     , m_document(document)
0463     , m_backgroundImage(backgroundImage)
0464     , m_rect(rect)
0465 {
0466 }
0467 
0468 void FitBackgroundImageCommand::redo()
0469 {
0470     m_rect = m_document->backgroundImages().fitBackgroundImage(m_backgroundImage, m_rect);
0471     m_document->editor()->resetSelectionArea();
0472     m_document->editor()->drawContents();
0473 }
0474 
0475 void FitBackgroundImageCommand::undo()
0476 {
0477     redo(); // same code required
0478 }
0479 
0480 ShowBackgroundImageCommand::ShowBackgroundImageCommand(Document *document, QSharedPointer<BackgroundImage> backgroundImage, bool visible)
0481     : QUndoCommand(i18n("Show Background Image"))
0482     , m_document(document)
0483     , m_backgroundImage(backgroundImage)
0484     , m_visible(visible)
0485 {
0486 }
0487 
0488 void ShowBackgroundImageCommand::redo()
0489 {
0490     m_visible = m_document->backgroundImages().showBackgroundImage(m_backgroundImage, m_visible);
0491     m_document->editor()->drawContents();
0492 }
0493 
0494 void ShowBackgroundImageCommand::undo()
0495 {
0496     redo(); // same code required
0497 }
0498 
0499 RemoveBackgroundImageCommand::RemoveBackgroundImageCommand(Document *document, QSharedPointer<BackgroundImage> backgroundImage, MainWindow *mainWindow)
0500     : QUndoCommand(i18n("Remove Background Image"))
0501     , m_document(document)
0502     , m_backgroundImage(backgroundImage)
0503     , m_mainWindow(mainWindow)
0504 {
0505 }
0506 
0507 RemoveBackgroundImageCommand::~RemoveBackgroundImageCommand()
0508 {
0509     // TODO resolve ownership of m_backgroundImage
0510     // delete m_backgroundImage;
0511     // m_backgroundImage may also be deleted by the document, potential for a crash or memory leak
0512 }
0513 
0514 void RemoveBackgroundImageCommand::redo()
0515 {
0516     m_document->backgroundImages().removeBackgroundImage(m_backgroundImage);
0517     m_mainWindow->updateBackgroundImageActionLists();
0518 
0519     if (m_backgroundImage->isVisible()) {
0520         m_document->editor()->drawContents();
0521     }
0522 }
0523 
0524 void RemoveBackgroundImageCommand::undo()
0525 {
0526     m_document->backgroundImages().addBackgroundImage(m_backgroundImage);
0527     m_mainWindow->updateBackgroundImageActionLists();
0528 
0529     if (m_backgroundImage->isVisible()) {
0530         m_document->editor()->drawContents();
0531     }
0532 }
0533 
0534 AddDocumentFlossCommand::AddDocumentFlossCommand(Document *document, int key, DocumentFloss *documentFloss, QUndoCommand *parent)
0535     : QUndoCommand(parent)
0536     , m_document(document)
0537     , m_key(key)
0538     , m_documentFloss(documentFloss)
0539 {
0540 }
0541 
0542 void AddDocumentFlossCommand::redo()
0543 {
0544     m_document->pattern()->palette().add(m_key, m_documentFloss);
0545 }
0546 
0547 void AddDocumentFlossCommand::undo()
0548 {
0549     m_document->pattern()->palette().remove(m_key);
0550 }
0551 
0552 RemoveDocumentFlossCommand::RemoveDocumentFlossCommand(Document *document, int key, DocumentFloss *documentFloss, QUndoCommand *parent)
0553     : QUndoCommand(parent)
0554     , m_document(document)
0555     , m_key(key)
0556     , m_documentFloss(documentFloss)
0557 {
0558 }
0559 
0560 RemoveDocumentFlossCommand::~RemoveDocumentFlossCommand()
0561 {
0562     delete m_documentFloss;
0563 }
0564 
0565 void RemoveDocumentFlossCommand::redo()
0566 {
0567     m_document->pattern()->palette().remove(m_key);
0568 }
0569 
0570 void RemoveDocumentFlossCommand::undo()
0571 {
0572     m_document->pattern()->palette().add(m_key, m_documentFloss);
0573 }
0574 
0575 ReplaceDocumentFlossCommand::ReplaceDocumentFlossCommand(Document *document, int key, DocumentFloss *documentFloss)
0576     : QUndoCommand()
0577     , m_document(document)
0578     , m_key(key)
0579     , m_documentFloss(documentFloss)
0580 {
0581 }
0582 
0583 ReplaceDocumentFlossCommand::~ReplaceDocumentFlossCommand()
0584 {
0585     delete m_documentFloss;
0586 }
0587 
0588 void ReplaceDocumentFlossCommand::redo()
0589 {
0590     m_documentFloss = m_document->pattern()->palette().replace(m_key, m_documentFloss);
0591 }
0592 
0593 void ReplaceDocumentFlossCommand::undo()
0594 {
0595     redo(); // same code required
0596 }
0597 
0598 ClearUnusedFlossesCommand::ClearUnusedFlossesCommand(Document *document)
0599     : QUndoCommand(i18n("Clear Unused Flosses"))
0600     , m_document(document)
0601 {
0602 }
0603 
0604 void ClearUnusedFlossesCommand::redo()
0605 {
0606     QUndoCommand::redo();
0607     m_document->palette()->update();
0608 }
0609 
0610 void ClearUnusedFlossesCommand::undo()
0611 {
0612     QUndoCommand::undo();
0613     m_document->palette()->update();
0614 }
0615 
0616 ResizeDocumentCommand::ResizeDocumentCommand(Document *document, int width, int height, QUndoCommand *parent)
0617     : QUndoCommand(i18n("Resize Document"), parent)
0618     , m_document(document)
0619     , m_width(width)
0620     , m_height(height)
0621 {
0622 }
0623 
0624 void ResizeDocumentCommand::redo()
0625 {
0626     m_originalWidth = m_document->pattern()->stitches().width();
0627     m_originalHeight = m_document->pattern()->stitches().height();
0628     QRect extents = m_document->pattern()->stitches().extents();
0629     int minx = std::min(extents.left(), m_width - extents.width());
0630     m_xOffset = minx - extents.left();
0631     int miny = std::min(extents.top(), m_height - extents.height());
0632     m_yOffset = miny - extents.top();
0633     m_document->pattern()->stitches().movePattern(m_xOffset, m_yOffset);
0634     m_document->pattern()->stitches().resize(m_width, m_height);
0635 }
0636 
0637 void ResizeDocumentCommand::undo()
0638 {
0639     m_document->pattern()->stitches().resize(m_originalWidth, m_originalHeight);
0640     m_document->pattern()->stitches().movePattern(-m_xOffset, -m_yOffset);
0641 }
0642 
0643 CropToPatternCommand::CropToPatternCommand(Document *document)
0644     : QUndoCommand(i18n("Crop to Pattern"))
0645     , m_document(document)
0646 {
0647 }
0648 
0649 void CropToPatternCommand::redo()
0650 {
0651     m_originalWidth = m_document->pattern()->stitches().width();
0652     m_originalHeight = m_document->pattern()->stitches().height();
0653     QRect extents = m_document->pattern()->stitches().extents();
0654     m_xOffset = -extents.left();
0655     m_yOffset = -extents.top();
0656     m_document->pattern()->stitches().movePattern(m_xOffset, m_yOffset);
0657     m_document->pattern()->stitches().resize(extents.width(), extents.height());
0658     m_document->editor()->readDocumentSettings();
0659     m_document->preview()->readDocumentSettings();
0660 }
0661 
0662 void CropToPatternCommand::undo()
0663 {
0664     m_document->pattern()->stitches().resize(m_originalWidth, m_originalHeight);
0665     m_document->pattern()->stitches().movePattern(-m_xOffset, -m_yOffset);
0666     m_document->editor()->readDocumentSettings();
0667     m_document->preview()->readDocumentSettings();
0668 }
0669 
0670 CropToSelectionCommand::CropToSelectionCommand(Document *document, const QRect &selectionArea)
0671     : QUndoCommand(i18n("Crop to Selection"))
0672     , m_document(document)
0673     , m_selectionArea(selectionArea)
0674 {
0675 }
0676 
0677 void CropToSelectionCommand::redo()
0678 {
0679     QList<Stitch::Type> maskStitches;
0680     maskStitches << Stitch::TLQtr << Stitch::TRQtr << Stitch::BLQtr << Stitch::BTHalf << Stitch::TL3Qtr << Stitch::BRQtr << Stitch::TBHalf << Stitch::TR3Qtr
0681                  << Stitch::BL3Qtr << Stitch::BR3Qtr << Stitch::Full << Stitch::TLSmallHalf << Stitch::TRSmallHalf << Stitch::BLSmallHalf << Stitch::BRSmallHalf
0682                  << Stitch::TLSmallFull << Stitch::TRSmallFull << Stitch::BLSmallFull << Stitch::BRSmallFull;
0683 
0684     QDataStream stream(&m_originalPattern, QIODevice::WriteOnly);
0685     stream << m_document->pattern()->stitches();
0686 
0687     Pattern *pattern = m_document->pattern()->copy(m_selectionArea, -1, maskStitches, false, false);
0688     m_document->pattern()->stitches().clear();
0689     m_document->pattern()->stitches().resize(m_selectionArea.width(), m_selectionArea.height());
0690     m_document->pattern()->paste(pattern, QPoint(0, 0), true);
0691     delete pattern;
0692 
0693     m_document->editor()->readDocumentSettings();
0694     m_document->preview()->readDocumentSettings();
0695 }
0696 
0697 void CropToSelectionCommand::undo()
0698 {
0699     QDataStream stream(&m_originalPattern, QIODevice::ReadOnly);
0700     stream >> m_document->pattern()->stitches();
0701     m_originalPattern.clear();
0702 
0703     m_document->editor()->readDocumentSettings();
0704     m_document->preview()->readDocumentSettings();
0705 }
0706 
0707 InsertColumnsCommand::InsertColumnsCommand(Document *document, const QRect &selectionArea)
0708     : QUndoCommand(i18n("Insert Columns"))
0709     , m_document(document)
0710     , m_selectionArea(selectionArea)
0711 {
0712 }
0713 
0714 void InsertColumnsCommand::redo()
0715 {
0716     m_document->pattern()->stitches().insertColumns(m_selectionArea.left(), m_selectionArea.width());
0717 
0718     auto backgroundImageIterator = m_document->backgroundImages().backgroundImages();
0719 
0720     while (backgroundImageIterator.hasNext()) {
0721         auto backgroundImage = backgroundImageIterator.next();
0722 
0723         if (backgroundImage->location().left() >= m_selectionArea.left()) {
0724             backgroundImage->setLocation(backgroundImage->location().translated(m_selectionArea.width(), 0));
0725         }
0726     }
0727 
0728     m_document->editor()->readDocumentSettings();
0729     m_document->preview()->readDocumentSettings();
0730 }
0731 
0732 void InsertColumnsCommand::undo()
0733 {
0734     m_document->pattern()->stitches().removeColumns(m_selectionArea.left(), m_selectionArea.width());
0735 
0736     auto backgroundImageIterator = m_document->backgroundImages().backgroundImages();
0737 
0738     while (backgroundImageIterator.hasNext()) {
0739         auto backgroundImage = backgroundImageIterator.next();
0740 
0741         if (backgroundImage->location().left() > m_selectionArea.left()) {
0742             backgroundImage->setLocation(backgroundImage->location().translated(-m_selectionArea.width(), 0));
0743         }
0744     }
0745 
0746     m_document->editor()->readDocumentSettings();
0747     m_document->preview()->readDocumentSettings();
0748 }
0749 
0750 InsertRowsCommand::InsertRowsCommand(Document *document, const QRect &selectionArea)
0751     : QUndoCommand(i18n("Insert Rows"))
0752     , m_document(document)
0753     , m_selectionArea(selectionArea)
0754 {
0755 }
0756 
0757 void InsertRowsCommand::redo()
0758 {
0759     m_document->pattern()->stitches().insertRows(m_selectionArea.top(), m_selectionArea.height());
0760 
0761     auto backgroundImageIterator = m_document->backgroundImages().backgroundImages();
0762 
0763     while (backgroundImageIterator.hasNext()) {
0764         auto backgroundImage = backgroundImageIterator.next();
0765 
0766         if (backgroundImage->location().top() >= m_selectionArea.top()) {
0767             backgroundImage->setLocation(backgroundImage->location().translated(0, m_selectionArea.height()));
0768         }
0769     }
0770 
0771     m_document->editor()->readDocumentSettings();
0772     m_document->preview()->readDocumentSettings();
0773 }
0774 
0775 void InsertRowsCommand::undo()
0776 {
0777     m_document->pattern()->stitches().removeRows(m_selectionArea.top(), m_selectionArea.height());
0778 
0779     auto backgroundImageIterator = m_document->backgroundImages().backgroundImages();
0780 
0781     while (backgroundImageIterator.hasNext()) {
0782         auto backgroundImage = backgroundImageIterator.next();
0783 
0784         if (backgroundImage->location().top() > m_selectionArea.top()) {
0785             backgroundImage->setLocation(backgroundImage->location().translated(0, -m_selectionArea.height()));
0786         }
0787     }
0788 
0789     m_document->editor()->readDocumentSettings();
0790     m_document->preview()->readDocumentSettings();
0791 }
0792 
0793 ExtendPatternCommand::ExtendPatternCommand(Document *document, int top, int left, int right, int bottom)
0794     : QUndoCommand(i18n("Extend Pattern"))
0795     , m_document(document)
0796     , m_top(top)
0797     , m_left(left)
0798     , m_right(right)
0799     , m_bottom(bottom)
0800 {
0801 }
0802 
0803 void ExtendPatternCommand::redo()
0804 {
0805     StitchData &stitchData = m_document->pattern()->stitches();
0806     stitchData.resize(stitchData.width() + m_left + m_right, stitchData.height() + m_top + m_bottom);
0807     stitchData.movePattern(m_left, m_top);
0808     auto backgroundImageIterator = m_document->backgroundImages().backgroundImages();
0809 
0810     while (backgroundImageIterator.hasNext()) {
0811         auto backgroundImage = backgroundImageIterator.next();
0812         backgroundImage->setLocation(backgroundImage->location().translated(m_left, m_top));
0813     }
0814 
0815     m_document->editor()->readDocumentSettings();
0816     m_document->preview()->readDocumentSettings();
0817 }
0818 
0819 void ExtendPatternCommand::undo()
0820 {
0821     StitchData &stitchData = m_document->pattern()->stitches();
0822     stitchData.movePattern(-m_left, -m_top);
0823     stitchData.resize(stitchData.width() - m_left - m_right, stitchData.height() - m_top - m_bottom);
0824     auto backgroundImageIterator = m_document->backgroundImages().backgroundImages();
0825 
0826     while (backgroundImageIterator.hasNext()) {
0827         auto backgroundImage = backgroundImageIterator.next();
0828         backgroundImage->setLocation(backgroundImage->location().translated(-m_left, -m_top));
0829     }
0830 
0831     m_document->editor()->readDocumentSettings();
0832     m_document->preview()->readDocumentSettings();
0833 }
0834 
0835 CentrePatternCommand::CentrePatternCommand(Document *document)
0836     : QUndoCommand(i18n("Center Pattern"))
0837     , m_document(document)
0838 {
0839 }
0840 
0841 void CentrePatternCommand::redo()
0842 {
0843     QRect extents = m_document->pattern()->stitches().extents();
0844 
0845     m_xOffset = ((m_document->pattern()->stitches().width() - extents.width()) / 2) - extents.left();
0846     m_yOffset = ((m_document->pattern()->stitches().height() - extents.height()) / 2) - extents.top();
0847 
0848     if (m_xOffset || m_yOffset) {
0849         m_document->pattern()->stitches().movePattern(m_xOffset, m_yOffset);
0850 
0851         m_document->editor()->drawContents();
0852         m_document->preview()->drawContents();
0853     }
0854 }
0855 
0856 void CentrePatternCommand::undo()
0857 {
0858     if (m_xOffset || m_yOffset) {
0859         m_document->pattern()->stitches().movePattern(-m_xOffset, -m_yOffset);
0860 
0861         m_document->editor()->drawContents();
0862         m_document->preview()->drawContents();
0863     }
0864 }
0865 
0866 UpdateDocumentPaletteCommand::UpdateDocumentPaletteCommand(Document *document, const DocumentPalette &palette)
0867     : QUndoCommand(i18n("Update Palette"))
0868     , m_document(document)
0869     , m_palette(palette)
0870 {
0871 }
0872 
0873 void UpdateDocumentPaletteCommand::redo()
0874 {
0875     DocumentPalette palette = m_document->pattern()->palette();
0876     m_document->pattern()->palette() = m_palette;
0877     m_palette = palette;
0878 
0879     m_document->editor()->drawContents();
0880     m_document->preview()->drawContents();
0881     m_document->palette()->update();
0882 }
0883 
0884 void UpdateDocumentPaletteCommand::undo()
0885 {
0886     redo(); // swaps the palette back
0887 }
0888 
0889 ChangeSchemeCommand::ChangeSchemeCommand(Document *document, const QString &schemeName, QUndoCommand *parent)
0890     : QUndoCommand(i18n("Change Floss Scheme"), parent)
0891     , m_document(document)
0892     , m_schemeName(schemeName)
0893 {
0894 }
0895 
0896 void ChangeSchemeCommand::redo()
0897 {
0898     QDataStream stream(&m_originalPalette, QIODevice::WriteOnly);
0899     stream << m_document->pattern()->palette();
0900     m_document->pattern()->palette().setSchemeName(m_schemeName);
0901 
0902     m_document->editor()->drawContents();
0903     m_document->preview()->drawContents();
0904     m_document->palette()->update();
0905 }
0906 
0907 void ChangeSchemeCommand::undo()
0908 {
0909     QDataStream stream(&m_originalPalette, QIODevice::ReadOnly);
0910     stream >> m_document->pattern()->palette();
0911     m_originalPalette.clear();
0912 
0913     m_document->editor()->drawContents();
0914     m_document->preview()->drawContents();
0915     m_document->palette()->update();
0916 }
0917 
0918 EditorReadDocumentSettingsCommand::EditorReadDocumentSettingsCommand(Editor *editor)
0919     : QUndoCommand()
0920     , m_editor(editor)
0921 {
0922 }
0923 
0924 void EditorReadDocumentSettingsCommand::redo()
0925 {
0926     m_editor->readDocumentSettings();
0927 }
0928 
0929 void EditorReadDocumentSettingsCommand::undo()
0930 {
0931     redo(); // same code required
0932 }
0933 
0934 PreviewReadDocumentSettingsCommand::PreviewReadDocumentSettingsCommand(Preview *preview)
0935     : QUndoCommand()
0936     , m_preview(preview)
0937 {
0938 }
0939 
0940 void PreviewReadDocumentSettingsCommand::redo()
0941 {
0942     m_preview->readDocumentSettings();
0943 }
0944 
0945 void PreviewReadDocumentSettingsCommand::undo()
0946 {
0947     redo(); // same code required
0948 }
0949 
0950 PaletteReplaceColorCommand::PaletteReplaceColorCommand(Document *document, int originalIndex, int replacementIndex)
0951     : QUndoCommand(i18n("Replace Color"))
0952     , m_document(document)
0953     , m_originalIndex(originalIndex)
0954     , m_replacementIndex(replacementIndex)
0955 {
0956 }
0957 
0958 void PaletteReplaceColorCommand::redo()
0959 {
0960     if (m_stitches.count() || m_backstitches.count() || m_knots.count()) {
0961         // populated from a previous redo call
0962         // iterator over the existing pointers
0963         for (Stitch *stitch : m_stitches) {
0964             stitch->colorIndex = m_replacementIndex;
0965         }
0966 
0967         for (Backstitch *backstitch : m_backstitches) {
0968             backstitch->colorIndex = m_replacementIndex;
0969         }
0970 
0971         for (Knot *knot : m_knots) {
0972             knot->colorIndex = m_replacementIndex;
0973         }
0974     } else {
0975         // search the stitch data for stitches of the required color
0976         StitchData &stitchData = m_document->pattern()->stitches();
0977 
0978         for (int row = 0; row < stitchData.height(); ++row) {
0979             for (int col = 0; col < stitchData.width(); ++col) {
0980                 StitchQueue *queue = stitchData.stitchQueueAt(QPoint(col, row));
0981 
0982                 if (queue) {
0983                     QListIterator<Stitch *> stitchIterator(*queue);
0984 
0985                     while (stitchIterator.hasNext()) {
0986                         Stitch *stitch = stitchIterator.next();
0987 
0988                         if (stitch->colorIndex == m_originalIndex) {
0989                             m_stitches.append(stitch);
0990                             stitch->colorIndex = m_replacementIndex;
0991                         }
0992                     }
0993                 }
0994             }
0995         }
0996 
0997         QListIterator<Backstitch *> backstitchIterator = stitchData.backstitchIterator();
0998 
0999         while (backstitchIterator.hasNext()) {
1000             Backstitch *backstitch = backstitchIterator.next();
1001 
1002             if (backstitch->colorIndex == m_originalIndex) {
1003                 m_backstitches.append(backstitch);
1004                 backstitch->colorIndex = m_replacementIndex;
1005             }
1006         }
1007 
1008         QListIterator<Knot *> knotIterator = stitchData.knotIterator();
1009 
1010         while (knotIterator.hasNext()) {
1011             Knot *knot = knotIterator.next();
1012 
1013             if (knot->colorIndex == m_originalIndex) {
1014                 m_knots.append(knot);
1015                 knot->colorIndex = m_replacementIndex;
1016             }
1017         }
1018     }
1019 
1020     m_document->editor()->drawContents();
1021     m_document->preview()->drawContents();
1022     m_document->palette()->update();
1023 }
1024 
1025 void PaletteReplaceColorCommand::undo()
1026 {
1027     QListIterator<Stitch *> stitchIterator(m_stitches);
1028 
1029     while (stitchIterator.hasNext()) {
1030         stitchIterator.next()->colorIndex = m_originalIndex;
1031     }
1032 
1033     QListIterator<Backstitch *> backstitchIterator(m_backstitches);
1034 
1035     while (backstitchIterator.hasNext()) {
1036         backstitchIterator.next()->colorIndex = m_originalIndex;
1037     }
1038 
1039     QListIterator<Knot *> knotIterator(m_knots);
1040 
1041     while (knotIterator.hasNext()) {
1042         knotIterator.next()->colorIndex = m_originalIndex;
1043     }
1044 
1045     m_document->editor()->drawContents();
1046     m_document->preview()->drawContents();
1047     m_document->palette()->update();
1048 }
1049 
1050 PaletteSwapColorCommand::PaletteSwapColorCommand(Document *document, int originalIndex, int swappedIndex)
1051     : QUndoCommand(i18n("Swap Colors"))
1052     , m_document(document)
1053     , m_originalIndex(originalIndex)
1054     , m_swappedIndex(swappedIndex)
1055 {
1056 }
1057 
1058 void PaletteSwapColorCommand::redo()
1059 {
1060     m_document->pattern()->palette().swap(m_originalIndex, m_swappedIndex);
1061     m_document->editor()->drawContents();
1062     m_document->preview()->drawContents();
1063     m_document->palette()->update();
1064 }
1065 
1066 void PaletteSwapColorCommand::undo()
1067 {
1068     redo();
1069 }
1070 
1071 UpdatePrinterConfigurationCommand::UpdatePrinterConfigurationCommand(Document *document, const PrinterConfiguration &printerConfiguration)
1072     : QUndoCommand(i18n("Update Printer Configuration"))
1073     , m_document(document)
1074     , m_printerConfiguration(printerConfiguration)
1075 {
1076 }
1077 
1078 void UpdatePrinterConfigurationCommand::redo()
1079 {
1080     PrinterConfiguration original = m_document->printerConfiguration();
1081     m_document->setPrinterConfiguration(m_printerConfiguration);
1082     m_printerConfiguration = original;
1083 }
1084 
1085 void UpdatePrinterConfigurationCommand::undo()
1086 {
1087     redo();
1088 }
1089 
1090 EditCutCommand::EditCutCommand(Document *document,
1091                                const QRect &selectionArea,
1092                                int colorMask,
1093                                const QList<Stitch::Type> &stitchMasks,
1094                                bool excludeBackstitches,
1095                                bool excludeKnots)
1096     : QUndoCommand(i18n("Cut"))
1097     , m_document(document)
1098     , m_selectionArea(selectionArea)
1099     , m_colorMask(colorMask)
1100     , m_stitchMasks(stitchMasks)
1101     , m_excludeBackstitches(excludeBackstitches)
1102     , m_excludeKnots(excludeKnots)
1103     , m_originalPattern(nullptr)
1104 {
1105 }
1106 
1107 EditCutCommand::~EditCutCommand()
1108 {
1109     delete m_originalPattern;
1110 }
1111 
1112 void EditCutCommand::redo()
1113 {
1114     m_originalPattern = m_document->pattern()->cut(m_selectionArea, m_colorMask, m_stitchMasks, m_excludeBackstitches, m_excludeKnots);
1115 
1116     QByteArray data;
1117     QDataStream stream(&data, QIODevice::WriteOnly);
1118     stream << *m_originalPattern;
1119 
1120     QMimeData *mimeData = new QMimeData();
1121     mimeData->setData(QStringLiteral("application/kxstitch"), data);
1122 
1123     QApplication::clipboard()->setMimeData(mimeData);
1124 
1125     m_document->editor()->drawContents();
1126     m_document->preview()->drawContents();
1127 }
1128 
1129 void EditCutCommand::undo()
1130 {
1131     m_document->pattern()->paste(m_originalPattern, m_selectionArea.topLeft(), true);
1132     delete m_originalPattern;
1133     m_originalPattern = nullptr;
1134 
1135     m_document->editor()->drawContents();
1136     m_document->preview()->drawContents();
1137 }
1138 
1139 EditPasteCommand::EditPasteCommand(Document *document, Pattern *pattern, const QPoint &cell, bool merge, const QString &source)
1140     : QUndoCommand(source)
1141     , m_document(document)
1142     , m_pastePattern(pattern)
1143     , m_cell(cell)
1144     , m_merge(merge)
1145 {
1146 }
1147 
1148 void EditPasteCommand::redo()
1149 {
1150     QDataStream stream(&m_originalPattern, QIODevice::WriteOnly);
1151     stream << *(m_document->pattern());
1152     m_document->pattern()->paste(m_pastePattern, m_cell, m_merge);
1153 
1154     m_document->editor()->drawContents();
1155     m_document->preview()->drawContents();
1156     m_document->palette()->update();
1157 }
1158 
1159 void EditPasteCommand::undo()
1160 {
1161     QDataStream stream(&m_originalPattern, QIODevice::ReadOnly);
1162     m_document->pattern()->clear();
1163     stream >> *(m_document->pattern());
1164     m_originalPattern.clear();
1165 
1166     m_document->editor()->drawContents();
1167     m_document->preview()->drawContents();
1168     m_document->palette()->update();
1169 }
1170 
1171 MirrorSelectionCommand::MirrorSelectionCommand(Document *document,
1172                                                const QRect &selectionArea,
1173                                                int colorMask,
1174                                                const QList<Stitch::Type> &stitchMasks,
1175                                                bool excludeBackstitches,
1176                                                bool excludeKnots,
1177                                                Qt::Orientation orientation,
1178                                                bool copies,
1179                                                const QByteArray &originalPatternData,
1180                                                Pattern *invertedPattern,
1181                                                const QPoint &pasteCell,
1182                                                bool merge)
1183     : QUndoCommand(i18n("Mirror Selection"))
1184     , m_document(document)
1185     , m_selectionArea(selectionArea)
1186     , m_colorMask(colorMask)
1187     , m_stitchMasks(stitchMasks)
1188     , m_excludeBackstitches(excludeBackstitches)
1189     , m_excludeKnots(excludeKnots)
1190     , m_orientation(orientation)
1191     , m_copies(copies)
1192     , m_originalPatternData(originalPatternData)
1193     , m_invertedPattern(invertedPattern)
1194     , m_pasteCell(pasteCell)
1195     , m_merge(merge)
1196 {
1197 }
1198 
1199 MirrorSelectionCommand::~MirrorSelectionCommand()
1200 {
1201     delete m_invertedPattern;
1202 }
1203 
1204 void MirrorSelectionCommand::redo()
1205 {
1206     if (!m_copies) {
1207         delete m_document->pattern()->cut(m_selectionArea, m_colorMask, m_stitchMasks, m_excludeBackstitches, m_excludeKnots);
1208     }
1209 
1210     m_document->pattern()->paste(m_invertedPattern, m_pasteCell, m_merge);
1211 
1212     m_document->editor()->drawContents();
1213     m_document->preview()->drawContents();
1214 }
1215 
1216 void MirrorSelectionCommand::undo()
1217 {
1218     m_document->pattern()->stitches().clear();
1219     QDataStream stream(&m_originalPatternData, QIODevice::ReadOnly);
1220     stream >> m_document->pattern()->stitches();
1221 
1222     m_document->editor()->drawContents();
1223     m_document->preview()->drawContents();
1224 }
1225 
1226 RotateSelectionCommand::RotateSelectionCommand(Document *document,
1227                                                const QRect &selectionArea,
1228                                                int colorMask,
1229                                                const QList<Stitch::Type> &stitchMasks,
1230                                                bool excludeBackstitches,
1231                                                bool excludeKnots,
1232                                                StitchData::Rotation rotation,
1233                                                bool copies,
1234                                                const QByteArray &originalPatternData,
1235                                                Pattern *rotatedPattern,
1236                                                const QPoint &pasteCell,
1237                                                bool merge)
1238     : QUndoCommand(i18n("Rotate Selection"))
1239     , m_document(document)
1240     , m_selectionArea(selectionArea)
1241     , m_colorMask(colorMask)
1242     , m_stitchMasks(stitchMasks)
1243     , m_excludeBackstitches(excludeBackstitches)
1244     , m_excludeKnots(excludeKnots)
1245     , m_rotation(rotation)
1246     , m_copies(copies)
1247     , m_originalPatternData(originalPatternData)
1248     , m_rotatedPattern(rotatedPattern)
1249     , m_pasteCell(pasteCell)
1250     , m_merge(merge)
1251 {
1252 }
1253 
1254 RotateSelectionCommand::~RotateSelectionCommand()
1255 {
1256     delete m_rotatedPattern;
1257 }
1258 
1259 void RotateSelectionCommand::redo()
1260 {
1261     if (!m_copies) {
1262         delete m_document->pattern()->cut(m_selectionArea, m_colorMask, m_stitchMasks, m_excludeBackstitches, m_excludeKnots);
1263     }
1264 
1265     m_document->pattern()->paste(m_rotatedPattern, m_pasteCell, m_merge);
1266 
1267     m_document->editor()->drawContents();
1268     m_document->preview()->drawContents();
1269 }
1270 
1271 void RotateSelectionCommand::undo()
1272 {
1273     m_document->pattern()->stitches().clear();
1274     QDataStream stream(&m_originalPatternData, QIODevice::ReadOnly);
1275     stream >> m_document->pattern()->stitches();
1276 
1277     m_document->editor()->drawContents();
1278     m_document->preview()->drawContents();
1279 }
1280 
1281 AlphabetCommand::AlphabetCommand(Document *document)
1282     : QUndoCommand(i18n("Alphabet"))
1283     , m_document(document)
1284 {
1285 }
1286 
1287 AlphabetCommand::~AlphabetCommand()
1288 {
1289     qDeleteAll(m_children);
1290 }
1291 
1292 void AlphabetCommand::redo()
1293 {
1294     for (int i = 0; i < m_children.size(); ++i) {
1295         m_children.at(i)->redo();
1296     }
1297 }
1298 
1299 void AlphabetCommand::undo()
1300 {
1301     for (int i = m_children.size() - 1; i >= 0; --i) {
1302         m_children.at(i)->undo();
1303     }
1304 }
1305 
1306 void AlphabetCommand::push(QUndoCommand *child)
1307 {
1308     m_children.append(child);
1309     child->redo();
1310 }
1311 
1312 QUndoCommand *AlphabetCommand::pop()
1313 {
1314     if (m_children.isEmpty()) {
1315         return nullptr;
1316     }
1317 
1318     m_children.last()->undo();
1319     return m_children.takeLast();
1320 }
1321 
1322 int AlphabetCommand::childCount() const
1323 {
1324     return m_children.count();
1325 }
1326 
1327 ConfigurationCommand::ConfigurationCommand(MainWindow *mainWindow)
1328     : QUndoCommand(i18n("Configure KXStitch"))
1329     , m_mainWindow(mainWindow)
1330 {
1331 }
1332 
1333 void ConfigurationCommand::redo()
1334 {
1335     QUndoCommand::redo();
1336     m_mainWindow->loadSettings();
1337 }
1338 
1339 void ConfigurationCommand::undo()
1340 {
1341     QUndoCommand::undo();
1342     m_mainWindow->loadSettings();
1343 }