📄 qtundo.cpp
字号:
/******************************************************************************** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.**** This file is part of the Qt Designer of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include <QApplication>#include <QAction>#include <qalgorithms.h>#include <QtCore/qdebug.h>#include "qtundo_p.h"Q_GLOBAL_STATIC(QtUndoManager, g_manager)class UndoRedoAction : public QAction{ Q_OBJECTpublic: UndoRedoAction(QObject *parent) : QAction(parent) {}public slots: // It's a pity QAction::setText() is not a slot... void setTextSlot(const QString &text) { setText(text); }};/*! \class QtCommand \brief The QtCommand class is the base class of all commands stored on a QtUndoStack. For an overview of the Qt Undo/Redo framework, see the \link overview.html overview\endlink. A QtCommand represents a single editing action which an application can make, for example, inserting or deleting a block of text in a text editor. QtCommand knows how to apply a change to an object and how to undo the change. A change is applied by calling redo(). A change is undone by calling undo(). The default implementations of these virtual functions in QtCommand do nothing, they must be overriden in a derived class. \code CmdChangeImage::CmdChangeImage(Face *face, const QString &image) { m_face = face; m_old_image = face->image(); m_new_image = image; setCanMerge(false); setDescription(tr("change %1 to %2").arg(m_old_image).arg(m_new_image)); } void CmdChangeImage::redo() { m_face->setImage(m_new_image); } void CmdChangeImage::undo() { m_face->setImage(m_old_image); } \endcode A QtCommand object has a type(), which is used to differentiate between ordinary commands and macro delimiters. An ordinary command is of type() \c Command. A macro delimiter's type() is either \c MacroBegin or \c MacroEnd. Sequences of commands between macro delimiters are undone and redone in one go, rather than one at a time. Each QtCommand has a merge flag, returned by canMerge(). QtUndoStack::push() will attempt to merge a new command with the current command in the stack only if they are both instances of the same class (ascertained using QObject::className()) \e and if the new command's merge flag is true. A QtCommand object has a description(), which describes its effect on the edited object. This description is used to give human-readable information to the widgets which trigger undo or redo in an application, such as the QAction objects returned by QtUndoManager::createUndoAction() and QtUndoManager::createRedoAction(). \warning All classes derived from QtCommand must contain the \c Q_OBJECT macro in their declaration. \sa QtUndoStack QtUndoManager*//*! \enum QtCommand::Type This enumerated type is used by QtCommand to differentiate between ordinary commands and macro delimiters. \value Command The command is a normal command which applies a change to an object. \value MacroBegin The command marks the start of a macro sequence. \value MacroEnd The command marks the end of a macro sequence.*//*! Constructs a QtCommand object with \a description and the merge flag set to \a canMerge. The command type is set to \c Command. This is the preferred constructor for commands which are not macro delimiters. \sa description() canMerge()*/QtCommand::QtCommand(const QString &description, bool canMerge){ setDescription(description); setCanMerge(canMerge); m_type = Command;}/*! Constructs a QtCommand object of the given \a type, with a \a description and the merge flag set to \a canMerge. This is the preferred constructor for macro delimiters. \sa QtCommand::Type description() canMerge()*/QtCommand::QtCommand(Type type, const QString &description, bool canMerge){ setDescription(description); setCanMerge(canMerge); m_type = type;}/*! \fn QtCommand::Type QtCommand::type() const Returns the type of this command.*//*! \fn bool QtCommand::isMacroBegin() const Returns true if the command is a macro start delimiter; otherwise returns false. \sa QtCommand::Type type()*//*! \fn bool QtCommand::isMacroEnd() const Returns true if the command is a macro end delimiter; otherwise returns false. \sa QtCommand::Type type()*//*! \fn bool QtCommand::isCommand() const Returns true if the command is an ordinary editing command; otherwise returns false. \sa QtCommand::Type type()*//*! \fn QString QtCommand::description() const Returns a string which describes the effect of this command on the edited object. Typical examples include "typing", "delete block", "change font", etc. This description is used to assign human-readable information to the widgets which trigger undo or redo in an application, such as the QAction objects returned by QtUndoManager::createUndoAction() and QtUndoManager::createRedoAction(). \sa setDescription() QtUndoStack::undoDescription() QtUndoStack::redoDescription() QtUndoManager::undoDescription() QtUndoManager::redoDescription()*//*! \fn void QtCommand::setDescription(const QString &s) Sets the description of this command to \a s. \sa description()*//*! \fn bool QtCommand::canMerge() const Returns the command's merge flag. QtUndoStack::push() will attempt to merge a new command with the command on top of the stack only if they are both instances of the same class (ascertained using QObject::className()) \e and if the new command's merge flag is true. \sa setCanMerge() mergeMeWith()*//*! \fn void QtCommand::setCanMerge(bool b) Sets the merge flag for this command to \a b. \sa canMerge() mergeMeWith()*//*! \fn bool QtCommand::mergeMeWith(QtCommand *other) Attempts to merge the \a other command into this command. Returns true if it succeeds; otherwise returns false. If this function returns false, QtUndoStack::push() will push the \a other command on top of the stack. The default implementation does nothing and returns false. This function must be reimplemented in each derived command class which sets its merge flag to true. \code CmdChangeColor::CmdChangeColor(Face *face, const QString &color) { ... setCanMerge(true); ... } bool CmdChangeColor::mergeMeWith(QtCommand *c) { CmdChangeColor *other = (CmdChangeColor*) c; if (m_face != other->m_face) return false; m_new_color = other->m_new_color; setDescription(tr("change %1 to %2").arg(m_old_color).arg(m_new_color)); return true; } \endcode \sa canMerge() setCanMerge()*/bool QtCommand::mergeMeWith(QtCommand *){ return false;}QtMultiCommand::QtMultiCommand(const QString &description) : QtCommand(Command, description, false){}QtMultiCommand::QtMultiCommand(const QList<QtCommand*> &command_list, const QString &description) : QtCommand(Command, description, false), m_command_list(command_list){}QtMultiCommand::~QtMultiCommand(){ while (!m_command_list.isEmpty()) delete m_command_list.takeLast();}void QtMultiCommand::append(QtCommand *command){ m_command_list.append(command);}QtCommand *QtMultiCommand::command(int i) const{ return m_command_list.at(i);}int QtMultiCommand::count() const{ return m_command_list.size();}void QtMultiCommand::redo(){ for (int i = 0; i < m_command_list.size(); ++i) m_command_list.at(i)->redo();}void QtMultiCommand::undo(){ for (int i = m_command_list.size() - 1; i >= 0; --i) m_command_list.at(i)->undo();}/*! \fn void QtCommand::redo() This virtual function must be reimplemented by subclasses to apply changes. \sa undo()*//*! \fn void QtCommand::undo() This virtual function must be reimplemented by subclasses to undo the changes applied by redo(). Calling redo() and then undo() should leave the edited object unmodified.*//*! \class QtUndoStack \brief The QtUndoStack class is a stack of QtCommand objects. For an overview of the Qt Undo/Redo framework, see the \link overview.html overview\endlink. New commands are added with push(). When a command is pushed on to the stack, QtUndoStack takes ownership of the command and applies it by calling QtCommand::redo(). Undo and redo are invoked with undo() and redo(). These functions may be called directly, or through the QtUndoManager::undoAction() and QtUndoManager::redoAction() QAction objects. In the latter case, QtUndoManager will choose a stack based on which object has the focus, and call the relevant undo() or redo() function. \code FaceEdit::FaceEdit(QWidget *parent, const char *name) : QWidget(parent, name, Qt::WDestructiveClose) { ... m_undo_stack = new QtUndoStack(this); ... } void FaceEdit::setImage(const QString &image_name) { Face *face = focusedFace(); ... m_undo_stack->push(new CmdChangeImage(face, image_name)); ... } \endcode QtUndoStack supports command compression. This is useful when several commands can be compressed into a single command, which can be undone and redone in one go. For example, in a text editor, when the user types in a character, a new action is created, which inserts that character into the document at the cursor position. However, it is more convenient for the user to be able to undo or redo typing in whole words, sentences, and paragraphs. Command compression allows these single-character commands to be merged into a single command which inserts or deletes chunks of text. See push() for more information on command compression. QtUndoStack supports command macros. A command macro is a sequence of commands which are undone and redone in one go. The sequence starts with a QtCommand object whose \link QtCommand::type() type()\endlink is \link QtCommand::MacroBegin MacroBegin\endlink. The \link QtCommand::description() description()\endlink of this command is taken to describe the effect of the entire macro. The sequence ends with a QtCommand object whose \link QtCommand::type() type()\endlink is \link QtCommand::MacroEnd MacroEnd\endlink. See undo() and redo() for more information on command macros. \code void FaceEdit::clearFaces() { ... m_undo_stack->push(new QtCommand(QtCommand::MacroBegin, "Clear faces")); for (; *child_it != 0; ++child_it) { Face *face = (Face*) *child_it; m_undo_stack->push(new CmdChangeImage(face, "none")); m_undo_stack->push(new CmdChangeColor(face, "green")); } m_undo_stack->push(new QtCommand(QtCommand::MacroEnd)); ... } \endcode A certain state of the edited object may be marked as "clean", using setClean(). This function is usually called whenever the edited object is saved. QtUndoStack emits the cleanChanged() signal whenever the edited object enters or leaves the clean state. \sa QtCommand QtUndoManager*//*! Constructs a QtUndoStack object. \a parent and \a name are passed to the QObject constructor. Additionally, \a parent is registered as the target for the newly created stack. When \a parent has the focus the QtUndoManager will use this undo stack for its undo() and redo() actions.*/QtUndoStack::QtUndoStack(QObject *parent) : QObject(parent), m_current_iter(-1){ QtUndoManager *manager = QtUndoManager::manager(); connect(this, SIGNAL(destroyed(QObject*)), manager, SLOT(stackDestroyed(QObject*))); manager->associateView(parent, this); m_macro_nest = 0; m_num_commands = 0; m_clean_command = 0; // the initial empty stack is clean m_have_clean_command = true;}/*! \internal*/QtCommand *QtUndoStack::commandAt(CommandIter it) const{ if (it == -1) return 0; return at(it);}/*! Returns true if the edited object is in a clean state; otherwise returns false. The edited object is in a clean state if setClean() was previously called and the state of the edited object at the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -