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:
|
||||
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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
@ -67,14 +68,18 @@ namespace Gorgonsub {
|
|||
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 ¬ification) const;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -58,19 +58,28 @@ void Model::DispatchNotifications(const Notification ¬ification) 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();
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue