Krita Source Code Documentation
Loading...
Searching...
No Matches
kundo2stack.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
3 * SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7/****************************************************************************
8**
9** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
10** All rights reserved.
11** Contact: Nokia Corporation (qt-info@nokia.com)
12**
13** This file is part of the QtGui module of the Qt Toolkit.
14**
15** $QT_BEGIN_LICENSE:LGPL$
16** No Commercial Usage
17** This file contains pre-release code and may not be distributed.
18** You may use this file in accordance with the terms and conditions
19** contained in the Technology Preview License Agreement accompanying
20** this package.
21**
22** GNU Lesser General Public License Usage
23** Alternatively, this file may be used under the terms of the GNU Lesser
24** General Public License version 2.1 as published by the Free Software
25** Foundation and appearing in the file LICENSE.LGPL included in the
26** packaging of this file. Please review the following information to
27** ensure the GNU Lesser General Public License version 2.1 requirements
28** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
29**
30** In addition, as a special exception, Nokia gives you certain additional
31** rights. These rights are described in the Nokia Qt LGPL Exception
32** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
33**
34** If you have questions regarding the use of this file, please contact
35** Nokia at qt-info@nokia.com.
36**
37**
38**
39**
40**
41**
42**
43**
44** $QT_END_LICENSE$
45**
46****************************************************************************/
47
48#include <QDebug>
49#include <klocalizedstring.h>
50#include <kstandardaction.h>
51#include <kactioncollection.h>
52#include "kundo2stack.h"
53#include "kundo2stack_p.h"
54#include "kundo2group.h"
55#include <KoIcon.h>
56#include <QtGlobal>
57#include "kis_assert.h"
58
59
60#ifndef QT_NO_UNDOCOMMAND
61
124 : m_hasParent(parent != 0)
125 , m_endOfCommand(QTime::currentTime())
126{
128 if (parent != 0) {
129 parent->d->child_list.append(this);
130 }
131 setText(text);
132 setTime();
133}
134
146 : m_hasParent(parent != 0)
147{
149 if (parent != 0)
150 parent->d->child_list.append(this);
151 setTime();
152}
153
161{
162 qDeleteAll(d->child_list);
163 delete d;
164}
165
182{
183 return -1;
184}
185
206{
207 Q_UNUSED(command);
208 return false;
209}
210
223{
224 for (int i = 0; i < d->child_list.size(); ++i)
225 d->child_list.at(i)->redo();
226}
227
241{
242 for (int i = d->child_list.size() - 1; i >= 0; --i)
243 d->child_list.at(i)->undo();
244}
245
257{
258 if (!d->actionText.isEmpty())
259 return d->actionText;
260 else
261 return QString();
262}
263
275{
276 return d->text;
277}
278
289{
290 d->text = undoText;
291 d->actionText = undoText.toSecondaryString();
292}
293
303{
304 return d->child_list.count();
305}
306
315const KUndo2Command *KUndo2Command::child(int index) const
316{
317 if (index < 0 || index >= d->child_list.count())
318 return 0;
319 return d->child_list.at(index);
320}
321
323{
324 return m_hasParent;
325}
326
328{
329 return m_timedID;
330}
335
337{
338 if(other->timedId() == this->timedId() && other->timedId() != -1 ) {
339 m_mergeCommandsVector.append(other);
340 m_timeOfCreation = other->time();
341 } else {
342 return false;
343 }
344 return true;
345}
365{
366 Q_UNUSED(other)
367 return false;
368}
369
371{
372 setTime(QTime::currentTime());
373}
374
375void KUndo2Command::setTime(const QTime &time)
376{
378}
379
381{
382 return m_timeOfCreation;
383}
384
386{
387 setEndTime(QTime::currentTime());
388}
389void KUndo2Command::setEndTime(const QTime &time)
390{
392}
394{
395 return m_endOfCommand;
396}
397
399{
400
401 undo();
402 if (!mergeCommandsVector().isEmpty()) {
403 QVectorIterator<KUndo2Command*> it(mergeCommandsVector());
404 it.toFront();
405 while (it.hasNext()) {
406 KUndo2Command* cmd = it.next();
407 cmd->undoMergedCommands();
408 }
409 }
410}
411
413{
414 if (!mergeCommandsVector().isEmpty()) {
415
416 QVectorIterator<KUndo2Command*> it(mergeCommandsVector());
417 it.toBack();
418 while (it.hasPrevious()) {
419 KUndo2Command* cmd = it.previous();
420 cmd->redoMergedCommands();
421 }
422 }
423 redo();
424}
430{
431 return !m_mergeCommandsVector.isEmpty();
432}
433
435{
436 return d->extraData.data();
437}
438
440{
441 d->extraData.reset(data);
442}
443
444
445#endif // QT_NO_UNDOCOMMAND
446
447#ifndef QT_NO_UNDOSTACK
448
526#ifndef QT_NO_ACTION
527
528KUndo2Action::KUndo2Action(const QString &textTemplate, const QString &defaultText, QObject *parent)
529 : QAction(parent)
530 , m_textTemplate(textTemplate)
531 , m_defaultText(defaultText)
532{
533}
534
535void KUndo2Action::setPrefixedText(const QString &text)
536{
537 if (text.isEmpty())
538 setText(m_defaultText);
539 else
540 setText(m_textTemplate.arg(text));
541}
542
543#endif // QT_NO_ACTION
544
550void KUndo2QStack::setIndex(int idx, bool clean)
551{
552 bool was_clean = m_index == m_clean_index;
553
554 if (idx != m_index) {
555 m_index = idx;
556 Q_EMIT indexChanged(m_index);
557 Q_EMIT canUndoChanged(canUndo());
558 Q_EMIT undoTextChanged(undoText());
559 Q_EMIT canRedoChanged(canRedo());
560 Q_EMIT redoTextChanged(redoText());
561 }
562
563 if (clean)
565
566 bool is_clean = m_index == m_clean_index;
567 if (is_clean != was_clean)
568 Q_EMIT cleanChanged(is_clean);
569}
570
572{
573 bool macro = !m_macro_stack.isEmpty();
574 if (macro) return;
575
576 bool redoStateChanged = false;
577 bool cleanStateChanged = false;
578
579 while (m_index < m_command_list.size()) {
580 delete m_command_list.takeLast();
581 redoStateChanged = true;
582 }
583
584 if (m_clean_index > m_index) {
585 m_clean_index = -1; // we've deleted the clean state
586 cleanStateChanged = true;
587 }
588
589 if (redoStateChanged) {
590 Q_EMIT canRedoChanged(canRedo());
591 Q_EMIT redoTextChanged(redoText());
592 }
593
594 if (cleanStateChanged) {
595 Q_EMIT cleanChanged(isClean());
596 }
597}
598
607{
608 if (m_undo_limit <= 0 || !m_macro_stack.isEmpty() || m_undo_limit >= m_command_list.count())
609 return false;
610
611 int del_count = m_command_list.count() - m_undo_limit;
612
613 for (int i = 0; i < del_count; ++i)
614 delete m_command_list.takeFirst();
615
616 m_index -= del_count;
617 if (m_clean_index != -1) {
618 if (m_clean_index < del_count)
619 m_clean_index = -1; // we've deleted the clean command
620 else
621 m_clean_index -= del_count;
622 }
623 return true;
624}
625
635 : QObject(parent), m_index(0), m_clean_index(0), m_group(0), m_undo_limit(0)
636 , m_useCumulativeUndoRedo(false)
637{
638#ifndef QT_NO_UNDOGROUP
639 if (KUndo2Group *group = qobject_cast<KUndo2Group*>(parent))
640 group->addStack(this);
641#endif
642}
643
652{
653#ifndef QT_NO_UNDOGROUP
654 if (m_group != 0)
655 m_group->removeStack(this);
656#endif
657 clear();
658}
659
676{
677 if (m_command_list.isEmpty())
678 return;
679
680 bool was_clean = isClean();
681
682 m_macro_stack.clear();
683 qDeleteAll(m_command_list);
684 m_command_list.clear();
685
686 m_index = 0;
687 m_clean_index = 0;
688
689 Q_EMIT indexChanged(0);
690 Q_EMIT canUndoChanged(false);
691 Q_EMIT undoTextChanged(QString());
692 Q_EMIT canRedoChanged(false);
693 Q_EMIT redoTextChanged(QString());
694
695 if (!was_clean)
696 Q_EMIT cleanChanged(true);
697}
698
723{
724 cmd->redoMergedCommands();
725
726 if (cmd->endTime().isNull()) {
727 cmd->setEndTime();
728 }
729
730 bool macro = !m_macro_stack.isEmpty();
731
732 KUndo2Command *cur = 0;
733 if (macro) {
734 KUndo2Command *macro_cmd = m_macro_stack.last();
735 if (!macro_cmd->d->child_list.isEmpty())
736 cur = macro_cmd->d->child_list.last();
737 } else {
738 if (m_index > 0)
739 cur = m_command_list.at(m_index - 1);
740 while (m_index < m_command_list.size())
741 delete m_command_list.takeLast();
743 m_clean_index = -1; // we've deleted the clean state
744 }
745
746 bool try_merge = cur != 0
747 && cur->id() != -1
748 && cur->id() == cmd->id()
749 && (macro || m_index != m_clean_index);
750
765 if (!macro && m_command_list.size() > 1 && cmd->timedId() != -1 && m_useCumulativeUndoRedo) {
766 KUndo2Command* lastcmd = m_command_list.last();
767
768 auto tryMergeBack =
769 [this] (auto revIt, bool *isMerged) {
772 auto dst = std::prev(revIt.base());
773 auto src = std::prev(dst);
774
775 if ((*dst)->timedId() != -1 &&
776 (*dst)->timedId() == (*src)->timedId() &&
777 (*src)->time().msecsTo((*dst)->endTime()) <= m_cumulativeUndoData.maxGroupDuration &&
778 (*src)->endTime().msecsTo((*dst)->time()) <= m_cumulativeUndoData.maxGroupSeparation &&
779 (*dst)->timedMergeWith(*src)) {
780
781 const int removedIndex = std::distance(m_command_list.begin(), src);
782
785 if (m_clean_index - 1 == removedIndex) {
786 m_clean_index = -1;
787 } else if (m_clean_index - 1 > removedIndex) {
789 }
790 m_index--;
791
792 dst = m_command_list.erase(src);
793 *isMerged = true;
794 } else {
795 *isMerged = false;
796 }
797
798 return std::make_reverse_iterator(std::next(dst));
799 };
800
801 int extraCheckDepth = 0;
802 int newDepth = 1; // `cmd` will be added soon and will increase the total depth!
803 QTime oldTimeBase = lastcmd->time(); // needed to calculate already processed items
804 QTime newTimeBase = cmd->time();
805
806 auto it = std::make_reverse_iterator(m_command_list.end());
807 auto next = std::next(it);
808
809 while (next != std::make_reverse_iterator(m_command_list.begin())) {
810
811 if (newDepth < m_cumulativeUndoData.excludeFromMerge) {
812 ++it;
813 ++newDepth;
814 next = std::next(it);
815 continue;
816 }
817
818 int oldTime = (*it)->endTime().msecsTo(oldTimeBase);
819 int newTime = (*it)->endTime().msecsTo(newTimeBase);
820
825 if (oldTime > m_cumulativeUndoData.mergeTimeout &&
826 extraCheckDepth++ >= m_cumulativeUndoData.excludeFromMerge) break;
827
828 if (newTime >= m_cumulativeUndoData.mergeTimeout) {
829 bool merged = true;
830
831 KUndo2Command *debugOldCmd = *it;
832
833 it = tryMergeBack(it, &merged);
834
835 KUndo2Command *debugNewCmd = *it;
836
837 KIS_SAFE_ASSERT_RECOVER_BREAK(it != std::make_reverse_iterator(m_command_list.begin()));
838 KIS_SAFE_ASSERT_RECOVER_BREAK(debugOldCmd == debugNewCmd);
839
840 if (!merged) {
841 ++it;
842 ++newDepth;
843 }
844
845 } else {
846 ++it;
847 ++newDepth;
848 }
849
850 next = std::next(it);
851 }
852 }
853
854 if (try_merge && !macro && cur->canAnnihilateWith(cmd)) {
855 delete cmd;
856 if (!macro) {
857 // this condition must be ruled out by try_merge check
858 // otherwise we would have to do cleanup for the clean state
859 Q_ASSERT(m_clean_index != m_index);
860
861 delete m_command_list.takeLast();
862 m_index--;
863
864 Q_EMIT indexChanged(m_index);
865 Q_EMIT canUndoChanged(canUndo());
866 Q_EMIT undoTextChanged(undoText());
867 Q_EMIT canRedoChanged(canRedo());
868 Q_EMIT redoTextChanged(redoText());
869 } else {
870 delete m_macro_stack.takeLast();
871 }
872
873 } else if (try_merge && cur->mergeWith(cmd)) {
874 delete cmd;
875 if (!macro) {
876 Q_EMIT indexChanged(m_index);
877 Q_EMIT canUndoChanged(canUndo());
878 Q_EMIT undoTextChanged(undoText());
879 Q_EMIT canRedoChanged(canRedo());
880 Q_EMIT redoTextChanged(redoText());
881 }
882 } else {
883 if (macro) {
884 m_macro_stack.last()->d->child_list.append(cmd);
885 } else {
886 m_command_list.append(cmd);
887
889 setIndex(m_index + 1, false);
890 }
891 }
892}
893
906{
907 if (!m_macro_stack.isEmpty()) {
908 qWarning("KUndo2QStack::setClean(): cannot set clean in the middle of a macro");
909 return;
910 }
911
912 setIndex(m_index, true);
913}
914
922{
923 if (!m_macro_stack.isEmpty())
924 return false;
925 return m_clean_index == m_index;
926}
927
940{
941 return m_clean_index;
942}
943
955{
956 if (m_index == 0)
957 return;
958
959 if (!m_macro_stack.isEmpty()) {
960 qWarning("KUndo2QStack::undo(): cannot undo in the middle of a macro");
961 return;
962 }
963
964 int idx = m_index - 1;
965 m_command_list.at(idx)->undoMergedCommands();
966 setIndex(idx, false);
967}
968
980{
981 if (m_index == m_command_list.size())
982 return;
983
984 if (!m_macro_stack.isEmpty()) {
985 qWarning("KUndo2QStack::redo(): cannot redo in the middle of a macro");
986 return;
987 }
988
989 m_command_list.at(m_index)->redoMergedCommands();
990 setIndex(m_index + 1, false);
991}
992
1001{
1002 return m_command_list.size();
1003}
1004
1014{
1015 return m_index;
1016}
1017
1027{
1028 if (!m_macro_stack.isEmpty()) {
1029 qWarning("KUndo2QStack::setIndex(): cannot set index in the middle of a macro");
1030 return;
1031 }
1032
1033 if (idx < 0)
1034 idx = 0;
1035 else if (idx > m_command_list.size())
1036 idx = m_command_list.size();
1037
1038 int i = m_index;
1039 while (i < idx) {
1040 m_command_list.at(i++)->redoMergedCommands();
1042 }
1043 while (i > idx) {
1044 m_command_list.at(--i)->undoMergedCommands();
1046 }
1047
1048 setIndex(idx, false);
1049}
1050
1051
1059
1072{
1073 if (!m_macro_stack.isEmpty())
1074 return false;
1075 return m_index > 0;
1076}
1077
1090{
1091 if (!m_macro_stack.isEmpty())
1092 return false;
1093 return m_index < m_command_list.size();
1094}
1095
1103{
1104 if (!m_macro_stack.isEmpty()) {
1105 return QString();
1106 }
1107 if (m_index > 0 && m_command_list.count() >= m_index -1 && m_command_list.at(m_index - 1) != 0) {
1108 return m_command_list.at(m_index - 1)->actionText();
1109 }
1110 return QString();
1111}
1112
1120{
1121 if (!m_macro_stack.isEmpty())
1122 return QString();
1123 if (m_index < m_command_list.size())
1124 return m_command_list.at(m_index)->actionText();
1125 return QString();
1126}
1127
1128#ifndef QT_NO_ACTION
1129
1143QAction *KUndo2QStack::createUndoAction(QObject *parent) const
1144{
1145 KUndo2Action *result = new KUndo2Action(i18n("Undo %1"), i18nc("Default text for undo action", "Undo"), parent);
1146 result->setEnabled(canUndo());
1147 result->setPrefixedText(undoText());
1148 connect(this, SIGNAL(canUndoChanged(bool)),
1149 result, SLOT(setEnabled(bool)));
1150 connect(this, SIGNAL(undoTextChanged(QString)),
1151 result, SLOT(setPrefixedText(QString)));
1152 connect(result, SIGNAL(triggered()), this, SLOT(undo()));
1153 return result;
1154}
1155
1169QAction *KUndo2QStack::createRedoAction(QObject *parent) const
1170{
1171 KUndo2Action *result = new KUndo2Action(i18n("Redo %1"), i18nc("Default text for redo action", "Redo"), parent);
1172 result->setEnabled(canRedo());
1173 result->setPrefixedText(redoText());
1174 connect(this, SIGNAL(canRedoChanged(bool)),
1175 result, SLOT(setEnabled(bool)));
1176 connect(this, SIGNAL(redoTextChanged(QString)),
1177 result, SLOT(setPrefixedText(QString)));
1178 connect(result, SIGNAL(triggered()), this, SLOT(redo()));
1179 return result;
1180}
1181
1182#endif // QT_NO_ACTION
1183
1215{
1216 KUndo2Command *cmd = new KUndo2Command();
1217 cmd->setText(text);
1218
1219 if (m_macro_stack.isEmpty()) {
1220 while (m_index < m_command_list.size())
1221 delete m_command_list.takeLast();
1222 if (m_clean_index > m_index)
1223 m_clean_index = -1; // we've deleted the clean state
1224 m_command_list.append(cmd);
1225 } else {
1226 m_macro_stack.last()->d->child_list.append(cmd);
1227 }
1228 m_macro_stack.append(cmd);
1229
1230 if (m_macro_stack.count() == 1) {
1231 Q_EMIT canUndoChanged(false);
1232 Q_EMIT undoTextChanged(QString());
1233 Q_EMIT canRedoChanged(false);
1234 Q_EMIT redoTextChanged(QString());
1235 }
1236}
1237
1248{
1249 if (m_macro_stack.isEmpty()) {
1250 qWarning("KUndo2QStack::endMacro(): no matching beginMacro()");
1251 return;
1252 }
1253
1254 m_macro_stack.removeLast();
1255
1256 if (m_macro_stack.isEmpty()) {
1258 setIndex(m_index + 1, false);
1259 }
1260}
1261
1275{
1276 if (index < 0 || index >= m_command_list.count())
1277 return 0;
1278 return m_command_list.at(index);
1279}
1280
1287QString KUndo2QStack::text(int idx) const
1288{
1289 if (idx < 0 || idx >= m_command_list.size())
1290 return QString();
1291 return m_command_list.at(idx)->text().toString();
1292}
1293
1310{
1311 if (!m_command_list.isEmpty()) {
1312 qWarning("KUndo2QStack::setUndoLimit(): an undo limit can only be set when the stack is empty");
1313 return;
1314 }
1315
1316 if (limit == m_undo_limit)
1317 return;
1318 m_undo_limit = limit;
1320}
1321
1323{
1324 return m_undo_limit;
1325}
1326
1345{
1346#ifdef QT_NO_UNDOGROUP
1347 Q_UNUSED(active);
1348#else
1349 if (m_group != 0) {
1350 if (active)
1351 m_group->setActiveStack(this);
1352 else if (m_group->activeStack() == this)
1354 }
1355#endif
1356}
1357
1359{
1360#ifdef QT_NO_UNDOGROUP
1361 return true;
1362#else
1363 return m_group == 0 || m_group->activeStack() == this;
1364#endif
1365}
1370
1375
1380
1385
1386QAction* KUndo2Stack::createRedoAction(KisKActionCollection* actionCollection, const QString& actionName)
1387{
1388 QAction* action = KUndo2QStack::createRedoAction(actionCollection);
1389
1390 if (actionName.isEmpty()) {
1391 action->setObjectName(KStandardAction::name(KStandardAction::Redo));
1392 } else {
1393 action->setObjectName(actionName);
1394 }
1395
1396 action->setIcon(koIcon("edit-redo"));
1397 action->setIconText(i18n("Redo"));
1398 action->setShortcuts(KStandardShortcut::redo());
1399
1400 actionCollection->addAction(action->objectName(), action);
1401
1402 return action;
1403}
1404
1405QAction* KUndo2Stack::createUndoAction(KisKActionCollection* actionCollection, const QString& actionName)
1406{
1407 QAction* action = KUndo2QStack::createUndoAction(actionCollection);
1408
1409 if (actionName.isEmpty()) {
1410 action->setObjectName(KStandardAction::name(KStandardAction::Undo));
1411 } else {
1412 action->setObjectName(actionName);
1413 }
1414
1415 action->setIcon(koIcon("edit-undo"));
1416 action->setIconText(i18n("Undo"));
1417 action->setShortcuts(KStandardShortcut::undo());
1418
1419 actionCollection->addAction(action->objectName(), action);
1420
1421 return action;
1422}
1423
1481 KUndo2QStack(parent)
1482{
1483}
1484
1485#endif // QT_NO_UNDOSTACK
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
QString m_defaultText
void setPrefixedText(const QString &text)
KUndo2Action(const QString &textTemplate, const QString &defaultText, QObject *parent=0)
QString m_textTemplate
QList< KUndo2Command * > child_list
KUndo2MagicString text
QScopedPointer< KUndo2CommandExtraData > extraData
virtual bool mergeWith(const KUndo2Command *other)
virtual ~KUndo2Command()
virtual void undo()
void setText(const KUndo2MagicString &text)
const KUndo2Command * child(int index) const
int childCount() const
virtual void redoMergedCommands()
KUndo2MagicString text() const
KUndo2CommandPrivate * d
Definition kundo2stack.h:88
QVector< KUndo2Command * > m_mergeCommandsVector
virtual void redo()
virtual void setTimedID(int timedID)
virtual bool timedMergeWith(KUndo2Command *other)
virtual QTime time() const
QTime m_endOfCommand
virtual QTime endTime() const
virtual bool canAnnihilateWith(const KUndo2Command *other) const
QTime m_timeOfCreation
virtual QVector< KUndo2Command * > mergeCommandsVector() const
bool hasParent() const
KUndo2Command(KUndo2Command *parent=0)
KUndo2CommandExtraData * extraData() const
virtual bool isMerged() const
virtual int id() const
virtual void undoMergedCommands()
QString actionText() const
virtual int timedId() const
void setExtraData(KUndo2CommandExtraData *data)
The KUndo2Group class is a group of KUndo2QStack objects.
Definition kundo2group.h:57
void removeStack(KUndo2QStack *stack)
void setActiveStack(KUndo2QStack *stack)
KUndo2QStack * activeStack() const
QString toSecondaryString() const
The KUndo2QStack class is a stack of KUndo2Command objects.
QList< KUndo2Command * > m_command_list
void setUndoLimit(int limit)
QString redoText() const
virtual void setIndex(int idx)
void setCumulativeUndoData(const KisCumulativeUndoData &data)
QString undoText() const
void cleanChanged(bool clean)
void beginMacro(const KUndo2MagicString &text)
QList< KUndo2Command * > m_macro_stack
virtual void undo()
void setUseCumulativeUndoRedo(bool value)
KisCumulativeUndoData cumulativeUndoData()
bool checkUndoLimit()
bool canUndo() const
void redoTextChanged(const QString &redoActionText)
bool useCumulativeUndoRedo() const
void push(KUndo2Command *cmd)
int cleanIndex() const
void indexChanged(int idx)
void canUndoChanged(bool canUndo)
bool active
the active status of this stack.
QAction * createUndoAction(QObject *parent) const
~KUndo2QStack() override
bool isActive() const
bool canRedo() const
void setActive(bool active=true)
QString text(int idx) const
bool m_useCumulativeUndoRedo
void canRedoChanged(bool canRedo)
void undoTextChanged(const QString &undoActionText)
virtual void redo()
KisCumulativeUndoData m_cumulativeUndoData
QAction * createRedoAction(QObject *parent) const
virtual void notifySetIndexChangedOneCommand()
bool isClean() const
KUndo2QStack(QObject *parent=0)
int index() const
KUndo2Group * m_group
int count() const
int undoLimit
the maximum number of commands on this stack.
void purgeRedoState()
const KUndo2Command * command(int index) const
QAction * createRedoAction(KisKActionCollection *actionCollection, const QString &actionName=QString())
KUndo2Stack(QObject *parent=0)
QAction * createUndoAction(KisKActionCollection *actionCollection, const QString &actionName=QString())
A container for a set of QAction objects.
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
#define KIS_SAFE_ASSERT_RECOVER_BREAK(cond)
Definition kis_assert.h:127
#define koIcon(name)
Use these macros for icons without any issues.
Definition kis_icon.h:25
const char * name(StandardAction id)