Qt 4.8
qundostack.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QtCore/qdebug.h>
43 #include "qundostack.h"
44 #include "qundogroup.h"
45 #include "qundostack_p.h"
46 
47 #ifndef QT_NO_UNDOCOMMAND
48 
50 
116 {
117  d = new QUndoCommandPrivate;
118  if (parent != 0)
119  parent->d->child_list.append(this);
120  setText(text);
121 }
122 
134 {
135  d = new QUndoCommandPrivate;
136  if (parent != 0)
137  parent->d->child_list.append(this);
138 }
139 
147 {
149  delete d;
150 }
151 
167 int QUndoCommand::id() const
168 {
169  return -1;
170 }
171 
192 {
193  Q_UNUSED(command);
194  return false;
195 }
196 
209 {
210  for (int i = 0; i < d->child_list.size(); ++i)
211  d->child_list.at(i)->redo();
212 }
213 
227 {
228  for (int i = d->child_list.size() - 1; i >= 0; --i)
229  d->child_list.at(i)->undo();
230 }
231 
242 {
243  return d->text;
244 }
245 
262 {
263  return d->actionText;
264 }
265 
282 {
283  int cdpos = text.indexOf(QLatin1Char('\n'));
284  if (cdpos > 0) {
285  d->text = text.left(cdpos);
286  d->actionText = text.mid(cdpos + 1);
287  } else {
288  d->text = text;
289  d->actionText = text;
290  }
291 }
292 
305 {
306  return d->child_list.count();
307 }
308 
321 {
322  if (index < 0 || index >= d->child_list.count())
323  return 0;
324  return d->child_list.at(index);
325 }
326 
327 #endif // QT_NO_UNDOCOMMAND
328 
329 #ifndef QT_NO_UNDOSTACK
330 
411 #ifndef QT_NO_ACTION
412 
413 QUndoAction::QUndoAction(const QString &prefix, QObject *parent)
414  : QAction(parent)
415 {
416  m_prefix = prefix;
417 }
418 
420 {
421  if (m_defaultText.isEmpty()) {
422  QString s = m_prefix;
423  if (!m_prefix.isEmpty() && !text.isEmpty())
424  s.append(QLatin1Char(' '));
425  s.append(text);
426  setText(s);
427  } else {
428  if (text.isEmpty())
430  else
431  setText(m_prefix.arg(text));
432  }
433 }
434 
435 void QUndoAction::setTextFormat(const QString &textFormat, const QString &defaultText)
436 {
437  m_prefix = textFormat;
438  m_defaultText = defaultText;
439 }
440 
441 #endif // QT_NO_ACTION
442 
451 void QUndoStackPrivate::setIndex(int idx, bool clean)
452 {
453  Q_Q(QUndoStack);
454 
455  bool was_clean = index == clean_index;
456 
457  if (idx != index) {
458  index = idx;
459  emit q->indexChanged(index);
460  emit q->canUndoChanged(q->canUndo());
461  emit q->undoTextChanged(q->undoText());
462  emit q->canRedoChanged(q->canRedo());
463  emit q->redoTextChanged(q->redoText());
464  }
465 
466  if (clean)
467  clean_index = index;
468 
469  bool is_clean = index == clean_index;
470  if (is_clean != was_clean)
471  emit q->cleanChanged(is_clean);
472 }
473 
485 {
486  if (undo_limit <= 0 || !macro_stack.isEmpty() || undo_limit >= command_list.count())
487  return false;
488 
489  int del_count = command_list.count() - undo_limit;
490 
491  for (int i = 0; i < del_count; ++i)
492  delete command_list.takeFirst();
493 
494  index -= del_count;
495  if (clean_index != -1) {
496  if (clean_index < del_count)
497  clean_index = -1; // we've deleted the clean command
498  else
499  clean_index -= del_count;
500  }
501 
502  return true;
503 }
504 
514  : QObject(*(new QUndoStackPrivate), parent)
515 {
516 #ifndef QT_NO_UNDOGROUP
517  if (QUndoGroup *group = qobject_cast<QUndoGroup*>(parent))
518  group->addStack(this);
519 #endif
520 }
521 
530 {
531 #ifndef QT_NO_UNDOGROUP
532  Q_D(QUndoStack);
533  if (d->group != 0)
534  d->group->removeStack(this);
535 #endif
536  clear();
537 }
538 
553 {
554  Q_D(QUndoStack);
555 
556  if (d->command_list.isEmpty())
557  return;
558 
559  bool was_clean = isClean();
560 
561  d->macro_stack.clear();
562  qDeleteAll(d->command_list);
563  d->command_list.clear();
564 
565  d->index = 0;
566  d->clean_index = 0;
567 
568  emit indexChanged(0);
569  emit canUndoChanged(false);
571  emit canRedoChanged(false);
573 
574  if (!was_clean)
575  emit cleanChanged(true);
576 }
577 
602 {
603  Q_D(QUndoStack);
604  cmd->redo();
605 
606  bool macro = !d->macro_stack.isEmpty();
607 
608  QUndoCommand *cur = 0;
609  if (macro) {
610  QUndoCommand *macro_cmd = d->macro_stack.last();
611  if (!macro_cmd->d->child_list.isEmpty())
612  cur = macro_cmd->d->child_list.last();
613  } else {
614  if (d->index > 0)
615  cur = d->command_list.at(d->index - 1);
616  while (d->index < d->command_list.size())
617  delete d->command_list.takeLast();
618  if (d->clean_index > d->index)
619  d->clean_index = -1; // we've deleted the clean state
620  }
621 
622  bool try_merge = cur != 0
623  && cur->id() != -1
624  && cur->id() == cmd->id()
625  && (macro || d->index != d->clean_index);
626 
627  if (try_merge && cur->mergeWith(cmd)) {
628  delete cmd;
629  if (!macro) {
630  emit indexChanged(d->index);
635  }
636  } else {
637  if (macro) {
638  d->macro_stack.last()->d->child_list.append(cmd);
639  } else {
640  d->command_list.append(cmd);
641  d->checkUndoLimit();
642  d->setIndex(d->index + 1, false);
643  }
644  }
645 }
646 
659 {
660  Q_D(QUndoStack);
661  if (!d->macro_stack.isEmpty()) {
662  qWarning("QUndoStack::setClean(): cannot set clean in the middle of a macro");
663  return;
664  }
665 
666  d->setIndex(d->index, true);
667 }
668 
676 {
677  Q_D(const QUndoStack);
678  if (!d->macro_stack.isEmpty())
679  return false;
680  return d->clean_index == d->index;
681 }
682 
695 {
696  Q_D(const QUndoStack);
697  return d->clean_index;
698 }
699 
711 {
712  Q_D(QUndoStack);
713  if (d->index == 0)
714  return;
715 
716  if (!d->macro_stack.isEmpty()) {
717  qWarning("QUndoStack::undo(): cannot undo in the middle of a macro");
718  return;
719  }
720 
721  int idx = d->index - 1;
722  d->command_list.at(idx)->undo();
723  d->setIndex(idx, false);
724 }
725 
737 {
738  Q_D(QUndoStack);
739  if (d->index == d->command_list.size())
740  return;
741 
742  if (!d->macro_stack.isEmpty()) {
743  qWarning("QUndoStack::redo(): cannot redo in the middle of a macro");
744  return;
745  }
746 
747  d->command_list.at(d->index)->redo();
748  d->setIndex(d->index + 1, false);
749 }
750 
758 int QUndoStack::count() const
759 {
760  Q_D(const QUndoStack);
761  return d->command_list.size();
762 }
763 
772 int QUndoStack::index() const
773 {
774  Q_D(const QUndoStack);
775  return d->index;
776 }
777 
786 void QUndoStack::setIndex(int idx)
787 {
788  Q_D(QUndoStack);
789  if (!d->macro_stack.isEmpty()) {
790  qWarning("QUndoStack::setIndex(): cannot set index in the middle of a macro");
791  return;
792  }
793 
794  if (idx < 0)
795  idx = 0;
796  else if (idx > d->command_list.size())
797  idx = d->command_list.size();
798 
799  int i = d->index;
800  while (i < idx)
801  d->command_list.at(i++)->redo();
802  while (i > idx)
803  d->command_list.at(--i)->undo();
804 
805  d->setIndex(idx, false);
806 }
807 
820 {
821  Q_D(const QUndoStack);
822  if (!d->macro_stack.isEmpty())
823  return false;
824  return d->index > 0;
825 }
826 
839 {
840  Q_D(const QUndoStack);
841  if (!d->macro_stack.isEmpty())
842  return false;
843  return d->index < d->command_list.size();
844 }
845 
853 {
854  Q_D(const QUndoStack);
855  if (!d->macro_stack.isEmpty())
856  return QString();
857  if (d->index > 0)
858  return d->command_list.at(d->index - 1)->actionText();
859  return QString();
860 }
861 
869 {
870  Q_D(const QUndoStack);
871  if (!d->macro_stack.isEmpty())
872  return QString();
873  if (d->index < d->command_list.size())
874  return d->command_list.at(d->index)->actionText();
875  return QString();
876 }
877 
878 #ifndef QT_NO_ACTION
879 
895 {
896  QUndoAction *result = new QUndoAction(prefix, parent);
897  if (prefix.isEmpty())
898  result->setTextFormat(tr("Undo %1"), tr("Undo", "Default text for undo action"));
899 
900  result->setEnabled(canUndo());
901  result->setPrefixedText(undoText());
902  connect(this, SIGNAL(canUndoChanged(bool)),
903  result, SLOT(setEnabled(bool)));
905  result, SLOT(setPrefixedText(QString)));
906  connect(result, SIGNAL(triggered()), this, SLOT(undo()));
907  return result;
908 }
909 
925 {
926  QUndoAction *result = new QUndoAction(prefix, parent);
927  if (prefix.isEmpty())
928  result->setTextFormat(tr("Redo %1"), tr("Redo", "Default text for redo action"));
929 
930  result->setEnabled(canRedo());
931  result->setPrefixedText(redoText());
932  connect(this, SIGNAL(canRedoChanged(bool)),
933  result, SLOT(setEnabled(bool)));
935  result, SLOT(setPrefixedText(QString)));
936  connect(result, SIGNAL(triggered()), this, SLOT(redo()));
937  return result;
938 }
939 
940 #endif // QT_NO_ACTION
941 
973 {
974  Q_D(QUndoStack);
975  QUndoCommand *cmd = new QUndoCommand();
976  cmd->setText(text);
977 
978  if (d->macro_stack.isEmpty()) {
979  while (d->index < d->command_list.size())
980  delete d->command_list.takeLast();
981  if (d->clean_index > d->index)
982  d->clean_index = -1; // we've deleted the clean state
983  d->command_list.append(cmd);
984  } else {
985  d->macro_stack.last()->d->child_list.append(cmd);
986  }
987  d->macro_stack.append(cmd);
988 
989  if (d->macro_stack.count() == 1) {
990  emit canUndoChanged(false);
992  emit canRedoChanged(false);
994  }
995 }
996 
1007 {
1008  Q_D(QUndoStack);
1009  if (d->macro_stack.isEmpty()) {
1010  qWarning("QUndoStack::endMacro(): no matching beginMacro()");
1011  return;
1012  }
1013 
1014  d->macro_stack.removeLast();
1015 
1016  if (d->macro_stack.isEmpty()) {
1017  d->checkUndoLimit();
1018  d->setIndex(d->index + 1, false);
1019  }
1020 }
1021 
1038 {
1039  Q_D(const QUndoStack);
1040 
1041  if (index < 0 || index >= d->command_list.count())
1042  return 0;
1043  return d->command_list.at(index);
1044 }
1045 
1053 {
1054  Q_D(const QUndoStack);
1055 
1056  if (idx < 0 || idx >= d->command_list.size())
1057  return QString();
1058  return d->command_list.at(idx)->text();
1059 }
1060 
1080 {
1081  Q_D(QUndoStack);
1082 
1083  if (!d->command_list.isEmpty()) {
1084  qWarning("QUndoStack::setUndoLimit(): an undo limit can only be set when the stack is empty");
1085  return;
1086  }
1087 
1088  if (limit == d->undo_limit)
1089  return;
1090  d->undo_limit = limit;
1091  d->checkUndoLimit();
1092 }
1093 
1094 int QUndoStack::undoLimit() const
1095 {
1096  Q_D(const QUndoStack);
1097 
1098  return d->undo_limit;
1099 }
1100 
1122 {
1123 #ifdef QT_NO_UNDOGROUP
1124  Q_UNUSED(active);
1125 #else
1126  Q_D(QUndoStack);
1127 
1128  if (d->group != 0) {
1129  if (active)
1130  d->group->setActiveStack(this);
1131  else if (d->group->activeStack() == this)
1132  d->group->setActiveStack(0);
1133  }
1134 #endif
1135 }
1136 
1138 {
1139 #ifdef QT_NO_UNDOGROUP
1140  return true;
1141 #else
1142  Q_D(const QUndoStack);
1143  return d->group == 0 || d->group->activeStack() == this;
1144 #endif
1145 }
1146 
1222 
1223 #endif // QT_NO_UNDOSTACK
double d
Definition: qnumeric_p.h:62
QString text(int idx) const
Returns the text of the command at index idx.
void clear()
Clears the command stack by deleting all commands on it, and returns the stack to the clean state...
Definition: qundostack.cpp:552
void indexChanged(int idx)
This signal is emitted whenever a command modifies the state of the document.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void setText(const QString &text)
Sets the command&#39;s text to be the text specified.
Definition: qundostack.cpp:281
virtual bool mergeWith(const QUndoCommand *other)
Attempts to merge this command with command.
Definition: qundostack.cpp:191
#define SLOT(a)
Definition: qobjectdefs.h:226
QList< QUndoCommand * > child_list
Definition: qundostack_p.h:71
const QUndoCommand * command(int index) const
Returns a const pointer to the command at index.
virtual void redo()
Applies a change to the document.
Definition: qundostack.cpp:208
void redoTextChanged(const QString &redoText)
This signal is emitted whenever the value of redoText() changes.
void undo()
Undoes the command below the current command by calling QUndoCommand::undo().
Definition: qundostack.cpp:710
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
void setActive(bool active=true)
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
void canUndoChanged(bool canUndo)
This signal is emitted whenever the value of canUndo() changes.
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
void setEnabled(bool)
Definition: qaction.cpp:1192
QString redoText() const
Returns the text of the command which will be redone in the next call to redo().
Definition: qundostack.cpp:868
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
#define Q_Q(Class)
Definition: qglobal.h:2483
virtual ~QUndoCommand()
Destroys the QUndoCommand object and all child commands.
Definition: qundostack.cpp:146
void setTextFormat(const QString &textFormat, const QString &defaultText)
Definition: qundostack.cpp:435
const QUndoCommand * child(int index) const
Returns the child command at index.
Definition: qundostack.cpp:320
The QUndoGroup class is a group of QUndoStack objects.
Definition: qundogroup.h:60
#define SIGNAL(a)
Definition: qobjectdefs.h:227
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QString m_defaultText
Definition: qundostack_p.h:107
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
void endMacro()
Ends composition of a macro command.
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
QUndoCommand(QUndoCommand *parent=0)
Constructs a QUndoCommand object with parent parent.
Definition: qundostack.cpp:133
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
void push(QUndoCommand *cmd)
Pushes cmd on the stack or merges it with the most recently executed command.
Definition: qundostack.cpp:601
Q_CORE_EXPORT void qWarning(const char *,...)
void setText(const QString &text)
Definition: qaction.cpp:860
QAction * createRedoAction(QObject *parent, const QString &prefix=QString()) const
Creates an redo QAction object with the given parent.
Definition: qundostack.cpp:924
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
int childCount() const
Returns the number of child commands in this command.
Definition: qundostack.cpp:304
QString undoText() const
Returns the text of the command which will be undone in the next call to undo().
Definition: qundostack.cpp:852
The QUndoStack class is a stack of QUndoCommand objects.
Definition: qundostack.h:91
void beginMacro(const QString &text)
Begins composition of a macro command with the given text description.
Definition: qundostack.cpp:972
virtual void undo()
Reverts a change to the document.
Definition: qundostack.cpp:226
void undoTextChanged(const QString &undoText)
This signal is emitted whenever the value of undoText() changes.
bool active
the active status of this stack.
Definition: qundostack.h:95
int undoLimit() const
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
bool checkUndoLimit()
If the number of commands on the stack exceedes the undo limit, deletes commands from the bottom of t...
Definition: qundostack.cpp:484
QString & append(QChar c)
Definition: qstring.cpp:1777
void setClean()
Marks the stack as clean and emits cleanChanged() if the stack was not already clean.
Definition: qundostack.cpp:658
QUndoCommandPrivate * d
Definition: qundostack.h:62
QString text() const
QAction * createUndoAction(QObject *parent, const QString &prefix=QString()) const
Creates an undo QAction object with the given parent.
Definition: qundostack.cpp:894
int cleanIndex() const
Returns the clean index.
Definition: qundostack.cpp:694
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
T & last()
Returns a reference to the last item in the list.
Definition: qlist.h:284
void setPrefixedText(const QString &text)
Definition: qundostack.cpp:419
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
void canRedoChanged(bool canRedo)
This signal is emitted whenever the value of canRedo() changes.
QString m_prefix
Definition: qundostack_p.h:106
int count() const
Returns the number of commands on the stack.
Definition: qundostack.cpp:758
bool isClean() const
If the stack is in the clean state, returns true; otherwise returns false.
Definition: qundostack.cpp:675
void setIndex(int idx)
Repeatedly calls undo() or redo() until the current command index reaches idx.
Definition: qundostack.cpp:786
quint16 index
void setIndex(int idx, bool clean)
Sets the current index to idx, emitting appropriate signals.
Definition: qundostack.cpp:451
bool canUndo() const
Returns true if there is a command available for undo; otherwise returns false.
Definition: qundostack.cpp:819
QUndoStack(QObject *parent=0)
Constructs an empty undo stack with the parent parent.
Definition: qundostack.cpp:513
bool canRedo() const
Returns true if there is a command available for redo; otherwise returns false.
Definition: qundostack.cpp:838
void cleanChanged(bool clean)
This signal is emitted whenever the stack enters or leaves the clean state.
QUndoAction(const QString &prefix, QObject *parent=0)
Definition: qundostack.cpp:413
void setUndoLimit(int limit)
void redo()
Redoes the current command by calling QUndoCommand::redo().
Definition: qundostack.cpp:736
int index() const
Returns the index of the current command.
Definition: qundostack.cpp:772
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
~QUndoStack()
Destroys the undo stack, deleting any commands that are on it.
Definition: qundostack.cpp:529
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
The QUndoCommand class is the base class of all commands stored on a QUndoStack.
Definition: qundostack.h:60
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
virtual int id() const
Returns the ID of this command.
Definition: qundostack.cpp:167
bool isActive() const
The QAction class provides an abstract user interface action that can be inserted into widgets...
Definition: qaction.h:64
QString text() const
Returns a short text string describing what this command does; for example, "insert text"...
Definition: qundostack.cpp:241
#define text
Definition: qobjectdefs.h:80
QString actionText() const
Returns a short text string describing what this command does; for example, "insert text"...
Definition: qundostack.cpp:261