📄 qtundo.cpp
字号:
time of the call was the same as it is now. More precisely, the edited object is in a clean state if the current QtUndoStack command is the same one as it was at the time of the last call to setClean(). \sa setClean() cleanChanged()*/bool QtUndoStack::isClean() const{ return m_have_clean_command && m_clean_command == commandAt(m_current_iter);}/*! \fn void QtUndoStack::cleanChanged(bool clean) This signal is emitted whenever the edited object enters or leaves the clean state. If \a clean is true, the edited object is currently clean; otherwise it is currently not clean. \sa isClean() setClean()*//*! Marks the state of the edited object as clean. This function is usually called whenever the edited object is saved. The cleanChanged() signal is emited whenever the edited object enters or leaves the clean state. \sa isClean() cleanChanged()*/void QtUndoStack::setClean(){ bool old_clean = isClean(); m_have_clean_command = true; m_clean_command = commandAt(m_current_iter); if (old_clean != isClean()) emit cleanChanged(isClean());}class QtUndoState{public: bool can_undo, can_redo, clean; QString undo_description, redo_description;};/*! \internal*/void QtUndoStack::beforeChange(QtUndoState &state){ state.clean = isClean(); state.can_undo = canUndo(); state.can_redo = canRedo(); state.undo_description = undoDescription(); state.redo_description = redoDescription();}/*! \internal*/void QtUndoStack::afterChange(const QtUndoState &state){ if (state.can_undo != canUndo()) emit canUndoChanged(canUndo()); if (state.can_redo != canRedo()) emit canRedoChanged(canRedo()); if (state.undo_description != undoDescription()) emit undoDescriptionChanged(undoDescription()); if (state.redo_description != redoDescription()) emit redoDescriptionChanged(redoDescription()); if (state.clean != isClean()) emit cleanChanged(isClean()); QtUndoManager::manager()->updateActions();}/*! \internal*/QtUndoStack::CommandIter QtUndoStack::findMacroBegin(CommandIter it) const{ int nest = 1; QtCommand *command = commandAt(it); Q_ASSERT(command != 0 && command->isMacroEnd()); do { --it; command = commandAt(it); Q_ASSERT(command != 0); if (command->isMacroBegin()) --nest; else if (command->isMacroEnd()) ++nest; Q_ASSERT(nest >= 0); } while (nest > 0 || !command->isMacroBegin()); return it;}/*! \internal*/QtUndoStack::CommandIter QtUndoStack::findMacroEnd(CommandIter it) const{ int nest = 1; QtCommand *command = commandAt(it); Q_ASSERT(command != 0 && command->isMacroBegin()); do { ++it; command = commandAt(it); Q_ASSERT(command != 0); if (command->isMacroEnd()) --nest; else if (command->isMacroBegin()) ++nest; Q_ASSERT(nest >= 0); } while (nest > 0 || !command->isMacroEnd()); return it;}/*! Pushes the \a command onto this stack or merges it with the current command, and calls the \a{command}'s QtCommand::redo() function to apply it. If the current command is not topmost on the stack, all commands above it are deleted. This function 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. If there is no current command on this stack, or \a command and the current command are of different types, or \a command's merge flag is false, or QtCommand::mergeMeWith() returns false, push() will push \a command onto the stack. \sa undo() redo() clear()*/void QtUndoStack::push(QtCommand *command){ QtUndoState state; beforeChange(state); command->redo(); // If the current command on the stack is not last, we delete all // commands that follow it before adding the new command. while (m_current_iter != size() - 1) { if (m_have_clean_command && commandAt(m_current_iter) == m_clean_command) { m_have_clean_command = false; m_clean_command = 0; } delete takeLast(); } QtCommand::Type t = command->type(); switch (t) { case QtCommand::Command: { // Either merge the new command with the current command, or append it to the // stack. QtCommand *current = commandAt(m_current_iter); if (command->canMerge() && current != 0 && current->metaObject() == command->metaObject() && (!m_have_clean_command || m_clean_command != current) && current->mergeMeWith(command)) delete command; else append(command); break; } case QtCommand::MacroBegin: append(command); ++m_macro_nest; break; case QtCommand::MacroEnd: if (m_macro_nest == 0) { qWarning("QtUndoStack::push(): MacroEnd without MacroBegin"); break; } append(command); --m_macro_nest; // Set the description to the corresponding MacroBegin's description CommandIter it = size() - 1; it = findMacroBegin(it); // I've just pushed the MacroEnd Q_ASSERT(it != -1); command->setDescription(commandAt(it)->description()); break; } m_current_iter = size() - 1; if (t != QtCommand::MacroBegin && m_macro_nest == 0) { ++m_num_commands; emit commandExecuted(); } afterChange(state);}/*! \fn bool QtUndoStack::canUndo() const Returns true if a command is available for undo; otherwise returns false. Undo is not possible if the stack is empty or if the bottom command on the stack has already been undone. \sa undo() canRedo()*/bool QtUndoStack::canUndo() const{ if (isEmpty()) return false; if (m_macro_nest > 0) return false; if (m_current_iter == -1) return false; return true;}/*! \fn bool QtUndoStack::canRedo() const Returns true if a command is available for redo; otherwise returns false. Redo is not possible if the stack is empty or if the top command on the stack has already been redone. \sa redo() canUndo()*/bool QtUndoStack::canRedo() const{ if (m_macro_nest > 0) return false; if (m_current_iter == size() - 1) return false; return true;}/*! \internal*/void QtUndoStack::undoMacro(){ Q_ASSERT(m_macro_nest == 0); Q_ASSERT(m_current_iter != -1); Q_ASSERT(commandAt(m_current_iter)->type() == QtCommand::MacroEnd); int nest = 1; QtCommand *command = 0; do { --m_current_iter; command = commandAt(m_current_iter); Q_ASSERT(command != 0); if (command->isMacroBegin()) --nest; else if (command->isMacroEnd()) ++nest; Q_ASSERT(nest >= 0); command->undo(); } while (nest > 0 || !command->isMacroBegin());}/*! \internal*/void QtUndoStack::redoMacro(){ Q_ASSERT(m_macro_nest == 0); Q_ASSERT(m_current_iter != -1); Q_ASSERT(commandAt(m_current_iter)->type() == QtCommand::MacroBegin); int nest = 1; QtCommand *command = 0; do { ++m_current_iter; command = commandAt(m_current_iter); Q_ASSERT(command != 0); if (command->isMacroBegin()) ++nest; else if (command->isMacroEnd()) --nest; Q_ASSERT(nest >= 0); command->redo(); } while (!command->isMacroEnd() || nest > 0);}/*! If the current command's \link QtCommand::type() type()\endlink is \c Command, calls the current command's \link QtCommand::undo() undo()\endlink function and moves the current position one command down the stack. If the current command's \link QtCommand::type() type()\endlink is \c MacroEnd, traverses the stack downwards calling each command's \link QtCommand::undo() undo()\endlink, until a command of type \c MacroBegin is found. The current position is then set to one command below the macro begin marker. This process is repeated \a count times. \a count defaults to 1. \sa push() redo() canUndo()*/void QtUndoStack::undo(int count){ QtUndoState state; beforeChange(state); int i = 0; for (; i < count; ++i) { if (!canUndo()) { qWarning("QtUndoStack::undo(): can't undo"); break; } QtCommand *command = commandAt(m_current_iter); Q_ASSERT(!command->isMacroBegin()); if (command->isCommand()) command->undo(); else undoMacro(); --m_current_iter; } if (i > 0) { afterChange(state); emit commandExecuted(); }}/*! If the current command's \link QtCommand::type() type()\endlink is \c Command, moves the current position one command up in the stack and calls the new current command's \link QtCommand::redo() redo()\endlink. If the current command's \link QtCommand::type() type()\endlink is \c MacroBegin, traverses the stack upwards calling each command's \link QtCommand::redo() redo()\endlink, until a command of type \c MacroEnd is found. The current position remains at this command. This process is repeated \a count times. \a count defaults to 1. \sa push() undo() canRedo()*/void QtUndoStack::redo(int count){ QtUndoState state; beforeChange(state); int i = 0; for (; i < count; ++i) { if (!canRedo()) { qWarning("QtUndoStack::redo(): can't redo"); break; } ++m_current_iter; QtCommand *command = commandAt(m_current_iter); Q_ASSERT(!command->isMacroEnd()); if (command->isCommand()) command->redo(); else redoMacro(); } if (i > 0) { afterChange(state); emit commandExecuted(); }}/*! Returns the \link QtCommand::description() description()\endlink of the current command on the stack, or an empty string if there is no current command. \sa QtUndoManager::undoDescription() QtCommand::description() redoDescription()*/QString QtUndoStack::undoDescription() const{ if (canUndo()) return commandAt(m_current_iter)->description(); else return QString();}/*! Returns the \link QtCommand::description() description()\endlink for the command preceding the current command on the stack, or an empty string if the current command is at the top. \sa QtUndoManager::redoDescription() QtCommand::description() undoDescription()*/QString QtUndoStack::redoDescription() const{ if (canRedo()) return commandAt(m_current_iter + 1)->description();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -