Some refactoring and a new way to read data.

Originally committed to SVN as r2077.
This commit is contained in:
Rodrigo Braz Monteiro 2008-03-18 02:09:33 +00:00
parent 39938d213a
commit cd9d6f1cfb
25 changed files with 316 additions and 205 deletions

View file

@ -40,7 +40,7 @@
namespace Gorgonsub { namespace Gorgonsub {
// Prototypes // Prototypes
class Model; class Model;
class SectionEntry; class Entry;
class Action; class Action;
class Section; class Section;
typedef shared_ptr<Action> ActionPtr; typedef shared_ptr<Action> ActionPtr;
@ -60,12 +60,12 @@ namespace Gorgonsub {
// Insert line // Insert line
class ActionInsert : public Action { class ActionInsert : public Action {
private: private:
shared_ptr<SectionEntry> entry; shared_ptr<Entry> entry;
const String section; const String section;
int lineNumber; int lineNumber;
public: public:
ActionInsert(shared_ptr<SectionEntry> entry,int line,const String &section); ActionInsert(shared_ptr<Entry> entry,int line,const String &section);
~ActionInsert() {} ~ActionInsert() {}
ActionPtr GetAntiAction(const Model &model) const; ActionPtr GetAntiAction(const Model &model) const;
@ -89,14 +89,14 @@ namespace Gorgonsub {
// Modify line // Modify line
class ActionModify : public Action { class ActionModify : public Action {
private: private:
shared_ptr<SectionEntry> entry; shared_ptr<Entry> entry;
shared_ptr<void> delta; shared_ptr<void> delta;
const String section; const String section;
int lineNumber; int lineNumber;
bool noTextFields; bool noTextFields;
public: public:
ActionModify(shared_ptr<SectionEntry> entry,int line,const String &section,bool noTextFields); ActionModify(shared_ptr<Entry> entry,int line,const String &section,bool noTextFields);
ActionModify(shared_ptr<void> delta,int line,const String &section); ActionModify(shared_ptr<void> delta,int line,const String &section);
~ActionModify() {} ~ActionModify() {}
@ -107,14 +107,14 @@ namespace Gorgonsub {
// Modify several line // Modify several line
class ActionModifyBatch : public Action { class ActionModifyBatch : public Action {
private: private:
std::vector<shared_ptr<SectionEntry> > entries; std::vector<shared_ptr<Entry> > entries;
std::vector<shared_ptr<void> > deltas; std::vector<shared_ptr<void> > deltas;
Selection selection; Selection selection;
const String section; const String section;
bool noTextFields; bool noTextFields;
public: public:
ActionModifyBatch(std::vector<shared_ptr<SectionEntry> > entries,std::vector<shared_ptr<void> > deltas,Selection selection,const String &section,bool noTextFields); ActionModifyBatch(std::vector<shared_ptr<Entry> > entries,std::vector<shared_ptr<void> > deltas,Selection selection,const String &section,bool noTextFields);
~ActionModifyBatch() {} ~ActionModifyBatch() {}
ActionPtr GetAntiAction(const Model &model) const; ActionPtr GetAntiAction(const Model &model) const;

View file

@ -71,10 +71,10 @@ namespace Gorgonsub {
void AddAction(const ActionPtr action); void AddAction(const ActionPtr action);
void Finish(); void Finish();
void InsertLine(SectionEntryPtr line,int position=-1,const String section=L""); void InsertLine(EntryPtr 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); EntryPtr ModifyLine(int position,const String section);
std::vector<SectionEntryPtr> ModifyLines(Selection selection,const String section); std::vector<EntryPtr> ModifyLines(Selection selection,const String section);
}; };
typedef shared_ptr<ActionList> ActionListPtr; typedef shared_ptr<ActionList> ActionListPtr;

View file

@ -1,71 +1,76 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro // Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: // modification, are permitted provided that the following conditions are met:
// //
// * Redistributions of source code must retain the above copyright notice, // * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, // * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation // this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. // and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors // * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software // may be used to endorse or promote products derived from this software
// without specific prior written permission. // without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. // POSSIBILITY OF SUCH DAMAGE.
// //
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// //
// AEGISUB/GORGONSUB // AEGISUB/GORGONSUB
// //
// Website: http://www.aegisub.net // Website: http://www.aegisub.net
// Contact: mailto:amz@aegisub.net // Contact: mailto:amz@aegisub.net
// //
#pragma once #pragma once
#include "gorgonstring.h" #include "gorgonstring.h"
#include "tr1.h" #include "tr1.h"
#include "format.h" #include "format.h"
namespace Gorgonsub { namespace Gorgonsub {
// Prototypes // Prototypes
class Model; class Model;
class ActionList; class ActionList;
typedef shared_ptr<ActionList> ActionListPtr; typedef shared_ptr<ActionList> ActionListPtr;
// Controller class // Controller class
class Controller { class Controller {
private: private:
Model &model; Model &model;
public: public:
Controller (Model &model); Controller (Model &model);
ActionListPtr CreateActionList(const String title,const String owner=L"",bool undoAble=true); 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 CanUndo(const String owner=L"") const;
bool CanRedo(const String owner=L"") const; bool CanRedo(const String owner=L"") const;
void Undo(const String owner=L""); void Undo(const String owner=L"");
void Redo(const String owner=L""); void Redo(const String owner=L"");
SectionEntryDialoguePtr CreateDialogue(); DialoguePtr CreateDialogue() const;
SectionEntryStylePtr CreateStyle(); StylePtr CreateStyle() const;
const FormatPtr GetFormat() const; DialogueConstPtr GetDialogue(size_t n) const;
}; DialogueConstPtr GetStyle(size_t n) const;
StyleConstPtr GetStyle(String name) const;
} EntryConstPtr GetEntry(size_t n,String section) const;
const FormatPtr GetFormat() const;
};
}

View file

@ -53,6 +53,7 @@ namespace Gorgonsub {
Unsupported_Format_Feature, Unsupported_Format_Feature,
Invalid_Token, Invalid_Token,
Out_Of_Range, Out_Of_Range,
Invalid_Section,
TODO TODO
}; };

View file

@ -67,8 +67,8 @@ namespace Gorgonsub {
virtual int GetTimingPrecision() const { return 10; } // In milliseconds virtual int GetTimingPrecision() const { return 10; } // In milliseconds
virtual int GetMaxTime() const { return 36000000-10; } // In milliseconds, default 9h 59min 59.99s virtual int GetMaxTime() const { return 36000000-10; } // In milliseconds, default 9h 59min 59.99s
virtual SectionEntryDialoguePtr CreateDialogue() const = 0; virtual DialoguePtr CreateDialogue() const = 0;
virtual SectionEntryStylePtr CreateStyle() const = 0; virtual StylePtr CreateStyle() const = 0;
}; };
typedef shared_ptr<Format> FormatPtr; typedef shared_ptr<Format> FormatPtr;

View file

@ -45,8 +45,9 @@ namespace Gorgonsub {
// Section class // Section class
class Section { class Section {
private: private:
std::vector<SectionEntryPtr> entries; std::vector<EntryPtr> entries;
std::map<String,String> properties; std::map<String,String> properties;
std::map<String,EntryPtr> index;
String name; String name;
public: public:
@ -65,12 +66,15 @@ namespace Gorgonsub {
size_t GetPropertyCount() const; size_t GetPropertyCount() const;
String GetPropertyName(size_t index) const; String GetPropertyName(size_t index) const;
// Indexed
EntryPtr GetFromIndex(String key) const;
// Entries // Entries
void AddEntry(SectionEntryPtr entry,int pos=-1); void AddEntry(EntryPtr entry,int pos=-1);
void RemoveEntryByIndex(size_t index); void RemoveEntryByIndex(size_t index);
void RemoveEntry(SectionEntryPtr entry); void RemoveEntry(EntryPtr entry);
SectionEntryPtr GetEntry(size_t index) const; EntryPtr GetEntry(size_t index) const;
SectionEntryPtr& GetEntryRef(size_t index); EntryPtr& GetEntryRef(size_t index);
size_t GetEntryCount() const; size_t GetEntryCount() const;
}; };
typedef shared_ptr<Section> SectionPtr; typedef shared_ptr<Section> SectionPtr;

View file

@ -50,51 +50,53 @@ namespace Gorgonsub {
}; };
// Prototypes // Prototypes
class SectionEntry; class Entry;
class SectionEntryPlain; class PlainText;
class SectionEntryDialogue; class Dialogue;
class SectionEntryStyle; class Style;
class SectionEntryFile; class Attachment;
class SectionEntryRaw; class RawEntry;
typedef shared_ptr<SectionEntry> SectionEntryPtr; typedef shared_ptr<Entry> EntryPtr;
typedef shared_ptr<SectionEntryPlain> SectionEntryPlainPtr; typedef shared_ptr<PlainText> PlainTextPtr;
typedef shared_ptr<SectionEntryDialogue> SectionEntryDialoguePtr; typedef shared_ptr<Dialogue> DialoguePtr;
typedef shared_ptr<SectionEntryStyle> SectionEntryStylePtr; typedef shared_ptr<Style> StylePtr;
typedef shared_ptr<SectionEntryFile> SectionEntryFilePtr; typedef shared_ptr<Attachment> AttachmentPtr;
typedef shared_ptr<SectionEntryRaw> SectionEntryRawPtr; typedef shared_ptr<RawEntry> RawEntryPtr;
typedef shared_ptr<const SectionEntry> SectionEntryConstPtr; typedef shared_ptr<const Entry> EntryConstPtr;
typedef shared_ptr<const SectionEntryPlain> SectionEntryPlainConstPtr; typedef shared_ptr<const PlainText> PlainTextConstPtr;
typedef shared_ptr<const SectionEntryDialogue> SectionEntryDialogueConstPtr; typedef shared_ptr<const Dialogue> DialogueConstPtr;
typedef shared_ptr<const SectionEntryStyle> SectionEntryStyleConstPtr; typedef shared_ptr<const Style> StyleConstPtr;
typedef shared_ptr<const SectionEntryFile> SectionEntryFileConstPtr; typedef shared_ptr<const Attachment> AttachmentConstPtr;
typedef shared_ptr<const SectionEntryRaw> SectionEntryRawConstPtr; typedef shared_ptr<const RawEntry> RawEntryConstPtr;
// Section entry class // Section entry class
class SectionEntry { class Entry {
protected: protected:
virtual ~SectionEntry() {} virtual ~Entry() {}
const String& EmptyString() const; const String& EmptyString() const;
public: public:
virtual SectionEntryType GetType() const =0; virtual SectionEntryType GetType() const =0;
virtual String GetDefaultGroup() const =0; virtual String GetDefaultGroup() const =0;
virtual SectionEntryPtr Clone() const =0; virtual EntryPtr Clone() const =0;
virtual DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(); } virtual DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(); }
virtual bool IsIndexable() const { return false; }
virtual String GetIndexName() const { return L""; }
static const SectionEntryPlainPtr GetAsPlain(const SectionEntryPtr &ptr); static const PlainTextPtr GetAsPlain(const EntryPtr &ptr);
static const SectionEntryDialoguePtr GetAsDialogue(const SectionEntryPtr &ptr); static const DialoguePtr GetAsDialogue(const EntryPtr &ptr);
static const SectionEntryDialogueConstPtr GetAsDialogue(const SectionEntryConstPtr &ptr); static const DialogueConstPtr GetAsDialogue(const EntryConstPtr &ptr);
static const SectionEntryStylePtr GetAsStyle(const SectionEntryPtr &ptr); static const StylePtr GetAsStyle(const EntryPtr &ptr);
static const SectionEntryFilePtr GetAsFile(const SectionEntryPtr &ptr); static const AttachmentPtr GetAsFile(const EntryPtr &ptr);
static const SectionEntryRawPtr GetAsRaw(const SectionEntryPtr &ptr); static const RawEntryPtr GetAsRaw(const EntryPtr &ptr);
}; };
// Section plain-text entry // Section plain-text entry
class SectionEntryPlain : public SectionEntry { class PlainText : public Entry {
public: public:
SectionEntryType GetType() const { return SECTION_ENTRY_PLAIN; } SectionEntryType GetType() const { return SECTION_ENTRY_PLAIN; }
virtual ~SectionEntryPlain() {} virtual ~PlainText() {}
virtual String GetText() const =0; virtual String GetText() const =0;
virtual void SetText(const String &_data) =0; virtual void SetText(const String &_data) =0;
}; };

View file

@ -43,18 +43,18 @@
namespace Gorgonsub { namespace Gorgonsub {
// Dialogue class // Dialogue class
class SectionEntryDialogue : public SectionEntry { class Dialogue : public Entry {
private: private:
static const bool dodgeWarning = true; static const bool dodgeWarning = true;
void ThrowUnsupported() const { if (dodgeWarning) throw Exception(Exception::Unsupported_Format_Feature); } void ThrowUnsupported() const { if (dodgeWarning) THROW_GORGON_EXCEPTION(Exception::Unsupported_Format_Feature); }
public: public:
// Destructor // Destructor
virtual ~SectionEntryDialogue() {} virtual ~Dialogue() {}
// Type // Type
SectionEntryType GetType() const { return SECTION_ENTRY_DIALOGUE; } SectionEntryType GetType() const { return SECTION_ENTRY_DIALOGUE; }
SectionEntryDialogue *GetAsDialogue() { return this; } Dialogue *GetAsDialogue() { return this; }
// Capabilities // Capabilities
virtual bool HasText() const { return false; } virtual bool HasText() const { return false; }

View file

@ -43,18 +43,18 @@
namespace Gorgonsub { namespace Gorgonsub {
// Style class // Style class
class SectionEntryStyle : public SectionEntry { class Style : public Entry {
private: private:
static const bool dodgeWarning = true; static const bool dodgeWarning = true;
void ThrowUnsupported() const { if (dodgeWarning) throw Exception(Exception::Unsupported_Format_Feature); } void ThrowUnsupported() const { if (dodgeWarning) THROW_GORGON_EXCEPTION(Exception::Unsupported_Format_Feature); }
public: public:
// Destructor // Destructor
virtual ~SectionEntryStyle() {} virtual ~Style() {}
// Type // Type
SectionEntryType GetType() const { return SECTION_ENTRY_STYLE; } SectionEntryType GetType() const { return SECTION_ENTRY_STYLE; }
SectionEntryStyle *GetAsStyle() { return this; } Style *GetAsStyle() { return this; }
// Read accessors // Read accessors
virtual String GetName() const=0; virtual String GetName() const=0;

View file

@ -49,7 +49,7 @@ SectionPtr Action::GetSection(const Model &model,const String &name) const
/////////////// ///////////////
// Constructor // Constructor
ActionInsert::ActionInsert(shared_ptr<SectionEntry> data,int line,const String &sName) ActionInsert::ActionInsert(shared_ptr<Entry> data,int line,const String &sName)
: entry(data), lineNumber(line), section(sName) {} : entry(data), lineNumber(line), section(sName) {}
@ -93,7 +93,7 @@ ActionRemove::ActionRemove(int line,const String &sName)
ActionPtr ActionRemove::GetAntiAction(const Model &model) const ActionPtr ActionRemove::GetAntiAction(const Model &model) const
{ {
SectionPtr sect = GetSection(model,section); SectionPtr sect = GetSection(model,section);
SectionEntryPtr entry = sect->GetEntry(lineNumber); EntryPtr entry = sect->GetEntry(lineNumber);
return ActionPtr(new ActionInsert(entry,lineNumber,section)); return ActionPtr(new ActionInsert(entry,lineNumber,section));
} }
@ -104,7 +104,7 @@ void ActionRemove::Execute(Model &model)
{ {
// Find the section to remote it from // Find the section to remote it from
String sect = section; String sect = section;
if (sect.IsEmpty()) throw Exception(Exception::TODO); // TODO if (sect.IsEmpty()) THROW_GORGON_EXCEPTION(Exception::TODO); // TODO
SectionPtr section = GetSection(model,sect); SectionPtr section = GetSection(model,sect);
// Remove the line // Remove the line
@ -116,7 +116,7 @@ void ActionRemove::Execute(Model &model)
//////////////// ////////////////
// Constructors // Constructors
ActionModify::ActionModify(shared_ptr<SectionEntry> data,int line,const String &sName,bool _noTextFields) ActionModify::ActionModify(shared_ptr<Entry> data,int line,const String &sName,bool _noTextFields)
: entry(data), lineNumber(line), section(sName), noTextFields(_noTextFields) {} : entry(data), lineNumber(line), section(sName), noTextFields(_noTextFields) {}
ActionModify::ActionModify(shared_ptr<void> _delta,int line,const String &sName) ActionModify::ActionModify(shared_ptr<void> _delta,int line,const String &sName)
@ -129,7 +129,7 @@ ActionPtr ActionModify::GetAntiAction(const Model &model) const
{ {
// Get section and original line // Get section and original line
SectionPtr sect = GetSection(model,section); SectionPtr sect = GetSection(model,section);
SectionEntryPtr oldEntry = sect->GetEntry(lineNumber); EntryPtr oldEntry = sect->GetEntry(lineNumber);
// Try to get a delta // Try to get a delta
DeltaCoderPtr deltaCoder = oldEntry->GetDeltaCoder(); DeltaCoderPtr deltaCoder = oldEntry->GetDeltaCoder();
@ -158,7 +158,7 @@ void ActionModify::Execute(Model &model)
// Modify the line // Modify the line
if (delta) { if (delta) {
SectionEntryPtr &ref = sect->GetEntryRef(lineNumber); EntryPtr &ref = sect->GetEntryRef(lineNumber);
ref->GetDeltaCoder()->ApplyDelta(delta,ref); ref->GetDeltaCoder()->ApplyDelta(delta,ref);
} }
else sect->GetEntryRef(lineNumber) = entry; else sect->GetEntryRef(lineNumber) = entry;
@ -167,7 +167,7 @@ void ActionModify::Execute(Model &model)
////////////////////////// Batch Modify line ////////////////////////// ////////////////////////// Batch Modify line //////////////////////////
ActionModifyBatch::ActionModifyBatch(std::vector<shared_ptr<SectionEntry> > _entries, std::vector<shared_ptr<void> > _deltas, Selection _selection,const String &_section,bool _noTextFields) ActionModifyBatch::ActionModifyBatch(std::vector<shared_ptr<Entry> > _entries, std::vector<shared_ptr<void> > _deltas, Selection _selection,const String &_section,bool _noTextFields)
: entries(_entries), deltas(_deltas), selection(_selection), section(_section), noTextFields(_noTextFields) {} : entries(_entries), deltas(_deltas), selection(_selection), section(_section), noTextFields(_noTextFields) {}
ActionPtr ActionModifyBatch::GetAntiAction(const Model &model) const ActionPtr ActionModifyBatch::GetAntiAction(const Model &model) const
@ -176,12 +176,12 @@ ActionPtr ActionModifyBatch::GetAntiAction(const Model &model) const
SectionPtr sect = GetSection(model,section); SectionPtr sect = GetSection(model,section);
size_t len = selection.GetCount(); size_t len = selection.GetCount();
std::vector<VoidPtr> _deltas(len); std::vector<VoidPtr> _deltas(len);
std::vector<SectionEntryPtr> oldEntries(len); std::vector<EntryPtr> oldEntries(len);
// For each line... // For each line...
for (size_t i=0;i<len;i++) { for (size_t i=0;i<len;i++) {
// Get old entry // Get old entry
SectionEntryPtr oldEntry = sect->GetEntry(selection.GetLine(i)); EntryPtr oldEntry = sect->GetEntry(selection.GetLine(i));
// Try to get a delta // Try to get a delta
DeltaCoderPtr deltaCoder = oldEntry->GetDeltaCoder(); DeltaCoderPtr deltaCoder = oldEntry->GetDeltaCoder();
@ -208,7 +208,7 @@ void ActionModifyBatch::Execute(Model &model)
// For each line... // For each line...
for (size_t i=0;i<len;i++) { for (size_t i=0;i<len;i++) {
if (i < deltas.size() && deltas[i]) { if (i < deltas.size() && deltas[i]) {
SectionEntryPtr &ref = sect->GetEntryRef(selection.GetLine(i)); EntryPtr &ref = sect->GetEntryRef(selection.GetLine(i));
ref->GetDeltaCoder()->ApplyDelta(deltas[i],ref); ref->GetDeltaCoder()->ApplyDelta(deltas[i],ref);
} }
else sect->GetEntryRef(selection.GetLine(i)) = entries[i]; else sect->GetEntryRef(selection.GetLine(i)) = entries[i];

View file

@ -58,7 +58,7 @@ ActionList::~ActionList()
// Add an action to the queue // Add an action to the queue
void ActionList::AddAction(const ActionPtr action) void ActionList::AddAction(const ActionPtr action)
{ {
if (!valid) throw Exception(Exception::Invalid_ActionList); if (!valid) THROW_GORGON_EXCEPTION(Exception::Invalid_ActionList);
actions.push_back(action); actions.push_back(action);
if (actions.size() > 2) { if (actions.size() > 2) {
int a = 0; int a = 0;
@ -71,7 +71,7 @@ void ActionList::AddAction(const ActionPtr action)
// Add an action to the start of the queue // Add an action to the start of the queue
void ActionList::AddActionStart(const ActionPtr action) void ActionList::AddActionStart(const ActionPtr action)
{ {
if (!valid) throw Exception(Exception::Invalid_ActionList); if (!valid) THROW_GORGON_EXCEPTION(Exception::Invalid_ActionList);
actions.push_front(action); actions.push_front(action);
if (actions.size() > 2) { if (actions.size() > 2) {
int a = 0; int a = 0;
@ -104,7 +104,7 @@ void ActionList::Finish()
////////////////////////////////// //////////////////////////////////
// Create an "insert line" action // Create an "insert line" action
void ActionList::InsertLine(SectionEntryPtr line,int position,const String section) void ActionList::InsertLine(EntryPtr line,int position,const String section)
{ {
ActionPtr action = ActionPtr (new ActionInsert(line,position,section)); ActionPtr action = ActionPtr (new ActionInsert(line,position,section));
AddAction(action); AddAction(action);
@ -122,10 +122,10 @@ void ActionList::RemoveLine(int position,const String section)
///////////////////////////////// /////////////////////////////////
// Insert a "modify line" action // Insert a "modify line" action
SectionEntryPtr ActionList::ModifyLine(int position,const String section) EntryPtr ActionList::ModifyLine(int position,const String section)
{ {
SectionPtr sect = model.GetSection(section); SectionPtr sect = model.GetSection(section);
SectionEntryPtr entry = sect->GetEntry(position)->Clone(); EntryPtr entry = sect->GetEntry(position)->Clone();
ActionPtr action = ActionPtr (new ActionModify(entry,position,section,false)); ActionPtr action = ActionPtr (new ActionModify(entry,position,section,false));
AddAction(action); AddAction(action);
return entry; return entry;
@ -134,13 +134,13 @@ SectionEntryPtr ActionList::ModifyLine(int position,const String section)
//////////////////////////////////////// ////////////////////////////////////////
// Insert a "modify lines" batch action // Insert a "modify lines" batch action
std::vector<SectionEntryPtr> ActionList::ModifyLines(Selection selection,const String section) std::vector<EntryPtr> ActionList::ModifyLines(Selection selection,const String section)
{ {
// Get section // Get section
SectionPtr sect = model.GetSection(section); SectionPtr sect = model.GetSection(section);
// Generate entries // Generate entries
std::vector<SectionEntryPtr> entries(selection.GetCount()); std::vector<EntryPtr> entries(selection.GetCount());
size_t len = selection.GetRanges(); size_t len = selection.GetRanges();
size_t n = 0; size_t n = 0;
for (size_t i=0;i<len;i++) { for (size_t i=0;i<len;i++) {

View file

@ -86,11 +86,11 @@ const FormatPtr Controller::GetFormat() const
////////////////// //////////////////
// Create entries // Create entries
SectionEntryDialoguePtr Controller::CreateDialogue() DialoguePtr Controller::CreateDialogue() const
{ {
return GetFormat()->CreateDialogue(); return GetFormat()->CreateDialogue();
} }
SectionEntryStylePtr Controller::CreateStyle() StylePtr Controller::CreateStyle() const
{ {
return GetFormat()->CreateStyle(); return GetFormat()->CreateStyle();
} }
@ -114,3 +114,48 @@ void Controller::Redo(const String owner)
{ {
model.Redo(owner); model.Redo(owner);
} }
////////////////////////
// Get the nth dialogue
DialogueConstPtr Controller::GetDialogue(size_t n) const
{
// TODO
(void) n;
THROW_GORGON_EXCEPTION(Exception::TODO);
}
/////////////////////
// Get the nth style
DialogueConstPtr Controller::GetStyle(size_t n) const
{
// TODO
(void) n;
THROW_GORGON_EXCEPTION(Exception::TODO);
}
///////////////////////
// Get a style by name
StyleConstPtr Controller::GetStyle(String name) const
{
// Get section
StylePtr dummy = CreateStyle();
String section = dummy->GetDefaultGroup();
SectionPtr sect = model.GetSection(section);
if (!sect) THROW_GORGON_EXCEPTION(Exception::Invalid_Section);
// Return from index
return dynamic_pointer_cast<const Style> (sect->GetFromIndex(name));
}
////////////////
// Get an entry
EntryConstPtr Controller::GetEntry(size_t n,String section) const
{
SectionPtr sect = model.GetSection(section);
if (!sect) THROW_GORGON_EXCEPTION(Exception::Invalid_Section);
return sect->GetEntry(n);
}

View file

@ -66,6 +66,7 @@ const char* Exception::GetMessageChar(int code)
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 Out_Of_Range: return "Out of range.";
case Invalid_Section: return "Invalid section.";
case TODO: return "TODO"; case TODO: return "TODO";
} }
return "Invalid code."; return "Invalid code.";

View file

@ -136,7 +136,7 @@ void FormatHandlerASS::Load(wxInputStream &file,const String encoding)
if (cur[0] == L'[') continue; if (cur[0] == L'[') continue;
// Create and insert line // Create and insert line
SectionEntryPtr entry = MakeEntry(cur,section,version); EntryPtr entry = MakeEntry(cur,section,version);
if (entry) section->AddEntry(entry); if (entry) section->AddEntry(entry);
} }
} }
@ -182,11 +182,11 @@ void FormatHandlerASS::Save(wxOutputStream &file,const String encoding)
/////////////// ///////////////
// Create line // Create line
SectionEntryPtr FormatHandlerASS::MakeEntry(const String &data,SectionPtr section,int version) EntryPtr FormatHandlerASS::MakeEntry(const String &data,SectionPtr section,int version)
{ {
// Variables // Variables
const String group = section->GetName(); const String group = section->GetName();
SectionEntryPtr final; EntryPtr final;
// Attachments // Attachments
if (group == _T("Fonts") || group == _T("Graphics")) { if (group == _T("Fonts") || group == _T("Graphics")) {
@ -226,17 +226,17 @@ SectionEntryPtr FormatHandlerASS::MakeEntry(const String &data,SectionPtr sectio
// Script info // Script info
else if (group == _T("Script Info")) { else if (group == _T("Script Info")) {
// Discard comments // Discard comments
if (data.Left(1) == _T(";")) return SectionEntryPtr(); if (data.Left(1) == _T(";")) return EntryPtr();
// Parse property // Parse property
size_t pos = data.Find(_T(':')); size_t pos = data.Find(_T(':'));
if (pos == wxNOT_FOUND) return SectionEntryPtr(); if (pos == wxNOT_FOUND) return EntryPtr();
wxString key = data.Left(pos).Trim(true).Trim(false); wxString key = data.Left(pos).Trim(true).Trim(false);
wxString value = data.Mid(pos+1).Trim(true).Trim(false); wxString value = data.Mid(pos+1).Trim(true).Trim(false);
// Insert property // Insert property
section->SetProperty(key,value); section->SetProperty(key,value);
return SectionEntryPtr(); return EntryPtr();
} }
// Unknown group, just leave it intact // Unknown group, just leave it intact
@ -316,7 +316,7 @@ void FormatHandlerASS::ProcessGroup(String cur,String &curGroup,int &version) {
if (versionString == _T("v4.00")) trueVersion = 0; if (versionString == _T("v4.00")) trueVersion = 0;
else if (versionString == _T("v4.00+")) trueVersion = 1; else if (versionString == _T("v4.00+")) trueVersion = 1;
else if (versionString == _T("v4.00++")) trueVersion = 2; else if (versionString == _T("v4.00++")) trueVersion = 2;
else throw Exception(Exception::Unknown_Format); else THROW_GORGON_EXCEPTION(Exception::Unknown_Format);
if (trueVersion != version) { if (trueVersion != version) {
// TODO: issue warning? // TODO: issue warning?
version = trueVersion; version = trueVersion;
@ -356,7 +356,7 @@ void FormatHandlerASS::WriteSection(TextFileWriter &writer,SectionPtr section)
// Write contents // Write contents
size_t entries = section->GetEntryCount(); size_t entries = section->GetEntryCount();
for (size_t i=0;i<entries;i++) { for (size_t i=0;i<entries;i++) {
SectionEntryConstPtr entry = section->GetEntry(i); EntryConstPtr entry = section->GetEntry(i);
shared_ptr<const SerializeText> serial = dynamic_pointer_cast<const SerializeText>(entry); shared_ptr<const SerializeText> serial = dynamic_pointer_cast<const SerializeText>(entry);
writer.WriteLineToFile(serial->ToText(formatVersion)); writer.WriteLineToFile(serial->ToText(formatVersion));
} }

View file

@ -54,7 +54,7 @@ namespace Gorgonsub {
private: private:
int formatVersion; int formatVersion;
SectionEntryPtr MakeEntry(const String &data,SectionPtr section,int version); EntryPtr MakeEntry(const String &data,SectionPtr section,int version);
void ProcessGroup(String cur,String &curGroup,int &version); void ProcessGroup(String cur,String &curGroup,int &version);
void WriteSection(TextFileWriter &writer,SectionPtr section); void WriteSection(TextFileWriter &writer,SectionPtr section);
@ -78,8 +78,8 @@ namespace Gorgonsub {
bool HasMargins() const { return true; } bool HasMargins() const { return true; }
bool HasActors() const { return true; } bool HasActors() const { return true; }
SectionEntryDialoguePtr CreateDialogue() const { return SectionEntryDialoguePtr(new DialogueASS()); } DialoguePtr CreateDialogue() const { return DialoguePtr(new DialogueASS()); }
SectionEntryStylePtr CreateStyle() const { return SectionEntryStylePtr(new StyleASS()); } StylePtr CreateStyle() const { return StylePtr(new StyleASS()); }
}; };
// Substation Alpha // Substation Alpha

View file

@ -42,7 +42,7 @@
namespace Gorgonsub { namespace Gorgonsub {
// Dialogue // Dialogue
class DialogueASS : public SectionEntryDialogue, public SerializeText { class DialogueASS : public Dialogue, public SerializeText {
friend class DialogueASSDeltaCoder; friend class DialogueASSDeltaCoder;
private: private:
@ -62,7 +62,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)); } EntryPtr Clone() const { return EntryPtr(new DialogueASS(*this)); }
//DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(new DialogueASSDeltaCoder()); } //DeltaCoderPtr GetDeltaCoder() const { return DeltaCoderPtr(new DialogueASSDeltaCoder()); }
// Capabilities // Capabilities

View file

@ -40,7 +40,7 @@
namespace Gorgonsub { namespace Gorgonsub {
// Raw line // Raw line
class PlainASS : public SectionEntryPlain, public SerializeText { class PlainASS : public PlainText, public SerializeText {
private: private:
String data; String data;
String ToText(int param) const { (void)param; return data; } String ToText(int param) const { (void)param; return data; }
@ -51,7 +51,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 PlainASS(*this)); } EntryPtr Clone() const { return EntryPtr(new PlainASS(*this)); }
String GetText() const { return data; } String GetText() const { return data; }
void SetText(const String &_data) { data = _data; } void SetText(const String &_data) { data = _data; }

View file

@ -238,8 +238,8 @@ String StyleASS::ToText(int version) const
String StyleASS::GetDefaultGroup() const String StyleASS::GetDefaultGroup() const
{ {
switch (formatVersion) { switch (formatVersion) {
case 0: return L"V4 Events"; case 0: return L"V4 Styles";
case 1: return L"V4+ Events"; case 1: return L"V4+ Styles";
default: return L"V4++ Events"; default: return L"V4++ Styles";
} }
} }

View file

@ -41,7 +41,7 @@
namespace Gorgonsub { namespace Gorgonsub {
// Style // Style
class StyleASS : public SectionEntryStyle, public SerializeText { class StyleASS : public Style, public SerializeText {
private: private:
String name; String name;
String font; String font;
@ -80,7 +80,11 @@ namespace Gorgonsub {
// Basic features // Basic features
String GetDefaultGroup() const; String GetDefaultGroup() const;
SectionEntryPtr Clone() const { return SectionEntryPtr(new StyleASS(*this)); } EntryPtr Clone() const { return EntryPtr(new StyleASS(*this)); }
// Indexing
virtual bool IsIndexable() const { return true; }
virtual String GetIndexName() const { return GetName(); }
// Read accessors // Read accessors
String GetName() const { return name; } String GetName() const { return name; }

View file

@ -99,12 +99,12 @@ void Model::Load(wxInputStream &input,const FormatPtr _format,const String encod
// TODO // TODO
// No format found // No format found
throw Exception(Exception::No_Format_Handler); THROW_GORGON_EXCEPTION(Exception::No_Format_Handler);
} }
// Get handler // Get handler
FormatHandlerPtr handler = _format->GetHandler(*this); FormatHandlerPtr handler = _format->GetHandler(*this);
if (!handler) throw Exception(Exception::No_Format_Handler); if (!handler) THROW_GORGON_EXCEPTION(Exception::No_Format_Handler);
// Clear the model first // Clear the model first
Clear(); Clear();
@ -124,12 +124,12 @@ void Model::Save(wxOutputStream &output,const FormatPtr _format,const String enc
// Use another format // Use another format
if (_format && _format != format) { if (_format && _format != format) {
// TODO // TODO
throw Exception(Exception::TODO); THROW_GORGON_EXCEPTION(Exception::TODO);
} }
// Get handler // Get handler
FormatHandlerPtr handler = format->GetHandler(*this); FormatHandlerPtr handler = format->GetHandler(*this);
if (!handler) throw Exception(Exception::No_Format_Handler); if (!handler) THROW_GORGON_EXCEPTION(Exception::No_Format_Handler);
// Load // Load
handler->Save(output,encoding); handler->Save(output,encoding);
@ -141,7 +141,7 @@ void Model::Save(wxOutputStream &output,const FormatPtr _format,const String enc
void Model::AddSection(String name) void Model::AddSection(String name)
{ {
SectionPtr prev = GetSection(name); SectionPtr prev = GetSection(name);
if (prev) throw Exception(Exception::Section_Already_Exists); if (prev) THROW_GORGON_EXCEPTION(Exception::Section_Already_Exists);
sections.push_back(SectionPtr(new Section(name))); sections.push_back(SectionPtr(new Section(name)));
} }

View file

@ -48,38 +48,65 @@ Section::Section(String _name)
/////////////////// ///////////////////
// Append an entry // Append an entry
void Section::AddEntry(SectionEntryPtr entry,int pos) void Section::AddEntry(EntryPtr entry,int pos)
{ {
// Insert to entry list
if (pos == -1) entries.push_back(entry); if (pos == -1) entries.push_back(entry);
else entries.insert(entries.begin()+pos,entry); else entries.insert(entries.begin()+pos,entry);
// Add to index too if it's indexable
if (entry->IsIndexable()) {
index[entry->GetIndexName()] = entry;
}
} }
void Section::RemoveEntryByIndex(size_t index)
/////////////////////////
// Removes the nth entry
void Section::RemoveEntryByIndex(size_t i)
{ {
entries.erase(entries.begin()+index); // Get entry iterator and erase
std::vector<EntryPtr>::iterator entry = entries.begin()+i;
entries.erase(entry);
// If it's indexable, remove it from index as well
if ((*entry)->IsIndexable()) index.erase((*entry)->GetIndexName());
} }
void Section::RemoveEntry(SectionEntryPtr entry)
/////////////////////////////////
// Removes an entry by its value
void Section::RemoveEntry(EntryPtr entry)
{ {
size_t len = entries.size(); size_t len = entries.size();
for (size_t i=0;i<len;i++) { for (size_t i=0;i<len;i++) {
if (entries[i] == entry) { if (entries[i] == entry) {
entries.erase(entries.begin()+i); entries.erase(entries.begin()+i);
if (entry->IsIndexable()) index.erase(entry->GetIndexName());
return; return;
} }
} }
} }
SectionEntryPtr Section::GetEntry(size_t index) const
////////////////////////////
// Retrieves entry by index
EntryPtr Section::GetEntry(size_t i) const
{ {
return entries[index]; return entries[i];
} }
SectionEntryPtr& Section::GetEntryRef(size_t index)
/////////////////////////////////////
// Retrieves a reference to an entry
EntryPtr& Section::GetEntryRef(size_t i)
{ {
return entries[index]; return entries[i];
} }
/////////////////////////
// Get number of entries
size_t Section::GetEntryCount() const size_t Section::GetEntryCount() const
{ {
return entries.size(); return entries.size();
@ -131,11 +158,21 @@ size_t Section::GetPropertyCount() const
/////////////////////////////////// ///////////////////////////////////
// Get name of a property by index // Get name of a property by index
String Section::GetPropertyName(size_t index) const String Section::GetPropertyName(size_t n) const
{ {
std::map<String,String>::const_iterator iter=properties.begin(); std::map<String,String>::const_iterator iter=properties.begin();
for (size_t i=0 ; iter!=properties.end() ; iter++,i++) { for (size_t i=0 ; iter!=properties.end() ; iter++,i++) {
if (i == index) return iter->first; if (i == n) return iter->first;
} }
return L""; return L"";
} }
///////////////////////
// Retrieve from index
EntryPtr Section::GetFromIndex(String key) const
{
std::map<String,EntryPtr>::const_iterator result = index.find(key);
if (result != index.end()) return result->second;
return EntryPtr();
}

View file

@ -42,34 +42,34 @@ using namespace Gorgonsub;
///////////////////////////////// /////////////////////////////////
// Returns a static empty string // Returns a static empty string
const String& SectionEntry::EmptyString() const const String& Entry::EmptyString() const
{ {
static const String str = _T(""); static const String str = _T("");
return str; return str;
} }
const SectionEntryPlainPtr SectionEntry::GetAsPlain(const SectionEntryPtr &ptr) const PlainTextPtr Entry::GetAsPlain(const EntryPtr &ptr)
{ {
(void) ptr; return SectionEntryPlainPtr(); (void) ptr; return PlainTextPtr();
} }
const SectionEntryDialoguePtr SectionEntry::GetAsDialogue(const SectionEntryPtr &ptr) const DialoguePtr Entry::GetAsDialogue(const EntryPtr &ptr)
{ {
return dynamic_pointer_cast<SectionEntryDialogue>(ptr); return dynamic_pointer_cast<Dialogue>(ptr);
} }
const SectionEntryDialogueConstPtr SectionEntry::GetAsDialogue(const SectionEntryConstPtr &ptr) const DialogueConstPtr Entry::GetAsDialogue(const EntryConstPtr &ptr)
{ {
return dynamic_pointer_cast<const SectionEntryDialogue>(ptr); return dynamic_pointer_cast<const Dialogue>(ptr);
} }
const SectionEntryStylePtr SectionEntry::GetAsStyle(const SectionEntryPtr &ptr) const StylePtr Entry::GetAsStyle(const EntryPtr &ptr)
{ {
return dynamic_pointer_cast<SectionEntryStyle>(ptr); return dynamic_pointer_cast<Style>(ptr);
} }
const SectionEntryFilePtr SectionEntry::GetAsFile(const SectionEntryPtr &ptr) const AttachmentPtr Entry::GetAsFile(const EntryPtr &ptr)
{ {
(void) ptr; return SectionEntryFilePtr(); (void) ptr; return AttachmentPtr();
} }
const SectionEntryRawPtr SectionEntry::GetAsRaw(const SectionEntryPtr &ptr) const RawEntryPtr Entry::GetAsRaw(const EntryPtr &ptr)
{ {
(void) ptr; return SectionEntryRawPtr(); (void) ptr; return RawEntryPtr();
} }

View file

@ -72,7 +72,7 @@ int Tokenizer::GetPosition()
String Tokenizer::GetString(bool trim) String Tokenizer::GetString(bool trim)
{ {
// Has any more? // Has any more?
if (!HasMoreTokens()) throw Exception(Exception::Invalid_Token); if (!HasMoreTokens()) THROW_GORGON_EXCEPTION(Exception::Invalid_Token);
// Find token // Find token
size_t len = string.Length(); size_t len = string.Length();

View file

@ -71,21 +71,25 @@ 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");
// Issue an action // Issue an action
cout << "Executing action 100 times... "; #ifdef WXDEBUG
const int n = 1;
#else
const int n = 100;
#endif
cout << "Executing action " << n << " times... ";
timer.Start(); timer.Start();
for (size_t i=0;i<100;i++) { for (size_t i=0;i<n;i++) {
ActionListPtr actions = control.CreateActionList(L"Test"); ActionListPtr actions = control.CreateActionList(L"Test");
Selection selection; Selection selection;
selection.AddRange(Range(0,5000)); selection.AddRange(Range(0,5000));
selection.AddRange(Range(4500,5500)); selection.AddRange(Range(4500,5500));
selection.AddRange(Range(9000,9100)); selection.AddRange(Range(9000,9100));
std::vector<SectionEntryPtr> entries = actions->ModifyLines(selection,L"Events"); std::vector<EntryPtr> entries = actions->ModifyLines(selection,L"Events");
size_t len = entries.size(); size_t len = entries.size();
for (size_t i=0;i<len;i++) { for (size_t i=0;i<len;i++) {
SectionEntryDialoguePtr diag = dynamic_pointer_cast<SectionEntryDialogue> (entries[i]); DialoguePtr diag = dynamic_pointer_cast<Dialogue> (entries[i]);
diag->SetStartTime(diag->GetStartTime() - 55555); diag->SetStartTime(diag->GetStartTime() - 55555);
diag->SetEndTime(diag->GetEndTime() + 5555); diag->SetEndTime(diag->GetEndTime() + 5555);
} }
@ -93,24 +97,29 @@ int main()
} }
timer.Pause(); timer.Pause();
cout << "Done in " << timer.Time() << " ms.\n"; cout << "Done in " << timer.Time() << " ms.\n";
system("pause");
// Rollback // Rollback
cout << "Undoing 99 times... "; cout << "Undoing " << n << " times... ";
for (size_t i=0;i<99;i++) { for (size_t i=0;i<n-1;i++) {
control.Undo(); control.Undo();
} }
cout << "Done.\n"; cout << "Done.\n";
// Undo // Undo
cout << "Undoing and redoing 1000 times... "; cout << "Undoing and redoing " << n*10 << " times... ";
timer.Start(); timer.Start();
for (size_t i=0;i<1000;i++) { for (size_t i=0;i<n*10;i++) {
control.Undo(); control.Undo();
control.Redo(); control.Redo();
} }
timer.Pause(); timer.Pause();
cout << "Done in " << timer.Time() << " ms.\n"; cout << "Done in " << timer.Time() << " ms.\n";
// Get style test
StyleConstPtr style = control.GetStyle(L"japro1_star");
cout << "Style " << style->GetName().mb_str() << " font is " << style->GetFontName().mb_str() << " " << style->GetFontSize() << ".\n";
// Save a few more
control.SaveFile(L"subs_out2.ass",L"UTF-8"); control.SaveFile(L"subs_out2.ass",L"UTF-8");
control.Undo(); control.Undo();
control.SaveFile(L"subs_out3.ass",L"UTF-8"); control.SaveFile(L"subs_out3.ass",L"UTF-8");

View file

@ -14,6 +14,7 @@ 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
[ ] Format comformity checks
[ ] Override tag support [ ] Override tag support
[:] ASS format support [:] ASS format support
[ ] ASS override tags [ ] ASS override tags
@ -21,6 +22,7 @@ x = done
[ ] Matroska-embedded subtitles support [ ] Matroska-embedded subtitles support
[ ] DVD subtitles support (*) [ ] DVD subtitles support (*)
[ ] Blu-Ray subtitles support (*) [ ] Blu-Ray subtitles support (*)
[ ] OCR support (through Tesseract) (*)
[:] Time helper class [:] Time helper class
[:] Colour helper class [:] Colour helper class
@ -28,11 +30,12 @@ x = done
[x] Exception class [x] Exception class
[x] Basic manipulation system [x] Basic manipulation system
[.] Reading subtitles data from model
[x] Inserting/removing/modifying lines
[.] Multi-line manipulation via selections
[:] Undo/redo stack [:] Undo/redo stack
[ ] Owner-based undo/redo operations [ ] Owner-based undo/redo operations
[x] Delta coded undo/redo [x] Delta coded undo/redo
[.] Multi-line manipulation via selections
[ ] Reading subtitles data from model
[x] Basic MVC structure [x] Basic MVC structure
[.] Controller [.] Controller