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:
String actionName;
String owner;
Model &model;
std::list<Action> actions;
bool valid;
bool undoAble;
ActionList();
ActionList(Model &model,const String actionName);
ActionList(Model &model,const String actionName,const String owner,bool undoAble);
void Start(const String actionName);
void AddAction(const Action &action);
public:
~ActionList();
void AddAction(const Action &action);
void Finish();
void InsertLine(SectionEntryPtr line,int position=-1,const String section=L"");
void RemoveLine(int position,const String section);
};
typedef shared_ptr<ActionList> ActionListPtr;

View file

@ -52,11 +52,16 @@ namespace Gorgonsub {
public:
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 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();
SectionEntryStylePtr CreateStyle();

View file

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

View file

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

View file

@ -39,8 +39,8 @@ using namespace Gorgonsub;
///////////////
// Constructor
ActionList::ActionList(Model &_model,String _actionName)
: model(_model)
ActionList::ActionList(Model &_model,String _actionName,const String _owner,bool _undoAble)
: model(_model), owner(_owner), undoAble(_undoAble)
{
Start(_actionName);
}
@ -77,7 +77,7 @@ void ActionList::Start(const String name)
void ActionList::Finish()
{
if (valid) {
model.ProcessActionList(*this,false);
model.ProcessActionList(*this);
actions.clear();
valid = false;
}
@ -91,3 +91,12 @@ void ActionList::InsertLine(SectionEntryPtr line,int position,const String secti
Action action = Action(ACTION_INSERT,line,section,position);
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
//
#include "controller.h"
#include "Gorgonsub.h"
using namespace Gorgonsub;
@ -47,9 +48,9 @@ Controller::Controller(Model &_model)
/////////////////////////
// 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();
}
////////
// 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
void Model::ProcessActionList(const ActionList &_actionList,bool insertInStack)
void Model::ProcessActionList(const ActionList &_actionList)
{
// Copy the list
ActionListPtr actions = ActionListPtr(new ActionList(_actionList));
// Inserts the opposite into the undo stack
if (insertInStack) {
undoStack.push_back(CreateAntiActionList(actions));
redoStack.clear();
if (actions->undoAble) {
undoStack.push(CreateAntiActionList(actions));
redoStack = ActionStack();
}
// Do actions
std::list<Action>::iterator cur;
// Execute list
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++) {
DoAction(*cur);
}
@ -85,7 +94,8 @@ void Model::ProcessActionList(const ActionList &_actionList,bool insertInStack)
void Model::DoAction(const Action &action)
{
switch (action.GetType()) {
case ACTION_INSERT: {
// Insert a line
case ACTION_INSERT: {
// Get the line
SectionEntryPtr entry = static_pointer_cast<SectionEntry>(action.GetData());
@ -96,6 +106,19 @@ void Model::DoAction(const Action &action)
// Insert the line
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
ActionListPtr Model::CreateAntiActionList(const ActionListPtr &src)
{
ActionListPtr dst(new ActionList(*this,src->actionName));
// TODO
// Create list
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;
}
///////////////////////////////////////////
// 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
void Model::Load(wxInputStream &input,const FormatPtr _format,const String encoding)
@ -200,6 +263,54 @@ size_t Model::GetSectionCount() const
void Model::Clear()
{
sections.clear();
undoStack.clear();
redoStack.clear();
undoStack = ActionStack();
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];
}

View file

@ -69,9 +69,30 @@ int main () {
cout << "Processing actions... ";
ActionListPtr actions = control.CreateActionList(L"Insert line");
actions->InsertLine(line,2);
actions->RemoveLine(3,L"Events");
actions->Finish();
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
cout << "Saving file... ";
control.SaveFile(L"subs_out.ass",L"UTF-8");