Broken undo/redo stack on gorgonsub

Originally committed to SVN as r2049.
This commit is contained in:
Rodrigo Braz Monteiro 2008-03-14 03:33:27 +00:00
parent b073b7d28d
commit 000271c087
9 changed files with 201 additions and 28 deletions

View file

@ -51,21 +51,22 @@ namespace Gorgonsub {
private: private:
String actionName; String actionName;
String owner;
Model &model; Model &model;
std::list<Action> actions; std::list<Action> actions;
bool valid; bool valid;
bool undoAble;
ActionList(); ActionList(Model &model,const String actionName,const String owner,bool undoAble);
ActionList(Model &model,const String actionName);
void Start(const String actionName); void Start(const String actionName);
void AddAction(const Action &action);
public: public:
~ActionList(); ~ActionList();
void AddAction(const Action &action);
void Finish(); void Finish();
void InsertLine(SectionEntryPtr line,int position=-1,const String section=L""); void InsertLine(SectionEntryPtr line,int position=-1,const String section=L"");
void RemoveLine(int position,const String section);
}; };
typedef shared_ptr<ActionList> ActionListPtr; typedef shared_ptr<ActionList> ActionListPtr;

View file

@ -52,11 +52,16 @@ namespace Gorgonsub {
public: public:
Controller (Model &model); Controller (Model &model);
ActionListPtr CreateActionList(const String title); ActionListPtr CreateActionList(const String title,const String owner=L"",bool undoAble=true);
void LoadFile(const String filename,const String encoding=L""); void LoadFile(const String filename,const String encoding=L"");
void SaveFile(const String filename,const String encoding=L"UTF-8"); void SaveFile(const String filename,const String encoding=L"UTF-8");
bool CanUndo(const String owner=L"") const;
bool CanRedo(const String owner=L"") const;
void Undo(const String owner=L"");
void Redo(const String owner=L"");
SectionEntryDialoguePtr CreateDialogue(); SectionEntryDialoguePtr CreateDialogue();
SectionEntryStylePtr CreateStyle(); SectionEntryStylePtr CreateStyle();

View file

@ -36,6 +36,7 @@
#pragma once #pragma once
#include <list> #include <list>
#include <vector> #include <vector>
#include <stack>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include "actionlist.h" #include "actionlist.h"
#include "section.h" #include "section.h"
@ -56,7 +57,7 @@ namespace Gorgonsub {
friend class Controller; friend class Controller;
typedef std::list<ViewPtr> ViewList; typedef std::list<ViewPtr> ViewList;
typedef std::list<ActionListPtr> ActionStack; typedef std::stack<ActionListPtr,std::list<ActionListPtr> > ActionStack;
typedef shared_ptr<Format> FormatPtr; typedef shared_ptr<Format> FormatPtr;
private: private:
@ -67,14 +68,18 @@ namespace Gorgonsub {
bool readOnly; bool readOnly;
FormatPtr format; FormatPtr format;
void ProcessActionList(const ActionList &actionList,bool insertInStack); void ProcessActionList(const ActionList &actionList);
void DoActionList(const ActionListPtr list);
void DoAction(const Action &action); void DoAction(const Action &action);
ActionListPtr CreateAntiActionList(const ActionListPtr &manipulator); ActionListPtr CreateAntiActionList(const ActionListPtr &manipulator);
Action GetAntiAction(const Action &action);
bool CanUndo(const String owner=L"") const; bool CanUndo(const String owner=L"") const;
bool CanRedo(const String owner=L"") const; bool CanRedo(const String owner=L"") const;
bool Undo(const String owner=L""); void Undo(const String owner=L"");
bool Redo(const String owner=L""); void Redo(const String owner=L"");
void ActivateStack(ActionStack &from,ActionStack &to,const String &owner);
void DispatchNotifications(const Notification &notification) const; void DispatchNotifications(const Notification &notification) const;

View file

@ -69,7 +69,7 @@ namespace Gorgonsub {
void AddEntry(SectionEntryPtr entry,int pos=-1); void AddEntry(SectionEntryPtr entry,int pos=-1);
void RemoveEntryByIndex(size_t index); void RemoveEntryByIndex(size_t index);
void RemoveEntry(SectionEntryPtr entry); void RemoveEntry(SectionEntryPtr entry);
SectionEntryConstPtr GetEntry(size_t index) const; SectionEntryPtr GetEntry(size_t index) const;
size_t GetEntryCount() const; size_t GetEntryCount() const;
}; };
typedef shared_ptr<Section> SectionPtr; typedef shared_ptr<Section> SectionPtr;

View file

@ -39,8 +39,8 @@ using namespace Gorgonsub;
/////////////// ///////////////
// Constructor // Constructor
ActionList::ActionList(Model &_model,String _actionName) ActionList::ActionList(Model &_model,String _actionName,const String _owner,bool _undoAble)
: model(_model) : model(_model), owner(_owner), undoAble(_undoAble)
{ {
Start(_actionName); Start(_actionName);
} }
@ -77,7 +77,7 @@ void ActionList::Start(const String name)
void ActionList::Finish() void ActionList::Finish()
{ {
if (valid) { if (valid) {
model.ProcessActionList(*this,false); model.ProcessActionList(*this);
actions.clear(); actions.clear();
valid = false; valid = false;
} }
@ -91,3 +91,12 @@ void ActionList::InsertLine(SectionEntryPtr line,int position,const String secti
Action action = Action(ACTION_INSERT,line,section,position); Action action = Action(ACTION_INSERT,line,section,position);
AddAction(action); AddAction(action);
} }
/////////////////////////////////
// Create a "remove line" action
void ActionList::RemoveLine(int position,const String section)
{
Action action = Action(ACTION_REMOVE,SectionEntryPtr(),section,position);
AddAction(action);
}

View file

@ -33,6 +33,7 @@
// Contact: mailto:amz@aegisub.net // Contact: mailto:amz@aegisub.net
// //
#include "controller.h"
#include "Gorgonsub.h" #include "Gorgonsub.h"
using namespace Gorgonsub; using namespace Gorgonsub;
@ -47,9 +48,9 @@ Controller::Controller(Model &_model)
///////////////////////// /////////////////////////
// Create an action list // Create an action list
ActionListPtr Controller::CreateActionList(const String title) ActionListPtr Controller::CreateActionList(const String title,const String owner,bool undoAble)
{ {
return ActionListPtr (new ActionList(model,title)); return ActionListPtr (new ActionList(model,title,owner,undoAble));
} }
@ -91,3 +92,23 @@ SectionEntryStylePtr Controller::CreateStyle()
{ {
return GetFormat()->CreateStyle(); return GetFormat()->CreateStyle();
} }
////////
// Undo
bool Controller::CanUndo(const String owner) const
{
return model.CanUndo(owner);
}
bool Controller::CanRedo(const String owner) const
{
return model.CanRedo(owner);
}
void Controller::Undo(const String owner)
{
model.Undo(owner);
}
void Controller::Redo(const String owner)
{
model.Redo(owner);
}

View file

@ -58,19 +58,28 @@ void Model::DispatchNotifications(const Notification &notification) const
//////////////////////////// ////////////////////////////
// Processes an action list // Processes an action list
void Model::ProcessActionList(const ActionList &_actionList,bool insertInStack) void Model::ProcessActionList(const ActionList &_actionList)
{ {
// Copy the list // Copy the list
ActionListPtr actions = ActionListPtr(new ActionList(_actionList)); ActionListPtr actions = ActionListPtr(new ActionList(_actionList));
// Inserts the opposite into the undo stack // Inserts the opposite into the undo stack
if (insertInStack) { if (actions->undoAble) {
undoStack.push_back(CreateAntiActionList(actions)); undoStack.push(CreateAntiActionList(actions));
redoStack.clear(); redoStack = ActionStack();
} }
// Do actions // Execute list
std::list<Action>::iterator cur; DoActionList(actions);
}
//////////////////////////
// Execute an action list
void Model::DoActionList(const ActionListPtr actions)
{
// Do each action
std::list<Action>::const_iterator cur;
for (cur=actions->actions.begin();cur!=actions->actions.end();cur++) { for (cur=actions->actions.begin();cur!=actions->actions.end();cur++) {
DoAction(*cur); DoAction(*cur);
} }
@ -85,7 +94,8 @@ void Model::ProcessActionList(const ActionList &_actionList,bool insertInStack)
void Model::DoAction(const Action &action) void Model::DoAction(const Action &action)
{ {
switch (action.GetType()) { switch (action.GetType()) {
case ACTION_INSERT: { // Insert a line
case ACTION_INSERT: {
// Get the line // Get the line
SectionEntryPtr entry = static_pointer_cast<SectionEntry>(action.GetData()); SectionEntryPtr entry = static_pointer_cast<SectionEntry>(action.GetData());
@ -96,6 +106,19 @@ void Model::DoAction(const Action &action)
// Insert the line // Insert the line
section->AddEntry(entry,action.GetLineNumber()); section->AddEntry(entry,action.GetLineNumber());
return;
}
// Delete a line
case ACTION_REMOVE: {
// Find the section to remote it from
String sectionName = action.GetSection();
if (sectionName.IsEmpty()) throw Exception(Exception::TODO); // TODO
SectionPtr section = GetSection(sectionName);
// Remove the line
section->RemoveEntryByIndex(action.GetLineNumber());
return;
} }
} }
} }
@ -105,12 +128,52 @@ void Model::DoAction(const Action &action)
// Create an anti-actionlist to undo the actions made by a actionlist // Create an anti-actionlist to undo the actions made by a actionlist
ActionListPtr Model::CreateAntiActionList(const ActionListPtr &src) ActionListPtr Model::CreateAntiActionList(const ActionListPtr &src)
{ {
ActionListPtr dst(new ActionList(*this,src->actionName)); // Create list
// TODO ActionListPtr dst(new ActionList(*this,src->actionName,src->owner,false));
// Insert anti-actions
std::list<Action>::const_reverse_iterator cur;
for (cur=src->actions.rbegin();cur!=src->actions.rend();cur++) {
//std::list<Action>::const_iterator cur;
//for (cur=src->actions.begin();cur!=src->actions.end();cur++) {
dst->AddAction(GetAntiAction(*cur));
}
// Return
return dst; return dst;
} }
///////////////////////////////////////////
// Create the action opposite to the input
Action Model::GetAntiAction(const Action &action)
{
switch (action.GetType()) {
// Create a remove
case ACTION_INSERT: {
// Find the section to insert it on
String section = action.GetSection();
if (section.IsEmpty()) {
SectionEntryPtr entry = static_pointer_cast<SectionEntry>(action.GetData());
section = entry->GetDefaultGroup();
}
return Action(ACTION_REMOVE,SectionEntryPtr(),section,action.GetLineNumber());
}
// Create an insert
case ACTION_REMOVE: {
int line = action.GetLineNumber();
const String &sName = action.GetSection();
SectionPtr section = GetSection(sName);
return Action(ACTION_INSERT,section->GetEntry(line),sName,line);
}
}
throw Exception(Exception::Invalid_ActionList);
}
////////////////// //////////////////
// Load subtitles // Load subtitles
void Model::Load(wxInputStream &input,const FormatPtr _format,const String encoding) void Model::Load(wxInputStream &input,const FormatPtr _format,const String encoding)
@ -200,6 +263,54 @@ size_t Model::GetSectionCount() const
void Model::Clear() void Model::Clear()
{ {
sections.clear(); sections.clear();
undoStack.clear(); undoStack = ActionStack();
redoStack.clear(); redoStack = ActionStack();
}
//////////////////
// Can undo/redo?
bool Model::CanUndo(const String owner) const
{
(void) owner;
return undoStack.size() > 0;
}
bool Model::CanRedo(const String owner) const
{
(void) owner;
return redoStack.size() > 0;
}
///////////////////
// Perform an undo
void Model::Undo(const String owner)
{
ActivateStack(undoStack,redoStack,owner);
}
//////////////////
// Perform a redo
void Model::Redo(const String owner)
{
ActivateStack(redoStack,undoStack,owner);
}
/////////////////////
// Perform undo/redo
void Model::ActivateStack(ActionStack &from,ActionStack &to,const String &owner)
{
// TODO: do something with this
(void) owner;
// Create opposite
to.push(CreateAntiActionList(from.top()));
// Process list
DoActionList(from.top());
// Pop original
from.pop();
} }

View file

@ -70,7 +70,7 @@ void Section::RemoveEntry(SectionEntryPtr entry)
} }
} }
SectionEntryConstPtr Section::GetEntry(size_t index) const SectionEntryPtr Section::GetEntry(size_t index) const
{ {
return entries[index]; return entries[index];
} }

View file

@ -69,9 +69,30 @@ int main () {
cout << "Processing actions... "; cout << "Processing actions... ";
ActionListPtr actions = control.CreateActionList(L"Insert line"); ActionListPtr actions = control.CreateActionList(L"Insert line");
actions->InsertLine(line,2); actions->InsertLine(line,2);
actions->RemoveLine(3,L"Events");
actions->Finish(); actions->Finish();
cout << "Done.\n"; cout << "Done.\n";
// Save subtitles
cout << "Saving file... ";
control.SaveFile(L"subs_out_mid1.ass",L"UTF-8");
cout << "Done.\n";
// Undo
cout << "Undoing... (can undo=" << (control.CanUndo()?"true":"false") << ") ";
control.Undo();
cout << "Done.\n";
// Save subtitles
cout << "Saving file... ";
control.SaveFile(L"subs_out_mid2.ass",L"UTF-8");
cout << "Done.\n";
// Redo
cout << "Undoing... (can redo=" << (control.CanRedo()?"true":"false") << ") ";
control.Redo();
cout << "Done.\n";
// Save subtitles // Save subtitles
cout << "Saving file... "; cout << "Saving file... ";
control.SaveFile(L"subs_out.ass",L"UTF-8"); control.SaveFile(L"subs_out.ass",L"UTF-8");