From 39938d213a9de940c01f282a3b701610a04e0a97 Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Mon, 17 Mar 2008 07:19:33 +0000 Subject: [PATCH] Implemented a multi-line modification action. Still a bit hacky, but works well. Originally committed to SVN as r2076. --- aegilib/include/aegilib/action.h | 6 +- aegilib/include/aegilib/actionlist.h | 2 +- aegilib/include/aegilib/exception.h | 1 + aegilib/include/aegilib/gorgontime.h | 5 +- aegilib/include/aegilib/selection.h | 3 + aegilib/include/aegilib/utils.h | 2 +- aegilib/src/action.cpp | 55 +++++++++++++++- aegilib/src/actionlist.cpp | 25 ++++++++ aegilib/src/exception.cpp | 1 + aegilib/src/formats/format_ass_dialogue.h | 2 +- aegilib/src/selection.cpp | 78 +++++++++++++++++++++-- aegilib/test/src/main.cpp | 38 ++++++++--- aegilib/todo.txt | 2 + 13 files changed, 196 insertions(+), 24 deletions(-) diff --git a/aegilib/include/aegilib/action.h b/aegilib/include/aegilib/action.h index c1025fd9a..9c29e8985 100644 --- a/aegilib/include/aegilib/action.h +++ b/aegilib/include/aegilib/action.h @@ -35,6 +35,7 @@ #pragma once #include "gorgonstring.h" +#include "selection.h" namespace Gorgonsub { // Prototypes @@ -108,13 +109,12 @@ namespace Gorgonsub { private: std::vector > entries; std::vector > deltas; - std::vector lines; + Selection selection; const String section; bool noTextFields; public: - ActionModifyBatch(shared_ptr entry,int line,const String §ion,bool noTextFields); - ActionModifyBatch(shared_ptr delta,int line,const String §ion); + ActionModifyBatch(std::vector > entries,std::vector > deltas,Selection selection,const String §ion,bool noTextFields); ~ActionModifyBatch() {} ActionPtr GetAntiAction(const Model &model) const; diff --git a/aegilib/include/aegilib/actionlist.h b/aegilib/include/aegilib/actionlist.h index 26e009ad8..4ce1b4508 100644 --- a/aegilib/include/aegilib/actionlist.h +++ b/aegilib/include/aegilib/actionlist.h @@ -74,7 +74,7 @@ namespace Gorgonsub { void InsertLine(SectionEntryPtr line,int position=-1,const String section=L""); void RemoveLine(int position,const String section); SectionEntryPtr ModifyLine(int position,const String section); - SectionEntryPtr ModifyLines(Selection selection,const String section); + std::vector ModifyLines(Selection selection,const String section); }; typedef shared_ptr ActionListPtr; diff --git a/aegilib/include/aegilib/exception.h b/aegilib/include/aegilib/exception.h index 9c8f06196..69b42e06a 100644 --- a/aegilib/include/aegilib/exception.h +++ b/aegilib/include/aegilib/exception.h @@ -52,6 +52,7 @@ namespace Gorgonsub { Parse_Error, Unsupported_Format_Feature, Invalid_Token, + Out_Of_Range, TODO }; diff --git a/aegilib/include/aegilib/gorgontime.h b/aegilib/include/aegilib/gorgontime.h index 91bd395ca..15663c62f 100644 --- a/aegilib/include/aegilib/gorgontime.h +++ b/aegilib/include/aegilib/gorgontime.h @@ -35,6 +35,7 @@ #pragma once #include "gorgonstring.h" +#include "utils.h" namespace Gorgonsub { @@ -45,7 +46,7 @@ namespace Gorgonsub { public: Time() { ms = 0; } - Time(int ms) { (void)ms; } + Time(int _ms) { ms = _ms; } void SetMS(int milliseconds) { ms = milliseconds; } int GetMS() const { return ms; } @@ -53,6 +54,8 @@ namespace Gorgonsub { String GetString(int ms_precision,int h_precision) const; void Parse(const String &data); + Time operator + (const int &par) const { return Max(0,ms+par); } + Time operator - (const int &par) const { return Max(0,ms-par); } bool operator == (const Time &par) const { return ms == par.ms; } bool operator != (const Time &par) const { return ms != par.ms; } bool operator < (const Time &par) const { return ms < par.ms; } diff --git a/aegilib/include/aegilib/selection.h b/aegilib/include/aegilib/selection.h index 3cea70637..0ebfe6260 100644 --- a/aegilib/include/aegilib/selection.h +++ b/aegilib/include/aegilib/selection.h @@ -58,6 +58,7 @@ namespace Gorgonsub { private: std::vector ranges; size_t count; + void UpdateCount(); public: Selection(); @@ -68,11 +69,13 @@ namespace Gorgonsub { void RemoveRange(const Range &range); void AddSelection (const Selection ¶m); void RemoveSelection (const Selection ¶m); + void NormalizeRanges (); size_t GetCount() const { return count; } size_t GetRanges() const { return ranges.size(); } size_t GetLine(size_t n) const; size_t GetLineInRange(size_t n,size_t range) const { return ranges.at(range).GetLine(n); } + size_t GetLinesInRange(size_t range) const { return ranges.at(range).GetSize(); } bool IsContiguous() const { return GetRanges() <= 1; } }; diff --git a/aegilib/include/aegilib/utils.h b/aegilib/include/aegilib/utils.h index 19ab0e73f..e415c29d2 100644 --- a/aegilib/include/aegilib/utils.h +++ b/aegilib/include/aegilib/utils.h @@ -35,7 +35,7 @@ #pragma once -#include "Gorgonsub.h" +#include "gorgonstring.h" ///////////// diff --git a/aegilib/src/action.cpp b/aegilib/src/action.cpp index 86db76105..46b384b7d 100644 --- a/aegilib/src/action.cpp +++ b/aegilib/src/action.cpp @@ -142,7 +142,7 @@ ActionPtr ActionModify::GetAntiAction(const Model &model) const // Store the whole original line else { - return ActionPtr(new ActionModify(oldEntry,lineNumber,section)); + return ActionPtr(new ActionModify(oldEntry,lineNumber,section,noTextFields)); } } @@ -151,7 +151,7 @@ ActionPtr ActionModify::GetAntiAction(const Model &model) const // Execute insertion void ActionModify::Execute(Model &model) { - // Find the section to insert it on + // Find the section to modify String sectionName = section; if (sectionName.IsEmpty()) sectionName = entry->GetDefaultGroup(); SectionPtr sect = GetSection(model,sectionName); @@ -163,3 +163,54 @@ void ActionModify::Execute(Model &model) } else sect->GetEntryRef(lineNumber) = entry; } + + +////////////////////////// Batch Modify line ////////////////////////// + +ActionModifyBatch::ActionModifyBatch(std::vector > _entries, std::vector > _deltas, Selection _selection,const String &_section,bool _noTextFields) +: entries(_entries), deltas(_deltas), selection(_selection), section(_section), noTextFields(_noTextFields) {} + +ActionPtr ActionModifyBatch::GetAntiAction(const Model &model) const +{ + // Get section + SectionPtr sect = GetSection(model,section); + size_t len = selection.GetCount(); + std::vector _deltas(len); + std::vector oldEntries(len); + + // For each line... + for (size_t i=0;iGetEntry(selection.GetLine(i)); + + // Try to get a delta + DeltaCoderPtr deltaCoder = oldEntry->GetDeltaCoder(); + if (deltaCoder) { + if (i < deltas.size() && deltas[i]) _deltas[i] = deltaCoder->EncodeReverseDelta(deltas[i],oldEntry); + _deltas[i] = deltaCoder->EncodeDelta(entries[i],oldEntry,!noTextFields); + } + + // Store the whole original line + else oldEntries[i] = oldEntry; + } + + return ActionPtr(new ActionModifyBatch(oldEntries,_deltas,selection,section,noTextFields)); +} + +void ActionModifyBatch::Execute(Model &model) +{ + // Find the section to modify + size_t len = selection.GetCount(); + String sectionName = section; + if (sectionName.IsEmpty()) sectionName = entries[0]->GetDefaultGroup(); + SectionPtr sect = GetSection(model,sectionName); + + // For each line... + for (size_t i=0;iGetEntryRef(selection.GetLine(i)); + ref->GetDeltaCoder()->ApplyDelta(deltas[i],ref); + } + else sect->GetEntryRef(selection.GetLine(i)) = entries[i]; + } +} diff --git a/aegilib/src/actionlist.cpp b/aegilib/src/actionlist.cpp index 370ab71c1..5214477d7 100644 --- a/aegilib/src/actionlist.cpp +++ b/aegilib/src/actionlist.cpp @@ -130,3 +130,28 @@ SectionEntryPtr ActionList::ModifyLine(int position,const String section) AddAction(action); return entry; } + + +//////////////////////////////////////// +// Insert a "modify lines" batch action +std::vector ActionList::ModifyLines(Selection selection,const String section) +{ + // Get section + SectionPtr sect = model.GetSection(section); + + // Generate entries + std::vector entries(selection.GetCount()); + size_t len = selection.GetRanges(); + size_t n = 0; + for (size_t i=0;iGetEntry(selection.GetLineInRange(j,i))->Clone(); + } + } + + // Generate the action + ActionPtr action = ActionPtr (new ActionModifyBatch(entries,std::vector(),selection,section,false)); + AddAction(action); + return entries; +} diff --git a/aegilib/src/exception.cpp b/aegilib/src/exception.cpp index 6ef56ff3d..be59e3280 100644 --- a/aegilib/src/exception.cpp +++ b/aegilib/src/exception.cpp @@ -65,6 +65,7 @@ const char* Exception::GetMessageChar(int code) case Parse_Error: return "Parse error."; case Unsupported_Format_Feature: return "This feature is not supported by this format."; case Invalid_Token: return "Invalid type for this token."; + case Out_Of_Range: return "Out of range."; case TODO: return "TODO"; } return "Invalid code."; diff --git a/aegilib/src/formats/format_ass_dialogue.h b/aegilib/src/formats/format_ass_dialogue.h index 6ae369fa9..93b0ea343 100644 --- a/aegilib/src/formats/format_ass_dialogue.h +++ b/aegilib/src/formats/format_ass_dialogue.h @@ -63,7 +63,7 @@ namespace Gorgonsub { // Basic features String GetDefaultGroup() const { return L"Events"; } SectionEntryPtr Clone() const { return SectionEntryPtr(new DialogueASS(*this)); } - DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(new DialogueASSDeltaCoder()); } + //DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(new DialogueASSDeltaCoder()); } // Capabilities bool HasText() const { return true; } diff --git a/aegilib/src/selection.cpp b/aegilib/src/selection.cpp index fd918e517..83c26320a 100644 --- a/aegilib/src/selection.cpp +++ b/aegilib/src/selection.cpp @@ -33,7 +33,7 @@ // Contact: mailto:amz@aegisub.net // -#include "selection.h" +#include "gorgonsub.h" using namespace Gorgonsub; @@ -49,8 +49,8 @@ Selection::Selection() // Adds a range void Selection::AddRange(const Range &range) { - // TODO - (void) range; + ranges.push_back(range); + UpdateCount(); } @@ -60,6 +60,53 @@ void Selection::RemoveRange(const Range &range) { // TODO (void) range; + THROW_GORGON_EXCEPTION(Exception::TODO); +} + + +//////////////////////////////////////////////////////////////////// +// Normalizes all ranges, that is, gets rid of overlaps and whatnot +void Selection::NormalizeRanges() +{ + // Has anything to do? + if (ranges.size() == 0) return; + + // Find largest value + size_t max = 0; + size_t len = ranges.size(); + for (size_t i=0;i max) max = ranges[i].GetEnd(); + } + + // Allocate a vector of that size + std::vector selected(max); + for (size_t i=0;i n) return ranges[i].GetLine(n-ranges[i].GetStart()); + size_t curLen = ranges[i].GetSize(); + if (cur+curLen > n) return ranges[i].GetLine(n-cur); + cur += curLen; } return ~0UL; } @@ -86,6 +134,18 @@ void Selection::AddSelection (const Selection ¶m) } +//////////////// +// Update count +void Selection::UpdateCount() +{ + count = 0; + size_t len = ranges.size(); + for (size_t i=0;iSetText(L"Hi, testing insertion of lines!"); - cout << "Done.\n"; + system("pause"); // Issue an action - ActionListPtr actions = control.CreateActionList(L"Test"); - SectionEntryDialoguePtr diag = dynamic_pointer_cast (actions->ModifyLine(10,L"Events")); - diag->SetText(L"Hay guise sup"); - actions->Finish(); + cout << "Executing action 100 times... "; + timer.Start(); + for (size_t i=0;i<100;i++) { + ActionListPtr actions = control.CreateActionList(L"Test"); + Selection selection; + selection.AddRange(Range(0,5000)); + selection.AddRange(Range(4500,5500)); + selection.AddRange(Range(9000,9100)); + std::vector entries = actions->ModifyLines(selection,L"Events"); + size_t len = entries.size(); + for (size_t i=0;i (entries[i]); + diag->SetStartTime(diag->GetStartTime() - 55555); + diag->SetEndTime(diag->GetEndTime() + 5555); + } + actions->Finish(); + } + timer.Pause(); + cout << "Done in " << timer.Time() << " ms.\n"; + system("pause"); + + // Rollback + cout << "Undoing 99 times... "; + for (size_t i=0;i<99;i++) { + control.Undo(); + } + cout << "Done.\n"; // Undo cout << "Undoing and redoing 1000 times... "; diff --git a/aegilib/todo.txt b/aegilib/todo.txt index 46d5277a4..b6546dcaf 100644 --- a/aegilib/todo.txt +++ b/aegilib/todo.txt @@ -14,7 +14,9 @@ x = done [x] Text file reader/writer [ ] Automatic character set detection [ ] Conversion between subtitle formats +[ ] Override tag support [:] ASS format support +[ ] ASS override tags [ ] Simple subtitles (srt, microdvd, encore, etc) format support [ ] Matroska-embedded subtitles support [ ] DVD subtitles support (*)