Started adding undo/redo framework.

This commit is contained in:
Jim Evins
2016-04-29 23:51:01 -04:00
parent 231dc66c0d
commit 61c41d8ba9
9 changed files with 445 additions and 13 deletions
+2
View File
@@ -51,6 +51,7 @@ set (glabels_sources
TemplatePicker.cpp TemplatePicker.cpp
TemplatePickerItem.cpp TemplatePickerItem.cpp
TextNode.cpp TextNode.cpp
UndoRedoModel.cpp
XmlLabelCreator.cpp XmlLabelCreator.cpp
XmlLabelParser.cpp XmlLabelParser.cpp
) )
@@ -87,6 +88,7 @@ set (glabels_qobject_headers
SimplePreview.h SimplePreview.h
StartupWizard.h StartupWizard.h
TemplatePicker.h TemplatePicker.h
UndoRedoModel.h
) )
set (glabels_forms set (glabels_forms
+10 -1
View File
@@ -28,6 +28,7 @@
#include "LabelModel.h" #include "LabelModel.h"
#include "LabelModelObject.h" #include "LabelModelObject.h"
#include "LabelModelBoxObject.h" #include "LabelModelBoxObject.h"
#include "UndoRedoModel.h"
#include "Settings.h" #include "Settings.h"
#include "Cursors.h" #include "Cursors.h"
@@ -81,6 +82,7 @@ LabelEditor::LabelEditor( QScrollArea* scrollArea, QWidget* parent )
mState = IdleState; mState = IdleState;
mModel = 0; mModel = 0;
mUndoRedoModel = 0;
mMarkupVisible = true; mMarkupVisible = true;
mGridVisible = true; mGridVisible = true;
mGridSpacing = 18; mGridSpacing = 18;
@@ -127,9 +129,10 @@ LabelEditor::qridVisible() const
/// Model Parameter Setter /// Model Parameter Setter
/// ///
void void
LabelEditor::setModel( LabelModel* model ) LabelEditor::setModel( LabelModel* model, UndoRedoModel* undoRedoModel )
{ {
mModel = model; mModel = model;
mUndoRedoModel = undoRedoModel;
if ( model ) if ( model )
{ {
@@ -571,6 +574,7 @@ LabelEditor::mouseMoveEvent( QMouseEvent* event )
break; break;
case ArrowMove: case ArrowMove:
mUndoRedoModel->checkpoint( tr("Move") );
mModel->moveSelection( (xWorld - mMoveLastX), mModel->moveSelection( (xWorld - mMoveLastX),
(yWorld - mMoveLastY) ); (yWorld - mMoveLastY) );
mMoveLastX = xWorld; mMoveLastX = xWorld;
@@ -867,22 +871,27 @@ LabelEditor::keyPressEvent( QKeyEvent* event )
{ {
case Qt::Key_Left: case Qt::Key_Left:
mUndoRedoModel->checkpoint( tr("Move") );
mModel->moveSelection( -mStepSize, glabels::Distance(0) ); mModel->moveSelection( -mStepSize, glabels::Distance(0) );
break; break;
case Qt::Key_Up: case Qt::Key_Up:
mUndoRedoModel->checkpoint( tr("Move") );
mModel->moveSelection( glabels::Distance(0), -mStepSize ); mModel->moveSelection( glabels::Distance(0), -mStepSize );
break; break;
case Qt::Key_Right: case Qt::Key_Right:
mUndoRedoModel->checkpoint( tr("Move") );
mModel->moveSelection( mStepSize, glabels::Distance(0) ); mModel->moveSelection( mStepSize, glabels::Distance(0) );
break; break;
case Qt::Key_Down: case Qt::Key_Down:
mUndoRedoModel->checkpoint( tr("Move") );
mModel->moveSelection( glabels::Distance(0), mStepSize ); mModel->moveSelection( glabels::Distance(0), mStepSize );
break; break;
case Qt::Key_Delete: case Qt::Key_Delete:
mUndoRedoModel->checkpoint( tr("Delete") );
mModel->deleteSelection(); mModel->deleteSelection();
setCursor( Qt::ArrowCursor ); setCursor( Qt::ArrowCursor );
break; break;
+3 -1
View File
@@ -31,6 +31,7 @@
// Forward References // Forward References
class LabelModel; class LabelModel;
class LabelModelObject; class LabelModelObject;
class UndoRedoModel;
class Handle; class Handle;
@@ -72,7 +73,7 @@ public:
// Model // Model
///////////////////////////////////// /////////////////////////////////////
public: public:
void setModel( LabelModel* model ); void setModel( LabelModel* model, UndoRedoModel* undoRedoModel );
///////////////////////////////////// /////////////////////////////////////
@@ -184,6 +185,7 @@ private:
glabels::Distance mStepSize; glabels::Distance mStepSize;
LabelModel* mModel; LabelModel* mModel;
UndoRedoModel* mUndoRedoModel;
State mState; State mState;
+39 -7
View File
@@ -44,6 +44,7 @@
#include "PrintView.h" #include "PrintView.h"
#include "LabelModel.h" #include "LabelModel.h"
#include "LabelModelBoxObject.h" #include "LabelModelBoxObject.h"
#include "UndoRedoModel.h"
#include "Icons.h" #include "Icons.h"
#include "File.h" #include "File.h"
#include "Help.h" #include "Help.h"
@@ -163,8 +164,10 @@ LabelModel* MainWindow::model() const
void MainWindow::setModel( LabelModel *label ) void MainWindow::setModel( LabelModel *label )
{ {
mModel = label; mModel = label;
mPropertiesView->setModel( mModel ); mUndoRedoModel = new UndoRedoModel( mModel );
mLabelEditor->setModel( mModel );
mPropertiesView->setModel( mModel, mUndoRedoModel );
mLabelEditor->setModel( mModel, mUndoRedoModel );
mObjectEditor->setModel( mModel ); mObjectEditor->setModel( mModel );
mPrintView->setModel( mModel ); mPrintView->setModel( mModel );
@@ -180,6 +183,7 @@ void MainWindow::setModel( LabelModel *label )
connect( mModel, SIGNAL(modifiedChanged()), this, SLOT(onModifiedChanged()) ); connect( mModel, SIGNAL(modifiedChanged()), this, SLOT(onModifiedChanged()) );
connect( mModel, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()) ); connect( mModel, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()) );
connect( mModel, SIGNAL(changed()), this, SLOT(onLabelChanged()) ); connect( mModel, SIGNAL(changed()), this, SLOT(onLabelChanged()) );
connect( mUndoRedoModel, SIGNAL(changed()), this, SLOT(onUndoRedoChanged()) );
} }
@@ -726,8 +730,8 @@ void MainWindow::setDocVerbsEnabled( bool enabled )
{ {
fileSaveAction->setEnabled( enabled ); fileSaveAction->setEnabled( enabled );
fileSaveAsAction->setEnabled( enabled ); fileSaveAsAction->setEnabled( enabled );
editUndoAction->setEnabled( enabled ); editUndoAction->setEnabled( enabled && mUndoRedoModel->canUndo() );
editRedoAction->setEnabled( enabled ); editRedoAction->setEnabled( enabled && mUndoRedoModel->canRedo() );
editDeleteAction->setEnabled( enabled ); editDeleteAction->setEnabled( enabled );
editSelectAllAction->setEnabled( enabled ); editSelectAllAction->setEnabled( enabled );
editUnSelectAllAction->setEnabled( enabled ); editUnSelectAllAction->setEnabled( enabled );
@@ -979,7 +983,7 @@ void MainWindow::fileExit()
/// ///
void MainWindow::editUndo() void MainWindow::editUndo()
{ {
qDebug() << "ACTION: edit->Undo"; mUndoRedoModel->undo();
} }
@@ -988,7 +992,7 @@ void MainWindow::editUndo()
/// ///
void MainWindow::editRedo() void MainWindow::editRedo()
{ {
qDebug() << "ACTION: edit->Redo"; mUndoRedoModel->redo();
} }
@@ -997,6 +1001,7 @@ void MainWindow::editRedo()
/// ///
void MainWindow::editCut() void MainWindow::editCut()
{ {
mUndoRedoModel->checkpoint( tr("Cut") );
mModel->cutSelection(); mModel->cutSelection();
} }
@@ -1006,6 +1011,7 @@ void MainWindow::editCut()
/// ///
void MainWindow::editCopy() void MainWindow::editCopy()
{ {
// Non-destructive -- do not checkpoint.
mModel->copySelection(); mModel->copySelection();
} }
@@ -1015,6 +1021,7 @@ void MainWindow::editCopy()
/// ///
void MainWindow::editPaste() void MainWindow::editPaste()
{ {
mUndoRedoModel->checkpoint( tr("Paste") );
mModel->paste(); mModel->paste();
} }
@@ -1024,6 +1031,7 @@ void MainWindow::editPaste()
/// ///
void MainWindow::editDelete() void MainWindow::editDelete()
{ {
mUndoRedoModel->checkpoint( tr("Delete") );
mModel->deleteSelection(); mModel->deleteSelection();
} }
@@ -1151,6 +1159,7 @@ void MainWindow::objectsCreateText()
/// ///
void MainWindow::objectsCreateBox() void MainWindow::objectsCreateBox()
{ {
mUndoRedoModel->checkpoint( tr("Create Box") );
mLabelEditor->createBoxMode(); mLabelEditor->createBoxMode();
} }
@@ -1196,6 +1205,7 @@ void MainWindow::objectsCreateBarcode()
/// ///
void MainWindow::objectsOrderRaise() void MainWindow::objectsOrderRaise()
{ {
mUndoRedoModel->checkpoint( tr("Bring To Front") );
mModel->raiseSelectionToTop(); mModel->raiseSelectionToTop();
} }
@@ -1205,6 +1215,7 @@ void MainWindow::objectsOrderRaise()
/// ///
void MainWindow::objectsOrderLower() void MainWindow::objectsOrderLower()
{ {
mUndoRedoModel->checkpoint( tr("Send To Back") );
mModel->lowerSelectionToBottom(); mModel->lowerSelectionToBottom();
} }
@@ -1214,6 +1225,7 @@ void MainWindow::objectsOrderLower()
/// ///
void MainWindow::objectsXformRotateLeft() void MainWindow::objectsXformRotateLeft()
{ {
mUndoRedoModel->checkpoint( tr("Rotate Left") );
mModel->rotateSelectionLeft(); mModel->rotateSelectionLeft();
} }
@@ -1223,6 +1235,7 @@ void MainWindow::objectsXformRotateLeft()
/// ///
void MainWindow::objectsXformRotateRight() void MainWindow::objectsXformRotateRight()
{ {
mUndoRedoModel->checkpoint( tr("Rotate Right") );
mModel->rotateSelectionRight(); mModel->rotateSelectionRight();
} }
@@ -1232,6 +1245,7 @@ void MainWindow::objectsXformRotateRight()
/// ///
void MainWindow::objectsXformFlipHoriz() void MainWindow::objectsXformFlipHoriz()
{ {
mUndoRedoModel->checkpoint( tr("Flip Horizontally") );
mModel->flipSelectionHoriz(); mModel->flipSelectionHoriz();
} }
@@ -1241,6 +1255,7 @@ void MainWindow::objectsXformFlipHoriz()
/// ///
void MainWindow::objectsXformFlipVert() void MainWindow::objectsXformFlipVert()
{ {
mUndoRedoModel->checkpoint( tr("Flip Vertically") );
mModel->flipSelectionVert(); mModel->flipSelectionVert();
} }
@@ -1250,6 +1265,7 @@ void MainWindow::objectsXformFlipVert()
/// ///
void MainWindow::objectsAlignLeft() void MainWindow::objectsAlignLeft()
{ {
mUndoRedoModel->checkpoint( tr("Align Left") );
mModel->alignSelectionLeft(); mModel->alignSelectionLeft();
} }
@@ -1259,6 +1275,7 @@ void MainWindow::objectsAlignLeft()
/// ///
void MainWindow::objectsAlignHCenter() void MainWindow::objectsAlignHCenter()
{ {
mUndoRedoModel->checkpoint( tr("Align Center") );
mModel->alignSelectionHCenter(); mModel->alignSelectionHCenter();
} }
@@ -1268,6 +1285,7 @@ void MainWindow::objectsAlignHCenter()
/// ///
void MainWindow::objectsAlignRight() void MainWindow::objectsAlignRight()
{ {
mUndoRedoModel->checkpoint( tr("Align Right") );
mModel->alignSelectionRight(); mModel->alignSelectionRight();
} }
@@ -1277,6 +1295,7 @@ void MainWindow::objectsAlignRight()
/// ///
void MainWindow::objectsAlignTop() void MainWindow::objectsAlignTop()
{ {
mUndoRedoModel->checkpoint( tr("Align Top") );
mModel->alignSelectionTop(); mModel->alignSelectionTop();
} }
@@ -1286,6 +1305,7 @@ void MainWindow::objectsAlignTop()
/// ///
void MainWindow::objectsAlignVCenter() void MainWindow::objectsAlignVCenter()
{ {
mUndoRedoModel->checkpoint( tr("Align Middle") );
mModel->alignSelectionVCenter(); mModel->alignSelectionVCenter();
} }
@@ -1295,6 +1315,7 @@ void MainWindow::objectsAlignVCenter()
/// ///
void MainWindow::objectsAlignBottom() void MainWindow::objectsAlignBottom()
{ {
mUndoRedoModel->checkpoint( tr("Align Bottom") );
mModel->alignSelectionBottom(); mModel->alignSelectionBottom();
} }
@@ -1304,6 +1325,7 @@ void MainWindow::objectsAlignBottom()
/// ///
void MainWindow::objectsCenterHoriz() void MainWindow::objectsCenterHoriz()
{ {
mUndoRedoModel->checkpoint( tr("Center Horizontally") );
mModel->centerSelectionHoriz(); mModel->centerSelectionHoriz();
} }
@@ -1313,6 +1335,7 @@ void MainWindow::objectsCenterHoriz()
/// ///
void MainWindow::objectsCenterVert() void MainWindow::objectsCenterVert()
{ {
mUndoRedoModel->checkpoint( tr("Center Vertically") );
mModel->centerSelectionVert(); mModel->centerSelectionVert();
} }
@@ -1416,5 +1439,14 @@ void MainWindow::onSelectionChanged()
/// ///
void MainWindow::onLabelChanged() void MainWindow::onLabelChanged()
{ {
/* @TODO: update undo/redo verbs. */ }
///
/// Undo/Redo changed handler
///
void MainWindow::onUndoRedoChanged()
{
editUndoAction->setEnabled( mUndoRedoModel->canUndo() );
editRedoAction->setEnabled( mUndoRedoModel->canRedo() );
} }
+5 -1
View File
@@ -37,6 +37,7 @@ class QScrollArea;
// Forward References // Forward References
class LabelModel; class LabelModel;
class UndoRedoModel;
class PropertiesView; class PropertiesView;
class LabelEditor; class LabelEditor;
class ObjectEditor; class ObjectEditor;
@@ -148,6 +149,7 @@ private slots:
void onModifiedChanged(); void onModifiedChanged();
void onSelectionChanged(); void onSelectionChanged();
void onLabelChanged(); void onLabelChanged();
void onUndoRedoChanged();
///////////////////////////////////// /////////////////////////////////////
@@ -204,9 +206,11 @@ private:
QToolBar* fileToolBar; QToolBar* fileToolBar;
QToolBar* editorToolBar; QToolBar* editorToolBar;
LabelModel* mModel;
UndoRedoModel* mUndoRedoModel;
QListWidget* mContents; QListWidget* mContents;
QStackedWidget* mPages; QStackedWidget* mPages;
LabelModel* mModel;
PropertiesView* mPropertiesView; PropertiesView* mPropertiesView;
QScrollArea* mLabelEditorScrollArea; QScrollArea* mLabelEditorScrollArea;
LabelEditor* mLabelEditor; LabelEditor* mLabelEditor;
+7 -1
View File
@@ -21,6 +21,7 @@
#include "PropertiesView.h" #include "PropertiesView.h"
#include "LabelModel.h" #include "LabelModel.h"
#include "UndoRedoModel.h"
#include "Settings.h" #include "Settings.h"
#include "libglabels/Db.h" #include "libglabels/Db.h"
@@ -55,9 +56,10 @@ PropertiesView::~PropertiesView()
/// ///
/// Set Model /// Set Model
/// ///
void PropertiesView::setModel( LabelModel* model ) void PropertiesView::setModel( LabelModel* model, UndoRedoModel* undoRedoModel )
{ {
mModel = model; mModel = model;
mUndoRedoModel = undoRedoModel;
connect( mModel, SIGNAL(sizeChanged()), this, SLOT(onLabelSizeChanged()) ); connect( mModel, SIGNAL(sizeChanged()), this, SLOT(onLabelSizeChanged()) );
@@ -171,11 +173,13 @@ void PropertiesView::onFormChanged()
} }
else if ( frame->w() > frame->h() ) else if ( frame->w() > frame->h() )
{ {
mUndoRedoModel->checkpoint( tr("Product Orientation") );
int index = orientationCombo->currentIndex(); int index = orientationCombo->currentIndex();
mModel->setRotate( index == 1 ); mModel->setRotate( index == 1 );
} }
else else
{ {
mUndoRedoModel->checkpoint( tr("Product Orientation") );
int index = orientationCombo->currentIndex(); int index = orientationCombo->currentIndex();
mModel->setRotate( index == 0 ); mModel->setRotate( index == 0 );
} }
@@ -193,6 +197,8 @@ void PropertiesView::onChangeProductButtonClicked()
const glabels::Template* tmplate = selectProductDialog.tmplate(); const glabels::Template* tmplate = selectProductDialog.tmplate();
if ( tmplate ) if ( tmplate )
{ {
mUndoRedoModel->checkpoint( tr("Change Product") );
mModel->setTmplate( tmplate ); mModel->setTmplate( tmplate );
// Don't rotate circular or round labels // Don't rotate circular or round labels
+5 -2
View File
@@ -25,7 +25,9 @@
#include "libglabels/Units.h" #include "libglabels/Units.h"
class LabelModel; // Forward reference // Forward references
class LabelModel;
class UndoRedoModel;
/// ///
@@ -47,7 +49,7 @@ public:
///////////////////////////////// /////////////////////////////////
// Public methods // Public methods
///////////////////////////////// /////////////////////////////////
void setModel( LabelModel* model ); void setModel( LabelModel* model, UndoRedoModel* undoRedoModel );
///////////////////////////////// /////////////////////////////////
@@ -65,6 +67,7 @@ private slots:
///////////////////////////////// /////////////////////////////////
private: private:
LabelModel* mModel; LabelModel* mModel;
UndoRedoModel* mUndoRedoModel;
glabels::Units mUnits; glabels::Units mUnits;
}; };
+255
View File
@@ -0,0 +1,255 @@
/* UndoRedoModel.cpp
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* This file is part of gLabels-qt.
*
* gLabels-qt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gLabels-qt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UndoRedoModel.h"
#include "LabelModel.h"
///
/// Constructor
///
UndoRedoModel::UndoRedoModel( LabelModel* model )
{
mModel = model;
mNewSelection = true;
connect( model, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()) );
}
///
/// Destructor
///
UndoRedoModel::~UndoRedoModel()
{
}
///
/// Checkpoint
///
void UndoRedoModel::checkpoint( const QString& description )
{
//
// Do not perform consecutive checkpoints that are identical.
// E.g. moving an object by dragging, would produce a large number
// of incremental checkpoints -- what we really want is a single
// checkpoint so that we can undo the entire dragging effort with
// one "undo"
//
if ( mNewSelection || (description != mLastDescription) )
{
/* Sever old redo "thread" */
mRedoStack.clear();
/* Save state onto undo stack. */
State* stateNow = new State( mModel, description );
mUndoStack.push( stateNow );
/* Track consecutive checkpoints. */
mNewSelection = false;
mLastDescription = description;
emit changed();
}
}
///
/// Undo
///
void UndoRedoModel::undo()
{
State* oldState = mUndoStack.pop();
State* stateNow = new State( mModel, oldState->description );
mRedoStack.push( stateNow );
mModel->restore( oldState->model );
delete oldState;
mNewSelection = true;
emit changed();
}
///
/// Redo
///
void UndoRedoModel::redo()
{
State* oldState = mRedoStack.pop();
State* stateNow = new State( mModel, oldState->description );
mUndoStack.push( stateNow );
mModel->restore( oldState->model );
delete oldState;
mNewSelection = true;
emit changed();
}
///
/// Can we undo?
///
bool UndoRedoModel::canUndo() const
{
return !mUndoStack.isEmpty();
}
///
/// Can we redo?
///
bool UndoRedoModel::canRedo() const
{
return !mRedoStack.isEmpty();
}
///
/// Undo description
///
QString UndoRedoModel::undoDescription() const
{
if ( canUndo() )
{
return mUndoStack.topState()->description;
}
else
{
return "";
}
}
///
/// Redo description
///
QString UndoRedoModel::redoDescription() const
{
if ( canRedo() )
{
return mRedoStack.topState()->description;
}
else
{
return "";
}
}
///
/// Selection changed handler
///
void UndoRedoModel::onSelectionChanged()
{
mNewSelection = true;
}
///
/// State constructor
///
UndoRedoModel::State::State( LabelModel* model, const QString& description )
{
this->model = model->save();
this->description = description;
}
///
/// State destructor
///
UndoRedoModel::State::~State()
{
delete model;
}
///
/// Stack constructor
///
UndoRedoModel::Stack::Stack()
{
}
///
/// Stack destructor
///
UndoRedoModel::Stack::~Stack()
{
clear();
}
///
/// Push state onto stack
///
void UndoRedoModel::Stack::push( UndoRedoModel::State* state )
{
list.push_front( state );
}
///
/// Pop state from stack
///
UndoRedoModel::State* UndoRedoModel::Stack::pop()
{
return list.takeFirst();
}
///
/// Peek at state at top of stack
///
const UndoRedoModel::State* UndoRedoModel::Stack::topState() const
{
return list.first();
}
///
/// Is stack empty?
///
bool UndoRedoModel::Stack::isEmpty() const
{
return list.isEmpty();
}
///
/// Clear stack
///
void UndoRedoModel::Stack::clear()
{
while ( !isEmpty() )
{
delete pop();
}
}
+119
View File
@@ -0,0 +1,119 @@
/* UndoRedoModel.h
*
* Copyright (C) 2016 Jim Evins <evins@snaught.com>
*
* This file is part of gLabels-qt.
*
* gLabels-qt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gLabels-qt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gLabels-qt. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UndoRedoModel_h
#define UndoRedoModel_h
#include <QObject>
#include <QString>
#include <QList>
class LabelModel;
///
/// UndoRedoModel
///
struct UndoRedoModel : QObject
{
Q_OBJECT
/////////////////////////////////
// Life Cycle
/////////////////////////////////
public:
UndoRedoModel( LabelModel* model );
virtual ~UndoRedoModel();
/////////////////////////////////
// Public Methods
/////////////////////////////////
public:
void checkpoint( const QString& description );
void undo();
void redo();
bool canUndo() const;
bool canRedo() const;
QString undoDescription() const;
QString redoDescription() const;
/////////////////////////////////
// Slots
/////////////////////////////////
private slots:
void onSelectionChanged();
/////////////////////////////////
// Signals
/////////////////////////////////
signals:
void changed();
/////////////////////////////////
// Private types
/////////////////////////////////
private:
class State
{
public:
State( LabelModel* model, const QString& description );
~State();
LabelModel* model;
QString description;
};
class Stack
{
public:
Stack();
~Stack();
void push( State* state );
State* pop();
const State* topState() const;
bool isEmpty() const;
void clear();
private:
QList<State*> list;
};
/////////////////////////////////
// Private data
/////////////////////////////////
private:
LabelModel *mModel;
Stack mUndoStack;
Stack mRedoStack;
bool mNewSelection;
QString mLastDescription;
};
#endif // UndoRedoModel_h