forked from mia/Aegisub
Broken undo/redo stack on gorgonsub
Originally committed to SVN as r2049.
This commit is contained in:
parent
b073b7d28d
commit
000271c087
9 changed files with 201 additions and 28 deletions
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -66,15 +67,19 @@ namespace Gorgonsub {
|
||||||
ViewList listeners;
|
ViewList listeners;
|
||||||
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 ¬ification) const;
|
void DispatchNotifications(const Notification ¬ification) const;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -58,19 +58,28 @@ void Model::DispatchNotifications(const Notification ¬ification) 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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in a new issue