Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example tools/undoframework
++ \title Undo Framework Example
++ \examplecategory {Data Processing & I/O}
++ \ingroup examples-widgets-tools
++
++ \brief This example shows how to implement undo/redo functionality
++ with the Qt undo framework.
++
++ \image undoframeworkexample.png The Undo Diagram Example
++
++ In the Qt undo framework, all actions that the user performs are
++ implemented in classes that inherit QUndoCommand. An undo command
++ class knows how to both \l{QUndoCommand::}{redo()} - or just do
++ the first time - and \l{QUndoCommand::}{undo()} an action. For
++ each action the user performs, a command is placed on a
++ QUndoStack. Since the stack contains all commands executed
++ (stacked in chronological order) on the document, it can roll the
++ state of the document backwards and forwards by undoing and redoing
++ its commands. See the \l{Overview of Qt's Undo Framework}{overview
++ document} for a high-level introduction to the undo framework.
++
++ The undo example implements a simple diagram application. It is
++ possible to add and delete items, which are either box or
++ rectangular shaped, and move the items by dragging them with the
++ mouse. The undo stack is shown in a QUndoView, which is a list in
++ which the commands are shown as list items. Undo and redo are
++ available through the edit menu. The user can also select a command
++ from the undo view.
++
++ We use the \l{Graphics View Framework}{graphics view
++ framework} to implement the diagram. We only treat the related
++ code briefly as the framework has examples of its own (e.g., the
++ \l{Diagram Scene Example}).
++
++ The example consists of the following classes:
++
++ \list
++ \li \c MainWindow is the main window and arranges the
++ example's widgets. It creates the commands based
++ on user input and keeps them on the command stack.
++ \li \c AddCommand adds an item to the scene.
++ \li \c DeleteCommand deletes an item from the scene.
++ \li \c MoveCommand when an item is moved the MoveCommand keeps record
++ of the start and stop positions of the move, and it
++ moves the item according to these when \c redo() and \c undo()
++ is called.
++ \li \c DiagramScene inherits QGraphicsScene and
++ emits signals for the \c MoveComands when an item is moved.
++ \li \c DiagramItem inherits QGraphicsPolygonItem and represents
++ an item in the diagram.
++ \endlist
++
++ \section1 MainWindow Class Definition
++
++ \snippet tools/undoframework/mainwindow.h 0
++
++ The \c MainWindow class maintains the undo stack, i.e., it creates
++ \l{QUndoCommand}s and pushes and pops them from the stack when it
++ receives the \c triggered() signal from \c undoAction and \c
++ redoAction.
++
++ \section1 MainWindow Class Implementation
++
++ We will start with a look at the constructor:
++
++ \snippet tools/undoframework/mainwindow.cpp 0
++
++ In the constructor, we set up the DiagramScene and QGraphicsView.
++ We only want \c deleteAction to be enabled when we have selected an
++ item, so we connect to the \c selectionChanged() signal of the scene
++ to \c updateActions() slot.
++
++ Here is the \c createUndoView() function:
++
++ \snippet tools/undoframework/mainwindow.cpp 1
++
++ The QUndoView is a widget that display the text, which is set with
++ the \l{QUndoCommand::}{setText()} function, for each QUndoCommand
++ in the undo stack in a list. We put it into a docking widget.
++
++ Here is the \c createActions() function:
++
++ \snippet tools/undoframework/mainwindow.cpp 2
++ \dots
++ \snippet tools/undoframework/mainwindow.cpp 5
++
++ The \c createActions() function sets up all the examples actions
++ in the manner shown above. The
++ \l{QUndoStack::}{createUndoAction()} and
++ \l{QUndoStack::}{createRedoAction()} methods help us create actions that
++ are disabled and enabled based on the state of the stack. Also,
++ the text of the action will be updated automatically based on the
++ \l{QUndoCommand::}{text()} of the undo commands. For the other
++ actions we have implemented slots in the \c MainWindow class.
++
++ \dots
++ \snippet tools/undoframework/mainwindow.cpp 6
++
++ Once all actions are created we update their state by calling the
++ same function that is connected to the \c selectionChanged signal of
++ the scene.
++
++ The \c createMenus() and \c createToolBars() functions add the
++ actions to menus and toolbars:
++
++ \snippet tools/undoframework/mainwindow.cpp 7
++ \dots
++ \snippet tools/undoframework/mainwindow.cpp 8
++ \dots
++ \snippet tools/undoframework/mainwindow.cpp 9
++
++ Here is the \c itemMoved() slot:
++
++ \snippet tools/undoframework/mainwindow.cpp 11
++
++ We simply push a MoveCommand on the stack, which calls \c redo()
++ on it.
++
++ Here is the \c deleteItem() slot:
++
++ \snippet tools/undoframework/mainwindow.cpp 12
++
++ An item must be selected to be deleted. We need to check if it is
++ selected as the \c deleteAction may be enabled even if an item is
++ not selected. This can happen as we do not catch a signal or event
++ when an item is selected.
++
++ Here is the \c addBox() slot:
++
++ \snippet tools/undoframework/mainwindow.cpp 13
++
++ The \c addBox() function creates an AddCommand and pushes it on
++ the undo stack.
++
++ Here is the \c addTriangle() sot:
++
++ \snippet tools/undoframework/mainwindow.cpp 14
++
++ The \c addTriangle() function creates an AddCommand and pushes it
++ on the undo stack.
++
++ Here is the implementation of \c about():
++
++ \snippet tools/undoframework/mainwindow.cpp 15
++
++ The about slot is triggered by the \c aboutAction and displays an
++ about box for the example.
++
++ \section1 AddCommand Class Definition
++
++ \snippet tools/undoframework/commands.h 2
++
++ The \c AddCommand class adds DiagramItem graphics items to the
++ DiagramScene.
++
++ \section1 AddCommand Class Implementation
++
++ We start with the constructor:
++
++ \snippet tools/undoframework/commands.cpp 7
++
++ We first create the DiagramItem to add to the DiagramScene. The
++ \l{QUndoCommand::}{setText()} function let us set a QString that
++ describes the command. We use this to get custom messages in the
++ QUndoView and in the menu of the main window.
++
++ \snippet tools/undoframework/commands.cpp 8
++
++ \c undo() removes the item from the scene.
++
++ \snippet tools/undoframework/commands.cpp 9
++
++ We set the position of the item as we do not do this in the
++ constructor.
++
++ \section1 DeleteCommand Class Definition
++
++ \snippet tools/undoframework/commands.h 1
++
++ The DeleteCommand class implements the functionality to remove an
++ item from the scene.
++
++ \section1 DeleteCommand Class Implementation
++
++ \snippet tools/undoframework/commands.cpp 4
++
++ We know that there must be one selected item as it is not possible
++ to create a DeleteCommand unless the item to be deleted is
++ selected and that only one item can be selected at any time.
++ The item must be unselected if it is inserted back into the
++ scene.
++
++ \snippet tools/undoframework/commands.cpp 5
++
++ The item is simply reinserted into the scene.
++
++ \snippet tools/undoframework/commands.cpp 6
++
++ The item is removed from the scene.
++
++ \section1 MoveCommand Class Definition
++
++ \snippet tools/undoframework/commands.h 0
++
++ The \l{QUndoCommand::}{mergeWith()} is reimplemented to make
++ consecutive moves of an item one MoveCommand, i.e, the item will
++ be moved back to the start position of the first move.
++
++ \section1 MoveCommand Class Implementation
++
++
++ The constructor of MoveCommand looks like this:
++
++ \snippet tools/undoframework/commands.cpp 0
++
++ We save both the old and new positions for undo and redo
++ respectively.
++
++ \snippet tools/undoframework/commands.cpp 2
++
++ We simply set the items old position and update the scene.
++
++ \snippet tools/undoframework/commands.cpp 3
++
++ We set the item to its new position.
++
++ \snippet tools/undoframework/commands.cpp 1
++
++ Whenever a MoveCommand is created, this function is called to
++ check if it should be merged with the previous command. It is the
++ previous command object that is kept on the stack. The function
++ returns true if the command is merged; otherwise false.
++
++ We first check whether it is the same item that has been moved
++ twice, in which case we merge the commands. We update the position
++ of the item so that it will take the last position in the move
++ sequence when undone.
++
++ \section1 DiagramScene Class Definition
++
++ \snippet tools/undoframework/diagramscene.h 0
++
++ The DiagramScene implements the functionality to move a
++ DiagramItem with the mouse. It emits a signal when a move is
++ completed. This is caught by the \c MainWindow, which makes
++ MoveCommands. We do not examine the implementation of DiagramScene
++ as it only deals with graphics framework issues.
++
++ \section1 The \c main() Function
++
++ The \c main() function of the program looks like this:
++
++ \snippet tools/undoframework/main.cpp 0
++
++ We draw a grid in the background of the DiagramScene, so we use a
++ resource file. The rest of the function creates the \c MainWindow and
++ shows it as a top level window.
++ */