Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented Undo support in EventView

  • Loading branch information...
commit 79c2833f0a85d59b447257e5e82921c2dc4e0afb 1 parent 6b83c11
@NicholasVanSickle NicholasVanSickle authored
Showing with 334 additions and 43 deletions.
  1. +2 −0  Charm/Application.cpp
  2. +1 −0  Charm/CMakeLists.txt
  3. +8 −1 Charm/CharmWindow.cpp
  4. +1 −0  Charm/CharmWindow.h
  5. +1 −1  Charm/Commands/CommandAddTask.cpp
  6. +17 −1 Charm/Commands/CommandDeleteEvent.cpp
  7. +4 −0 Charm/Commands/CommandDeleteEvent.h
  8. +1 −1  Charm/Commands/CommandDeleteTask.cpp
  9. +1 −1  Charm/Commands/CommandExportToXml.cpp
  10. +1 −1  Charm/Commands/CommandImportFromXml.cpp
  11. +1 −1  Charm/Commands/CommandMakeAndActivateEvent.cpp
  12. +28 −2 Charm/Commands/CommandMakeEvent.cpp
  13. +5 −0 Charm/Commands/CommandMakeEvent.h
  14. +17 −2 Charm/Commands/CommandModifyEvent.cpp
  15. +6 −1 Charm/Commands/CommandModifyEvent.h
  16. +1 −1  Charm/Commands/CommandModifyTask.cpp
  17. +7 −1 Charm/Commands/CommandRelayCommand.cpp
  18. +1 −0  Charm/Commands/CommandRelayCommand.h
  19. +1 −1  Charm/Commands/CommandSetAllTasks.cpp
  20. +0 −1  Charm/EventModelAdapter.cpp
  21. +62 −9 Charm/EventView.cpp
  22. +11 −1 Charm/EventView.h
  23. +2 −0  Charm/EventWindow.cpp
  24. +1 −0  Charm/EventWindow.h
  25. +4 −5 Charm/ModelConnector.cpp
  26. +1 −1  Charm/ModelConnector.h
  27. +1 −2  Charm/TaskModelAdapter.cpp
  28. +0 −1  Charm/TasksView.cpp
  29. +1 −0  Charm/TasksView.h
  30. +7 −0 Charm/TasksWindow.cpp
  31. +2 −0  Charm/TasksWindow.h
  32. +2 −1  Charm/TimeTrackingView/TimeTrackingWindow.cpp
  33. +1 −0  Charm/TimeTrackingView/TimeTrackingWindow.h
  34. +27 −0 Charm/UndoCharmCommandWrapper.cpp
  35. +25 −0 Charm/UndoCharmCommandWrapper.h
  36. +2 −0  Charm/ViewHelpers.cpp
  37. +23 −2 Core/CharmCommand.cpp
  38. +19 −1 Core/CharmCommand.h
  39. +6 −3 Core/CharmDataModel.cpp
  40. +1 −1  Core/CharmDataModel.h
  41. +24 −0 Core/Controller.cpp
  42. +2 −0  Core/Controller.h
  43. +4 −0 Core/ControllerInterface.h
  44. +2 −0  Core/ViewInterface.h
View
2  Charm/Application.cpp
@@ -103,6 +103,8 @@ Application::Application(int& argc, char** argv)
if ( window != &mainView() ) { // main view acts as the main relay
connect( window, SIGNAL( emitCommand( CharmCommand* ) ),
&mainView(), SLOT( sendCommand( CharmCommand* ) ) );
+ connect( window, SIGNAL( emitCommandRollback( CharmCommand* ) ),
+ &mainView(), SLOT( sendCommandRollback( CharmCommand* ) ) );
}
// save the configuration (configuration is managed by the application)
connect( window, SIGNAL(saveConfiguration() ),
View
1  Charm/CMakeLists.txt
@@ -40,6 +40,7 @@ SET(
Reports/ActivityReport.cpp
Reports/WeeklyTimesheet.cpp
Reports/ReportPreviewWindow.cpp
+ UndoCharmCommandWrapper.cpp
Commands/CommandRelayCommand.cpp
Commands/CommandModifyEvent.cpp
Commands/CommandDeleteEvent.cpp
View
9 Charm/CharmWindow.cpp
@@ -134,6 +134,14 @@ void CharmWindow::sendCommand( CharmCommand* cmd )
emit emitCommand( relay );
}
+void CharmWindow::sendCommandRollback(CharmCommand *cmd)
+{
+ cmd->prepare();
+ CommandRelayCommand* relay = new CommandRelayCommand( this );
+ relay->setCommand( cmd );
+ emit emitCommandRollback ( relay );
+}
+
void CharmWindow::handleShowHide( bool visible )
{
const QString text = visible ? tr( "Hide %1 Window" ).arg( m_windowName )
@@ -145,7 +153,6 @@ void CharmWindow::handleShowHide( bool visible )
void CharmWindow::commitCommand( CharmCommand* command )
{
command->finalize();
- delete command;
}
void CharmWindow::keyPressEvent( QKeyEvent* event )
View
1  Charm/CharmWindow.h
@@ -55,6 +55,7 @@ class CharmWindow : public QMainWindow,
/* reimpl */ void saveConfiguration();
public slots:
+ /* reimpl */ void sendCommandRollback( CharmCommand* );
/* reimpl */ void sendCommand( CharmCommand* );
/* reimpl */ void commitCommand( CharmCommand* );
void restore();
View
2  Charm/Commands/CommandAddTask.cpp
@@ -7,7 +7,7 @@
#include "CommandAddTask.h"
CommandAddTask::CommandAddTask( const Task& task, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Add Task"), parent )
, m_task( task )
, m_success( false )
{
View
18 Charm/Commands/CommandDeleteEvent.cpp
@@ -3,7 +3,7 @@
#include "CommandDeleteEvent.h"
CommandDeleteEvent::CommandDeleteEvent( const Event& event, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Delete Event"), parent )
, m_event( event )
{
}
@@ -24,10 +24,26 @@ bool CommandDeleteEvent::execute( ControllerInterface* controller )
return controller->deleteEvent( m_event );
}
+bool CommandDeleteEvent::rollback(ControllerInterface *controller)
+{
+ int oldId = m_event.id();
+ m_event = controller->cloneEvent(m_event);
+ int newId = m_event.id();
+ if(oldId != newId)
+ emit emitSlotEventIdChanged(oldId, newId);
+ return m_event.isValid();
+}
+
bool CommandDeleteEvent::finalize()
{
return true;
}
+void CommandDeleteEvent::eventIdChanged(int oid, int nid)
+{
+ if(m_event.id() == oid)
+ m_event.setId(nid);
+}
+
#include "CommandDeleteEvent.moc"
View
4 Charm/Commands/CommandDeleteEvent.h
@@ -14,8 +14,12 @@ class CommandDeleteEvent : public CharmCommand
bool prepare();
bool execute( ControllerInterface* );
+ bool rollback( ControllerInterface* );
bool finalize();
+public slots:
+ virtual void eventIdChanged(int,int);
+
private:
Event m_event;
};
View
2  Charm/Commands/CommandDeleteTask.cpp
@@ -8,7 +8,7 @@
#include "CommandDeleteTask.h"
CommandDeleteTask::CommandDeleteTask( const Task& task, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Delete Task"), parent )
, m_task( task )
, m_success( false )
{
View
2  Charm/Commands/CommandExportToXml.cpp
@@ -10,7 +10,7 @@
#include "CommandExportToXml.h"
CommandExportToXml::CommandExportToXml( QString filename, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Export to XML"), parent )
, m_error( false )
, m_filename( filename )
{
View
2  Charm/Commands/CommandImportFromXml.cpp
@@ -9,7 +9,7 @@
#include "CommandImportFromXml.h"
CommandImportFromXml::CommandImportFromXml( QString filename, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Import from XML"), parent )
, m_filename( filename )
{
}
View
2  Charm/Commands/CommandMakeAndActivateEvent.cpp
@@ -9,7 +9,7 @@
CommandMakeAndActivateEvent::CommandMakeAndActivateEvent( const Task& task,
QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Create Event"), parent )
, m_task( task )
{
}
View
30 Charm/Commands/CommandMakeEvent.cpp
@@ -8,14 +8,14 @@
CommandMakeEvent::CommandMakeEvent( const Task& task,
QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Create Event"), parent )
, m_task( task )
{
}
CommandMakeEvent::CommandMakeEvent( const Event& event,
QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Create Event"), parent )
, m_event( event )
{
}
@@ -33,6 +33,18 @@ bool CommandMakeEvent::prepare()
bool CommandMakeEvent::execute( ControllerInterface* controller )
{
+ m_rollback = false;
+
+ if(m_event.id()) //if it already has an id, this is a redo operation
+ {
+ int oid = m_event.id();
+ m_event = controller->cloneEvent(m_event);
+ int nid = m_event.id();
+ if(oid != nid)
+ emit emitSlotEventIdChanged(oid, nid);
+ return m_event.isValid();
+ }
+
Event event = controller->makeEvent( m_task );
if ( !event.isValid() )
return false;
@@ -58,8 +70,16 @@ bool CommandMakeEvent::execute( ControllerInterface* controller )
}
}
+bool CommandMakeEvent::rollback(ControllerInterface *controller )
+{
+ m_rollback = true;
+ return controller->deleteEvent(m_event);
+}
+
bool CommandMakeEvent::finalize()
{
+ if ( m_rollback )
+ return false;
if ( m_event.isValid() ) {
EventView* view = dynamic_cast<EventView*>( owner() );
if ( view )
@@ -71,4 +91,10 @@ bool CommandMakeEvent::finalize()
}
}
+void CommandMakeEvent::eventIdChanged(int oid, int nid)
+{
+ if(m_event.id() == oid)
+ m_event.setId(nid);
+}
+
#include "CommandMakeEvent.moc"
View
5 Charm/Commands/CommandMakeEvent.h
@@ -18,12 +18,17 @@ class CommandMakeEvent : public CharmCommand
bool prepare();
bool execute( ControllerInterface* );
+ bool rollback( ControllerInterface* );
bool finalize();
+public slots:
+ virtual void eventIdChanged(int,int);
+
Q_SIGNALS:
void finishedOk( const Event& );
private:
+ bool m_rollback; //don't show the event in finalize
Task m_task; // the task the new event should be assigned to
Event m_event; // the result, only valid after the event has been created
};
View
19 Charm/Commands/CommandModifyEvent.cpp
@@ -3,9 +3,10 @@
#include "CommandModifyEvent.h"
-CommandModifyEvent::CommandModifyEvent( const Event& event, QObject* parent )
- : CharmCommand( parent )
+CommandModifyEvent::CommandModifyEvent( const Event& event, const Event& oldEvent, QObject* parent )
+ : CharmCommand( tr("Modify Event"), parent )
, m_event( event )
+ , m_oldEvent( oldEvent )
{
}
@@ -25,11 +26,25 @@ bool CommandModifyEvent::execute( ControllerInterface* controller )
return controller->modifyEvent( m_event );
}
+bool CommandModifyEvent::rollback(ControllerInterface *controller)
+{
+ return controller->modifyEvent( m_oldEvent );
+}
+
bool CommandModifyEvent::finalize()
{
return true;
}
+void CommandModifyEvent::eventIdChanged(int oid, int nid)
+{
+ if(m_event.id() == oid)
+ {
+ m_event.setId(nid);
+ m_oldEvent.setId(nid);
+ }
+}
+
#include "CommandModifyEvent.moc"
View
7 Charm/Commands/CommandModifyEvent.h
@@ -9,15 +9,20 @@ class CommandModifyEvent : public CharmCommand
Q_OBJECT
public:
- explicit CommandModifyEvent( const Event&, QObject* parent = 0 );
+ explicit CommandModifyEvent( const Event&, const Event&, QObject* parent = 0 );
~CommandModifyEvent();
bool prepare();
bool execute( ControllerInterface* );
+ bool rollback( ControllerInterface* );
bool finalize();
+public slots:
+ virtual void eventIdChanged(int,int);
+
private:
Event m_event;
+ Event m_oldEvent;
};
#endif
View
2  Charm/Commands/CommandModifyTask.cpp
@@ -7,7 +7,7 @@
#include "CommandModifyTask.h"
CommandModifyTask::CommandModifyTask( const Task& task, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Edit Task"), parent )
, m_task( task )
, m_success( false )
{
View
8 Charm/Commands/CommandRelayCommand.cpp
@@ -4,7 +4,7 @@
#include "CommandRelayCommand.h"
CommandRelayCommand::CommandRelayCommand( QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Relay"), parent )
, m_payload( 0 )
{ // as long as Charm is single-threaded, this does not do anything,
// because there will be no repaint
@@ -33,8 +33,14 @@ bool CommandRelayCommand::execute( ControllerInterface* controller )
return m_payload->execute( controller );
}
+bool CommandRelayCommand::rollback( ControllerInterface* controller )
+{
+ return m_payload->rollback( controller );
+}
+
bool CommandRelayCommand::finalize()
{
+ QApplication::restoreOverrideCursor();
m_payload->owner()->commitCommand( m_payload );
return true;
}
View
1  Charm/Commands/CommandRelayCommand.h
@@ -22,6 +22,7 @@ class CommandRelayCommand : public CharmCommand
bool prepare();
bool execute( ControllerInterface* );
+ bool rollback( ControllerInterface* );
bool finalize();
private:
View
2  Charm/Commands/CommandSetAllTasks.cpp
@@ -7,7 +7,7 @@
#include "CommandSetAllTasks.h"
CommandSetAllTasks::CommandSetAllTasks( const TaskList& tasks, QObject* parent )
- : CharmCommand( parent )
+ : CharmCommand( tr("Import Tasks"), parent )
, m_tasks( tasks )
, m_success( false )
{
View
1  Charm/EventModelAdapter.cpp
@@ -105,7 +105,6 @@ void EventModelAdapter::eventDeactivated( EventId id )
void EventModelAdapter::commitCommand( CharmCommand* command )
{
command->finalize();
- delete command;
}
const Event& EventModelAdapter::eventForIndex( const QModelIndex& index ) const
View
71 Charm/EventView.cpp
@@ -31,6 +31,8 @@
EventView::EventView( QToolBar* toolBar, QWidget* parent )
: QWidget( parent )
, m_model( 0 )
+ , m_actionUndo( this )
+ , m_actionRedo( this )
, m_actionNewEvent( this )
, m_actionEditEvent( this )
, m_actionDeleteEvent( this )
@@ -61,6 +63,24 @@ EventView::EventView( QToolBar* toolBar, QWidget* parent )
// SLOT( slotCommitTimeout() ) );
// m_commitTimer.setSingleShot( true );
+ m_actionUndo.setText(tr("Undo"));
+ m_actionUndo.setToolTip(tr("Undo the latest change"));
+ m_actionUndo.setShortcut(QKeySequence::Undo);
+ m_actionUndo.setEnabled(false);
+
+ m_actionRedo.setText(tr("Redo"));
+ m_actionRedo.setToolTip(tr("Redo the last undone change."));
+ m_actionRedo.setShortcut(QKeySequence::Redo);
+ m_actionRedo.setEnabled(false);
+
+ m_undoStack = new QUndoStack(this);
+ connect(m_undoStack, SIGNAL(canUndoChanged(bool)), &m_actionUndo, SLOT(setEnabled(bool)));
+ connect(m_undoStack, SIGNAL(undoTextChanged(QString)), this, SLOT(slotUndoTextChanged(QString)));
+ connect(&m_actionUndo, SIGNAL(triggered()), m_undoStack, SLOT(undo()));
+
+ connect(m_undoStack, SIGNAL(canRedoChanged(bool)), &m_actionRedo, SLOT(setEnabled(bool)));
+ connect(m_undoStack, SIGNAL(redoTextChanged(QString)), this, SLOT(slotRedoTextChanged(QString)));
+ connect(&m_actionRedo, SIGNAL(triggered()), m_undoStack, SLOT(redo()));
m_actionNewEvent.setText( tr( "New Event..." ) );
m_actionNewEvent.setToolTip( tr( "Create a new Event" ) );
@@ -122,6 +142,9 @@ void EventView::delayedInitialization()
void EventView::populateEditMenu( QMenu* menu )
{
+ menu->addAction( &m_actionUndo );
+ menu->addAction( &m_actionRedo );
+ menu->addSeparator();
menu->addAction( &m_actionNewEvent );
menu->addAction( &m_actionEditEvent );
menu->addAction( &m_actionDeleteEvent );
@@ -165,7 +188,6 @@ void EventView::reject()
void EventView::commitCommand( CharmCommand* command )
{
command->finalize();
- delete command;
}
void EventView::slotCurrentItemChanged( const QModelIndex& start,
@@ -191,6 +213,15 @@ void EventView::setCurrentEvent( const Event& event )
m_event = event;
}
+void EventView::stageCommand(CharmCommand *command)
+{
+ UndoCharmCommandWrapper* undoCommand = new UndoCharmCommandWrapper(command);
+ connect(command, SIGNAL(emitExecute(CharmCommand*)), this, SIGNAL(emitCommand(CharmCommand*)));
+ connect(command, SIGNAL(emitRollback(CharmCommand*)), this, SIGNAL(emitCommandRollback(CharmCommand*)));
+ connect(command, SIGNAL(emitSlotEventIdChanged(int,int)), this, SLOT(slotEventIdChanged(int,int)));
+ m_undoStack->push(undoCommand);
+}
+
void EventView::slotNewEvent()
{
SelectTaskDialog dialog( this );
@@ -223,7 +254,7 @@ void EventView::slotDeleteEvent()
== QMessageBox::Yes ) {
CommandDeleteEvent* command = new CommandDeleteEvent( m_event, this );
command->prepare();
- emitCommand( command );
+ stageCommand( command );
}
}
@@ -338,6 +369,25 @@ void EventView::slotUpdateCurrent()
slotUpdateTotal();
}
+void EventView::slotUndoTextChanged(const QString &text)
+{
+ m_actionUndo.setText(tr("Undo %1").arg(text));
+}
+
+void EventView::slotRedoTextChanged(const QString &text)
+{
+ m_actionRedo.setText(tr("Redo %1").arg(text));
+}
+
+void EventView::slotEventIdChanged(int oldId, int newId)
+{
+ foreach(QObject* o, m_undoStack->children()) {
+ UndoCharmCommandWrapper* wrapper = dynamic_cast<UndoCharmCommandWrapper*>(o);
+ Q_ASSERT(wrapper);
+ wrapper->command()->eventIdChanged(oldId, newId);
+ }
+}
+
void EventView::slotUpdateTotal()
{ // what matching signal does the proxy emit?
int seconds = m_model->totalDuration();
@@ -421,23 +471,26 @@ void EventView::slotEditEvent( const Event& event )
CommandMakeEvent* command =
new CommandMakeEvent( newEvent, this );
connect( command, SIGNAL( finishedOk( const Event& ) ),
- this, SLOT( slotEditEventCompleted( const Event& ) ),
+ this, SLOT( slotEditNewEventCompleted( const Event& ) ),
Qt::QueuedConnection );
- emitCommand( command );
+ stageCommand( command );
return;
-
} else {
- slotEditEventCompleted( newEvent );
+ CommandModifyEvent* command =
+ new CommandModifyEvent( newEvent, event, this );
+ stageCommand( command );
}
}
}
-void EventView::slotEditEventCompleted( const Event& event )
+void EventView::slotEditNewEventCompleted( const Event& event )
{
+ // make event editor finished, bypass the undo stack to set its contents
+ // undo will just target CommandMakeEvent instead
CommandModifyEvent* command =
- new CommandModifyEvent( event, this );
+ new CommandModifyEvent( event, event, this );
emitCommand( command );
+ delete command;
}
-
#include "EventView.moc"
View
12 Charm/EventView.h
@@ -3,12 +3,14 @@
#include <QWidget>
#include <QAction>
+#include <QUndoStack>
#include "Core/Event.h"
#include "Core/TimeSpans.h"
#include "Core/CommandEmitterInterface.h"
#include "ViewModeInterface.h"
+#include "UndoCharmCommandWrapper.h"
class QModelIndex;
@@ -49,6 +51,7 @@ class EventView : public QWidget,
signals:
void visible( bool );
void emitCommand( CharmCommand* );
+ void emitCommandRollback( CharmCommand* );
public slots:
void commitCommand( CharmCommand* );
@@ -61,7 +64,7 @@ private slots:
void slotEventDoubleClicked( const QModelIndex& );
void slotEditEvent();
void slotEditEvent( const Event& );
- void slotEditEventCompleted( const Event& );
+ void slotEditNewEventCompleted( const Event& );
void slotCurrentItemChanged( const QModelIndex&, const QModelIndex& );
void slotContextMenuRequested( const QPoint& );
void slotNextEvent();
@@ -72,14 +75,21 @@ private slots:
void slotEventDeactivated( EventId );
void slotUpdateTotal();
void slotUpdateCurrent();
+ void slotUndoTextChanged(const QString&);
+ void slotRedoTextChanged(const QString&);
+ void slotEventIdChanged(int oldId, int newId);
private:
Event newSettings();
void setCurrentEvent( const Event& );
+ void stageCommand( CharmCommand* );
+ QUndoStack* m_undoStack;
QList<NamedTimeSpan> m_timeSpans;
Event m_event;
EventModelFilter* m_model;
+ QAction m_actionUndo;
+ QAction m_actionRedo;
QAction m_actionNewEvent;
QAction m_actionEditEvent;
QAction m_actionDeleteEvent;
View
2  Charm/EventWindow.cpp
@@ -18,6 +18,8 @@ EventWindow::EventWindow( QWidget* parent )
setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding );
connect( m_eventView, SIGNAL( emitCommand( CharmCommand* ) ),
SIGNAL( emitCommand( CharmCommand* ) ) );
+ connect( m_eventView, SIGNAL( emitCommandRollback( CharmCommand* ) ),
+ SIGNAL( emitCommandRollback( CharmCommand* ) ) );
}
EventWindow::~EventWindow()
View
1  Charm/EventWindow.h
@@ -25,6 +25,7 @@ public slots:
signals:
/* reimpl */ void emitCommand( CharmCommand* );
+ /* reimpl */ void emitCommandRollback( CharmCommand* );
/* reimpl */ void quit();
private:
View
9 Charm/ModelConnector.cpp
@@ -14,8 +14,8 @@ ModelConnector::ModelConnector()
{
connect( &m_dataModel, SIGNAL( makeAndActivateEvent( const Task& ) ),
SLOT( slotMakeAndActivateEvent( const Task& ) ) );
- connect( &m_dataModel, SIGNAL( requestEventModification( const Event& ) ),
- SLOT( slotRequestEventModification( const Event& ) ) );
+ connect( &m_dataModel, SIGNAL( requestEventModification( const Event&, const Event& ) ),
+ SLOT( slotRequestEventModification( const Event&, const Event& ) ) );
connect( &m_dataModel, SIGNAL( sysTrayUpdate( const QString&, bool ) ),
SLOT( slotSysTrayUpdate( const QString&, bool ) ) );
connect( &m_iconTimer, SIGNAL( timeout() ),
@@ -53,7 +53,6 @@ void ModelConnector::commitCommand( CharmCommand* command )
<< command->metaObject()->className()
<< "command has failed";
}
- delete command;
}
void ModelConnector::slotMakeAndActivateEvent( const Task& task )
@@ -64,9 +63,9 @@ void ModelConnector::slotMakeAndActivateEvent( const Task& task )
VIEW.sendCommand( command );
}
-void ModelConnector::slotRequestEventModification( const Event& event )
+void ModelConnector::slotRequestEventModification( const Event& newEvent, const Event& oldEvent )
{
- CommandModifyEvent* command = new CommandModifyEvent( event, this );
+ CommandModifyEvent* command = new CommandModifyEvent( newEvent, oldEvent, this );
VIEW.sendCommand( command );
}
View
2  Charm/ModelConnector.h
@@ -26,7 +26,7 @@ class ModelConnector : public QObject,
public slots:
void slotMakeAndActivateEvent( const Task& );
- void slotRequestEventModification( const Event& );
+ void slotRequestEventModification(const Event&newEvent, const Event& oldEvent);
void slotSysTrayUpdate( const QString&, bool );
void slotSysTrayIconUpdate();
View
3  Charm/TaskModelAdapter.cpp
@@ -175,7 +175,7 @@ bool TaskModelAdapter::setData( const QModelIndex & index, const QVariant & valu
QString comment = value.toString();
Event event( old );
event.setComment( comment );
- CommandModifyEvent* command = new CommandModifyEvent( event, this );
+ CommandModifyEvent* command = new CommandModifyEvent( event, old, this );
VIEW.sendCommand( command );
return true;
} else if ( role == Qt::CheckStateRole ) {
@@ -349,7 +349,6 @@ void TaskModelAdapter::commitCommand( CharmCommand* command )
{
Q_ASSERT( command->owner() == this );
command->finalize();
- delete command;
}
#include "TaskModelAdapter.moc"
View
1  Charm/TasksView.cpp
@@ -420,7 +420,6 @@ void TasksView::configureUi()
void TasksView::commitCommand( CharmCommand* command )
{
command->finalize();
- delete command;
}
void TasksView::slotEventActivated( EventId )
View
1  Charm/TasksView.h
@@ -45,6 +45,7 @@ public Q_SLOTS:
// FIXME connect to MainWindow
void saveConfiguration();
void emitCommand( CharmCommand* );
+ void emitCommandRollback( CharmCommand* );
private slots:
void actionNewTask();
View
7 Charm/TasksWindow.cpp
@@ -15,6 +15,8 @@ TasksWindow::TasksWindow( QWidget* parent )
setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding );
connect( m_tasksView, SIGNAL( emitCommand( CharmCommand* ) ),
SIGNAL( emitCommand( CharmCommand* ) ) );
+ connect( m_tasksView, SIGNAL( emitCommandRollback( CharmCommand* ) ),
+ SIGNAL( emitCommandRollback( CharmCommand* ) ) );
connect( m_tasksView, SIGNAL( saveConfiguration() ),
SIGNAL( saveConfiguration() ) );
}
@@ -55,6 +57,11 @@ void TasksWindow::sendCommand( CharmCommand* )
Q_ASSERT( false ); // should not be called
}
+void TasksWindow::sendCommandRollback( CharmCommand* )
+{
+ Q_ASSERT( false ); // should not be called
+}
+
void TasksWindow::commitCommand( CharmCommand* )
{
}
View
2  Charm/TasksWindow.h
@@ -15,6 +15,7 @@ class TasksWindow : public CharmWindow
/* reimpl */ void stateChanged( State previous );
/* reimpl */ void sendCommand( CharmCommand* );
+ /* reimpl */ void sendCommandRollback( CharmCommand* );
/* reimpl */ void commitCommand( CharmCommand* );
// restore the view
@@ -28,6 +29,7 @@ public slots:
signals:
/* reimpl */ void emitCommand( CharmCommand* );
+ /* reimpl */ void emitCommandRollback( CharmCommand* );
/* reimpl */ void quit();
private:
View
3  Charm/TimeTrackingView/TimeTrackingWindow.cpp
@@ -458,10 +458,11 @@ void TimeTrackingWindow::maybeIdle()
Q_FOREACH ( EventId eventId, activeEvents ) {
Event event = DATAMODEL->eventForId( eventId );
if ( event.isValid() ) {
+ Event old = event;
QDateTime start = period.first; // initializes a valid QDateTime
event.setEndDateTime( qMax( event.startDateTime(), start ) );
Q_ASSERT( event.isValid() );
- CommandModifyEvent* cmd = new CommandModifyEvent( event, this );
+ CommandModifyEvent* cmd = new CommandModifyEvent( event, old, this );
emit emitCommand( cmd );
}
}
View
1  Charm/TimeTrackingView/TimeTrackingWindow.h
@@ -75,6 +75,7 @@ private slots:
signals:
void emitCommand( CharmCommand* );
+ void emitCommandRollback( CharmCommand* );
private:
void showPreview( ReportConfigurationDialog*, int result );
View
27 Charm/UndoCharmCommandWrapper.cpp
@@ -0,0 +1,27 @@
+#include "UndoCharmCommandWrapper.h"
+
+UndoCharmCommandWrapper::UndoCharmCommandWrapper(CharmCommand* command)
+ : m_command(command)
+{
+ setText(command->description());
+}
+
+UndoCharmCommandWrapper::~UndoCharmCommandWrapper()
+{
+ delete m_command;
+}
+
+void UndoCharmCommandWrapper::undo()
+{
+ m_command->requestRollback();
+}
+
+void UndoCharmCommandWrapper::redo()
+{
+ m_command->requestExecute();
+}
+
+CharmCommand *UndoCharmCommandWrapper::command() const
+{
+ return m_command;
+}
View
25 Charm/UndoCharmCommandWrapper.h
@@ -0,0 +1,25 @@
+#ifndef UNDOCHARMCOMMANDWRAPPER_H
+#define UNDOCHARMCOMMANDWRAPPER_H
+
+#include <QUndoCommand>
+
+#include "Core/CharmCommand.h"
+
+/**
+ Thin wrapper for CharmCommand -> QUndoCommand
+
+ It simply forwards the command text and emits signals for commit/rollback on undo/redo
+ **/
+class UndoCharmCommandWrapper : public QUndoCommand
+{
+public:
+ UndoCharmCommandWrapper(CharmCommand* command);
+ virtual ~UndoCharmCommandWrapper();
+ virtual void undo();
+ virtual void redo();
+ CharmCommand* command() const;
+private:
+ CharmCommand* m_command;
+};
+
+#endif
View
2  Charm/ViewHelpers.cpp
@@ -8,6 +8,8 @@ void connectControllerAndView( Controller* controller, CharmWindow* view )
// make controller process commands send by the view:
QObject::connect( view, SIGNAL( emitCommand( CharmCommand* ) ),
controller, SLOT( executeCommand( CharmCommand* ) ) );
+ QObject::connect( view, SIGNAL( emitCommandRollback( CharmCommand* ) ),
+ controller, SLOT( rollbackCommand( CharmCommand* ) ) );
// make view receive done commands from the controller:
QObject::connect( controller, SIGNAL( commandCompleted( CharmCommand* ) ),
view, SLOT( commitCommand( CharmCommand* ) ) );
View
25 Core/CharmCommand.cpp
@@ -1,8 +1,9 @@
#include "CommandEmitterInterface.h"
#include "CharmCommand.h"
-CharmCommand::CharmCommand( QObject* parent )
- : QObject( parent )
+CharmCommand::CharmCommand( const QString& description, QObject *parent )
+ : QObject( parent ),
+ m_description(description)
{
CommandEmitterInterface* emitter = dynamic_cast<CommandEmitterInterface*>( parent );
if ( emitter ) {
@@ -18,9 +19,29 @@ CharmCommand::~CharmCommand()
{
}
+QString CharmCommand::description() const
+{
+ return m_description;
+}
+
CommandEmitterInterface* CharmCommand::owner() const
{
return m_owner;
}
+void CharmCommand::requestExecute()
+{
+ emit emitExecute(this);
+}
+
+void CharmCommand::requestRollback()
+{
+ emit emitRollback(this);
+}
+
+void CharmCommand::requestSlotEventIdChanged(int oldId, int newId)
+{
+ emit emitSlotEventIdChanged(oldId,newId);
+}
+
#include "CharmCommand.moc"
View
20 Core/CharmCommand.h
@@ -38,19 +38,37 @@ class CharmCommand : public QObject
Q_OBJECT
public:
- explicit CharmCommand( QObject* parent = 0 );
+ explicit CharmCommand( const QString& description, QObject* parent = 0 );
virtual ~CharmCommand();
+ QString description() const;
+
virtual bool prepare() = 0;
virtual bool execute( ControllerInterface* controller ) = 0;
+ virtual bool rollback( ControllerInterface* controller ) { return false; }
virtual bool finalize() = 0;
CommandEmitterInterface* owner() const;
+ //used by UndoCharmCommandWrapper to forward signal firing
+ //forwards to emitExecute/emitRollback/emitRequestSlotEventIdChanged
+ void requestExecute();
+ void requestRollback();
+ void requestSlotEventIdChanged(int oldId, int newId);
+
+ //notify CharmCommands in a QUndoStack that an event ID has changed
+ virtual void eventIdChanged(int,int){}
+
+signals:
+ void emitExecute(CharmCommand*);
+ void emitRollback(CharmCommand*);
+ void emitSlotEventIdChanged(int,int);
+
private:
CharmCommand( const CharmCommand& ); // disallow copying
CommandEmitterInterface* m_owner;
+ const QString m_description;
};
#endif
View
9 Core/CharmDataModel.cpp
@@ -424,9 +424,10 @@ void CharmDataModel::endEventRequested( const Task& task )
Q_ASSERT( eventId != 0 );
Event& event = findEvent( eventId );
+ Event old = event;
event.setEndDateTime( QDateTime::currentDateTime() );
- emit requestEventModification( event );
+ emit requestEventModification( event, old );
if ( m_activeEventIds.isEmpty() ) m_timer.stop();
updateToolTip();
@@ -444,9 +445,10 @@ void CharmDataModel::endAllEventsRequested()
Q_ASSERT( eventId != 0 );
Event& event = findEvent( eventId );
+ Event old = event;
event.setEndDateTime( currentDateTime );
- emit requestEventModification( event );
+ emit requestEventModification( event, old );
}
m_timer.stop();
@@ -459,9 +461,10 @@ void CharmDataModel::eventUpdateTimerEvent()
// Not a ref (Event &), since we want to diff "old event"
// and "new event" in *Adapter::eventModified
Event event = findEvent( id );
+ Event old = event;
event.setEndDateTime( QDateTime::currentDateTime() );
- emit requestEventModification( event );
+ emit requestEventModification( event, old );
}
updateToolTip();
}
View
2  Core/CharmDataModel.h
@@ -99,7 +99,7 @@ class CharmDataModel : public QObject
// these need to be implemented in the respective application to
// be able to track time:
void makeAndActivateEvent( const Task& );
- void requestEventModification( const Event& );
+ void requestEventModification( const Event&, const Event& );
void sysTrayUpdate( const QString&, bool );
public slots:
View
24 Core/Controller.cpp
@@ -36,6 +36,22 @@ Event Controller::makeEvent( const Task& task )
return event;
}
+Event Controller::cloneEvent(const Event &e)
+{
+ Event event = m_storage->makeEvent();
+ Q_ASSERT( event.isValid() );
+
+ int id = event.id();
+ event = e;
+ event.setId(id);
+ if ( m_storage->modifyEvent( event ) ) {
+ emit eventAdded( event );
+ } else {
+ event = Event();
+ }
+ return event;
+}
+
bool Controller::modifyEvent( const Event& e )
{
if ( m_storage->modifyEvent( e ) )
@@ -329,6 +345,14 @@ void Controller::executeCommand( CharmCommand* command )
emit commandCompleted( command );
}
+void Controller::rollbackCommand( CharmCommand* command )
+{
+ command->rollback( this );
+ // send it back to the view:
+ emit commandCompleted( command );
+}
+
+
StorageInterface* Controller::storage()
{
return m_storage;
View
2  Core/Controller.h
@@ -30,6 +30,7 @@ class Controller : public QObject,
// FIXME add the add/modify/delete functions will not be slots anymore
Event makeEvent( const Task& );
+ Event cloneEvent( const Event& );
bool modifyEvent( const Event& );
bool deleteEvent( const Event& );
@@ -45,6 +46,7 @@ class Controller : public QObject,
public slots:
void executeCommand( CharmCommand* );
+ void rollbackCommand ( CharmCommand* );
signals:
void eventAdded( const Event& event );
View
4 Core/ControllerInterface.h
@@ -28,6 +28,8 @@ class ControllerInterface
/** Add an event.
Return a valid event if successfull. */
virtual Event makeEvent( const Task& ) = 0;
+ /** Add an event, copying data from another event. */
+ virtual Event cloneEvent( const Event& ) = 0;
/** Modify an event. */
virtual bool modifyEvent( const Event& ) = 0;
/** Delete an event. */
@@ -42,6 +44,8 @@ class ControllerInterface
virtual bool setAllTasks( const TaskList& tasks ) = 0;
/** Receive a command from the view. */
virtual void executeCommand( CharmCommand* ) = 0;
+ /** Receive an undo command from the view. */
+ virtual void rollbackCommand( CharmCommand* ) = 0;
/** Export the database contents into a XML document. */
virtual QDomDocument exportDatabasetoXml() const = 0 ;
/** Import the content of the Xml document into the currently open database.
View
2  Core/ViewInterface.h
@@ -19,7 +19,9 @@ class ViewInterface
virtual void saveConfiguration() = 0;
virtual void emitCommand( CharmCommand* ) = 0;
+ virtual void emitCommandRollback( CharmCommand* ) = 0;
virtual void sendCommand( CharmCommand* ) = 0;
+ virtual void sendCommandRollback( CharmCommand* ) = 0;
virtual void commitCommand( CharmCommand* ) = 0;
// restore the view
Please sign in to comment.
Something went wrong with that request. Please try again.