Implemented a multi-line modification action. Still a bit hacky, but works well.

Originally committed to SVN as r2076.
This commit is contained in:
Rodrigo Braz Monteiro 2008-03-17 07:19:33 +00:00
parent 18488241e8
commit 39938d213a
13 changed files with 196 additions and 24 deletions

View file

@ -35,6 +35,7 @@
#pragma once #pragma once
#include "gorgonstring.h" #include "gorgonstring.h"
#include "selection.h"
namespace Gorgonsub { namespace Gorgonsub {
// Prototypes // Prototypes
@ -108,13 +109,12 @@ namespace Gorgonsub {
private: private:
std::vector<shared_ptr<SectionEntry> > entries; std::vector<shared_ptr<SectionEntry> > entries;
std::vector<shared_ptr<void> > deltas; std::vector<shared_ptr<void> > deltas;
std::vector<int> lines; Selection selection;
const String section; const String section;
bool noTextFields; bool noTextFields;
public: public:
ActionModifyBatch(shared_ptr<SectionEntry> entry,int line,const String &section,bool noTextFields); ActionModifyBatch(std::vector<shared_ptr<SectionEntry> > entries,std::vector<shared_ptr<void> > deltas,Selection selection,const String &section,bool noTextFields);
ActionModifyBatch(shared_ptr<void> delta,int line,const String &section);
~ActionModifyBatch() {} ~ActionModifyBatch() {}
ActionPtr GetAntiAction(const Model &model) const; ActionPtr GetAntiAction(const Model &model) const;

View file

@ -74,7 +74,7 @@ namespace Gorgonsub {
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); void RemoveLine(int position,const String section);
SectionEntryPtr ModifyLine(int position,const String section); SectionEntryPtr ModifyLine(int position,const String section);
SectionEntryPtr ModifyLines(Selection selection,const String section); std::vector<SectionEntryPtr> ModifyLines(Selection selection,const String section);
}; };
typedef shared_ptr<ActionList> ActionListPtr; typedef shared_ptr<ActionList> ActionListPtr;

View file

@ -52,6 +52,7 @@ namespace Gorgonsub {
Parse_Error, Parse_Error,
Unsupported_Format_Feature, Unsupported_Format_Feature,
Invalid_Token, Invalid_Token,
Out_Of_Range,
TODO TODO
}; };

View file

@ -35,6 +35,7 @@
#pragma once #pragma once
#include "gorgonstring.h" #include "gorgonstring.h"
#include "utils.h"
namespace Gorgonsub { namespace Gorgonsub {
@ -45,7 +46,7 @@ namespace Gorgonsub {
public: public:
Time() { ms = 0; } Time() { ms = 0; }
Time(int ms) { (void)ms; } Time(int _ms) { ms = _ms; }
void SetMS(int milliseconds) { ms = milliseconds; } void SetMS(int milliseconds) { ms = milliseconds; }
int GetMS() const { return ms; } int GetMS() const { return ms; }
@ -53,6 +54,8 @@ namespace Gorgonsub {
String GetString(int ms_precision,int h_precision) const; String GetString(int ms_precision,int h_precision) const;
void Parse(const String &data); void Parse(const String &data);
Time operator + (const int &par) const { return Max<int>(0,ms+par); }
Time operator - (const int &par) const { return Max<int>(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; } 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; }

View file

@ -58,6 +58,7 @@ namespace Gorgonsub {
private: private:
std::vector<Range> ranges; std::vector<Range> ranges;
size_t count; size_t count;
void UpdateCount();
public: public:
Selection(); Selection();
@ -68,11 +69,13 @@ namespace Gorgonsub {
void RemoveRange(const Range &range); void RemoveRange(const Range &range);
void AddSelection (const Selection &param); void AddSelection (const Selection &param);
void RemoveSelection (const Selection &param); void RemoveSelection (const Selection &param);
void NormalizeRanges ();
size_t GetCount() const { return count; } size_t GetCount() const { return count; }
size_t GetRanges() const { return ranges.size(); } size_t GetRanges() const { return ranges.size(); }
size_t GetLine(size_t n) const; 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 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; } bool IsContiguous() const { return GetRanges() <= 1; }
}; };

View file

@ -35,7 +35,7 @@
#pragma once #pragma once
#include "Gorgonsub.h" #include "gorgonstring.h"
///////////// /////////////

View file

@ -142,7 +142,7 @@ ActionPtr ActionModify::GetAntiAction(const Model &model) const
// Store the whole original line // Store the whole original line
else { 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 // Execute insertion
void ActionModify::Execute(Model &model) void ActionModify::Execute(Model &model)
{ {
// Find the section to insert it on // Find the section to modify
String sectionName = section; String sectionName = section;
if (sectionName.IsEmpty()) sectionName = entry->GetDefaultGroup(); if (sectionName.IsEmpty()) sectionName = entry->GetDefaultGroup();
SectionPtr sect = GetSection(model,sectionName); SectionPtr sect = GetSection(model,sectionName);
@ -163,3 +163,54 @@ void ActionModify::Execute(Model &model)
} }
else sect->GetEntryRef(lineNumber) = entry; else sect->GetEntryRef(lineNumber) = entry;
} }
////////////////////////// Batch Modify line //////////////////////////
ActionModifyBatch::ActionModifyBatch(std::vector<shared_ptr<SectionEntry> > _entries, std::vector<shared_ptr<void> > _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<VoidPtr> _deltas(len);
std::vector<SectionEntryPtr> oldEntries(len);
// For each line...
for (size_t i=0;i<len;i++) {
// Get old entry
SectionEntryPtr oldEntry = sect->GetEntry(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;i<len;i++) {
if (i < deltas.size() && deltas[i]) {
SectionEntryPtr &ref = sect->GetEntryRef(selection.GetLine(i));
ref->GetDeltaCoder()->ApplyDelta(deltas[i],ref);
}
else sect->GetEntryRef(selection.GetLine(i)) = entries[i];
}
}

View file

@ -130,3 +130,28 @@ SectionEntryPtr ActionList::ModifyLine(int position,const String section)
AddAction(action); AddAction(action);
return entry; return entry;
} }
////////////////////////////////////////
// Insert a "modify lines" batch action
std::vector<SectionEntryPtr> ActionList::ModifyLines(Selection selection,const String section)
{
// Get section
SectionPtr sect = model.GetSection(section);
// Generate entries
std::vector<SectionEntryPtr> entries(selection.GetCount());
size_t len = selection.GetRanges();
size_t n = 0;
for (size_t i=0;i<len;i++) {
size_t rLen = selection.GetLinesInRange(i);
for (size_t j=0;j<rLen;j++) {
entries[n++] = sect->GetEntry(selection.GetLineInRange(j,i))->Clone();
}
}
// Generate the action
ActionPtr action = ActionPtr (new ActionModifyBatch(entries,std::vector<VoidPtr>(),selection,section,false));
AddAction(action);
return entries;
}

View file

@ -65,6 +65,7 @@ const char* Exception::GetMessageChar(int code)
case Parse_Error: return "Parse error."; case Parse_Error: return "Parse error.";
case Unsupported_Format_Feature: return "This feature is not supported by this format."; case Unsupported_Format_Feature: return "This feature is not supported by this format.";
case Invalid_Token: return "Invalid type for this token."; case Invalid_Token: return "Invalid type for this token.";
case Out_Of_Range: return "Out of range.";
case TODO: return "TODO"; case TODO: return "TODO";
} }
return "Invalid code."; return "Invalid code.";

View file

@ -63,7 +63,7 @@ namespace Gorgonsub {
// Basic features // Basic features
String GetDefaultGroup() const { return L"Events"; } String GetDefaultGroup() const { return L"Events"; }
SectionEntryPtr Clone() const { return SectionEntryPtr(new DialogueASS(*this)); } SectionEntryPtr Clone() const { return SectionEntryPtr(new DialogueASS(*this)); }
DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(new DialogueASSDeltaCoder()); } //DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(new DialogueASSDeltaCoder()); }
// Capabilities // Capabilities
bool HasText() const { return true; } bool HasText() const { return true; }

View file

@ -33,7 +33,7 @@
// Contact: mailto:amz@aegisub.net // Contact: mailto:amz@aegisub.net
// //
#include "selection.h" #include "gorgonsub.h"
using namespace Gorgonsub; using namespace Gorgonsub;
@ -49,8 +49,8 @@ Selection::Selection()
// Adds a range // Adds a range
void Selection::AddRange(const Range &range) void Selection::AddRange(const Range &range)
{ {
// TODO ranges.push_back(range);
(void) range; UpdateCount();
} }
@ -60,6 +60,53 @@ void Selection::RemoveRange(const Range &range)
{ {
// TODO // TODO
(void) range; (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<len;i++) {
if (ranges[i].GetEnd() > max) max = ranges[i].GetEnd();
}
// Allocate a vector of that size
std::vector<bool> selected(max);
for (size_t i=0;i<len;i++) {
for (size_t j=ranges[i].GetStart();j<ranges[i].GetEnd();j++) {
selected[j] = true;
}
}
// Clear ranges and re-build them
ranges.clear();
size_t start = 0;
bool inside = false;
for (size_t i=0;i<max;i++) {
// Enter
if (!inside && selected[i]) {
start = i;
inside = true;
}
// Exit
else if (inside && !selected[i]) {
ranges.push_back(Range(start,i));
inside = false;
}
}
if (inside) ranges.push_back(Range(start,max));
// Update count
UpdateCount();
} }
@ -71,8 +118,9 @@ size_t Selection::GetLine(size_t n) const
size_t cur = 0; size_t cur = 0;
size_t len = ranges.size(); size_t len = ranges.size();
for (size_t i=0;i<len;i++) { for (size_t i=0;i<len;i++) {
cur += ranges[i].GetSize(); size_t curLen = ranges[i].GetSize();
if (cur > n) return ranges[i].GetLine(n-ranges[i].GetStart()); if (cur+curLen > n) return ranges[i].GetLine(n-cur);
cur += curLen;
} }
return ~0UL; return ~0UL;
} }
@ -86,6 +134,18 @@ void Selection::AddSelection (const Selection &param)
} }
////////////////
// Update count
void Selection::UpdateCount()
{
count = 0;
size_t len = ranges.size();
for (size_t i=0;i<len;i++) {
count += ranges[i].GetSize();
}
}
////////////////////////////// //////////////////////////////
// Subtract another selection // Subtract another selection
void Selection::RemoveSelection (const Selection &param) void Selection::RemoveSelection (const Selection &param)
@ -93,3 +153,11 @@ void Selection::RemoveSelection (const Selection &param)
(void) param; (void) param;
} }
/////////////////////
// Get line in range
size_t Range::GetLine(size_t n) const
{
if (start+n < end) return start+n;
else THROW_GORGON_EXCEPTION(Exception::Out_Of_Range);
}

View file

@ -71,18 +71,36 @@ int main()
control.SaveFile(L"subs_out.ass",L"UTF-8"); control.SaveFile(L"subs_out.ass",L"UTF-8");
timer.Pause(); timer.Pause();
cout << "Done in " << timer.Time() << " ms.\n"; cout << "Done in " << timer.Time() << " ms.\n";
system("pause");
// Create line to be inserted
cout << "Creating data... ";
SectionEntryDialoguePtr line = control.CreateDialogue();
line->SetText(L"Hi, testing insertion of lines!");
cout << "Done.\n";
// Issue an action // Issue an action
ActionListPtr actions = control.CreateActionList(L"Test"); cout << "Executing action 100 times... ";
SectionEntryDialoguePtr diag = dynamic_pointer_cast<SectionEntryDialogue> (actions->ModifyLine(10,L"Events")); timer.Start();
diag->SetText(L"Hay guise sup"); for (size_t i=0;i<100;i++) {
actions->Finish(); 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<SectionEntryPtr> entries = actions->ModifyLines(selection,L"Events");
size_t len = entries.size();
for (size_t i=0;i<len;i++) {
SectionEntryDialoguePtr diag = dynamic_pointer_cast<SectionEntryDialogue> (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 // Undo
cout << "Undoing and redoing 1000 times... "; cout << "Undoing and redoing 1000 times... ";

View file

@ -14,7 +14,9 @@ x = done
[x] Text file reader/writer [x] Text file reader/writer
[ ] Automatic character set detection [ ] Automatic character set detection
[ ] Conversion between subtitle formats [ ] Conversion between subtitle formats
[ ] Override tag support
[:] ASS format support [:] ASS format support
[ ] ASS override tags
[ ] Simple subtitles (srt, microdvd, encore, etc) format support [ ] Simple subtitles (srt, microdvd, encore, etc) format support
[ ] Matroska-embedded subtitles support [ ] Matroska-embedded subtitles support
[ ] DVD subtitles support (*) [ ] DVD subtitles support (*)