Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 2a3fccde authored by Tusooa Zhu's avatar Tusooa Zhu 🔼

Control the merging and creation of KisChangeGuidesCommand

Only adding/removing/moving a guide will trigger the creation
of KisChangeGuidesCommand. Only consecutive movements, or creation
then movement, or movement then deletion of the same guide
will trigger the merging of the commands.

CCBUG: 361012
parent 9d099549
......@@ -22,17 +22,68 @@
#include "KisDocument.h"
#include <kis_image.h>
#include <QList>
#include <QListIterator>
struct KisChangeGuidesCommand::Private
{
Private(KisDocument *_doc) : doc(_doc) {}
bool sameOrOnlyMovedOneGuideBetween(const KisGuidesConfig &first, const KisGuidesConfig &second);
enum Status {
NO_DIFF = 0,
ONE_DIFF = 1, /// only one difference including adding or removing
OTHER_DIFF = 4
};
Status diff(const QList<qreal> &first, const QList<qreal> &second);
KisDocument *doc;
KisGuidesConfig oldGuides;
KisGuidesConfig newGuides;
};
bool KisChangeGuidesCommand::Private::sameOrOnlyMovedOneGuideBetween(const KisGuidesConfig &first, const KisGuidesConfig &second)
{
return diff(first.horizontalGuideLines(), second.horizontalGuideLines()) +
diff(first.verticalGuideLines(), second.verticalGuideLines()) <= 1;
}
KisChangeGuidesCommand::Private::Status KisChangeGuidesCommand::Private::diff(const QList<qreal> &first, const QList<qreal> &second)
{
if (first.size() == second.size()) {
int diffCount = 0;
for (int i = 0; i < first.size(); ++i) {
if (first[i] != second[i]) {
++diffCount;
if (diffCount > 1) {
return OTHER_DIFF;
}
}
}
return diffCount == 0 ? NO_DIFF : ONE_DIFF;
} else if (first.size() - second.size() == -1) { // added a guide
QList<qreal> beforeRemoval = second;
beforeRemoval.takeLast();
return first == beforeRemoval ? ONE_DIFF : OTHER_DIFF;
} else if (first.size() - second.size() == 1) { // removed a guide
bool skippedItem = false;
for (QListIterator<qreal> i(first), j(second); i.hasNext() && j.hasNext(); ) {
qreal curFirst = i.next();
qreal curSecond = j.next();
if (!skippedItem && curFirst != curSecond) {
curFirst = i.next(); // try to go to the next item and see if it matches
}
if (curFirst != curSecond) {
return OTHER_DIFF;
}
}
// here we conclude only one guide is removed
return ONE_DIFF;
} else {
return OTHER_DIFF;
}
}
KisChangeGuidesCommand::KisChangeGuidesCommand(KisDocument *doc, const KisGuidesConfig &newGuides)
: KUndo2Command(kundo2_i18n("Edit Guides")),
......@@ -69,8 +120,15 @@ bool KisChangeGuidesCommand::mergeWith(const KUndo2Command *command)
dynamic_cast<const KisChangeGuidesCommand*>(command);
if (rhs) {
m_d->newGuides = rhs->m_d->newGuides;
result = true;
// we want to only merge consecutive movements, or creation then movement, or movement then deletion
// there should not be any changes not on the stack (see kis_guides_manager.cpp)
// nor any addition/removal of guides
// nor the movement of other guides
if (m_d->newGuides == rhs->m_d->oldGuides &&
m_d->sameOrOnlyMovedOneGuideBetween(m_d->oldGuides, rhs->m_d->newGuides)) {
m_d->newGuides = rhs->m_d->newGuides;
result = true;
}
}
return result;
......
......@@ -97,6 +97,12 @@ bool KisGuidesConfig::operator==(const KisGuidesConfig &rhs) const
return *d == *rhs.d;
}
bool KisGuidesConfig::hasSamePositionAs(const KisGuidesConfig &rhs) const
{
return horizontalGuideLines() == rhs.horizontalGuideLines() &&
verticalGuideLines() == rhs.verticalGuideLines();
}
void KisGuidesConfig::setHorizontalGuideLines(const QList<qreal> &lines)
{
d->horzGuideLines = lines;
......
......@@ -50,6 +50,7 @@ public:
KisGuidesConfig(const KisGuidesConfig &rhs);
KisGuidesConfig& operator=(const KisGuidesConfig &rhs);
bool operator==(const KisGuidesConfig &rhs) const;
bool hasSamePositionAs(const KisGuidesConfig &rhs) const;
/**
* @brief Set the positions of the horizontal guide lines
......
......@@ -83,6 +83,7 @@ struct KisGuidesManager::Private
Qt::MouseButton getButtonFromEvent(QEvent *event);
QAction* createShortenedAction(const QString &text, const QString &parentId, QObject *parent);
void syncAction(const QString &actionName, bool value);
bool needsUndoCommand();
GuideHandle currentGuide;
......@@ -131,8 +132,10 @@ void KisGuidesManager::slotUploadConfigToDocument()
KisSignalsBlocker b(doc);
if (m_d->shouldSetModified) {
KUndo2Command *cmd = new KisChangeGuidesCommand(doc, value);
doc->addCommand(cmd);
if (m_d->needsUndoCommand()) {
KUndo2Command *cmd = new KisChangeGuidesCommand(doc, value);
doc->addCommand(cmd);
}
} else {
doc->setGuidesConfig(value);
}
......@@ -196,6 +199,17 @@ void KisGuidesManager::Private::syncAction(const QString &actionName, bool value
action->setChecked(value);
}
bool KisGuidesManager::Private::needsUndoCommand()
{
const KisGuidesConfig &value = guidesConfig;
KisDocument *doc = view ? view->document() : 0;
if (!doc) {
return false;
}
return !(doc->guidesConfig().hasSamePositionAs(value));
}
void KisGuidesManager::syncActionsStatus()
{
if (!m_d->view) return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment