Started adding undo/redo framework.
This commit is contained in:
@@ -51,6 +51,7 @@ set (glabels_sources
|
||||
TemplatePicker.cpp
|
||||
TemplatePickerItem.cpp
|
||||
TextNode.cpp
|
||||
UndoRedoModel.cpp
|
||||
XmlLabelCreator.cpp
|
||||
XmlLabelParser.cpp
|
||||
)
|
||||
@@ -87,6 +88,7 @@ set (glabels_qobject_headers
|
||||
SimplePreview.h
|
||||
StartupWizard.h
|
||||
TemplatePicker.h
|
||||
UndoRedoModel.h
|
||||
)
|
||||
|
||||
set (glabels_forms
|
||||
|
||||
+10
-1
@@ -28,6 +28,7 @@
|
||||
#include "LabelModel.h"
|
||||
#include "LabelModelObject.h"
|
||||
#include "LabelModelBoxObject.h"
|
||||
#include "UndoRedoModel.h"
|
||||
#include "Settings.h"
|
||||
#include "Cursors.h"
|
||||
|
||||
@@ -81,6 +82,7 @@ LabelEditor::LabelEditor( QScrollArea* scrollArea, QWidget* parent )
|
||||
mState = IdleState;
|
||||
|
||||
mModel = 0;
|
||||
mUndoRedoModel = 0;
|
||||
mMarkupVisible = true;
|
||||
mGridVisible = true;
|
||||
mGridSpacing = 18;
|
||||
@@ -127,9 +129,10 @@ LabelEditor::qridVisible() const
|
||||
/// Model Parameter Setter
|
||||
///
|
||||
void
|
||||
LabelEditor::setModel( LabelModel* model )
|
||||
LabelEditor::setModel( LabelModel* model, UndoRedoModel* undoRedoModel )
|
||||
{
|
||||
mModel = model;
|
||||
mUndoRedoModel = undoRedoModel;
|
||||
|
||||
if ( model )
|
||||
{
|
||||
@@ -571,6 +574,7 @@ LabelEditor::mouseMoveEvent( QMouseEvent* event )
|
||||
break;
|
||||
|
||||
case ArrowMove:
|
||||
mUndoRedoModel->checkpoint( tr("Move") );
|
||||
mModel->moveSelection( (xWorld - mMoveLastX),
|
||||
(yWorld - mMoveLastY) );
|
||||
mMoveLastX = xWorld;
|
||||
@@ -867,22 +871,27 @@ LabelEditor::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
|
||||
case Qt::Key_Left:
|
||||
mUndoRedoModel->checkpoint( tr("Move") );
|
||||
mModel->moveSelection( -mStepSize, glabels::Distance(0) );
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
mUndoRedoModel->checkpoint( tr("Move") );
|
||||
mModel->moveSelection( glabels::Distance(0), -mStepSize );
|
||||
break;
|
||||
|
||||
case Qt::Key_Right:
|
||||
mUndoRedoModel->checkpoint( tr("Move") );
|
||||
mModel->moveSelection( mStepSize, glabels::Distance(0) );
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
mUndoRedoModel->checkpoint( tr("Move") );
|
||||
mModel->moveSelection( glabels::Distance(0), mStepSize );
|
||||
break;
|
||||
|
||||
case Qt::Key_Delete:
|
||||
mUndoRedoModel->checkpoint( tr("Delete") );
|
||||
mModel->deleteSelection();
|
||||
setCursor( Qt::ArrowCursor );
|
||||
break;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
// Forward References
|
||||
class LabelModel;
|
||||
class LabelModelObject;
|
||||
class UndoRedoModel;
|
||||
class Handle;
|
||||
|
||||
|
||||
@@ -72,7 +73,7 @@ public:
|
||||
// Model
|
||||
/////////////////////////////////////
|
||||
public:
|
||||
void setModel( LabelModel* model );
|
||||
void setModel( LabelModel* model, UndoRedoModel* undoRedoModel );
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
@@ -184,6 +185,7 @@ private:
|
||||
glabels::Distance mStepSize;
|
||||
|
||||
LabelModel* mModel;
|
||||
UndoRedoModel* mUndoRedoModel;
|
||||
|
||||
State mState;
|
||||
|
||||
|
||||
+39
-7
@@ -44,6 +44,7 @@
|
||||
#include "PrintView.h"
|
||||
#include "LabelModel.h"
|
||||
#include "LabelModelBoxObject.h"
|
||||
#include "UndoRedoModel.h"
|
||||
#include "Icons.h"
|
||||
#include "File.h"
|
||||
#include "Help.h"
|
||||
@@ -163,8 +164,10 @@ LabelModel* MainWindow::model() const
|
||||
void MainWindow::setModel( LabelModel *label )
|
||||
{
|
||||
mModel = label;
|
||||
mPropertiesView->setModel( mModel );
|
||||
mLabelEditor->setModel( mModel );
|
||||
mUndoRedoModel = new UndoRedoModel( mModel );
|
||||
|
||||
mPropertiesView->setModel( mModel, mUndoRedoModel );
|
||||
mLabelEditor->setModel( mModel, mUndoRedoModel );
|
||||
mObjectEditor->setModel( mModel );
|
||||
mPrintView->setModel( mModel );
|
||||
|
||||
@@ -180,6 +183,7 @@ void MainWindow::setModel( LabelModel *label )
|
||||
connect( mModel, SIGNAL(modifiedChanged()), this, SLOT(onModifiedChanged()) );
|
||||
connect( mModel, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()) );
|
||||
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 );
|
||||
fileSaveAsAction->setEnabled( enabled );
|
||||
editUndoAction->setEnabled( enabled );
|
||||
editRedoAction->setEnabled( enabled );
|
||||
editUndoAction->setEnabled( enabled && mUndoRedoModel->canUndo() );
|
||||
editRedoAction->setEnabled( enabled && mUndoRedoModel->canRedo() );
|
||||
editDeleteAction->setEnabled( enabled );
|
||||
editSelectAllAction->setEnabled( enabled );
|
||||
editUnSelectAllAction->setEnabled( enabled );
|
||||
@@ -979,7 +983,7 @@ void MainWindow::fileExit()
|
||||
///
|
||||
void MainWindow::editUndo()
|
||||
{
|
||||
qDebug() << "ACTION: edit->Undo";
|
||||
mUndoRedoModel->undo();
|
||||
}
|
||||
|
||||
|
||||
@@ -988,7 +992,7 @@ void MainWindow::editUndo()
|
||||
///
|
||||
void MainWindow::editRedo()
|
||||
{
|
||||
qDebug() << "ACTION: edit->Redo";
|
||||
mUndoRedoModel->redo();
|
||||
}
|
||||
|
||||
|
||||
@@ -997,6 +1001,7 @@ void MainWindow::editRedo()
|
||||
///
|
||||
void MainWindow::editCut()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Cut") );
|
||||
mModel->cutSelection();
|
||||
}
|
||||
|
||||
@@ -1006,6 +1011,7 @@ void MainWindow::editCut()
|
||||
///
|
||||
void MainWindow::editCopy()
|
||||
{
|
||||
// Non-destructive -- do not checkpoint.
|
||||
mModel->copySelection();
|
||||
}
|
||||
|
||||
@@ -1015,6 +1021,7 @@ void MainWindow::editCopy()
|
||||
///
|
||||
void MainWindow::editPaste()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Paste") );
|
||||
mModel->paste();
|
||||
}
|
||||
|
||||
@@ -1024,6 +1031,7 @@ void MainWindow::editPaste()
|
||||
///
|
||||
void MainWindow::editDelete()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Delete") );
|
||||
mModel->deleteSelection();
|
||||
}
|
||||
|
||||
@@ -1151,6 +1159,7 @@ void MainWindow::objectsCreateText()
|
||||
///
|
||||
void MainWindow::objectsCreateBox()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Create Box") );
|
||||
mLabelEditor->createBoxMode();
|
||||
}
|
||||
|
||||
@@ -1196,6 +1205,7 @@ void MainWindow::objectsCreateBarcode()
|
||||
///
|
||||
void MainWindow::objectsOrderRaise()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Bring To Front") );
|
||||
mModel->raiseSelectionToTop();
|
||||
}
|
||||
|
||||
@@ -1205,6 +1215,7 @@ void MainWindow::objectsOrderRaise()
|
||||
///
|
||||
void MainWindow::objectsOrderLower()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Send To Back") );
|
||||
mModel->lowerSelectionToBottom();
|
||||
}
|
||||
|
||||
@@ -1214,6 +1225,7 @@ void MainWindow::objectsOrderLower()
|
||||
///
|
||||
void MainWindow::objectsXformRotateLeft()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Rotate Left") );
|
||||
mModel->rotateSelectionLeft();
|
||||
}
|
||||
|
||||
@@ -1223,6 +1235,7 @@ void MainWindow::objectsXformRotateLeft()
|
||||
///
|
||||
void MainWindow::objectsXformRotateRight()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Rotate Right") );
|
||||
mModel->rotateSelectionRight();
|
||||
}
|
||||
|
||||
@@ -1232,6 +1245,7 @@ void MainWindow::objectsXformRotateRight()
|
||||
///
|
||||
void MainWindow::objectsXformFlipHoriz()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Flip Horizontally") );
|
||||
mModel->flipSelectionHoriz();
|
||||
}
|
||||
|
||||
@@ -1241,6 +1255,7 @@ void MainWindow::objectsXformFlipHoriz()
|
||||
///
|
||||
void MainWindow::objectsXformFlipVert()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Flip Vertically") );
|
||||
mModel->flipSelectionVert();
|
||||
}
|
||||
|
||||
@@ -1250,6 +1265,7 @@ void MainWindow::objectsXformFlipVert()
|
||||
///
|
||||
void MainWindow::objectsAlignLeft()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Align Left") );
|
||||
mModel->alignSelectionLeft();
|
||||
}
|
||||
|
||||
@@ -1259,6 +1275,7 @@ void MainWindow::objectsAlignLeft()
|
||||
///
|
||||
void MainWindow::objectsAlignHCenter()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Align Center") );
|
||||
mModel->alignSelectionHCenter();
|
||||
}
|
||||
|
||||
@@ -1268,6 +1285,7 @@ void MainWindow::objectsAlignHCenter()
|
||||
///
|
||||
void MainWindow::objectsAlignRight()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Align Right") );
|
||||
mModel->alignSelectionRight();
|
||||
}
|
||||
|
||||
@@ -1277,6 +1295,7 @@ void MainWindow::objectsAlignRight()
|
||||
///
|
||||
void MainWindow::objectsAlignTop()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Align Top") );
|
||||
mModel->alignSelectionTop();
|
||||
}
|
||||
|
||||
@@ -1286,6 +1305,7 @@ void MainWindow::objectsAlignTop()
|
||||
///
|
||||
void MainWindow::objectsAlignVCenter()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Align Middle") );
|
||||
mModel->alignSelectionVCenter();
|
||||
}
|
||||
|
||||
@@ -1295,6 +1315,7 @@ void MainWindow::objectsAlignVCenter()
|
||||
///
|
||||
void MainWindow::objectsAlignBottom()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Align Bottom") );
|
||||
mModel->alignSelectionBottom();
|
||||
}
|
||||
|
||||
@@ -1304,6 +1325,7 @@ void MainWindow::objectsAlignBottom()
|
||||
///
|
||||
void MainWindow::objectsCenterHoriz()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Center Horizontally") );
|
||||
mModel->centerSelectionHoriz();
|
||||
}
|
||||
|
||||
@@ -1313,6 +1335,7 @@ void MainWindow::objectsCenterHoriz()
|
||||
///
|
||||
void MainWindow::objectsCenterVert()
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Center Vertically") );
|
||||
mModel->centerSelectionVert();
|
||||
}
|
||||
|
||||
@@ -1416,5 +1439,14 @@ void MainWindow::onSelectionChanged()
|
||||
///
|
||||
void MainWindow::onLabelChanged()
|
||||
{
|
||||
/* @TODO: update undo/redo verbs. */
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Undo/Redo changed handler
|
||||
///
|
||||
void MainWindow::onUndoRedoChanged()
|
||||
{
|
||||
editUndoAction->setEnabled( mUndoRedoModel->canUndo() );
|
||||
editRedoAction->setEnabled( mUndoRedoModel->canRedo() );
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ class QScrollArea;
|
||||
|
||||
// Forward References
|
||||
class LabelModel;
|
||||
class UndoRedoModel;
|
||||
class PropertiesView;
|
||||
class LabelEditor;
|
||||
class ObjectEditor;
|
||||
@@ -148,6 +149,7 @@ private slots:
|
||||
void onModifiedChanged();
|
||||
void onSelectionChanged();
|
||||
void onLabelChanged();
|
||||
void onUndoRedoChanged();
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
@@ -204,9 +206,11 @@ private:
|
||||
QToolBar* fileToolBar;
|
||||
QToolBar* editorToolBar;
|
||||
|
||||
LabelModel* mModel;
|
||||
UndoRedoModel* mUndoRedoModel;
|
||||
|
||||
QListWidget* mContents;
|
||||
QStackedWidget* mPages;
|
||||
LabelModel* mModel;
|
||||
PropertiesView* mPropertiesView;
|
||||
QScrollArea* mLabelEditorScrollArea;
|
||||
LabelEditor* mLabelEditor;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "PropertiesView.h"
|
||||
|
||||
#include "LabelModel.h"
|
||||
#include "UndoRedoModel.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "libglabels/Db.h"
|
||||
@@ -55,9 +56,10 @@ PropertiesView::~PropertiesView()
|
||||
///
|
||||
/// Set Model
|
||||
///
|
||||
void PropertiesView::setModel( LabelModel* model )
|
||||
void PropertiesView::setModel( LabelModel* model, UndoRedoModel* undoRedoModel )
|
||||
{
|
||||
mModel = model;
|
||||
mUndoRedoModel = undoRedoModel;
|
||||
|
||||
connect( mModel, SIGNAL(sizeChanged()), this, SLOT(onLabelSizeChanged()) );
|
||||
|
||||
@@ -171,11 +173,13 @@ void PropertiesView::onFormChanged()
|
||||
}
|
||||
else if ( frame->w() > frame->h() )
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Product Orientation") );
|
||||
int index = orientationCombo->currentIndex();
|
||||
mModel->setRotate( index == 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Product Orientation") );
|
||||
int index = orientationCombo->currentIndex();
|
||||
mModel->setRotate( index == 0 );
|
||||
}
|
||||
@@ -193,6 +197,8 @@ void PropertiesView::onChangeProductButtonClicked()
|
||||
const glabels::Template* tmplate = selectProductDialog.tmplate();
|
||||
if ( tmplate )
|
||||
{
|
||||
mUndoRedoModel->checkpoint( tr("Change Product") );
|
||||
|
||||
mModel->setTmplate( tmplate );
|
||||
|
||||
// Don't rotate circular or round labels
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
#include "libglabels/Units.h"
|
||||
|
||||
class LabelModel; // Forward reference
|
||||
// Forward references
|
||||
class LabelModel;
|
||||
class UndoRedoModel;
|
||||
|
||||
|
||||
///
|
||||
@@ -47,7 +49,7 @@ public:
|
||||
/////////////////////////////////
|
||||
// Public methods
|
||||
/////////////////////////////////
|
||||
void setModel( LabelModel* model );
|
||||
void setModel( LabelModel* model, UndoRedoModel* undoRedoModel );
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
@@ -65,6 +67,7 @@ private slots:
|
||||
/////////////////////////////////
|
||||
private:
|
||||
LabelModel* mModel;
|
||||
UndoRedoModel* mUndoRedoModel;
|
||||
glabels::Units mUnits;
|
||||
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user