File indexing completed on 2025-02-23 04:08:58

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_change_guides_command.h"
0008 
0009 #include "kis_guides_config.h"
0010 #include "KisDocument.h"
0011 #include <kis_image.h>
0012 
0013 #include <QList>
0014 #include <QListIterator>
0015 
0016 struct KisChangeGuidesCommand::Private
0017 {
0018     Private(KisDocument *_doc, KisChangeGuidesCommand *q) : doc(_doc), q(q), firstRedo(true) {}
0019 
0020     bool sameOrOnlyMovedOneGuideBetween(const KisGuidesConfig &first, const KisGuidesConfig &second);
0021     enum Status {
0022         NO_DIFF = 0,
0023         ONE_DIFF = 1,
0024         ADDITION = 4,
0025         REMOVAL = 16,
0026         OTHER_DIFF = 1024
0027     };
0028     Status diff(const QList<qreal> &first, const QList<qreal> &second);
0029 
0030     void switchTo(const KisGuidesConfig &config);
0031 
0032     KisDocument *doc;
0033     KisChangeGuidesCommand *q;
0034 
0035     KisGuidesConfig oldGuides;
0036     KisGuidesConfig newGuides;
0037 
0038     bool firstRedo;
0039 };
0040 
0041 bool KisChangeGuidesCommand::Private::sameOrOnlyMovedOneGuideBetween(const KisGuidesConfig &first, const KisGuidesConfig &second)
0042 {
0043     int ret = diff(first.horizontalGuideLines(), second.horizontalGuideLines()) +
0044         diff(first.verticalGuideLines(), second.verticalGuideLines());
0045 
0046     if (ret == ADDITION) {
0047         q->setText(kundo2_i18n("Add Guide"));
0048     } else if (ret == REMOVAL) {
0049         q->setText(kundo2_i18n("Remove Guide"));
0050     } else if (ret == NO_DIFF || ret == ONE_DIFF) { // meaning we will still merge it
0051         // XXX: how to deal with NO_DIFF (the command "should" be removed -- how?)
0052         q->setText(kundo2_i18n("Edit Guides"));
0053     } else {
0054         return false;
0055     }
0056     return true;
0057 }
0058 
0059 KisChangeGuidesCommand::Private::Status KisChangeGuidesCommand::Private::diff(const QList<qreal> &first, const QList<qreal> &second)
0060 {
0061     if (first.size() == second.size()) {
0062         int diffCount = 0;
0063         for (int i = 0; i < first.size(); ++i) {
0064             if (first[i] != second[i]) {
0065                 ++diffCount;
0066                 if (diffCount > 1) {
0067                     return OTHER_DIFF;
0068                 }
0069             }
0070         }
0071         return diffCount == 0 ? NO_DIFF : ONE_DIFF;
0072     } else if (first.size() - second.size() == -1) { // added a guide
0073         QList<qreal> beforeRemoval = second;
0074         beforeRemoval.takeLast();
0075         return first == beforeRemoval ? ADDITION : OTHER_DIFF;
0076     } else if (first.size() - second.size() == 1) { // removed a guide
0077         bool skippedItem = false;
0078         for (QListIterator<qreal> i(first), j(second); i.hasNext() && j.hasNext(); ) {
0079             qreal curFirst = i.next();
0080             qreal curSecond = j.next();
0081             if (!skippedItem && curFirst != curSecond) {
0082                 curFirst = i.next(); // try to go to the next item and see if it matches
0083             }
0084             if (curFirst != curSecond) {
0085                 return OTHER_DIFF;
0086             }
0087         }
0088         // here we conclude only one guide is removed
0089         return REMOVAL;
0090     } else {
0091         return OTHER_DIFF;
0092     }
0093 }
0094 
0095 void KisChangeGuidesCommand::Private::switchTo(const KisGuidesConfig &config)
0096 {
0097     KisGuidesConfig curConfig = doc->guidesConfig();
0098     curConfig.setHorizontalGuideLines(config.horizontalGuideLines());
0099     curConfig.setVerticalGuideLines(config.verticalGuideLines());
0100     doc->setGuidesConfig(curConfig);
0101 }
0102 
0103 KisChangeGuidesCommand::KisChangeGuidesCommand(KisDocument *doc, const KisGuidesConfig &oldGuides, const KisGuidesConfig &newGuides)
0104     : KUndo2Command(kundo2_i18n("Edit Guides")),
0105       m_d(new Private(doc, this))
0106 {
0107     m_d->oldGuides = oldGuides;
0108     m_d->newGuides = newGuides;
0109     // update the undo command text
0110     m_d->sameOrOnlyMovedOneGuideBetween(m_d->oldGuides, m_d->newGuides);
0111 }
0112 
0113 KisChangeGuidesCommand::~KisChangeGuidesCommand()
0114 {
0115 }
0116 
0117 void KisChangeGuidesCommand::undo()
0118 {
0119     m_d->switchTo(m_d->oldGuides);
0120 }
0121 
0122 void KisChangeGuidesCommand::redo()
0123 {
0124     if (m_d->firstRedo) {
0125         m_d->firstRedo = false;
0126         return;
0127     }
0128     m_d->switchTo(m_d->newGuides);
0129 }
0130 
0131 int KisChangeGuidesCommand::id() const
0132 {
0133     return 1863;
0134 }
0135