Rewrite Undo/Redo code

Make the undo and redo stacks non-static members of AssFile, making it
theoretically possible to have multiple open AssFiles with working undo.

Slightly improve tracking of whether the file is modified: saving,
making a change, then undoing the change now results in the file being
shown as unmodified as with most programs with undo.

Add basic undo coalescing support.

Originally committed to SVN as r4667.
This commit is contained in:
Thomas Goyne 2010-07-09 07:31:34 +00:00
parent 518e78ac6f
commit 2e5dc176db
22 changed files with 158 additions and 219 deletions

View file

@ -61,10 +61,17 @@
#include "utils.h" #include "utils.h"
#include "version.h" #include "version.h"
namespace std {
template<>
void swap(AssFile &lft, AssFile &rgt) {
lft.swap(rgt);
}
}
/// @brief AssFile constructor /// @brief AssFile constructor
AssFile::AssFile () { AssFile::AssFile ()
loaded = false; : loaded(false)
Modified = false; {
} }
/// @brief AssFile destructor /// @brief AssFile destructor
@ -74,6 +81,7 @@ AssFile::~AssFile() {
void AssFile::Load (const wxString &_filename,wxString charset,bool addToRecent) { void AssFile::Load (const wxString &_filename,wxString charset,bool addToRecent) {
bool ok = false; bool ok = false;
Clear();
try { try {
// Try to open file // Try to open file
@ -141,6 +149,10 @@ void AssFile::Load (const wxString &_filename,wxString charset,bool addToRecent)
AddComment(_T("http://www.aegisub.org/")); AddComment(_T("http://www.aegisub.org/"));
SetScriptInfo(_T("ScriptType"),_T("v4.00+")); SetScriptInfo(_T("ScriptType"),_T("v4.00+"));
// Push the initial state of the file onto the undo stack
Commit("", commitId);
savedCommitId = commitId;
// Add to recent // Add to recent
if (addToRecent) AddToRecent(_filename); if (addToRecent) AddToRecent(_filename);
} }
@ -171,7 +183,7 @@ void AssFile::Save(wxString _filename,bool setfilename,bool addToRecent,const wx
// Done // Done
if (setfilename) { if (setfilename) {
Modified = false; savedCommitId = commitId;
filename = _filename; filename = _filename;
} }
} }
@ -416,7 +428,11 @@ void AssFile::Clear() {
loaded = false; loaded = false;
filename.clear(); filename.clear();
Modified = false; UndoStack.clear();
RedoStack.clear();
undoDescription.clear();
commitId = -1;
savedCommitId = 0;
} }
void AssFile::LoadDefault (bool defline) { void AssFile::LoadDefault (bool defline) {
@ -445,20 +461,30 @@ void AssFile::LoadDefault (bool defline) {
AddLine(def.GetEntryData(),_T("[Events]"),version); AddLine(def.GetEntryData(),_T("[Events]"),version);
} }
Commit("");
savedCommitId = commitId;
loaded = true; loaded = true;
} }
AssFile::AssFile (const AssFile &from) { void AssFile::swap(AssFile &that) throw() {
filename = from.filename; // Intentionally does not swap undo stack related things
loaded = from.loaded; std::swap(filename, that.filename);
Modified = from.Modified; std::swap(loaded, that.loaded);
std::swap(commitId, that.commitId);
std::swap(undoDescription, that.undoDescription);
std::swap(Line, that.Line);
}
AssFile::AssFile(const AssFile &from)
: undoDescription(from.undoDescription)
, commitId(from.commitId)
, filename(from.filename)
, loaded(from.loaded)
{
std::transform(from.Line.begin(), from.Line.end(), std::back_inserter(Line), std::mem_fun(&AssEntry::Clone)); std::transform(from.Line.begin(), from.Line.end(), std::back_inserter(Line), std::mem_fun(&AssEntry::Clone));
} }
AssFile& AssFile::operator=(AssFile from) { AssFile& AssFile::operator=(AssFile from) {
filename = from.filename; std::swap(*this, from);
loaded = from.loaded;
Modified = from.Modified;
std::swap(Line, from.Line);
return *this; return *this;
} }
@ -747,120 +773,55 @@ void AssFile::CompressForStack() {
} }
} }
bool AssFile::IsModified() { int AssFile::Commit(wxString desc, int amendId) {
return Modified; ++commitId;
} // Allow coalescing only if it's the last change and the file has not been
// saved since the last change
void AssFile::FlagAsModified(wxString desc) { if (commitId == amendId+1 && RedoStack.empty() && savedCommitId != commitId) {
if (!RedoStack.empty()) { UndoStack.back() = *this;
delete_clear(RedoStack); UndoStack.back().CompressForStack();
return commitId;
} }
Modified = true; RedoStack.clear();
StackPush(desc);
}
void AssFile::StackPush(wxString desc) { // Place copy on stack
// Places copy on stack undoDescription = desc;
AssFile *curcopy = new AssFile(*top); UndoStack.push_back(*this);
curcopy->CompressForStack(); UndoStack.back().CompressForStack();
curcopy->undodescription = desc;
UndoStack.push_back(curcopy);
StackModified = true;
// Cap depth // Cap depth
int n = 0;
for (std::list<AssFile*>::iterator cur=UndoStack.begin();cur!=UndoStack.end();cur++) {
n++;
}
int depth = OPT_GET("Limits/Undo Levels")->GetInt(); int depth = OPT_GET("Limits/Undo Levels")->GetInt();
while (n > depth) { while ((int)UndoStack.size() > depth) {
delete UndoStack.front();
UndoStack.pop_front(); UndoStack.pop_front();
n--;
}
}
void AssFile::StackPop() {
bool addcopy = false;
wxString undodesc="";
if (StackModified) {
undodesc=UndoStack.back()->undodescription;
delete UndoStack.back();
UndoStack.pop_back();
StackModified = false;
addcopy = true;
} }
if (!UndoStack.empty()) { return commitId;
//delete top;
AssFile *undo = UndoStack.back();
top->CompressForStack();
top->undodescription = undodesc;
RedoStack.push_back(top);
top = undo;
UndoStack.pop_back();
Popping = true;
}
if (addcopy) {
StackPush(top->undodescription);
}
} }
void AssFile::StackRedo() { void AssFile::Undo() {
bool addcopy = false; if (UndoStack.size() <= 1) return;
if (StackModified) {
delete UndoStack.back();
UndoStack.pop_back();
StackModified = false;
addcopy = true;
}
if (!RedoStack.empty()) { RedoStack.push_back(AssFile());
top->CompressForStack(); std::swap(RedoStack.back(), *this);
UndoStack.push_back(top); UndoStack.pop_back();
top = RedoStack.back(); *this = UndoStack.back();
RedoStack.pop_back();
Popping = true;
}
if (addcopy) {
StackPush(top->undodescription);
}
} }
void AssFile::StackClear() { void AssFile::Redo() {
delete_clear(UndoStack); if (RedoStack.empty()) return;
delete_clear(RedoStack);
Popping = false; std::swap(*this, RedoStack.back());
UndoStack.push_back(*this);
RedoStack.pop_back();
} }
void AssFile::StackReset() { wxString AssFile::GetUndoDescription() const {
StackClear(); return IsUndoStackEmpty() ? "" : UndoStack.back().undoDescription;
delete top;
top = new AssFile;
StackModified = false;
} }
bool AssFile::IsUndoStackEmpty() { wxString AssFile::GetRedoDescription() const {
if (StackModified) return (UndoStack.size() <= 1); return IsRedoStackEmpty() ? "" : RedoStack.back().undoDescription;
else return UndoStack.empty();
}
bool AssFile::IsRedoStackEmpty() {
return RedoStack.empty();
}
wxString AssFile::GetUndoDescription() {
return (IsUndoStackEmpty())?_T(""):(UndoStack.back())->undodescription;
}
wxString AssFile::GetRedoDescription() {
return (IsRedoStackEmpty())?_T(""):(RedoStack.back())->undodescription;
} }
bool AssFile::CompStart(const AssDialogue* lft, const AssDialogue* rgt) { bool AssFile::CompStart(const AssDialogue* lft, const AssDialogue* rgt) {
@ -909,7 +870,3 @@ void AssFile::Sort(std::list<AssDialogue*> &lst, CompFunc comp) {
} }
AssFile *AssFile::top; AssFile *AssFile::top;
std::list<AssFile*> AssFile::UndoStack;
std::list<AssFile*> AssFile::RedoStack;
bool AssFile::Popping;
bool AssFile::StackModified;

View file

@ -62,26 +62,15 @@ typedef std::list<AssEntry*>::iterator entryIter;
/// ///
/// DOCME /// DOCME
class AssFile { class AssFile {
private: std::list<AssFile> UndoStack;
std::list<AssFile> RedoStack;
/// DOCME wxString undoDescription;
bool Modified; /// Revision counter for undo coalescing and modified state tracking
int commitId;
/// Last saved version of this file
/// DOCME int savedCommitId;
static std::list<AssFile*> UndoStack;
/// DOCME
static std::list<AssFile*> RedoStack;
/// DOCME
static bool StackModified;
static void StackClear();
wxString undodescription;
public: public:
/// The lines in the file /// The lines in the file
std::list<AssEntry*> Line; std::list<AssEntry*> Line;
/// The filename of this file, if any /// The filename of this file, if any
@ -95,12 +84,10 @@ public:
~AssFile(); ~AssFile();
/// Does the file have unsaved changes? /// Does the file have unsaved changes?
bool IsModified(); bool IsModified() const {return commitId != savedCommitId; };
/// @brief Flag the file as modified and push a copy onto the undo stack
/// @param desc Undo description
void FlagAsModified(wxString desc);
/// Clear the file /// Clear the file
void Clear(); void Clear();
/// Discard some parsed data to reduce the size of the undo stack /// Discard some parsed data to reduce the size of the undo stack
void CompressForStack(); void CompressForStack();
/// @brief Load default file /// @brief Load default file
@ -119,6 +106,7 @@ public:
/// @return Pointer to style or NULL /// @return Pointer to style or NULL
AssStyle *GetStyle(wxString name); AssStyle *GetStyle(wxString name);
void swap(AssFile &) throw();
/// @brief Load from a file /// @brief Load from a file
/// @param file File name /// @param file File name
@ -164,26 +152,23 @@ public:
/// @param[out] outGroup Group it was actually added to; attachments do something strange here /// @param[out] outGroup Group it was actually added to; attachments do something strange here
void AddLine(wxString data,wxString group,int &version,wxString *outGroup=NULL); void AddLine(wxString data,wxString group,int &version,wxString *outGroup=NULL);
/// Pop subs from stack and set 'top' to it /// @brief Flag the file as modified and push a copy onto the undo stack
static void StackPop(); /// @param desc Undo description
/// Redo action on stack /// @param commitId Commit to amend rather than pushing a new commit
static void StackRedo(); /// @return Unique identifier for the new undo group
/// @brief Put a copy of 'top' on the stack int Commit(wxString desc, int commitId = -1);
/// @param desc Undo message /// @brief Undo the last set of changes to the file
static void StackPush(wxString desc); void Undo();
/// Clear the stack. Do before loading new subtitles. /// @brief Redo the last undone changes
static void StackReset(); void Redo();
/// Check if undo stack is empty /// Check if undo stack is empty
static bool IsUndoStackEmpty(); bool IsUndoStackEmpty() const { return UndoStack.size() <= 1; };
/// Check if redo stack is empty /// Check if redo stack is empty
static bool IsRedoStackEmpty(); bool IsRedoStackEmpty() const { return RedoStack.empty(); };
/// Get the description of the first undoable change /// Get the description of the first undoable change
static wxString GetUndoDescription(); wxString GetUndoDescription() const;
/// Get the description of the first redoable change /// Get the description of the first redoable change
static wxString GetRedoDescription(); wxString GetRedoDescription() const;
/// Flags the stack as popping. You must unset this after popping
static bool Popping;
/// Current script file. It is "above" the stack. /// Current script file. It is "above" the stack.
static AssFile *top; static AssFile *top;

View file

@ -1209,7 +1209,7 @@ void AudioDisplay::CommitChanges (bool nextLine) {
// Update grid // Update grid
grid->editBox->Update(!karaoke->enabled); grid->editBox->Update(!karaoke->enabled);
grid->ass->FlagAsModified(_T("")); grid->ass->Commit(_T(""));
grid->CommitChanges(); grid->CommitChanges();
karaoke->SetSelection(karaSelStart, karaSelEnd); karaoke->SetSelection(karaSelStart, karaSelEnd);
blockUpdate = false; blockUpdate = false;

View file

@ -1014,7 +1014,7 @@ namespace Automation4 {
description = wxString(lua_tostring(L, 1), wxConvUTF8); description = wxString(lua_tostring(L, 1), wxConvUTF8);
lua_pop(L, 1); lua_pop(L, 1);
} }
AssFile::top->FlagAsModified(description); AssFile::top->Commit(description);
laf->ass = AssFile::top; // make sure we're still working on the most recent undo point laf->ass = AssFile::top; // make sure we're still working on the most recent undo point
return 0; return 0;

View file

@ -174,7 +174,7 @@ DialogAttachments::~DialogAttachments() {
} }
if (removed_any) { if (removed_any) {
AssFile::top->FlagAsModified(_("remove empty attachments sections")); AssFile::top->Commit(_("remove empty attachments sections"));
} }
} }
@ -223,7 +223,7 @@ void DialogAttachments::OnAttachFont(wxCommandEvent &event) {
AssFile::top->InsertAttachment(newAttach); AssFile::top->InsertAttachment(newAttach);
} }
AssFile::top->FlagAsModified(_("attach font file")); AssFile::top->Commit(_("attach font file"));
// Update // Update
UpdateList(); UpdateList();
@ -261,7 +261,7 @@ void DialogAttachments::OnAttachGraphics(wxCommandEvent &event) {
AssFile::top->InsertAttachment(newAttach); AssFile::top->InsertAttachment(newAttach);
} }
AssFile::top->FlagAsModified(_("attach graphics file")); AssFile::top->Commit(_("attach graphics file"));
// Update // Update
UpdateList(); UpdateList();
@ -316,7 +316,7 @@ void DialogAttachments::OnDelete(wxCommandEvent &event) {
i = listView->GetNextSelected(i); i = listView->GetNextSelected(i);
} }
AssFile::top->FlagAsModified(_("remove attachment")); AssFile::top->Commit(_("remove attachment"));
// Update list // Update list
UpdateList(); UpdateList();

View file

@ -514,7 +514,7 @@ void FontsCollectorThread::Collect() {
// Modify file if it was attaching // Modify file if it was attaching
if (oper == 3 && someOk) { if (oper == 3 && someOk) {
wxMutexGuiEnter(); wxMutexGuiEnter();
subs->FlagAsModified(_("font attachment")); subs->Commit(_("font attachment"));
collector->main->SubsGrid->CommitChanges(); collector->main->SubsGrid->CommitChanges();
wxMutexGuiLeave(); wxMutexGuiLeave();
} }

View file

@ -940,7 +940,7 @@ void DialogKanjiTimer::OnClose(wxCommandEvent &event) {
line->Text = p.second; line->Text = p.second;
} }
if (modified) { if (modified) {
grid->ass->FlagAsModified(_("kanji timing")); grid->ass->Commit(_("kanji timing"));
grid->CommitChanges(); grid->CommitChanges();
grid->UpdateMaps(); grid->UpdateMaps();
LinesToChange.clear(); LinesToChange.clear();

View file

@ -211,7 +211,7 @@ void DialogProperties::OnOK(wxCommandEvent &event) {
count += SetInfoIfDifferent(_T("Collisions"),col[collision->GetSelection()]); count += SetInfoIfDifferent(_T("Collisions"),col[collision->GetSelection()]);
count += SetInfoIfDifferent(_T("ScaledBorderAndShadow"),ScaleBorder->GetValue()? _T("yes") : _T("no")); count += SetInfoIfDifferent(_T("ScaledBorderAndShadow"),ScaleBorder->GetValue()? _T("yes") : _T("no"));
if (count) AssFile::top->FlagAsModified(_("property changes")); if (count) AssFile::top->Commit(_("property changes"));
EndModal(count?1:0); EndModal(count?1:0);
} }

View file

@ -321,7 +321,7 @@ void DialogResample::OnResample (wxCommandEvent &event) {
subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2)); subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2));
// Flag as modified // Flag as modified
subs->FlagAsModified(_("resolution resampling")); subs->Commit(_("resolution resampling"));
grid->CommitChanges(); grid->CommitChanges();
grid->editBox->Update(); grid->editBox->Update();
EndModal(0); EndModal(0);

View file

@ -437,7 +437,7 @@ void SearchReplaceEngine::ReplaceNext(bool DoReplace) {
} }
// Commit // Commit
grid->ass->FlagAsModified(_("replace")); grid->ass->Commit(_("replace"));
grid->CommitChanges(); grid->CommitChanges();
} }
@ -544,7 +544,7 @@ void SearchReplaceEngine::ReplaceAll() {
// Commit // Commit
if (count > 0) { if (count > 0) {
grid->ass->FlagAsModified(_("replace")); grid->ass->Commit(_("replace"));
grid->CommitChanges(); grid->CommitChanges();
grid->editBox->Update(); grid->editBox->Update();
wxMessageBox(wxString::Format(_("%i matches were replaced."),count)); wxMessageBox(wxString::Format(_("%i matches were replaced."),count));

View file

@ -311,7 +311,7 @@ void DialogShiftTimes::OnOK(wxCommandEvent &event) {
OPT_SET("Tool/Shift Times/Direction")->SetBool(backward); OPT_SET("Tool/Shift Times/Direction")->SetBool(backward);
// End dialog // End dialog
grid->ass->FlagAsModified(_("shifting")); grid->ass->Commit(_("shifting"));
grid->CommitChanges(); grid->CommitChanges();
grid->UpdateMaps(); grid->UpdateMaps();
grid->editBox->Update(); grid->editBox->Update();

View file

@ -390,7 +390,7 @@ void DialogSpellChecker::Replace() {
lastPos = wordStart + replaceWord->GetValue().Length(); lastPos = wordStart + replaceWord->GetValue().Length();
// Commit // Commit
grid->ass->FlagAsModified(_("Spell check replace")); grid->ass->Commit(_("Spell check replace"));
grid->CommitChanges(); grid->CommitChanges();
} }

View file

@ -581,7 +581,7 @@ void DialogStyleEditor::Apply (bool apply,bool close) {
*style = *work; *style = *work;
style->UpdateData(); style->UpdateData();
if (isLocal) { if (isLocal) {
AssFile::top->FlagAsModified(_("style change")); AssFile::top->Commit(_("style change"));
grid->CommitChanges(); grid->CommitChanges();
} }

View file

@ -576,7 +576,7 @@ void DialogStyleManager::OnCopyToCurrent (wxCommandEvent &) {
for (list<wxString>::iterator name = copied.begin(); name != copied.end(); ++name) { for (list<wxString>::iterator name = copied.begin(); name != copied.end(); ++name) {
CurrentList->SetStringSelection(*name, true); CurrentList->SetStringSelection(*name, true);
} }
grid->ass->FlagAsModified(_("style copy")); grid->ass->Commit(_("style copy"));
grid->CommitChanges(); grid->CommitChanges();
wxCommandEvent dummy; wxCommandEvent dummy;
OnCurrentChange(dummy); OnCurrentChange(dummy);
@ -625,7 +625,7 @@ void DialogStyleManager::OnCurrentCopy (wxCommandEvent &) {
} }
else delete temp; else delete temp;
grid->ass->FlagAsModified(_("style copy")); grid->ass->Commit(_("style copy"));
grid->CommitChanges(); grid->CommitChanges();
UpdateMoveButtons(); UpdateMoveButtons();
} }
@ -678,7 +678,7 @@ void DialogStyleManager::PasteToCurrent() {
AssFile::top->InsertStyle(s); AssFile::top->InsertStyle(s);
LoadCurrentStyles(AssFile::top); LoadCurrentStyles(AssFile::top);
grid->ass->FlagAsModified(_("style paste")); grid->ass->Commit(_("style paste"));
grid->CommitChanges(); grid->CommitChanges();
} }
else else
@ -822,7 +822,7 @@ void DialogStyleManager::OnCurrentDelete (wxCommandEvent &) {
CurrentCopy->Enable(false); CurrentCopy->Enable(false);
CurrentDelete->Enable(false); CurrentDelete->Enable(false);
grid->ass->FlagAsModified(_("style delete")); grid->ass->Commit(_("style delete"));
grid->CommitChanges(); grid->CommitChanges();
} }
UpdateMoveButtons(); UpdateMoveButtons();
@ -884,7 +884,7 @@ void DialogStyleManager::OnCurrentImport(wxCommandEvent &) {
// Update // Update
if (modified) { if (modified) {
LoadCurrentStyles(grid->ass); LoadCurrentStyles(grid->ass);
grid->ass->FlagAsModified(_("style import")); grid->ass->Commit(_("style import"));
grid->CommitChanges(); grid->CommitChanges();
} }
} }
@ -1081,7 +1081,7 @@ void DialogStyleManager::MoveStyles(bool storage, int type) {
} }
// Flag as modified // Flag as modified
grid->ass->FlagAsModified(_("style move")); grid->ass->Commit(_("style move"));
grid->CommitChanges(); grid->CommitChanges();
} }

View file

@ -169,7 +169,7 @@ wxDialog (parent, -1, _("Styling assistant"), wxDefaultPosition, wxDefaultSize,
DialogStyling::~DialogStyling () { DialogStyling::~DialogStyling () {
GetPosition(&lastx, &lasty); GetPosition(&lastx, &lasty);
if (needCommit) { if (needCommit) {
grid->ass->FlagAsModified(_("style changes")); grid->ass->Commit(_("style changes"));
grid->CommitChanges(); grid->CommitChanges();
} }
} }
@ -232,7 +232,7 @@ void DialogStyling::SetStyle (wxString curName, bool jump) {
// Update grid/subs // Update grid/subs
grid->Refresh(false); grid->Refresh(false);
if (PreviewCheck->IsChecked()) { if (PreviewCheck->IsChecked()) {
grid->ass->FlagAsModified(_("styling assistant")); grid->ass->Commit(_("styling assistant"));
grid->CommitChanges(); grid->CommitChanges();
} }
else needCommit = true; else needCommit = true;
@ -264,7 +264,7 @@ void DialogStyling::OnActivate(wxActivateEvent &event) {
// Dialog lost focus // Dialog lost focus
if (!event.GetActive()) { if (!event.GetActive()) {
if (needCommit) { if (needCommit) {
grid->ass->FlagAsModified(_("styling assistant")); grid->ass->Commit(_("styling assistant"));
grid->CommitChanges(); grid->CommitChanges();
needCommit = false; needCommit = false;
} }

View file

@ -542,6 +542,6 @@ void DialogTimingProcessor::Process() {
} }
// Update grid // Update grid
grid->ass->FlagAsModified(_("timing processor")); grid->ass->Commit(_("timing processor"));
grid->CommitChanges(); grid->CommitChanges();
} }

View file

@ -357,7 +357,7 @@ void DialogTranslation::OnTransBoxKey(wxKeyEvent &event) {
// Update line // Update line
cur->UpdateText(); cur->UpdateText();
cur->ClearBlocks(); cur->ClearBlocks();
subs->FlagAsModified(_("translation assistant")); subs->Commit(_("translation assistant"));
grid->CommitChanges(); grid->CommitChanges();
((FrameMain*)main)->UpdateTitle(); ((FrameMain*)main)->UpdateTitle();
UpdatePreview(); UpdatePreview();

View file

@ -570,6 +570,7 @@ void FrameMain::InitMenu() {
/// @brief Initialize contents /// @brief Initialize contents
void FrameMain::InitContents() { void FrameMain::InitContents() {
AssFile::top = new AssFile;
// Set a background panel // Set a background panel
StartupLog(_T("Create background panel")); StartupLog(_T("Create background panel"));
Panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN); Panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN);
@ -590,8 +591,6 @@ void FrameMain::InitContents() {
StartupLog(_T("Create subtitles grid")); StartupLog(_T("Create subtitles grid"));
SubsGrid = new SubtitlesGrid(this,Panel,-1,wxDefaultPosition,wxSize(600,100),wxWANTS_CHARS | wxSUNKEN_BORDER,_T("Subs grid")); SubsGrid = new SubtitlesGrid(this,Panel,-1,wxDefaultPosition,wxSize(600,100),wxWANTS_CHARS | wxSUNKEN_BORDER,_T("Subs grid"));
BottomSizer->Add(SubsGrid,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,0); BottomSizer->Add(SubsGrid,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,0);
StartupLog(_T("Reset undo stack"));
AssFile::StackReset();
videoBox->videoSlider->grid = SubsGrid; videoBox->videoSlider->grid = SubsGrid;
VideoContext::Get()->grid = SubsGrid; VideoContext::Get()->grid = SubsGrid;
StartupLog(_T("Reset video zoom")); StartupLog(_T("Reset video zoom"));
@ -638,7 +637,6 @@ void FrameMain::DeInitContents() {
SubsGrid->ClearMaps(); SubsGrid->ClearMaps();
delete EditBox; delete EditBox;
delete videoBox; delete videoBox;
AssFile::StackReset();
delete AssFile::top; delete AssFile::top;
HelpButton::ClearPages(); HelpButton::ClearPages();
VideoContext::Get()->audio = NULL; VideoContext::Get()->audio = NULL;
@ -708,7 +706,6 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
// Proceed into loading // Proceed into loading
SubsGrid->ClearMaps(); SubsGrid->ClearMaps();
AssFile::StackReset();
if (isFile) { if (isFile) {
AssFile::top->Load(filename,charset); AssFile::top->Load(filename,charset);
SubsGrid->UpdateMaps(); SubsGrid->UpdateMaps();
@ -1135,7 +1132,7 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
// Always change script res // Always change script res
SubsGrid->ass->SetScriptInfo(_T("PlayResX"), wxString::Format(_T("%d"), vidx)); SubsGrid->ass->SetScriptInfo(_T("PlayResX"), wxString::Format(_T("%d"), vidx));
SubsGrid->ass->SetScriptInfo(_T("PlayResY"), wxString::Format(_T("%d"), vidy)); SubsGrid->ass->SetScriptInfo(_T("PlayResY"), wxString::Format(_T("%d"), vidy));
SubsGrid->ass->FlagAsModified(_("Change script resolution")); SubsGrid->ass->Commit(_("Change script resolution"));
SubsGrid->CommitChanges(); SubsGrid->CommitChanges();
break; break;
case 0: case 0:
@ -1350,8 +1347,8 @@ bool FrameMain::LoadList(wxArrayString list) {
/// @brief Sets the descriptions for undo/redo /// @brief Sets the descriptions for undo/redo
void FrameMain::SetUndoRedoDesc() { void FrameMain::SetUndoRedoDesc() {
editMenu->SetHelpString(0,_T("Undo ")+AssFile::GetUndoDescription()); editMenu->SetHelpString(0,_T("Undo ")+AssFile::top->GetUndoDescription());
editMenu->SetHelpString(1,_T("Redo ")+AssFile::GetRedoDescription()); editMenu->SetHelpString(1,_T("Redo ")+AssFile::top->GetRedoDescription());
} }
/// @brief Check if ASSDraw is available /// @brief Check if ASSDraw is available

View file

@ -435,16 +435,16 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
else if (curMenu == editMenu) { else if (curMenu == editMenu) {
// Undo state // Undo state
wxMenuItem *item; wxMenuItem *item;
wxString undo_text = _("&Undo") + wxString(_T(" ")) + AssFile::GetUndoDescription() + wxString(_T("\t")) + Hotkeys.GetText(_T("Undo")); wxString undo_text = _("&Undo") + wxString(_T(" ")) + AssFile::top->GetUndoDescription() + wxString(_T("\t")) + Hotkeys.GetText(_T("Undo"));
item = editMenu->FindItem(Menu_Edit_Undo); item = editMenu->FindItem(Menu_Edit_Undo);
item->SetItemLabel(undo_text); item->SetItemLabel(undo_text);
item->Enable(!AssFile::IsUndoStackEmpty()); item->Enable(!AssFile::top->IsUndoStackEmpty());
// Redo state // Redo state
wxString redo_text = _("&Redo") + wxString(_T(" ")) + AssFile::GetRedoDescription() + wxString(_T("\t")) + Hotkeys.GetText(_T("Redo")); wxString redo_text = _("&Redo") + wxString(_T(" ")) + AssFile::top->GetRedoDescription() + wxString(_T("\t")) + Hotkeys.GetText(_T("Redo"));
item = editMenu->FindItem(Menu_Edit_Redo); item = editMenu->FindItem(Menu_Edit_Redo);
item->SetItemLabel(redo_text); item->SetItemLabel(redo_text);
item->Enable(!AssFile::IsRedoStackEmpty()); item->Enable(!AssFile::top->IsRedoStackEmpty());
// Copy/cut/paste // Copy/cut/paste
wxArrayInt sels = SubsGrid->GetSelection(); wxArrayInt sels = SubsGrid->GetSelection();
@ -1133,7 +1133,7 @@ void FrameMain::OnSnapToScene (wxCommandEvent &) {
// Commit // Commit
SubsGrid->editBox->Update(true); SubsGrid->editBox->Update(true);
SubsGrid->ass->FlagAsModified(_("snap to scene")); SubsGrid->ass->Commit(_("snap to scene"));
SubsGrid->CommitChanges(); SubsGrid->CommitChanges();
} }
@ -1160,7 +1160,7 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &) {
} }
// Commit // Commit
SubsGrid->ass->FlagAsModified(_("shift to frame")); SubsGrid->ass->Commit(_("shift to frame"));
SubsGrid->CommitChanges(); SubsGrid->CommitChanges();
SubsGrid->editBox->Update(true,false); SubsGrid->editBox->Update(true,false);
} }
@ -1168,17 +1168,17 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &) {
/// @brief Undo /// @brief Undo
void FrameMain::OnUndo(wxCommandEvent&) { void FrameMain::OnUndo(wxCommandEvent&) {
VideoContext::Get()->Stop(); VideoContext::Get()->Stop();
AssFile::StackPop(); AssFile::top->Undo();
UpdateTitle();
SubsGrid->UpdateMaps(); SubsGrid->UpdateMaps();
AssFile::Popping = false;
} }
/// @brief Redo /// @brief Redo
void FrameMain::OnRedo(wxCommandEvent&) { void FrameMain::OnRedo(wxCommandEvent&) {
VideoContext::Get()->Stop(); VideoContext::Get()->Stop();
AssFile::StackRedo(); AssFile::top->Redo();
UpdateTitle();
SubsGrid->UpdateMaps(); SubsGrid->UpdateMaps();
AssFile::Popping = false;
} }
/// @brief Find /// @brief Find
@ -1347,21 +1347,21 @@ void FrameMain::OnSelect (wxCommandEvent &) {
/// @brief Sort subtitles by start time /// @brief Sort subtitles by start time
void FrameMain::OnSortStart (wxCommandEvent &) { void FrameMain::OnSortStart (wxCommandEvent &) {
AssFile::top->Sort(); AssFile::top->Sort();
AssFile::top->FlagAsModified(_("sort")); AssFile::top->Commit(_("sort"));
SubsGrid->UpdateMaps(); SubsGrid->UpdateMaps();
SubsGrid->CommitChanges(); SubsGrid->CommitChanges();
} }
/// @brief Sort subtitles by end time /// @brief Sort subtitles by end time
void FrameMain::OnSortEnd (wxCommandEvent &) { void FrameMain::OnSortEnd (wxCommandEvent &) {
AssFile::top->Sort(AssFile::CompEnd); AssFile::top->Sort(AssFile::CompEnd);
AssFile::top->FlagAsModified(_("sort")); AssFile::top->Commit(_("sort"));
SubsGrid->UpdateMaps(); SubsGrid->UpdateMaps();
SubsGrid->CommitChanges(); SubsGrid->CommitChanges();
} }
/// @brief Sort subtitles by style name /// @brief Sort subtitles by style name
void FrameMain::OnSortStyle (wxCommandEvent &) { void FrameMain::OnSortStyle (wxCommandEvent &) {
AssFile::top->Sort(AssFile::CompStyle); AssFile::top->Sort(AssFile::CompStyle);
AssFile::top->FlagAsModified(_("sort")); AssFile::top->Commit(_("sort"));
SubsGrid->UpdateMaps(); SubsGrid->UpdateMaps();
SubsGrid->CommitChanges(); SubsGrid->CommitChanges();
} }

View file

@ -573,7 +573,7 @@ void SubsEditBox::OnStyleChange(wxCommandEvent &event) {
cur->Style = StyleBox->GetValue(); cur->Style = StyleBox->GetValue();
} }
} }
grid->ass->FlagAsModified(_("style change")); grid->ass->Commit(_("style change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -605,7 +605,7 @@ void SubsEditBox::OnActorChange(wxCommandEvent &event) {
} }
// Update grid // Update grid
grid->ass->FlagAsModified(_("actor change")); grid->ass->Commit(_("actor change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -633,7 +633,7 @@ void SubsEditBox::OnLayerChange(wxSpinEvent &event) {
} }
// Done // Done
grid->ass->FlagAsModified(_("layer change")); grid->ass->Commit(_("layer change"));
grid->CommitChanges(); grid->CommitChanges();
} }
@ -660,7 +660,7 @@ void SubsEditBox::OnLayerEnter(wxCommandEvent &event) {
} }
// Done // Done
grid->ass->FlagAsModified(_("layer change")); grid->ass->Commit(_("layer change"));
grid->CommitChanges(); grid->CommitChanges();
} }
@ -746,7 +746,7 @@ void SubsEditBox::CommitTimes(bool start,bool end,bool fromStart,bool commit) {
StartTime->Update(); StartTime->Update();
EndTime->Update(); EndTime->Update();
Duration->Update(); Duration->Update();
grid->ass->FlagAsModified(_("modify times")); grid->ass->Commit(_("modify times"));
grid->CommitChanges(); grid->CommitChanges();
int sel0 = grid->GetFirstSelRow(); int sel0 = grid->GetFirstSelRow();
audio->SetDialogue(grid,grid->GetDialogue(sel0),sel0); audio->SetDialogue(grid,grid->GetDialogue(sel0),sel0);
@ -772,7 +772,7 @@ void SubsEditBox::OnMarginLChange(wxCommandEvent &event) {
} }
} }
MarginL->SetValue(cur->GetMarginString(0,false)); MarginL->SetValue(cur->GetMarginString(0,false));
grid->ass->FlagAsModified(_("MarginL change")); grid->ass->Commit(_("MarginL change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -795,7 +795,7 @@ void SubsEditBox::OnMarginRChange(wxCommandEvent &event) {
} }
} }
MarginR->SetValue(cur->GetMarginString(1,false)); MarginR->SetValue(cur->GetMarginString(1,false));
grid->ass->FlagAsModified(_("MarginR change")); grid->ass->Commit(_("MarginR change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -819,7 +819,7 @@ void SubsEditBox::OnMarginVChange(wxCommandEvent &event) {
} }
} }
MarginV->SetValue(cur->GetMarginString(2,false)); MarginV->SetValue(cur->GetMarginString(2,false));
grid->ass->FlagAsModified(_("MarginV change")); grid->ass->Commit(_("MarginV change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -841,7 +841,7 @@ void SubsEditBox::OnEffectChange(wxCommandEvent &event) {
cur->Effect = Effect->GetValue(); cur->Effect = Effect->GetValue();
} }
} }
grid->ass->FlagAsModified(_("effect change")); grid->ass->Commit(_("effect change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -862,7 +862,7 @@ void SubsEditBox::OnCommentChange(wxCommandEvent &event) {
cur->Comment = CommentBox->GetValue(); cur->Comment = CommentBox->GetValue();
} }
} }
grid->ass->FlagAsModified(_("comment change")); grid->ass->Commit(_("comment change"));
grid->CommitChanges(); grid->CommitChanges();
grid->EndBatch(); grid->EndBatch();
} }
@ -945,7 +945,7 @@ void SubsEditBox::Commit(bool stay) {
// Update file // Update file
if (textNeedsCommit) { if (textNeedsCommit) {
grid->ass->FlagAsModified(_("editing")); grid->ass->Commit(_("editing"));
grid->CommitChanges(); grid->CommitChanges();
} }
else if (StartTime->HasBeenModified() || EndTime->HasBeenModified()) { else if (StartTime->HasBeenModified() || EndTime->HasBeenModified()) {

View file

@ -427,7 +427,7 @@ void SubtitlesGrid::OnSplitByKaraoke (wxCommandEvent &event) {
didSplit |= SplitLineByKaraoke(sels[i]); didSplit |= SplitLineByKaraoke(sels[i]);
} }
if (didSplit) { if (didSplit) {
ass->FlagAsModified(_("splitting")); ass->Commit(_("splitting"));
CommitChanges(); CommitChanges();
} }
EndBatch(); EndBatch();
@ -692,7 +692,7 @@ void SubtitlesGrid::OnRecombine(wxCommandEvent &event) {
} }
// Commit // Commit
ass->FlagAsModified(_("combining")); ass->Commit(_("combining"));
CommitChanges(); CommitChanges();
} }
@ -848,7 +848,7 @@ void SubtitlesGrid::SwapLines(int n1,int n2) {
std::swap(*dlg1, *dlg2); std::swap(*dlg1, *dlg2);
UpdateMaps(); UpdateMaps();
ass->FlagAsModified(_("swap lines")); ass->Commit(_("swap lines"));
CommitChanges(); CommitChanges();
} }
@ -872,7 +872,7 @@ void SubtitlesGrid::InsertLine(AssDialogue *line,int n,bool after,bool update) {
// Update // Update
if (update) { if (update) {
ass->FlagAsModified(_("line insertion")); ass->Commit(_("line insertion"));
CommitChanges(); CommitChanges();
AdjustScrollbar(); AdjustScrollbar();
} }
@ -1005,7 +1005,7 @@ void SubtitlesGrid::PasteLines(int n,bool pasteOver) {
// Commit // Commit
UpdateMaps(); UpdateMaps();
AdjustScrollbar(); AdjustScrollbar();
ass->FlagAsModified(_("paste")); ass->Commit(_("paste"));
CommitChanges(); CommitChanges();
// Set selection // Set selection
@ -1055,7 +1055,7 @@ void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
UpdateMaps(); UpdateMaps();
AdjustScrollbar(); AdjustScrollbar();
if (flagModified) { if (flagModified) {
ass->FlagAsModified(_("delete")); ass->Commit(_("delete"));
CommitChanges(); CommitChanges();
} }
@ -1118,7 +1118,7 @@ void SubtitlesGrid::JoinLines(int n1,int n2,bool concat) {
// Delete remaining lines (this will auto commit) // Delete remaining lines (this will auto commit)
DeleteLines(GetRangeArray(n1+1,n2), false); DeleteLines(GetRangeArray(n1+1,n2), false);
ass->FlagAsModified(_("join lines")); ass->Commit(_("join lines"));
CommitChanges(); CommitChanges();
// Select new line // Select new line
@ -1160,7 +1160,7 @@ void SubtitlesGrid::AdjoinLines(int n1,int n2,bool setStart) {
} }
// Commit // Commit
AssFile::top->FlagAsModified(_("adjoin")); AssFile::top->Commit(_("adjoin"));
CommitChanges(); CommitChanges();
} }
@ -1210,7 +1210,7 @@ void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) {
// Delete remaining lines (this will auto commit) // Delete remaining lines (this will auto commit)
DeleteLines(GetRangeArray(n1+1,n2), false); DeleteLines(GetRangeArray(n1+1,n2), false);
ass->FlagAsModified(_("join as karaoke")); ass->Commit(_("join as karaoke"));
CommitChanges(); CommitChanges();
// Select new line // Select new line
@ -1330,7 +1330,7 @@ void SubtitlesGrid::SplitLine(int n,int pos,int mode,wxString textIn) {
//editBox->SetToLine(n); //editBox->SetToLine(n);
// Commit // Commit
ass->FlagAsModified(_("split")); ass->Commit(_("split"));
CommitChanges(); CommitChanges();
} }
@ -1439,7 +1439,7 @@ void SubtitlesGrid::SetSubsToVideo(bool start) {
// Commit // Commit
if (modified) { if (modified) {
ass->FlagAsModified(_("timing")); ass->Commit(_("timing"));
CommitChanges(); CommitChanges();
editBox->Update(true); editBox->Update(true);
} }

View file

@ -266,7 +266,7 @@ void VisualTool<FeatureType>::Commit(bool full, wxString message) {
if (message.empty()) { if (message.empty()) {
message = _("visual typesetting"); message = _("visual typesetting");
} }
grid->ass->FlagAsModified(message); grid->ass->Commit(message);
} }
grid->CommitChanges(false,!full); grid->CommitChanges(false,!full);
if (full) if (full)