Convert AssFile::Line to an intrusive list

Gives O(1) pointer -> iterator conversions, better memory usage, better
performance, and overall slightly simplifies the code using it.
This commit is contained in:
Thomas Goyne 2012-10-12 10:16:39 -07:00
parent 28175aadbe
commit 83761d881a
53 changed files with 384 additions and 422 deletions

View file

@ -21,6 +21,7 @@
<Configurations> <Configurations>
<Configuration <Configuration
Name="Debug|Win32" Name="Debug|Win32"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1" ConfigurationType="1"
InheritedPropertySheets=".\suffix_debug32.vsprops;.\wxlib_include.vsprops;.\wxlib_lib32.vsprops;.\libraries_outdirs.vsprops;.\contrib_includedirs.vsprops;.\aegisub_exe_filename.vsprops;.\ffms2_lib_include_dir.vsprops;.\compiler_options.vsprops;.\compiler_options_debug.vsprops;.\svn_rev_header_update.vsprops;.\delayload_portaudio_32.vsprops;.\delayload_openal_32.vsprops;.\libaegisub_include_dir.vsprops" InheritedPropertySheets=".\suffix_debug32.vsprops;.\wxlib_include.vsprops;.\wxlib_lib32.vsprops;.\libraries_outdirs.vsprops;.\contrib_includedirs.vsprops;.\aegisub_exe_filename.vsprops;.\ffms2_lib_include_dir.vsprops;.\compiler_options.vsprops;.\compiler_options_debug.vsprops;.\svn_rev_header_update.vsprops;.\delayload_portaudio_32.vsprops;.\delayload_openal_32.vsprops;.\libaegisub_include_dir.vsprops"
CharacterSet="1" CharacterSet="1"

View file

@ -6,7 +6,7 @@
> >
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalOptions="/Zm130" AdditionalOptions="/Zm150"
Optimization="3" Optimization="3"
EnableIntrinsicFunctions="true" EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2" FavorSizeOrSpeed="2"

View file

@ -71,9 +71,7 @@
#include <windows.h> #include <windows.h>
#include <objbase.h> #include <objbase.h>
#include <mmsystem.h> #include <mmsystem.h>
#else #else
#include <sys/fcntl.h> #include <sys/fcntl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -82,6 +80,9 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/algorithm_ext.hpp>
///////////////////// /////////////////////
// wxWidgets headers // wxWidgets headers
#include <wx/wxprec.h> // Leave this first. #include <wx/wxprec.h> // Leave this first.

View file

@ -32,13 +32,14 @@
/// @ingroup subs_storage /// @ingroup subs_storage
/// ///
#pragma once #pragma once
#ifndef AGI_PRE #ifndef AGI_PRE
#include <wx/string.h> #include <wx/string.h>
#endif #endif
#include <boost/intrusive/list_hook.hpp>
enum AssEntryType { enum AssEntryType {
ENTRY_BASE, ENTRY_BASE,
ENTRY_DIALOGUE, ENTRY_DIALOGUE,
@ -46,7 +47,7 @@ enum AssEntryType {
ENTRY_ATTACHMENT ENTRY_ATTACHMENT
}; };
class AssEntry { class AssEntry : public boost::intrusive::make_list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink> >::type {
/// Raw data, exactly the same line that appears on the .ass (note that this will be in ass even if source wasn't) /// Raw data, exactly the same line that appears on the .ass (note that this will be in ass even if source wasn't)
wxString data; wxString data;

View file

@ -39,7 +39,6 @@
#endif #endif
#include "ass_export_filter.h" #include "ass_export_filter.h"
#include "ass_file.h"
#include "utils.h" #include "utils.h"
AssExportFilter::AssExportFilter(wxString const& name, wxString const& description, int priority, bool auto_apply) AssExportFilter::AssExportFilter(wxString const& name, wxString const& description, int priority, bool auto_apply)

View file

@ -33,6 +33,8 @@
#include "config.h" #include "config.h"
#include "ass_file.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
@ -46,7 +48,6 @@
#include "ass_attachment.h" #include "ass_attachment.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_override.h" #include "ass_override.h"
#include "ass_style.h" #include "ass_style.h"
#include "compat.h" #include "compat.h"
@ -87,7 +88,7 @@ void AssFile::Load(const wxString &_filename, wxString const& charset) {
// Check if the file has at least one style and at least one dialogue line // Check if the file has at least one style and at least one dialogue line
for (entryIter it = temp.Line.begin(); it != temp.Line.end(); ++it) { for (entryIter it = temp.Line.begin(); it != temp.Line.end(); ++it) {
AssEntryType type = (*it)->GetType(); AssEntryType type = it->GetType();
if (type == ENTRY_STYLE) found_style = true; if (type == ENTRY_STYLE) found_style = true;
if (type == ENTRY_DIALOGUE) found_dialogue = true; if (type == ENTRY_DIALOGUE) found_dialogue = true;
if (found_style && found_dialogue) break; if (found_style && found_dialogue) break;
@ -180,7 +181,7 @@ void AssFile::SaveMemory(std::vector<char> &dst) {
// Write file // Write file
for (entryIter cur = Line.begin(); cur != Line.end(); ++cur) { for (entryIter cur = Line.begin(); cur != Line.end(); ++cur) {
wxCharBuffer buffer = ((*cur)->GetEntryData() + "\r\n").utf8_str(); wxCharBuffer buffer = (cur->GetEntryData() + "\r\n").utf8_str();
copy(buffer.data(), buffer.data() + buffer.length(), back_inserter(dst)); copy(buffer.data(), buffer.data() + buffer.length(), back_inserter(dst));
} }
} }
@ -208,25 +209,25 @@ void AssFile::LoadDefault(bool defline) {
Clear(); Clear();
// Write headers // Write headers
Line.push_back(new AssEntry("[Script Info]", "[Script Info]")); Line.push_back(*new AssEntry("[Script Info]", "[Script Info]"));
Line.push_back(new AssEntry("Title: Default Aegisub file", "[Script Info]")); Line.push_back(*new AssEntry("Title: Default Aegisub file", "[Script Info]"));
Line.push_back(new AssEntry("ScriptType: v4.00+", "[Script Info]")); Line.push_back(*new AssEntry("ScriptType: v4.00+", "[Script Info]"));
Line.push_back(new AssEntry("WrapStyle: 0", "[Script Info]")); Line.push_back(*new AssEntry("WrapStyle: 0", "[Script Info]"));
Line.push_back(new AssEntry("ScaledBorderAndShadow: yes", "[Script Info]")); Line.push_back(*new AssEntry("ScaledBorderAndShadow: yes", "[Script Info]"));
Line.push_back(new AssEntry("Collisions: Normal", "[Script Info]")); Line.push_back(*new AssEntry("Collisions: Normal", "[Script Info]"));
if (!OPT_GET("Subtitle/Default Resolution/Auto")->GetBool()) { if (!OPT_GET("Subtitle/Default Resolution/Auto")->GetBool()) {
Line.push_back(new AssEntry(wxString::Format("PlayResX: %" PRId64, OPT_GET("Subtitle/Default Resolution/Width")->GetInt()), "[Script Info]")); Line.push_back(*new AssEntry(wxString::Format("PlayResX: %" PRId64, OPT_GET("Subtitle/Default Resolution/Width")->GetInt()), "[Script Info]"));
Line.push_back(new AssEntry(wxString::Format("PlayResY: %" PRId64, OPT_GET("Subtitle/Default Resolution/Height")->GetInt()), "[Script Info]")); Line.push_back(*new AssEntry(wxString::Format("PlayResY: %" PRId64, OPT_GET("Subtitle/Default Resolution/Height")->GetInt()), "[Script Info]"));
} }
Line.push_back(new AssEntry("YCbCr Matrix: None", "[Script Info]")); Line.push_back(*new AssEntry("YCbCr Matrix: None", "[Script Info]"));
InsertStyle(new AssStyle); InsertStyle(new AssStyle);
Line.push_back(new AssEntry("[Events]", "[Events]")); Line.push_back(*new AssEntry("[Events]", "[Events]"));
Line.push_back(new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]")); Line.push_back(*new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
if (defline) if (defline)
Line.push_back(new AssDialogue); Line.push_back(*new AssDialogue);
autosavedCommitId = savedCommitId = commitId + 1; autosavedCommitId = savedCommitId = commitId + 1;
Commit("", COMMIT_NEW); Commit("", COMMIT_NEW);
@ -237,10 +238,11 @@ void AssFile::LoadDefault(bool defline) {
void AssFile::swap(AssFile &that) throw() { void AssFile::swap(AssFile &that) throw() {
// Intentionally does not swap undo stack related things // Intentionally does not swap undo stack related things
std::swap(loaded, that.loaded); using std::swap;
std::swap(commitId, that.commitId); swap(loaded, that.loaded);
std::swap(undoDescription, that.undoDescription); swap(commitId, that.commitId);
std::swap(Line, that.Line); swap(undoDescription, that.undoDescription);
swap(Line, that.Line);
} }
AssFile::AssFile(const AssFile &from) AssFile::AssFile(const AssFile &from)
@ -249,22 +251,22 @@ AssFile::AssFile(const AssFile &from)
, filename(from.filename) , filename(from.filename)
, loaded(from.loaded) , loaded(from.loaded)
{ {
std::transform(from.Line.begin(), from.Line.end(), std::back_inserter(Line), std::mem_fun(&AssEntry::Clone)); Line.clone_from(from.Line, std::mem_fun_ref(&AssEntry::Clone), delete_ptr());
} }
AssFile& AssFile::operator=(AssFile from) { AssFile& AssFile::operator=(AssFile from) {
std::swap(*this, from); std::swap(*this, from);
return *this; return *this;
} }
static bool try_insert(std::list<AssEntry*> &lines, AssEntry *entry) { static bool try_insert(EntryList &lines, AssEntry *entry) {
if (lines.empty()) return false; if (lines.empty()) return false;
// Search for insertion point // Search for insertion point
std::list<AssEntry*>::iterator it = lines.end(); entryIter it = lines.end();
do { do {
--it; --it;
if ((*it)->group == entry->group) { if (it->group == entry->group) {
lines.insert(++it, entry); lines.insert(++it, *entry);
return true; return true;
} }
} while (it != lines.begin()); } while (it != lines.begin());
@ -276,17 +278,17 @@ void AssFile::InsertStyle(AssStyle *style) {
if (try_insert(Line, style)) return; if (try_insert(Line, style)) return;
// No styles found, add them // No styles found, add them
Line.push_back(new AssEntry("[V4+ Styles]", "[V4+ Styles]")); Line.push_back(*new AssEntry("[V4+ Styles]", "[V4+ Styles]"));
Line.push_back(new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]")); Line.push_back(*new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]"));
Line.push_back(style); Line.push_back(*style);
} }
void AssFile::InsertAttachment(AssAttachment *attach) { void AssFile::InsertAttachment(AssAttachment *attach) {
if (try_insert(Line, attach)) return; if (try_insert(Line, attach)) return;
// Didn't find a group of the appropriate type so create it // Didn't find a group of the appropriate type so create it
Line.push_back(new AssEntry(attach->group, attach->group)); Line.push_back(*new AssEntry(attach->group, attach->group));
Line.push_back(attach); Line.push_back(*attach);
} }
void AssFile::InsertAttachment(wxString filename) { void AssFile::InsertAttachment(wxString filename) {
@ -306,9 +308,9 @@ void AssFile::InsertDialogue(AssDialogue *diag) {
if (try_insert(Line, diag)) return; if (try_insert(Line, diag)) return;
// Didn't find a group of the appropriate type so create it // Didn't find a group of the appropriate type so create it
Line.push_back(new AssEntry("[Events]", "[Events]")); Line.push_back(*new AssEntry("[Events]", "[Events]"));
Line.push_back(new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]")); Line.push_back(*new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
Line.push_back(diag); Line.push_back(*diag);
} }
wxString AssFile::GetScriptInfo(wxString key) const { wxString AssFile::GetScriptInfo(wxString key) const {
@ -316,10 +318,10 @@ wxString AssFile::GetScriptInfo(wxString key) const {
key += ":"; key += ":";
bool GotIn = false; bool GotIn = false;
for (std::list<AssEntry*>::const_iterator cur = Line.begin(); cur != Line.end(); ++cur) { for (constEntryIter cur = Line.begin(); cur != Line.end(); ++cur) {
if ((*cur)->group == "[Script Info]") { if (cur->group == "[Script Info]") {
GotIn = true; GotIn = true;
wxString curText = (*cur)->GetEntryData(); wxString curText = cur->GetEntryData();
if (curText.Lower().StartsWith(key)) if (curText.Lower().StartsWith(key))
return curText.Mid(key.size()).Trim(true).Trim(false); return curText.Mid(key.size()).Trim(true).Trim(false);
} }
@ -338,21 +340,21 @@ int AssFile::GetScriptInfoAsInt(wxString const& key) const {
void AssFile::SetScriptInfo(wxString const& key, wxString const& value) { void AssFile::SetScriptInfo(wxString const& key, wxString const& value) {
wxString search_key = key.Lower() + ":"; wxString search_key = key.Lower() + ":";
size_t key_size = search_key.size(); size_t key_size = search_key.size();
std::list<AssEntry*>::iterator script_info_end; entryIter script_info_end;
bool found_script_info = false; bool found_script_info = false;
for (std::list<AssEntry*>::iterator cur = Line.begin(); cur != Line.end(); ++cur) { for (entryIter cur = Line.begin(); cur != Line.end(); ++cur) {
if ((*cur)->group == "[Script Info]") { if (cur->group == "[Script Info]") {
found_script_info = true; found_script_info = true;
wxString cur_text = (*cur)->GetEntryData().Left(key_size).Lower(); wxString cur_text = cur->GetEntryData().Left(key_size).Lower();
if (cur_text == search_key) { if (cur_text == search_key) {
if (value.empty()) { if (value.empty()) {
delete *cur; delete &*cur;
Line.erase(cur); Line.erase(cur);
} }
else { else {
(*cur)->SetEntryData(key + ": " + value); cur->SetEntryData(key + ": " + value);
} }
return; return;
} }
@ -360,7 +362,7 @@ void AssFile::SetScriptInfo(wxString const& key, wxString const& value) {
} }
else if (found_script_info) { else if (found_script_info) {
if (value.size()) if (value.size())
Line.insert(script_info_end, new AssEntry(key + ": " + value, "[Script Info]")); Line.insert(script_info_end, *new AssEntry(key + ": " + value, "[Script Info]"));
return; return;
} }
} }
@ -368,11 +370,11 @@ void AssFile::SetScriptInfo(wxString const& key, wxString const& value) {
// Found a script info section, but not this key or anything after it, // Found a script info section, but not this key or anything after it,
// so add it at the end of the file // so add it at the end of the file
if (found_script_info) if (found_script_info)
Line.push_back(new AssEntry(key + ": " + value, "[Script Info]")); Line.push_back(*new AssEntry(key + ": " + value, "[Script Info]"));
// Script info section not found, so add it at the beginning of the file // Script info section not found, so add it at the beginning of the file
else { else {
Line.push_front(new AssEntry(key + ": " + value, "[Script Info]")); Line.push_front(*new AssEntry(key + ": " + value, "[Script Info]"));
Line.push_front(new AssEntry("[Script Info]", "[Script Info]")); Line.push_front(*new AssEntry("[Script Info]", "[Script Info]"));
} }
} }
@ -400,8 +402,8 @@ void AssFile::GetResolution(int &sw,int &sh) const {
wxArrayString AssFile::GetStyles() const { wxArrayString AssFile::GetStyles() const {
wxArrayString styles; wxArrayString styles;
for (std::list<AssEntry*>::const_iterator cur = Line.begin(); cur != Line.end(); ++cur) { for (constEntryIter cur = Line.begin(); cur != Line.end(); ++cur) {
if (AssStyle *curstyle = dynamic_cast<AssStyle*>(*cur)) if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(&*cur))
styles.Add(curstyle->name); styles.Add(curstyle->name);
} }
return styles; return styles;
@ -409,7 +411,7 @@ wxArrayString AssFile::GetStyles() const {
AssStyle *AssFile::GetStyle(wxString const& name) { AssStyle *AssFile::GetStyle(wxString const& name) {
for (entryIter cur = Line.begin(); cur != Line.end(); ++cur) { for (entryIter cur = Line.begin(); cur != Line.end(); ++cur) {
AssStyle *curstyle = dynamic_cast<AssStyle*>(*cur); AssStyle *curstyle = dynamic_cast<AssStyle*>(&*cur);
if (curstyle && curstyle->name == name) if (curstyle && curstyle->name == name)
return curstyle; return curstyle;
} }
@ -430,12 +432,12 @@ int AssFile::Commit(wxString const& desc, int type, int amendId, AssEntry *singl
// If only one line changed just modify it instead of copying the file // If only one line changed just modify it instead of copying the file
if (single_line) { if (single_line) {
entryIter this_it = Line.begin(), undo_it = UndoStack.back().Line.begin(); entryIter this_it = Line.begin(), undo_it = UndoStack.back().Line.begin();
while (*this_it != single_line) { while (&*this_it != single_line) {
++this_it; ++this_it;
++undo_it; ++undo_it;
} }
delete *undo_it; UndoStack.back().Line.insert(undo_it, *single_line->Clone());
*undo_it = single_line->Clone(); delete &*undo_it;
} }
else { else {
UndoStack.back() = *this; UndoStack.back() = *this;
@ -467,7 +469,7 @@ void AssFile::Undo() {
if (UndoStack.size() <= 1) return; if (UndoStack.size() <= 1) return;
RedoStack.push_back(AssFile()); RedoStack.push_back(AssFile());
std::swap(RedoStack.back(), *this); swap(RedoStack.back());
UndoStack.pop_back(); UndoStack.pop_back();
*this = UndoStack.back(); *this = UndoStack.back();
@ -477,7 +479,7 @@ void AssFile::Undo() {
void AssFile::Redo() { void AssFile::Redo() {
if (RedoStack.empty()) return; if (RedoStack.empty()) return;
std::swap(*this, RedoStack.back()); swap(RedoStack.back());
UndoStack.push_back(*this); UndoStack.push_back(*this);
RedoStack.pop_back(); RedoStack.pop_back();
@ -515,10 +517,10 @@ void AssFile::Sort(CompFunc comp, std::set<AssDialogue*> const& limit) {
Sort(Line, comp, limit); Sort(Line, comp, limit);
} }
namespace { namespace {
struct AssEntryComp : public std::binary_function<const AssEntry*, const AssEntry*, bool> { struct AssEntryComp : public std::binary_function<AssEntry, AssEntry, bool> {
AssFile::CompFunc comp; AssFile::CompFunc comp;
bool operator()(const AssEntry* a, const AssEntry* b) const { bool operator()(AssEntry const&a, AssEntry const&b) const {
return comp(static_cast<const AssDialogue*>(a), static_cast<const AssDialogue*>(b)); return comp(static_cast<const AssDialogue*>(&a), static_cast<const AssDialogue*>(&b));
} }
}; };
@ -527,17 +529,18 @@ namespace {
return d && (limit.empty() || limit.count(d)); return d && (limit.empty() || limit.count(d));
} }
} }
void AssFile::Sort(std::list<AssEntry*> &lst, CompFunc comp, std::set<AssDialogue*> const& limit) {
void AssFile::Sort(EntryList &lst, CompFunc comp, std::set<AssDialogue*> const& limit) {
AssEntryComp compE; AssEntryComp compE;
compE.comp = comp; compE.comp = comp;
// Sort each block of AssDialogues separately, leaving everything else untouched // Sort each block of AssDialogues separately, leaving everything else untouched
for (entryIter begin = lst.begin(); begin != lst.end(); ++begin) { for (entryIter begin = lst.begin(); begin != lst.end(); ++begin) {
if (!is_dialogue(*begin, limit)) continue; if (!is_dialogue(&*begin, limit)) continue;
entryIter end = begin; entryIter end = begin;
while (end != lst.end() && is_dialogue(*end, limit)) ++end; while (end != lst.end() && is_dialogue(&*end, limit)) ++end;
// used instead of std::list::sort for partial list sorting // used instead of std::list::sort for partial list sorting
std::list<AssEntry*> tmp; EntryList tmp;
tmp.splice(tmp.begin(), lst, begin, end); tmp.splice(tmp.begin(), lst, begin, end);
tmp.sort(compE); tmp.sort(compE);
lst.splice(end, tmp); lst.splice(end, tmp);
@ -545,8 +548,5 @@ void AssFile::Sort(std::list<AssEntry*> &lst, CompFunc comp, std::set<AssDialogu
begin = --end; begin = --end;
} }
} }
void AssFile::Sort(std::list<AssDialogue*> &lst, CompFunc comp) {
lst.sort(comp);
}
AssFile *AssFile::top; AssFile *AssFile::top;

View file

@ -41,14 +41,19 @@
#include <wx/arrstr.h> #include <wx/arrstr.h>
#endif #endif
#include <boost/intrusive/list.hpp>
#include <libaegisub/signal.h> #include <libaegisub/signal.h>
#include "ass_entry.h"
class AssDialogue; class AssDialogue;
class AssStyle; class AssStyle;
class AssAttachment; class AssAttachment;
class AssEntry;
typedef std::list<AssEntry*>::iterator entryIter; typedef boost::intrusive::make_list<AssEntry, boost::intrusive::constant_time_size<false> >::type EntryList;
typedef EntryList::iterator entryIter;
typedef EntryList::const_iterator constEntryIter;
/// DOCME /// DOCME
/// @class AssFile /// @class AssFile
@ -78,7 +83,7 @@ class AssFile {
public: public:
/// The lines in the file /// The lines in the file
std::list<AssEntry*> Line; EntryList Line;
/// The filename of this file, if any /// The filename of this file, if any
wxString filename; wxString filename;
/// Is the file loaded? /// Is the file loaded?
@ -229,8 +234,5 @@ public:
/// @brief Sort the dialogue lines in the given list /// @brief Sort the dialogue lines in the given list
/// @param comp Comparison function to use. Defaults to sorting by start time. /// @param comp Comparison function to use. Defaults to sorting by start time.
/// @param limit If non-empty, only lines in this set are sorted /// @param limit If non-empty, only lines in this set are sorted
static void Sort(std::list<AssEntry*>& lst, CompFunc comp = CompStart, std::set<AssDialogue*> const& limit = std::set<AssDialogue*>()); static void Sort(EntryList& lst, CompFunc comp = CompStart, std::set<AssDialogue*> const& limit = std::set<AssDialogue*>());
/// @brief Sort the dialogue lines in the given list
/// @param comp Comparison function to use. Defaults to sorting by start time.
static void Sort(std::list<AssDialogue*>& lst, CompFunc comp = CompStart);
}; };

View file

@ -291,8 +291,8 @@ void AssKaraoke::SplitLines(std::set<AssDialogue*> const& lines, agi::Context *c
SubtitleSelection sel = c->selectionController->GetSelectedSet(); SubtitleSelection sel = c->selectionController->GetSelectedSet();
bool did_split = false; bool did_split = false;
for (std::list<AssEntry*>::iterator it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag || !lines.count(diag)) continue; if (!diag || !lines.count(diag)) continue;
kara.SetLine(diag); kara.SetLine(diag);
@ -311,7 +311,7 @@ void AssKaraoke::SplitLines(std::set<AssDialogue*> const& lines, agi::Context *c
new_line->End = kit->start_time + kit->duration; new_line->End = kit->start_time + kit->duration;
new_line->Text = kit->GetText(false); new_line->Text = kit->GetText(false);
c->ass->Line.insert(it, new_line); c->ass->Line.insert(it, *new_line);
if (in_sel) if (in_sel)
sel.insert(new_line); sel.insert(new_line);

View file

@ -51,7 +51,7 @@ void AssParser::ParseAttachmentLine(wxString const& data) {
// Data is over, add attachment to the file // Data is over, add attachment to the file
if (!valid_data || is_filename) { if (!valid_data || is_filename) {
attach->Finish(); attach->Finish();
target->Line.push_back(attach.release()); target->Line.push_back(*attach.release());
AddLine(data); AddLine(data);
} }
else { else {
@ -60,7 +60,7 @@ void AssParser::ParseAttachmentLine(wxString const& data) {
// Done building // Done building
if (data.Length() < 80) { if (data.Length() < 80) {
attach->Finish(); attach->Finish();
target->Line.push_back(attach.release()); target->Line.push_back(*attach.release());
} }
} }
} }
@ -68,7 +68,7 @@ void AssParser::ParseAttachmentLine(wxString const& data) {
void AssParser::ParseScriptInfoLine(wxString const& data) { void AssParser::ParseScriptInfoLine(wxString const& data) {
// If the first nonblank line isn't a header pretend it starts with [Script Info] // If the first nonblank line isn't a header pretend it starts with [Script Info]
if (target->Line.empty()) if (target->Line.empty())
target->Line.push_back(new AssEntry("[Script Info]", "[Script Info]")); target->Line.push_back(*new AssEntry("[Script Info]", "[Script Info]"));
if (data.StartsWith(";")) { if (data.StartsWith(";")) {
// Skip stupid comments added by other programs // Skip stupid comments added by other programs
@ -91,21 +91,21 @@ void AssParser::ParseScriptInfoLine(wxString const& data) {
} }
} }
target->Line.push_back(new AssEntry(data, "[Script Info]")); target->Line.push_back(*new AssEntry(data, "[Script Info]"));
} }
void AssParser::ParseEventLine(wxString const& data) { void AssParser::ParseEventLine(wxString const& data) {
if (data.StartsWith("Dialogue:") || data.StartsWith("Comment:")) if (data.StartsWith("Dialogue:") || data.StartsWith("Comment:"))
target->Line.push_back(new AssDialogue(data)); target->Line.push_back(*new AssDialogue(data));
else if (data.StartsWith("Format:")) else if (data.StartsWith("Format:"))
target->Line.push_back(new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]")); target->Line.push_back(*new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
} }
void AssParser::ParseStyleLine(wxString const& data) { void AssParser::ParseStyleLine(wxString const& data) {
if (data.StartsWith("Style:")) if (data.StartsWith("Style:"))
target->Line.push_back(new AssStyle(data, version)); target->Line.push_back(*new AssStyle(data, version));
else if (data.StartsWith("Format:")) else if (data.StartsWith("Format:"))
target->Line.push_back(new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]")); target->Line.push_back(*new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]"));
} }
void AssParser::ParseFontLine(wxString const& data) { void AssParser::ParseFontLine(wxString const& data) {
@ -121,7 +121,7 @@ void AssParser::ParseGraphicsLine(wxString const& data) {
} }
void AssParser::AppendUnknownLine(wxString const& data) { void AssParser::AppendUnknownLine(wxString const& data) {
target->Line.push_back(new AssEntry(data, target->Line.back()->group)); target->Line.push_back(*new AssEntry(data, target->Line.back().group));
} }
void AssParser::AddLine(wxString const& data) { void AssParser::AddLine(wxString const& data) {
@ -166,7 +166,7 @@ void AssParser::AddLine(wxString const& data) {
state = &AssParser::AppendUnknownLine; state = &AssParser::AppendUnknownLine;
} }
target->Line.push_back(new AssEntry(header, header)); target->Line.push_back(*new AssEntry(header, header));
return; return;
} }

View file

@ -720,21 +720,21 @@ void AudioTimingControllerDialogue::SetMarkers(std::vector<AudioMarker*> const&
AnnounceMarkerMoved(); AnnounceMarkerMoved();
} }
static bool noncomment_dialogue(AssEntry *e) static bool noncomment_dialogue(AssEntry const& e)
{ {
if (AssDialogue *diag = dynamic_cast<AssDialogue*>(e)) if (const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&e))
return !diag->Comment; return !diag->Comment;
return false; return false;
} }
static bool dialogue(AssEntry *e) static bool dialogue(AssEntry const& e)
{ {
return !!dynamic_cast<AssDialogue*>(e); return !!dynamic_cast<const AssDialogue*>(&e);
} }
void AudioTimingControllerDialogue::RegenerateInactiveLines() void AudioTimingControllerDialogue::RegenerateInactiveLines()
{ {
bool (*predicate)(AssEntry*) = inactive_line_comments->GetBool() ? dialogue : noncomment_dialogue; bool (*predicate)(AssEntry const&) = inactive_line_comments->GetBool() ? dialogue : noncomment_dialogue;
bool was_empty = inactive_lines.empty(); bool was_empty = inactive_lines.empty();
inactive_lines.clear(); inactive_lines.clear();
@ -747,32 +747,31 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
case 2: // Previous and next lines case 2: // Previous and next lines
if (AssDialogue *line = context->selectionController->GetActiveLine()) if (AssDialogue *line = context->selectionController->GetActiveLine())
{ {
std::list<AssEntry*>::iterator current_line = entryIter current_line = context->ass->Line.iterator_to(*line);
find(context->ass->Line.begin(), context->ass->Line.end(), line);
if (current_line == context->ass->Line.end()) if (current_line == context->ass->Line.end())
break; break;
std::list<AssEntry*>::iterator prev = current_line; entryIter prev = current_line;
while (--prev != context->ass->Line.begin() && !predicate(*prev)) ; while (--prev != context->ass->Line.begin() && !predicate(*prev)) ;
if (prev != context->ass->Line.begin()) if (prev != context->ass->Line.begin())
AddInactiveLine(sel, static_cast<AssDialogue*>(*prev)); AddInactiveLine(sel, static_cast<AssDialogue*>(&*prev));
if (mode == 2) if (mode == 2)
{ {
std::list<AssEntry*>::iterator next = entryIter next =
find_if(++current_line, context->ass->Line.end(), predicate); find_if(++current_line, context->ass->Line.end(), predicate);
if (next != context->ass->Line.end()) if (next != context->ass->Line.end())
AddInactiveLine(sel, static_cast<AssDialogue*>(*next)); AddInactiveLine(sel, static_cast<AssDialogue*>(&*next));
} }
} }
break; break;
case 3: // All inactive lines case 3: // All inactive lines
{ {
AssDialogue *active_line = context->selectionController->GetActiveLine(); AssDialogue *active_line = context->selectionController->GetActiveLine();
for (std::list<AssEntry*>::const_iterator it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it) for (entryIter it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it)
{ {
if (*it != active_line && predicate(*it)) if (&*it != active_line && predicate(*it))
AddInactiveLine(sel, static_cast<AssDialogue*>(*it)); AddInactiveLine(sel, static_cast<AssDialogue*>(&*it));
} }
break; break;
} }

View file

@ -843,7 +843,7 @@ namespace Automation4 {
int row = 1; int row = 1;
int idx = 1; int idx = 1;
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it, ++row) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it, ++row) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
if (diag == active_line) active_idx = row; if (diag == active_line) active_idx = row;
@ -935,7 +935,7 @@ namespace Automation4 {
advance(it, cur - last_idx); advance(it, cur - last_idx);
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) { if (!diag) {
wxLogError("Selected row %d is not a dialogue line", cur); wxLogError("Selected row %d is not a dialogue line", cur);
break; break;

View file

@ -40,6 +40,8 @@
#include <assert.h> #include <assert.h>
#include <algorithm> #include <algorithm>
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/algorithm_ext.hpp>
#include <wx/log.h> #include <wx/log.h>
#endif #endif
@ -660,14 +662,14 @@ namespace Automation4 {
// Apply any pending commits // Apply any pending commits
for (std::deque<PendingCommit>::iterator it = pending_commits.begin(); it != pending_commits.end(); ++it) { for (std::deque<PendingCommit>::iterator it = pending_commits.begin(); it != pending_commits.end(); ++it) {
ass->Line.clear(); ass->Line.clear();
ass->Line.insert(ass->Line.end(), it->lines.begin(), it->lines.end()); boost::push_back(ass->Line, it->lines | boost::adaptors::indirected);
ass->Commit(it->mesage, it->modification_type); ass->Commit(it->mesage, it->modification_type);
} }
// Commit any changes after the last undo point was set // Commit any changes after the last undo point was set
if (modification_type) { if (modification_type) {
ass->Line.clear(); ass->Line.clear();
ass->Line.insert(ass->Line.end(), lines.begin(), lines.end()); boost::push_back(ass->Line, lines | boost::adaptors::indirected);
} }
if (modification_type && can_set_undo && !undo_description.empty()) if (modification_type && can_set_undo && !undo_description.empty())
ass->Commit(undo_description, modification_type); ass->Commit(undo_description, modification_type);
@ -691,8 +693,10 @@ namespace Automation4 {
, can_set_undo(can_set_undo) , can_set_undo(can_set_undo)
, modification_type(0) , modification_type(0)
, references(2) , references(2)
, lines(ass->Line.begin(), ass->Line.end())
{ {
for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ++it)
lines.push_back(&*it);
// prepare userdata object // prepare userdata object
*static_cast<LuaAssFile**>(lua_newuserdata(L, sizeof(LuaAssFile*))) = this; *static_cast<LuaAssFile**>(lua_newuserdata(L, sizeof(LuaAssFile*))) = this;

View file

@ -279,7 +279,7 @@ void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
line_index_map.clear(); line_index_map.clear();
for (entryIter cur = context->ass->Line.begin(); cur != context->ass->Line.end(); ++cur) { for (entryIter cur = context->ass->Line.begin(); cur != context->ass->Line.end(); ++cur) {
if (AssDialogue *curdiag = dynamic_cast<AssDialogue*>(*cur)) { if (AssDialogue *curdiag = dynamic_cast<AssDialogue*>(&*cur)) {
line_index_map[curdiag] = (int)index_line_map.size(); line_index_map[curdiag] = (int)index_line_map.size();
index_line_map.push_back(curdiag); index_line_map.push_back(curdiag);
} }

View file

@ -86,7 +86,7 @@ void paste_lines(agi::Context *c, bool paste_over) {
if (!data) return; if (!data) return;
AssDialogue *rel_line = c->selectionController->GetActiveLine(); AssDialogue *rel_line = c->selectionController->GetActiveLine();
entryIter pos = find(c->ass->Line.begin(), c->ass->Line.end(), rel_line); entryIter pos = c->ass->Line.iterator_to(*rel_line);
AssDialogue *first = 0; AssDialogue *first = 0;
SubtitleSelection newsel; SubtitleSelection newsel;
@ -118,7 +118,7 @@ void paste_lines(agi::Context *c, bool paste_over) {
if (!paste_over) { if (!paste_over) {
newsel.insert(curdiag); newsel.insert(curdiag);
c->ass->Line.insert(pos, curdiag); c->ass->Line.insert(pos, *curdiag);
} }
else { else {
// Get list of options to paste over, if not asked yet // Get list of options to paste over, if not asked yet
@ -131,7 +131,7 @@ void paste_lines(agi::Context *c, bool paste_over) {
pasteOverOptions = OPT_GET("Tool/Paste Lines Over/Fields")->GetListBool(); pasteOverOptions = OPT_GET("Tool/Paste Lines Over/Fields")->GetListBool();
} }
AssDialogue *line = static_cast<AssDialogue *>(*pos); AssDialogue *line = static_cast<AssDialogue *>(&*pos);
if (pasteOverOptions[0]) line->Layer = curdiag->Layer; if (pasteOverOptions[0]) line->Layer = curdiag->Layer;
if (pasteOverOptions[1]) line->Start = curdiag->Start; if (pasteOverOptions[1]) line->Start = curdiag->Start;
if (pasteOverOptions[2]) line->End = curdiag->End; if (pasteOverOptions[2]) line->End = curdiag->End;
@ -147,7 +147,7 @@ void paste_lines(agi::Context *c, bool paste_over) {
do { do {
++pos; ++pos;
} while (pos != c->ass->Line.end() && !dynamic_cast<AssDialogue*>(*pos)); } while (pos != c->ass->Line.end() && !dynamic_cast<AssDialogue*>(&*pos));
if (pos == c->ass->Line.end()) if (pos == c->ass->Line.end())
break; break;
} }
@ -488,7 +488,7 @@ static void copy_lines(agi::Context *c) {
wxString data; wxString data;
SubtitleSelection sel = c->selectionController->GetSelectedSet(); SubtitleSelection sel = c->selectionController->GetSelectedSet();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (diag && sel.count(diag)) { if (diag && sel.count(diag)) {
if (!data.empty()) if (!data.empty())
data += "\r\n"; data += "\r\n";
@ -508,7 +508,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
bool hit_active = false; bool hit_active = false;
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
if (diag == active) { if (diag == active) {
@ -524,10 +524,8 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
// Delete selected lines // Delete selected lines
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ) {
if (sel.count(static_cast<AssDialogue*>(*it))) { if (sel.count(static_cast<AssDialogue*>(&*it)))
delete *it; delete &*it++;
c->ass->Line.erase(it++);
}
else else
++it; ++it;
} }
@ -598,12 +596,12 @@ struct edit_line_delete : public validate_sel_nonempty {
} }
}; };
struct in_selection : public std::unary_function<AssEntry*, bool> { struct in_selection : public std::unary_function<AssEntry, bool> {
SubtitleSelectionController::Selection const& sel; SubtitleSelectionController::Selection const& sel;
in_selection(SubtitleSelectionController::Selection const& sel) : sel(sel) { } in_selection(SubtitleSelectionController::Selection const& sel) : sel(sel) { }
bool operator()(AssEntry *e) const { bool operator()(AssEntry const& e) const {
AssDialogue *d = dynamic_cast<AssDialogue*>(e); const AssDialogue *d = dynamic_cast<const AssDialogue*>(&e);
return d && sel.count(d); return d && sel.count(const_cast<AssDialogue *>(d));
} }
}; };
@ -612,24 +610,24 @@ static void duplicate_lines(agi::Context *c, bool shift) {
SubtitleSelectionController::Selection new_sel; SubtitleSelectionController::Selection new_sel;
AssDialogue *new_active = 0; AssDialogue *new_active = 0;
std::list<AssEntry*>::iterator start = c->ass->Line.begin(); entryIter start = c->ass->Line.begin();
std::list<AssEntry*>::iterator end = c->ass->Line.end(); entryIter end = c->ass->Line.end();
while (start != end) { while (start != end) {
// Find the first line in the selection // Find the first line in the selection
start = find_if(start, end, sel); start = find_if(start, end, sel);
if (start == end) break; if (start == end) break;
// And the last line in this contiguous selection // And the last line in this contiguous selection
std::list<AssEntry*>::iterator insert_pos = find_if(start, end, std::not1(sel)); entryIter insert_pos = find_if(start, end, std::not1(sel));
std::list<AssEntry*>::iterator last = insert_pos; entryIter last = insert_pos;
--last; --last;
// Duplicate each of the selected lines, inserting them in a block // Duplicate each of the selected lines, inserting them in a block
// after the selected block // after the selected block
do { do {
AssDialogue *new_diag = static_cast<AssDialogue*>((*start)->Clone()); AssDialogue *new_diag = static_cast<AssDialogue*>(start->Clone());
c->ass->Line.insert(insert_pos, new_diag); c->ass->Line.insert(insert_pos, *new_diag);
new_sel.insert(new_diag); new_sel.insert(new_diag);
if (!new_active) if (!new_active)
new_active = new_diag; new_active = new_diag;
@ -686,26 +684,20 @@ static void combine_lines(agi::Context *c, void (*combiner)(AssDialogue *, AssDi
SubtitleSelection sel = c->selectionController->GetSelectedSet(); SubtitleSelection sel = c->selectionController->GetSelectedSet();
AssDialogue *first = 0; AssDialogue *first = 0;
entryIter out = c->ass->Line.begin(); for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ) {
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it++);
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); if (!diag || !sel.count(diag))
if (!diag || !sel.count(diag)) {
*out++ = *it;
continue; continue;
}
if (!first) { if (!first) {
first = diag; first = diag;
*out++ = *it;
continue; continue;
} }
combiner(first, diag); combiner(first, diag);
first->End = std::max(first->End, diag->End); first->End = std::max(first->End, diag->End);
delete diag; delete diag;
} }
c->ass->Line.erase(out, c->ass->Line.end());
sel.clear(); sel.clear();
sel.insert(first); sel.insert(first);
c->selectionController->SetSelectionAndActive(sel, first); c->selectionController->SetSelectionAndActive(sel, first);

View file

@ -85,8 +85,8 @@ struct grid_line_next_create : public Command {
newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt(); newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt();
newline->Style = cur->Style; newline->Style = cur->Style;
entryIter pos = find(c->ass->Line.begin(), c->ass->Line.end(), cur); entryIter pos = c->ass->Line.iterator_to(*cur);
c->ass->Line.insert(++pos, newline); c->ass->Line.insert(++pos, *newline);
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM); c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
c->selectionController->NextLine(); c->selectionController->NextLine();
} }
@ -353,13 +353,12 @@ static bool move_one(T begin, T end, U const& value) {
size_t move_count = 0; size_t move_count = 0;
T prev = end; T prev = end;
for (; begin != end; ++begin) { for (; begin != end; ++begin) {
typename U::key_type cur = dynamic_cast<typename U::key_type>(*begin); typename U::key_type cur = dynamic_cast<typename U::key_type>(&*begin);
bool in_set = !!value.count(cur); bool in_set = !!value.count(cur);
if (!in_set && cur) if (!in_set && cur)
prev = begin; prev = begin;
else if (in_set && prev != end) { else if (in_set && prev != end) {
using std::swap; begin->swap_nodes(*prev);
swap(*begin, *prev);
prev = begin; prev = begin;
if (++move_count == value.size()) if (++move_count == value.size())
break; break;
@ -420,11 +419,7 @@ struct grid_swap : public Command {
void operator()(agi::Context *c) { void operator()(agi::Context *c) {
SubtitleSelection sel = c->selectionController->GetSelectedSet(); SubtitleSelection sel = c->selectionController->GetSelectedSet();
if (sel.size() == 2) { if (sel.size() == 2) {
entryIter a = find(c->ass->Line.begin(), c->ass->Line.end(), *sel.begin()); (*sel.begin())->swap_nodes(**sel.rbegin());
entryIter b = find(c->ass->Line.begin(), c->ass->Line.end(), *sel.rbegin());
using std::swap;
swap(*a, *b);
c->ass->Commit(_("swap lines"), AssFile::COMMIT_ORDER); c->ass->Commit(_("swap lines"), AssFile::COMMIT_ORDER);
} }
} }

View file

@ -129,10 +129,10 @@ static void insert_subtitle_at_video(agi::Context *c, bool after) {
def->End = video_ms + OPT_GET("Timing/Default Duration")->GetInt(); def->End = video_ms + OPT_GET("Timing/Default Duration")->GetInt();
def->Style = c->selectionController->GetActiveLine()->Style; def->Style = c->selectionController->GetActiveLine()->Style;
entryIter pos = find(c->ass->Line.begin(), c->ass->Line.end(), c->selectionController->GetActiveLine()); entryIter pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
if (after) ++pos; if (after) ++pos;
c->ass->Line.insert(pos, def); c->ass->Line.insert(pos, *def);
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM); c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
SubtitleSelection sel; SubtitleSelection sel;
@ -156,7 +156,7 @@ struct subtitle_insert_after : public validate_nonempty_selection {
new_line->End = new_line->Start + OPT_GET("Timing/Default Duration")->GetInt(); new_line->End = new_line->Start + OPT_GET("Timing/Default Duration")->GetInt();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
// Limit the line to the available time // Limit the line to the available time
if (diag && diag->Start >= new_line->Start) if (diag && diag->Start >= new_line->Start)
@ -165,7 +165,7 @@ struct subtitle_insert_after : public validate_nonempty_selection {
// If we just hit the active line, insert the new line after it // If we just hit the active line, insert the new line after it
if (diag == active_line) { if (diag == active_line) {
++it; ++it;
c->ass->Line.insert(it, new_line); c->ass->Line.insert(it, *new_line);
--it; --it;
} }
} }
@ -206,7 +206,7 @@ struct subtitle_insert_before : public validate_nonempty_selection {
new_line->Start = new_line->End - OPT_GET("Timing/Default Duration")->GetInt(); new_line->Start = new_line->End - OPT_GET("Timing/Default Duration")->GetInt();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
// Limit the line to the available time // Limit the line to the available time
if (diag && diag->End <= new_line->End) if (diag && diag->End <= new_line->End)
@ -214,7 +214,7 @@ struct subtitle_insert_before : public validate_nonempty_selection {
// If we just hit the active line, insert the new line before it // If we just hit the active line, insert the new line before it
if (diag == active_line) if (diag == active_line)
c->ass->Line.insert(it, new_line); c->ass->Line.insert(it, *new_line);
} }
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM); c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
@ -408,7 +408,7 @@ struct subtitle_select_visible : public Command {
int frame = c->videoController->GetFrameN(); int frame = c->videoController->GetFrameN();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (diag && if (diag &&
c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame && c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame &&
c->videoController->FrameAtTime(diag->End, agi::vfr::END) >= frame) c->videoController->FrameAtTime(diag->End, agi::vfr::END) >= frame)

View file

@ -72,7 +72,7 @@ namespace {
size_t found = 0; size_t found = 0;
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
if (sel.count(diag)) { if (sel.count(diag)) {

View file

@ -102,10 +102,8 @@ void DialogAttachments::UpdateList() {
listView->InsertColumn(2, _("Group"), wxLIST_FORMAT_LEFT, 100); listView->InsertColumn(2, _("Group"), wxLIST_FORMAT_LEFT, 100);
// Fill list // Fill list
AssAttachment *attach; for (entryIter cur = ass->Line.begin();cur != ass->Line.end();cur++) {
for (std::list<AssEntry*>::iterator cur = ass->Line.begin();cur != ass->Line.end();cur++) { if (AssAttachment *attach = dynamic_cast<AssAttachment*>(&*cur)) {
attach = dynamic_cast<AssAttachment*>(*cur);
if (attach) {
// Add item // Add item
int row = listView->GetItemCount(); int row = listView->GetItemCount();
listView->InsertItem(row,attach->GetFileName(true)); listView->InsertItem(row,attach->GetFileName(true));
@ -210,19 +208,19 @@ void DialogAttachments::OnDelete(wxCommandEvent &) {
if (i == -1) return; if (i == -1) return;
while (i != -1) { while (i != -1) {
ass->Line.remove((AssEntry*)wxUIntToPtr(listView->GetItemData(i))); delete (AssEntry*)wxUIntToPtr(listView->GetItemData(i));
i = listView->GetNextSelected(i); i = listView->GetNextSelected(i);
} }
// Remove empty attachment sections in the file // Remove empty attachment sections in the file
for (std::list<AssEntry*>::iterator it = ass->Line.begin(); it != ass->Line.end(); ) { for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ) {
if ((*it)->GetType() == ENTRY_BASE && ((*it)->group == "[Fonts]" || (*it)->group == "[Graphics]")) { if (it->GetType() == ENTRY_BASE && (it->group == "[Fonts]" || it->group == "[Graphics]")) {
wxString group = (*it)->group; wxString group = it->group;
std::list<AssEntry*>::iterator header = it; entryIter header = it;
bool has_attachments = false; bool has_attachments = false;
for (++it; it != ass->Line.end() && (*it)->group == group; ++it) { for (++it; it != ass->Line.end() && it->group == group; ++it) {
if ((*it)->GetType() == ENTRY_ATTACHMENT) { if (it->GetType() == ENTRY_ATTACHMENT) {
has_attachments = true; has_attachments = true;
break; break;
} }
@ -230,10 +228,8 @@ void DialogAttachments::OnDelete(wxCommandEvent &) {
// Empty group found, delete it // Empty group found, delete it
if (!has_attachments) { if (!has_attachments) {
while (header != it) { while (header != it)
delete *header; delete &*header++;
ass->Line.erase(header++);
}
} }
} }
else else

View file

@ -88,7 +88,7 @@ class FontsCollectorThread : public wxThread {
std::vector<wxString> GetFontPaths(wxString const&, int, bool, std::set<wxUniChar> const&) { return std::vector<wxString>(); } std::vector<wxString> GetFontPaths(wxString const&, int, bool, std::set<wxUniChar> const&) { return std::vector<wxString>(); }
} lister; } lister;
#endif #endif
std::vector<wxString> paths = FontCollector(callback, lister).GetFontPaths(subs->Line); std::vector<wxString> paths = FontCollector(callback, lister).GetFontPaths(subs);
if (paths.empty()) return; if (paths.empty()) return;
// Copy fonts // Copy fonts

View file

@ -629,15 +629,13 @@ bool KaraokeLineMatchDisplay::UndoMatch()
} }
DialogKanjiTimer::DialogKanjiTimer(agi::Context *c) DialogKanjiTimer::DialogKanjiTimer(agi::Context *c)
: wxDialog(c->parent,-1,_("Kanji timing"),wxDefaultPosition) : wxDialog(c->parent, -1, _("Kanji timing"))
, subs(c->ass)
, currentSourceLine(0)
, currentDestinationLine(0)
{ {
SetIcon(GETICON(kara_timing_copier_16)); SetIcon(GETICON(kara_timing_copier_16));
subs = c->ass;
currentSourceLine = subs->Line.begin();
currentDestinationLine = subs->Line.begin();
//Sizers
wxSizer *DisplayBoxSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Text")); wxSizer *DisplayBoxSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Text"));
wxSizer *StylesBoxSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Styles")); wxSizer *StylesBoxSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Styles"));
wxFlexGridSizer *StylesGridSizer = new wxFlexGridSizer(2, 2, 6, 6); wxFlexGridSizer *StylesGridSizer = new wxFlexGridSizer(2, 2, 6, 6);
@ -744,8 +742,8 @@ void DialogKanjiTimer::OnStart(wxCommandEvent &) {
else if (SourceStyle->GetValue() == DestStyle->GetValue()) else if (SourceStyle->GetValue() == DestStyle->GetValue())
wxMessageBox(_("The source and destination styles must be different."),_("Error"),wxICON_EXCLAMATION | wxOK); wxMessageBox(_("The source and destination styles must be different."),_("Error"),wxICON_EXCLAMATION | wxOK);
else { else {
currentSourceLine = FindNextStyleMatch(subs->Line.begin(), SourceStyle->GetValue()); currentSourceLine = FindNextStyleMatch(&*subs->Line.begin(), SourceStyle->GetValue());
currentDestinationLine = FindNextStyleMatch(subs->Line.begin(), DestStyle->GetValue()); currentDestinationLine = FindNextStyleMatch(&*subs->Line.begin(), DestStyle->GetValue());
ResetForNewLine(); ResetForNewLine();
} }
LinesToChange.clear(); LinesToChange.clear();
@ -784,11 +782,11 @@ void DialogKanjiTimer::OnGoBack(wxCommandEvent &) {
} }
void DialogKanjiTimer::OnAccept(wxCommandEvent &) { void DialogKanjiTimer::OnAccept(wxCommandEvent &) {
if (currentDestinationLine == subs->Line.end()) return; if (!currentDestinationLine) return;
if (display->GetRemainingSource() > 0) if (display->GetRemainingSource() > 0)
wxMessageBox(_("Group all of the source text."),_("Error"),wxICON_EXCLAMATION | wxOK); wxMessageBox(_("Group all of the source text."),_("Error"),wxICON_EXCLAMATION | wxOK);
else if (AssDialogue *destLine = dynamic_cast<AssDialogue*>(*currentDestinationLine)) { else if (AssDialogue *destLine = dynamic_cast<AssDialogue*>(currentDestinationLine)) {
LinesToChange.push_back(std::make_pair(destLine, display->GetOutputLine())); LinesToChange.push_back(std::make_pair(destLine, display->GetOutputLine()));
currentSourceLine = FindNextStyleMatch(currentSourceLine, SourceStyle->GetValue()); currentSourceLine = FindNextStyleMatch(currentSourceLine, SourceStyle->GetValue());
@ -834,10 +832,10 @@ void DialogKanjiTimer::ResetForNewLine()
AssDialogue *src = 0; AssDialogue *src = 0;
AssDialogue *dst = 0; AssDialogue *dst = 0;
if (currentSourceLine != subs->Line.end()) if (currentSourceLine)
src = dynamic_cast<AssDialogue*>(*currentSourceLine); src = dynamic_cast<AssDialogue*>(currentSourceLine);
if (currentDestinationLine != subs->Line.end()) if (currentDestinationLine)
dst = dynamic_cast<AssDialogue*>(*currentDestinationLine); dst = dynamic_cast<AssDialogue*>(currentDestinationLine);
if (src == 0 || dst == 0) if (src == 0 || dst == 0)
{ {
@ -858,30 +856,30 @@ void DialogKanjiTimer::TryAutoMatch()
display->AutoMatchJapanese(); display->AutoMatchJapanese();
} }
entryIter DialogKanjiTimer::FindNextStyleMatch(entryIter search_from, const wxString &search_style) AssEntry *DialogKanjiTimer::FindNextStyleMatch(AssEntry *search_from, const wxString &search_style)
{ {
if (search_from == subs->Line.end()) return search_from; if (!search_from) return search_from;
while (++search_from != subs->Line.end()) for (entryIter it = subs->Line.iterator_to(*search_from); it != subs->Line.end(); ++it)
{ {
AssDialogue *dlg = dynamic_cast<AssDialogue*>(*search_from); AssDialogue *dlg = dynamic_cast<AssDialogue*>(&*it);
if (dlg && dlg->Style == search_style) if (dlg && dlg->Style == search_style)
break; return dlg;
} }
return search_from; return 0;
} }
entryIter DialogKanjiTimer::FindPrevStyleMatch(entryIter search_from, const wxString &search_style) AssEntry *DialogKanjiTimer::FindPrevStyleMatch(AssEntry *search_from, const wxString &search_style)
{ {
if (search_from == subs->Line.begin()) return search_from; if (!search_from) return search_from;
while (--search_from != subs->Line.begin()) for (EntryList::reverse_iterator it = EntryList::reverse_iterator(subs->Line.iterator_to(*search_from)); it != subs->Line.rend(); ++it)
{ {
AssDialogue *dlg = dynamic_cast<AssDialogue*>(*search_from); AssDialogue *dlg = dynamic_cast<AssDialogue*>(&*it);
if (dlg && dlg->Style == search_style) if (dlg && dlg->Style == search_style)
break; return dlg;
} }
return search_from; return 0;
} }

View file

@ -53,32 +53,17 @@ class wxCheckBox;
/// ///
/// DOCME /// DOCME
class DialogKanjiTimer : public wxDialog { class DialogKanjiTimer : public wxDialog {
typedef std::list<AssEntry*>::iterator entryIter;
/// DOCME
AssFile *subs; AssFile *subs;
/// DOCME
KaraokeLineMatchDisplay *display; KaraokeLineMatchDisplay *display;
/// DOCME
/// DOCME
wxComboBox *SourceStyle, *DestStyle; wxComboBox *SourceStyle, *DestStyle;
/// DOCME
wxCheckBox *Interpolate; wxCheckBox *Interpolate;
/// DOCME
std::vector<std::pair<AssDialogue*, wxString> > LinesToChange; std::vector<std::pair<AssDialogue*, wxString> > LinesToChange;
/// DOCME AssEntry *currentSourceLine;
entryIter currentSourceLine; AssEntry *currentDestinationLine;
/// DOCME
entryIter currentDestinationLine;
void OnClose(wxCommandEvent &event); void OnClose(wxCommandEvent &event);
void OnStart(wxCommandEvent &event); void OnStart(wxCommandEvent &event);
@ -93,8 +78,8 @@ class DialogKanjiTimer : public wxDialog {
void ResetForNewLine(); void ResetForNewLine();
void TryAutoMatch(); void TryAutoMatch();
entryIter FindNextStyleMatch(entryIter search_from, const wxString &search_style); AssEntry *FindNextStyleMatch(AssEntry *search_from, const wxString &search_style);
entryIter FindPrevStyleMatch(entryIter search_from, const wxString &search_style); AssEntry *FindPrevStyleMatch(AssEntry *search_from, const wxString &search_style);
public: public:
DialogKanjiTimer(agi::Context *context); DialogKanjiTimer(agi::Context *context);

View file

@ -200,8 +200,8 @@ namespace {
cur->Set<int>((cur->Get<int>() + shift) * resizer + 0.5); cur->Set<int>((cur->Get<int>() + shift) * resizer + 0.5);
} }
void resample_line(resample_state *state, AssEntry *line) { void resample_line(resample_state *state, AssEntry &line) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(line); AssDialogue *diag = dynamic_cast<AssDialogue*>(&line);
if (diag && !(diag->Comment && (diag->Effect.StartsWith("template") || diag->Effect.StartsWith("code")))) { if (diag && !(diag->Comment && (diag->Effect.StartsWith("template") || diag->Effect.StartsWith("code")))) {
diag->ParseAssTags(); diag->ParseAssTags();
diag->ProcessParameters(resample_tags, state); diag->ProcessParameters(resample_tags, state);
@ -217,7 +217,7 @@ namespace {
diag->UpdateText(); diag->UpdateText();
diag->ClearBlocks(); diag->ClearBlocks();
} }
else if (AssStyle *style = dynamic_cast<AssStyle*>(line)) { else if (AssStyle *style = dynamic_cast<AssStyle*>(&line)) {
style->fontsize = int(style->fontsize * state->ry + 0.5); style->fontsize = int(style->fontsize * state->ry + 0.5);
style->outline_w *= state->ry; style->outline_w *= state->ry;
style->shadow_w *= state->ry; style->shadow_w *= state->ry;

View file

@ -379,8 +379,8 @@ void SearchReplaceEngine::ReplaceAll() {
bool inSel = affect == 1; bool inSel = affect == 1;
// Scan // Scan
for (std::list<AssEntry*>::iterator it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it) { for (entryIter it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
// Check if row is selected // Check if row is selected

View file

@ -114,7 +114,7 @@ static std::set<AssDialogue*> process(wxString match_text, bool match_case, int
std::set<AssDialogue*> matches; std::set<AssDialogue*> matches;
for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ++it) { for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
if (diag->Comment && !comments) continue; if (diag->Comment && !comments) continue;
if (!diag->Comment && !dialogue) continue; if (!diag->Comment && !dialogue) continue;

View file

@ -353,7 +353,7 @@ void DialogShiftTimes::Process(wxCommandEvent &) {
json::Array shifted_blocks; json::Array shifted_blocks;
for (entryIter it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it) { for (entryIter it = context->ass->Line.begin(); it != context->ass->Line.end(); ++it) {
AssDialogue *line = dynamic_cast<AssDialogue*>(*it); AssDialogue *line = dynamic_cast<AssDialogue*>(&*it);
if (!line) continue; if (!line) continue;
++row_number; ++row_number;

View file

@ -213,7 +213,7 @@ bool DialogSpellChecker::FindNext() {
if (CheckLine(active_line, start_pos, &commit_id)) if (CheckLine(active_line, start_pos, &commit_id))
return true; return true;
std::list<AssEntry*>::iterator it = find(context->ass->Line.begin(), context->ass->Line.end(), active_line); entryIter it = context->ass->Line.iterator_to(*active_line);
// Note that it is deliberate that the start line is checked twice, as if // Note that it is deliberate that the start line is checked twice, as if
// the cursor is past the first misspelled word in the current line, that // the cursor is past the first misspelled word in the current line, that
@ -225,7 +225,7 @@ bool DialogSpellChecker::FindNext() {
it = context->ass->Line.begin(); it = context->ass->Line.begin();
has_looped = true; has_looped = true;
} }
} while (!(active_line = dynamic_cast<AssDialogue*>(*it))); } while (!(active_line = dynamic_cast<AssDialogue*>(&*it)));
if (CheckLine(active_line, 0, &commit_id)) if (CheckLine(active_line, 0, &commit_id))
return true; return true;

View file

@ -88,7 +88,7 @@ class StyleRenamer {
do_replace = replace; do_replace = replace;
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
if (diag->Style == source_name) { if (diag->Style == source_name) {

View file

@ -275,7 +275,7 @@ void DialogStyleManager::LoadCurrentStyles(int commit_type) {
styleMap.clear(); styleMap.clear();
for (entryIter cur = c->ass->Line.begin(); cur != c->ass->Line.end(); ++cur) { for (entryIter cur = c->ass->Line.begin(); cur != c->ass->Line.end(); ++cur) {
if (AssStyle *style = dynamic_cast<AssStyle*>(*cur)) { if (AssStyle *style = dynamic_cast<AssStyle*>(&*cur)) {
CurrentList->Append(style->name); CurrentList->Append(style->name);
styleMap.push_back(style); styleMap.push_back(style);
} }
@ -562,10 +562,8 @@ void DialogStyleManager::OnCurrentDelete() {
int n = CurrentList->GetSelections(selections); int n = CurrentList->GetSelections(selections);
if (confirm_delete(n, this, _("Confirm delete from current")) == wxYES) { if (confirm_delete(n, this, _("Confirm delete from current")) == wxYES) {
for (int i=0;i<n;i++) { for (int i = 0; i < n; i++) {
AssStyle *temp = styleMap.at(selections[i]); delete styleMap.at(selections[i]);
c->ass->Line.remove(temp);
delete temp;
} }
c->ass->Commit(_("style delete"), AssFile::COMMIT_STYLES); c->ass->Commit(_("style delete"), AssFile::COMMIT_STYLES);
} }
@ -780,8 +778,8 @@ void DialogStyleManager::MoveStyles(bool storage, int type) {
for (entryIter cur = c->ass->Line.begin(); cur != c->ass->Line.end(); cur = next) { for (entryIter cur = c->ass->Line.begin(); cur != c->ass->Line.end(); cur = next) {
next = cur; next = cur;
next++; next++;
if (dynamic_cast<AssStyle*>(*cur)) { if (dynamic_cast<AssStyle*>(&*cur)) {
c->ass->Line.insert(cur, styleMap[curn]); c->ass->Line.insert(cur, *styleMap[curn]);
c->ass->Line.erase(cur); c->ass->Line.erase(cur);
curn++; curn++;
} }

View file

@ -304,7 +304,6 @@ std::vector<AssDialogue*> DialogTimingProcessor::SortDialogues() {
} }
std::vector<AssDialogue*> sorted; std::vector<AssDialogue*> sorted;
sorted.reserve(c->ass->Line.size());
if (onlySelection->IsChecked()) { if (onlySelection->IsChecked()) {
SubtitleSelection sel = c->selectionController->GetSelectedSet(); SubtitleSelection sel = c->selectionController->GetSelectedSet();

View file

@ -69,7 +69,7 @@ DialogTranslation::DialogTranslation(agi::Context *c)
, active_line(c->selectionController->GetActiveLine()) , active_line(c->selectionController->GetActiveLine())
, cur_block(0) , cur_block(0)
, line_count(count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>())) , line_count(count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>()))
, line_number(count_if(c->ass->Line.begin(), find(c->ass->Line.begin(), c->ass->Line.end(), active_line), cast<AssDialogue*>()) + 1) , line_number(count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*active_line), cast<AssDialogue*>()) + 1)
, switching_lines(false) , switching_lines(false)
{ {
SetIcon(GETICON(translation_toolbutton_16)); SetIcon(GETICON(translation_toolbutton_16));
@ -177,7 +177,7 @@ void DialogTranslation::OnActiveLineChanged(AssDialogue *new_line) {
active_line = new_line; active_line = new_line;
active_line->ParseAssTags(); active_line->ParseAssTags();
cur_block = 0; cur_block = 0;
line_number = count_if(c->ass->Line.begin(), find(c->ass->Line.begin(), c->ass->Line.end(), active_line), cast<AssDialogue*>()) + 1; line_number = count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*new_line), cast<AssDialogue*>()) + 1;
if (bad_block(active_line->Blocks[cur_block]) && !NextBlock()) { if (bad_block(active_line->Blocks[cur_block]) && !NextBlock()) {
wxMessageBox(_("No more lines to translate.")); wxMessageBox(_("No more lines to translate."));

View file

@ -54,7 +54,7 @@ void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *) {
styles.Sort(); styles.Sort();
for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
if (AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur)) { if (AssDialogue *diag = dynamic_cast<AssDialogue*>(&*cur)) {
if (!std::binary_search(styles.begin(), styles.end(), diag->Style.Lower())) { if (!std::binary_search(styles.begin(), styles.end(), diag->Style.Lower())) {
diag->Style = "Default"; diag->Style = "Default";
} }

View file

@ -209,7 +209,7 @@ void AssTransformFramerateFilter::TransformTimeTags(wxString name,int n,AssOverr
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) { void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
if (!Input->IsLoaded() || !Output->IsLoaded()) return; if (!Input->IsLoaded() || !Output->IsLoaded()) return;
for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur); AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(&*cur);
if (curDialogue) { if (curDialogue) {
line = curDialogue; line = curDialogue;

View file

@ -24,9 +24,10 @@
#include "font_file_lister.h" #include "font_file_lister.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_override.h" #include "ass_override.h"
#include "ass_style.h" #include "ass_style.h"
#include "utils.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <algorithm> #include <algorithm>
@ -44,17 +45,17 @@ FontCollector::FontCollector(FontCollectorStatusCallback status_callback, FontFi
{ {
} }
void FontCollector::ProcessDialogueLine(AssDialogue *line, int index) { void FontCollector::ProcessDialogueLine(const AssDialogue *line, int index) {
if (line->Comment) return; if (line->Comment) return;
line->ParseAssTags(); std::vector<AssDialogueBlock*> blocks = line->ParseTags();
StyleInfo style = styles[line->Style]; StyleInfo style = styles[line->Style];
StyleInfo initial = style; StyleInfo initial = style;
bool overriden = false; bool overriden = false;
for (size_t i = 0; i < line->Blocks.size(); ++i) { for (size_t i = 0; i < blocks.size(); ++i) {
if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride *>(line->Blocks[i])) { if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride *>(blocks[i])) {
for (size_t j = 0; j < ovr->Tags.size(); ++j) { for (size_t j = 0; j < ovr->Tags.size(); ++j) {
AssOverrideTag *tag = ovr->Tags[j]; AssOverrideTag *tag = ovr->Tags[j];
wxString name = tag->Name; wxString name = tag->Name;
@ -77,7 +78,7 @@ void FontCollector::ProcessDialogueLine(AssDialogue *line, int index) {
} }
} }
} }
else if (AssDialogueBlockPlain *txt = dynamic_cast<AssDialogueBlockPlain *>(line->Blocks[i])) { else if (AssDialogueBlockPlain *txt = dynamic_cast<AssDialogueBlockPlain *>(blocks[i])) {
wxString text = txt->GetText(); wxString text = txt->GetText();
if (text.empty() || (text.size() >= 2 && text.StartsWith("{") && text.EndsWith("}"))) if (text.empty() || (text.size() >= 2 && text.StartsWith("{") && text.EndsWith("}")))
@ -102,7 +103,7 @@ void FontCollector::ProcessDialogueLine(AssDialogue *line, int index) {
} }
// Do nothing with drawing blocks // Do nothing with drawing blocks
} }
line->ClearBlocks(); delete_clear(blocks);
} }
void FontCollector::ProcessChunk(std::pair<StyleInfo, UsageData> const& style) { void FontCollector::ProcessChunk(std::pair<StyleInfo, UsageData> const& style) {
@ -148,22 +149,22 @@ void FontCollector::PrintUsage(UsageData const& data) {
status_callback("\n", 2); status_callback("\n", 2);
} }
std::vector<wxString> FontCollector::GetFontPaths(std::list<AssEntry*> const& file) { std::vector<wxString> FontCollector::GetFontPaths(const AssFile *file) {
missing = 0; missing = 0;
missing_glyphs = 0; missing_glyphs = 0;
status_callback(_("Parsing file\n"), 0); status_callback(_("Parsing file\n"), 0);
int index = 0; int index = 0;
for (std::list<AssEntry*>::const_iterator cur = file.begin(); cur != file.end(); ++cur) { for (constEntryIter cur = file->Line.begin(); cur != file->Line.end(); ++cur) {
if (AssStyle *style = dynamic_cast<AssStyle*>(*cur)) { if (const AssStyle *style = dynamic_cast<const AssStyle*>(&*cur)) {
StyleInfo &info = styles[style->name]; StyleInfo &info = styles[style->name];
info.facename = style->font; info.facename = style->font;
info.bold = style->bold; info.bold = style->bold;
info.italic = style->italic; info.italic = style->italic;
used_styles[info].styles.insert(style->name); used_styles[info].styles.insert(style->name);
} }
else if (AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur)) else if (const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&*cur))
ProcessDialogueLine(diag, ++index); ProcessDialogueLine(diag, ++index);
} }

View file

@ -31,8 +31,8 @@
#include <wx/string.h> #include <wx/string.h>
#endif #endif
class AssEntry;
class AssDialogue; class AssDialogue;
class AssFile;
typedef std::tr1::function<void (wxString, int)> FontCollectorStatusCallback; typedef std::tr1::function<void (wxString, int)> FontCollectorStatusCallback;
@ -91,7 +91,7 @@ class FontCollector {
int missing_glyphs; int missing_glyphs;
/// Gather all of the unique styles with text on a line /// Gather all of the unique styles with text on a line
void ProcessDialogueLine(AssDialogue *line, int index); void ProcessDialogueLine(const AssDialogue *line, int index);
/// Get the font for a single style /// Get the font for a single style
void ProcessChunk(std::pair<StyleInfo, UsageData> const& style); void ProcessChunk(std::pair<StyleInfo, UsageData> const& style);
@ -109,5 +109,5 @@ public:
/// @param file Lines in the subtitle file to check /// @param file Lines in the subtitle file to check
/// @param status Callback function for messages /// @param status Callback function for messages
/// @return List of paths to fonts /// @return List of paths to fonts
std::vector<wxString> GetFontPaths(std::list<AssEntry*> const& file); std::vector<wxString> GetFontPaths(const AssFile *file);
}; };

View file

@ -316,7 +316,7 @@ void SubsEditBox::PopulateList(wxComboBox *combo, wxString AssDialogue::*field)
std::set<wxString> values; std::set<wxString> values;
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
if (AssDialogue *diag = dynamic_cast<AssDialogue*>(*it)) if (AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it))
values.insert(diag->*field); values.insert(diag->*field);
} }
values.erase(""); values.erase("");

View file

@ -853,7 +853,7 @@ void SubsTextEditCtrl::SplitLine(bool estimateTimes) {
AssDialogue *n1 = context->selectionController->GetActiveLine(); AssDialogue *n1 = context->selectionController->GetActiveLine();
AssDialogue *n2 = new AssDialogue(*n1); AssDialogue *n2 = new AssDialogue(*n1);
context->ass->Line.insert(++find(context->ass->Line.begin(), context->ass->Line.end(), n1), n2); context->ass->Line.insert(++context->ass->Line.iterator_to(*n1), *n2);
wxString orig = n1->Text; wxString orig = n1->Text;
n1->Text = orig.Left(from).Trim(true); // Trim off trailing whitespace n1->Text = orig.Left(from).Trim(true); // Trim off trailing whitespace

View file

@ -91,20 +91,17 @@ void SubtitlesGrid::RecombineLines() {
// 1, 1+2 (or 2+1), 2 gets turned into 1, 2, 2 so kill the duplicate // 1, 1+2 (or 2+1), 2 gets turned into 1, 2, 2 so kill the duplicate
if (d1->Text == (*d2)->Text) { if (d1->Text == (*d2)->Text) {
expand_times(d1, *d2); expand_times(d1, *d2);
context->ass->Line.remove(d1);
delete d1; delete d1;
continue; continue;
} }
// 1, 1+2, 1 turns into 1, 2, [empty] // 1, 1+2, 1 turns into 1, 2, [empty]
if (d1->Text.empty()) { if (d1->Text.empty()) {
context->ass->Line.remove(d1);
delete d1; delete d1;
continue; continue;
} }
// If d2 is the last line in the selection it'll never hit the above test // If d2 is the last line in the selection it'll never hit the above test
if (d2 == end && (*d2)->Text.empty()) { if (d2 == end && (*d2)->Text.empty()) {
context->ass->Line.remove(*d2);
delete *d2; delete *d2;
continue; continue;
} }

View file

@ -61,7 +61,7 @@ SubtitlesPreview::SubtitlesPreview(wxWindow *parent, wxSize size, int winStyle,
subFile->LoadDefault(); subFile->LoadDefault();
subFile->InsertStyle(style); subFile->InsertStyle(style);
subFile->Line.push_back(line); subFile->Line.push_back(*line);
SetSizeHints(size.GetWidth(), size.GetHeight(), -1, -1); SetSizeHints(size.GetWidth(), size.GetHeight(), -1, -1);
wxSizeEvent evt(size); wxSizeEvent evt(size);

View file

@ -79,18 +79,18 @@ bool SubtitleFormat::CanWriteFile(wxString const& filename) const {
bool SubtitleFormat::CanSave(const AssFile *subs) const { bool SubtitleFormat::CanSave(const AssFile *subs) const {
AssStyle defstyle; AssStyle defstyle;
for (std::list<AssEntry*>::const_iterator cur = subs->Line.begin(); cur != subs->Line.end(); ++cur) { for (constEntryIter cur = subs->Line.begin(); cur != subs->Line.end(); ++cur) {
// Check style, if anything non-default is found, return false // Check style, if anything non-default is found, return false
if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(*cur)) { if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(&*cur)) {
if (curstyle->GetEntryData() != defstyle.GetEntryData()) if (curstyle->GetEntryData() != defstyle.GetEntryData())
return false; return false;
} }
// Check for attachments, if any is found, return false // Check for attachments, if any is found, return false
if (dynamic_cast<const AssAttachment*>(*cur)) return false; if (dynamic_cast<const AssAttachment*>(&*cur)) return false;
// Check dialog // Check dialog
if (const AssDialogue *curdiag = dynamic_cast<const AssDialogue*>(*cur)) { if (const AssDialogue *curdiag = dynamic_cast<const AssDialogue*>(&*cur)) {
if (curdiag->GetStrippedText() != curdiag->Text) if (curdiag->GetStrippedText() != curdiag->Text)
return false; return false;
} }
@ -163,17 +163,17 @@ agi::vfr::Framerate SubtitleFormat::AskForFPS(bool allow_vfr, bool show_smpte) {
return Framerate(); return Framerate();
} }
void SubtitleFormat::StripTags(LineList &lines) { void SubtitleFormat::StripTags(AssFile &file) {
for (LineList::iterator cur = lines.begin(); cur != lines.end(); ++cur) { for (entryIter cur = file.Line.begin(); cur != file.Line.end(); ++cur) {
if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) { if (AssDialogue *current = dynamic_cast<AssDialogue*>(&*cur)) {
current->StripTags(); current->StripTags();
} }
} }
} }
void SubtitleFormat::ConvertNewlines(LineList &lines, wxString const& newline, bool mergeLineBreaks) { void SubtitleFormat::ConvertNewlines(AssFile &file, wxString const& newline, bool mergeLineBreaks) {
for (LineList::iterator cur = lines.begin(); cur != lines.end(); ++cur) { for (entryIter cur = file.Line.begin(); cur != file.Line.end(); ++cur) {
if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) { if (AssDialogue *current = dynamic_cast<AssDialogue*>(&*cur)) {
current->Text.Replace("\\h", " "); current->Text.Replace("\\h", " ");
current->Text.Replace("\\n", newline); current->Text.Replace("\\n", newline);
current->Text.Replace("\\N", newline); current->Text.Replace("\\N", newline);
@ -184,59 +184,57 @@ void SubtitleFormat::ConvertNewlines(LineList &lines, wxString const& newline, b
} }
} }
void SubtitleFormat::StripComments(LineList &lines) { void SubtitleFormat::StripComments(AssFile &file) {
for (LineList::iterator it = lines.begin(); it != lines.end(); ) { for (entryIter it = file.Line.begin(); it != file.Line.end(); ) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag || (!diag->Comment && diag->Text.size())) if (!diag || (!diag->Comment && diag->Text.size()))
++it; ++it;
else { else {
delete *it; delete &*it++;
lines.erase(it++);
} }
} }
} }
void SubtitleFormat::StripNonDialogue(LineList &lines) { void SubtitleFormat::StripNonDialogue(AssFile &file) {
for (LineList::iterator it = lines.begin(); it != lines.end(); ) { for (entryIter it = file.Line.begin(); it != file.Line.end(); ) {
if (dynamic_cast<AssDialogue*>(*it)) if (dynamic_cast<AssDialogue*>(&*it))
++it; ++it;
else { else {
delete *it; delete &*it++;
lines.erase(it++);
} }
} }
} }
static bool dialog_start_lt(AssEntry *pos, AssDialogue *to_insert) { static bool dialog_start_lt(AssEntry &pos, AssDialogue *to_insert) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(pos); AssDialogue *diag = dynamic_cast<AssDialogue*>(&pos);
return diag && diag->Start > to_insert->Start; return diag && diag->Start > to_insert->Start;
} }
/// @brief Split and merge lines so there are no overlapping lines /// @brief Split and merge lines so there are no overlapping lines
/// ///
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge /// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
void SubtitleFormat::RecombineOverlaps(LineList &lines) { void SubtitleFormat::RecombineOverlaps(AssFile &file) {
LineList::iterator cur, next = lines.begin(); entryIter cur, next = file.Line.begin();
cur = next++; cur = next++;
for (; next != lines.end(); cur = next++) { for (; next != file.Line.end(); cur = next++) {
AssDialogue *prevdlg = dynamic_cast<AssDialogue*>(*cur); AssDialogue *prevdlg = dynamic_cast<AssDialogue*>(&*cur);
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*next); AssDialogue *curdlg = dynamic_cast<AssDialogue*>(&*next);
if (!curdlg || !prevdlg) continue; if (!curdlg || !prevdlg) continue;
if (prevdlg->End <= curdlg->Start) continue; if (prevdlg->End <= curdlg->Start) continue;
// Use names like in the algorithm description and prepare for erasing // Use names like in the algorithm description and prepare for erasing
// old dialogues from the list // old dialogues from the list
LineList::iterator prev = cur; entryIter prev = cur;
cur = next; cur = next;
next++; next++;
// std::list::insert() inserts items before the given iterator, so // std::list::insert() inserts items before the given iterator, so
// we need 'next' for inserting. 'prev' and 'cur' can safely be erased // we need 'next' for inserting. 'prev' and 'cur' can safely be erased
// from the list now. // from the list now.
lines.erase(prev); file.Line.erase(prev);
lines.erase(cur); file.Line.erase(cur);
//Is there an A part before the overlap? //Is there an A part before the overlap?
if (curdlg->Start > prevdlg->Start) { if (curdlg->Start > prevdlg->Start) {
@ -246,7 +244,7 @@ void SubtitleFormat::RecombineOverlaps(LineList &lines) {
newdlg->End = curdlg->Start; newdlg->End = curdlg->Start;
newdlg->Text = prevdlg->Text; newdlg->Text = prevdlg->Text;
lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); file.Line.insert(find_if(next, file.Line.end(), bind(dialog_start_lt, _1, newdlg)), *newdlg);
} }
// Overlapping A+B part // Overlapping A+B part
@ -257,7 +255,7 @@ void SubtitleFormat::RecombineOverlaps(LineList &lines) {
// Put an ASS format hard linewrap between lines // Put an ASS format hard linewrap between lines
newdlg->Text = curdlg->Text + "\\N" + prevdlg->Text; newdlg->Text = curdlg->Text + "\\N" + prevdlg->Text;
lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); file.Line.insert(find_if(next, file.Line.end(), bind(dialog_start_lt, _1, newdlg)), *newdlg);
} }
// Is there an A part after the overlap? // Is there an A part after the overlap?
@ -268,7 +266,7 @@ void SubtitleFormat::RecombineOverlaps(LineList &lines) {
newdlg->End = prevdlg->End; newdlg->End = prevdlg->End;
newdlg->Text = prevdlg->Text; newdlg->Text = prevdlg->Text;
lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); file.Line.insert(find_if(next, file.Line.end(), bind(dialog_start_lt, _1, newdlg)), *newdlg);
} }
// Is there a B part after the overlap? // Is there a B part after the overlap?
@ -279,7 +277,7 @@ void SubtitleFormat::RecombineOverlaps(LineList &lines) {
newdlg->End = curdlg->End; newdlg->End = curdlg->End;
newdlg->Text = curdlg->Text; newdlg->Text = curdlg->Text;
lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); file.Line.insert(find_if(next, file.Line.end(), bind(dialog_start_lt, _1, newdlg)), *newdlg);
} }
next--; next--;
@ -287,13 +285,13 @@ void SubtitleFormat::RecombineOverlaps(LineList &lines) {
} }
/// @brief Merge identical lines that follow each other /// @brief Merge identical lines that follow each other
void SubtitleFormat::MergeIdentical(LineList &lines) { void SubtitleFormat::MergeIdentical(AssFile &file) {
LineList::iterator cur, next = lines.begin(); entryIter cur, next = file.Line.begin();
cur = next++; cur = next++;
for (; next != lines.end(); cur = next++) { for (; next != file.Line.end(); cur = next++) {
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*cur); AssDialogue *curdlg = dynamic_cast<AssDialogue*>(&*cur);
AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(*next); AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(&*next);
if (curdlg && nextdlg && curdlg->End == nextdlg->Start && curdlg->Text == nextdlg->Text) { if (curdlg && nextdlg && curdlg->End == nextdlg->Start && curdlg->Text == nextdlg->Text) {
// Merge timing // Merge timing
@ -301,8 +299,7 @@ void SubtitleFormat::MergeIdentical(LineList &lines) {
nextdlg->End = std::max(nextdlg->End, curdlg->End); nextdlg->End = std::max(nextdlg->End, curdlg->End);
// Remove duplicate line // Remove duplicate line
delete *cur; delete curdlg;
lines.erase(cur);
} }
} }
} }

View file

@ -64,24 +64,22 @@ class SubtitleFormat {
static std::list<SubtitleFormat*> formats; static std::list<SubtitleFormat*> formats;
public: public:
typedef std::list<AssEntry*> LineList;
/// Strip override tags /// Strip override tags
static void StripTags(LineList &lines); static void StripTags(AssFile &file);
/// Convert newlines to the specified character(s) /// Convert newlines to the specified character(s)
/// @param lineEnd newline character(s) /// @param lineEnd newline character(s)
/// @param mergeLineBreaks Should multiple consecutive line breaks be merged into one? /// @param mergeLineBreaks Should multiple consecutive line breaks be merged into one?
static void ConvertNewlines(LineList &lines, wxString const& newline, bool mergeLineBreaks = true); static void ConvertNewlines(AssFile &file, wxString const& newline, bool mergeLineBreaks = true);
/// Remove All commented and empty lines /// Remove All commented and empty lines
static void StripComments(LineList &lines); static void StripComments(AssFile &file);
/// Remove everything but the dialogue lines /// Remove everything but the dialogue lines
static void StripNonDialogue(LineList &lines); static void StripNonDialogue(AssFile &file);
/// @brief Split and merge lines so there are no overlapping lines /// @brief Split and merge lines so there are no overlapping lines
/// ///
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge /// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
static void RecombineOverlaps(LineList &lines); static void RecombineOverlaps(AssFile &file);
/// Merge sequential identical lines /// Merge sequential identical lines
static void MergeIdentical(LineList &lines); static void MergeIdentical(AssFile &file);
/// Prompt the user for a frame rate to use /// Prompt the user for a frame rate to use
/// @param allow_vfr Include video frame rate as an option even if it's vfr /// @param allow_vfr Include video frame rate as an option even if it's vfr

View file

@ -36,7 +36,6 @@
#include "subtitle_format_ass.h" #include "subtitle_format_ass.h"
#include "ass_entry.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_parser.h" #include "ass_parser.h"
#include "compat.h" #include "compat.h"
@ -92,14 +91,14 @@ void AssSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename,
bool ssa = filename.Right(4).Lower() == ".ssa"; bool ssa = filename.Right(4).Lower() == ".ssa";
wxString group = src->Line.front()->group; wxString group = src->Line.front().group;
for (LineList::const_iterator cur = src->Line.begin(); cur != src->Line.end(); ++cur) { for (constEntryIter cur = src->Line.begin(); cur != src->Line.end(); ++cur) {
// Add a blank line between each group // Add a blank line between each group
if ((*cur)->group != group) { if (cur->group != group) {
file.WriteLineToFile(""); file.WriteLineToFile("");
group = (*cur)->group; group = cur->group;
} }
file.WriteLineToFile(ssa ? (*cur)->GetSSAText() : (*cur)->GetEntryData(), true); file.WriteLineToFile(ssa ? cur->GetSSAText() : cur->GetEntryData(), true);
} }
} }

View file

@ -370,10 +370,10 @@ namespace
std::vector<EbuSubtitle> convert_subtitles(AssFile &copy, EbuExportSettings const& export_settings) std::vector<EbuSubtitle> convert_subtitles(AssFile &copy, EbuExportSettings const& export_settings)
{ {
SubtitleFormat::StripComments(copy.Line); SubtitleFormat::StripComments(copy);
copy.Sort(); copy.Sort();
SubtitleFormat::RecombineOverlaps(copy.Line); SubtitleFormat::RecombineOverlaps(copy);
SubtitleFormat::MergeIdentical(copy.Line); SubtitleFormat::MergeIdentical(copy);
int line_wrap_type = copy.GetScriptInfoAsInt("WrapStyle"); int line_wrap_type = copy.GetScriptInfoAsInt("WrapStyle");
@ -388,7 +388,7 @@ namespace
// convert to intermediate format // convert to intermediate format
for (entryIter orgline = copy.Line.begin(); orgline != copy.Line.end(); ++orgline) for (entryIter orgline = copy.Line.begin(); orgline != copy.Line.end(); ++orgline)
{ {
AssDialogue *line = dynamic_cast<AssDialogue*>(*orgline); AssDialogue *line = dynamic_cast<AssDialogue*>(&*orgline);
if (!line) continue; if (!line) continue;
// add a new subtitle and work on it // add a new subtitle and work on it

View file

@ -62,11 +62,11 @@ void EncoreSubtitleFormat::WriteFile(const AssFile *src, wxString const& filenam
// Convert to encore // Convert to encore
AssFile copy(*src); AssFile copy(*src);
copy.Sort(); copy.Sort();
StripComments(copy.Line); StripComments(copy);
RecombineOverlaps(copy.Line); RecombineOverlaps(copy);
MergeIdentical(copy.Line); MergeIdentical(copy);
StripTags(copy.Line); StripTags(copy);
ConvertNewlines(copy.Line, "\r\n"); ConvertNewlines(copy, "\r\n");
// Encode wants ; for NTSC and : for PAL // Encode wants ; for NTSC and : for PAL
@ -77,8 +77,8 @@ void EncoreSubtitleFormat::WriteFile(const AssFile *src, wxString const& filenam
// Write lines // Write lines
int i = 0; int i = 0;
TextFileWriter file(filename, "UTF-8"); TextFileWriter file(filename, "UTF-8");
for (LineList::const_iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { for (constEntryIter cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) {
if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) { if (const AssDialogue *current = dynamic_cast<const AssDialogue*>(&*cur)) {
++i; ++i;
file.WriteLineToFile(wxString::Format("%i %s %s %s", i, ft.ToSMPTE(current->Start), ft.ToSMPTE(current->End), current->Text)); file.WriteLineToFile(wxString::Format("%i %s %s %s", i, ft.ToSMPTE(current->Start), ft.ToSMPTE(current->End), current->Text));
} }

View file

@ -117,7 +117,7 @@ void MicroDVDSubtitleFormat::ReadFile(AssFile *target, wxString const& filename,
diag->Start = fps.TimeAtFrame(f1, agi::vfr::START); diag->Start = fps.TimeAtFrame(f1, agi::vfr::START);
diag->End = fps.TimeAtFrame(f2, agi::vfr::END); diag->End = fps.TimeAtFrame(f2, agi::vfr::END);
diag->Text = text; diag->Text = text;
target->Line.push_back(diag); target->Line.push_back(*diag);
} }
} }
} }
@ -128,11 +128,11 @@ void MicroDVDSubtitleFormat::WriteFile(const AssFile *src, wxString const& filen
AssFile copy(*src); AssFile copy(*src);
copy.Sort(); copy.Sort();
StripComments(copy.Line); StripComments(copy);
RecombineOverlaps(copy.Line); RecombineOverlaps(copy);
MergeIdentical(copy.Line); MergeIdentical(copy);
StripTags(copy.Line); StripTags(copy);
ConvertNewlines(copy.Line, "|"); ConvertNewlines(copy, "|");
TextFileWriter file(filename, encoding); TextFileWriter file(filename, encoding);
@ -142,8 +142,8 @@ void MicroDVDSubtitleFormat::WriteFile(const AssFile *src, wxString const& filen
} }
// Write lines // Write lines
for (LineList::const_iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { for (constEntryIter cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) {
if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) { if (const AssDialogue *current = dynamic_cast<const AssDialogue*>(&*cur)) {
int start = fps.FrameAtTime(current->Start, agi::vfr::START); int start = fps.FrameAtTime(current->Start, agi::vfr::START);
int end = fps.FrameAtTime(current->End, agi::vfr::END); int end = fps.FrameAtTime(current->End, agi::vfr::END);

View file

@ -431,7 +431,7 @@ found_timestamps:
line->Start = ReadSRTTime(timestamp_regex.GetMatch(text_line, 1)); line->Start = ReadSRTTime(timestamp_regex.GetMatch(text_line, 1));
line->End = ReadSRTTime(timestamp_regex.GetMatch(text_line, 2)); line->End = ReadSRTTime(timestamp_regex.GetMatch(text_line, 2));
// store pointer to subtitle, we'll continue working on it // store pointer to subtitle, we'll continue working on it
target->Line.push_back(line); target->Line.push_back(*line);
// next we're reading the text // next we're reading the text
state = 3; state = 3;
break; break;
@ -500,19 +500,19 @@ void SRTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename,
// Convert to SRT // Convert to SRT
AssFile copy(*src); AssFile copy(*src);
copy.Sort(); copy.Sort();
StripComments(copy.Line); StripComments(copy);
RecombineOverlaps(copy.Line); RecombineOverlaps(copy);
MergeIdentical(copy.Line); MergeIdentical(copy);
#ifdef _WIN32 #ifdef _WIN32
ConvertNewlines(copy.Line, "\r\n", false); ConvertNewlines(copy, "\r\n", false);
#else #else
ConvertNewlines(copy.Line, "\n", false); ConvertNewlines(copy, "\n", false);
#endif #endif
// Write lines // Write lines
int i=1; int i=1;
for (LineList::const_iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { for (constEntryIter cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) {
if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) { if (const AssDialogue *current = dynamic_cast<const AssDialogue*>(&*cur)) {
file.WriteLineToFile(wxString::Format("%d", i++)); file.WriteLineToFile(wxString::Format("%d", i++));
file.WriteLineToFile(WriteSRTTime(current->Start) + " --> " + WriteSRTTime(current->End)); file.WriteLineToFile(WriteSRTTime(current->Start) + " --> " + WriteSRTTime(current->End));
file.WriteLineToFile(ConvertTags(current)); file.WriteLineToFile(ConvertTags(current));
@ -525,18 +525,18 @@ bool SRTSubtitleFormat::CanSave(const AssFile *file) const {
wxString supported_tags[] = { "\\b", "\\i", "\\s", "\\u" }; wxString supported_tags[] = { "\\b", "\\i", "\\s", "\\u" };
AssStyle defstyle; AssStyle defstyle;
for (std::list<AssEntry*>::const_iterator cur = file->Line.begin(); cur != file->Line.end(); ++cur) { for (constEntryIter cur = file->Line.begin(); cur != file->Line.end(); ++cur) {
// Check style, if anything non-default is found, return false // Check style, if anything non-default is found, return false
if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(*cur)) { if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(&*cur)) {
if (curstyle->GetEntryData() != defstyle.GetEntryData()) if (curstyle->GetEntryData() != defstyle.GetEntryData())
return false; return false;
} }
// Check for attachments, if any is found, return false // Check for attachments, if any is found, return false
if (dynamic_cast<const AssAttachment*>(*cur)) return false; if (dynamic_cast<const AssAttachment*>(&*cur)) return false;
// Check dialogue // Check dialogue
if (const AssDialogue *curdiag = dynamic_cast<const AssDialogue*>(*cur)) { if (const AssDialogue *curdiag = dynamic_cast<const AssDialogue*>(&*cur)) {
std::vector<AssDialogueBlock*> blocks = curdiag->ParseTags(); std::vector<AssDialogueBlock*> blocks = curdiag->ParseTags();
for (size_t i = 0; i < blocks.size(); ++i) { for (size_t i = 0; i < blocks.size(); ++i) {
AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(blocks[i]); AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(blocks[i]);
@ -557,7 +557,7 @@ bool SRTSubtitleFormat::CanSave(const AssFile *file) const {
return true; return true;
} }
wxString SRTSubtitleFormat::ConvertTags(AssDialogue *diag) const { wxString SRTSubtitleFormat::ConvertTags(const AssDialogue *diag) const {
wxString final; wxString final;
std::map<char, bool> tag_states; std::map<char, bool> tag_states;
tag_states['i'] = false; tag_states['i'] = false;
@ -565,10 +565,10 @@ wxString SRTSubtitleFormat::ConvertTags(AssDialogue *diag) const {
tag_states['u'] = false; tag_states['u'] = false;
tag_states['s'] = false; tag_states['s'] = false;
diag->ParseAssTags(); std::vector<AssDialogueBlock *> blocks = diag->ParseTags();
for (size_t i = 0; i < diag->Blocks.size(); ++i) { for (size_t i = 0; i < blocks.size(); ++i) {
if (AssDialogueBlockOverride* block = dynamic_cast<AssDialogueBlockOverride*>(diag->Blocks[i])) { if (AssDialogueBlockOverride* block = dynamic_cast<AssDialogueBlockOverride*>(blocks[i])) {
// Iterate through overrides // Iterate through overrides
for (size_t j = 0; j < block->Tags.size(); j++) { for (size_t j = 0; j < block->Tags.size(); j++) {
AssOverrideTag *tag = block->Tags[j]; AssOverrideTag *tag = block->Tags[j];
@ -586,7 +586,7 @@ wxString SRTSubtitleFormat::ConvertTags(AssDialogue *diag) const {
} }
} }
// Plain text // Plain text
else if (AssDialogueBlockPlain *plain = dynamic_cast<AssDialogueBlockPlain*>(diag->Blocks[i])) { else if (AssDialogueBlockPlain *plain = dynamic_cast<AssDialogueBlockPlain*>(blocks[i])) {
final += plain->GetText(); final += plain->GetText();
} }
} }
@ -598,7 +598,7 @@ wxString SRTSubtitleFormat::ConvertTags(AssDialogue *diag) const {
final += wxString::Format("</%c>", it->first); final += wxString::Format("</%c>", it->first);
} }
diag->ClearBlocks(); delete_clear(blocks);
return final; return final;
} }

View file

@ -42,7 +42,7 @@ class AssDialogue;
/// ///
/// DOCME /// DOCME
class SRTSubtitleFormat : public SubtitleFormat { class SRTSubtitleFormat : public SubtitleFormat {
wxString ConvertTags(AssDialogue *diag) const; wxString ConvertTags(const AssDialogue *diag) const;
public: public:
SRTSubtitleFormat(); SRTSubtitleFormat();
wxArrayString GetReadWildcards() const; wxArrayString GetReadWildcards() const;

View file

@ -68,15 +68,15 @@ void TranStationSubtitleFormat::WriteFile(const AssFile *src, wxString const& fi
// Convert to TranStation // Convert to TranStation
AssFile copy(*src); AssFile copy(*src);
copy.Sort(); copy.Sort();
StripComments(copy.Line); StripComments(copy);
RecombineOverlaps(copy.Line); RecombineOverlaps(copy);
MergeIdentical(copy.Line); MergeIdentical(copy);
SmpteFormatter ft(fps); SmpteFormatter ft(fps);
TextFileWriter file(filename, encoding); TextFileWriter file(filename, encoding);
AssDialogue *prev = 0; AssDialogue *prev = 0;
for (std::list<AssEntry*>::iterator it = copy.Line.begin(); it != copy.Line.end(); ++it) { for (entryIter it = copy.Line.begin(); it != copy.Line.end(); ++it) {
AssDialogue *cur = dynamic_cast<AssDialogue*>(*it); AssDialogue *cur = dynamic_cast<AssDialogue*>(&*it);
if (prev && cur) { if (prev && cur) {
file.WriteLineToFile(ConvertLine(&copy, prev, fps, ft, cur->Start)); file.WriteLineToFile(ConvertLine(&copy, prev, fps, ft, cur->Start));

View file

@ -91,7 +91,7 @@ void TTXTSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxS
if (child->GetName() == "TextSample") { if (child->GetName() == "TextSample") {
if ((diag = ProcessLine(child, diag, version))) { if ((diag = ProcessLine(child, diag, version))) {
lines++; lines++;
target->Line.push_back(diag); target->Line.push_back(*diag);
} }
} }
// Header // Header
@ -102,7 +102,7 @@ void TTXTSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxS
// No lines? // No lines?
if (lines == 0) if (lines == 0)
target->Line.push_back(new AssDialogue); target->Line.push_back(*new AssDialogue);
} }
AssDialogue *TTXTSubtitleFormat::ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const { AssDialogue *TTXTSubtitleFormat::ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const {
@ -175,9 +175,9 @@ void TTXTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename,
WriteHeader(root); WriteHeader(root);
// Create lines // Create lines
AssDialogue *prev = 0; const AssDialogue *prev = 0;
for (LineList::iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { for (constEntryIter cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) {
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur); const AssDialogue *current = dynamic_cast<const AssDialogue*>(&*cur);
if (current && !current->Comment) { if (current && !current->Comment) {
WriteLine(root, prev, current); WriteLine(root, prev, current);
prev = current; prev = current;
@ -240,7 +240,7 @@ void TTXTSubtitleFormat::WriteHeader(wxXmlNode *root) const {
root->AddChild(node); root->AddChild(node);
} }
void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *prev, AssDialogue *line) const { void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, const AssDialogue *prev, const AssDialogue *line) const {
// If it doesn't start at the end of previous, add blank // If it doesn't start at the end of previous, add blank
if (prev && prev->End != line->Start) { if (prev && prev->End != line->Start) {
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample"); wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample");
@ -260,16 +260,16 @@ void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *prev, AssDialog
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const { void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
file.Sort(); file.Sort();
StripComments(file.Line); StripComments(file);
RecombineOverlaps(file.Line); RecombineOverlaps(file);
MergeIdentical(file.Line); MergeIdentical(file);
StripTags(file.Line); StripTags(file);
ConvertNewlines(file.Line, "\r\n"); ConvertNewlines(file, "\r\n");
// Find last line // Find last line
AssTime lastTime; AssTime lastTime;
for (LineList::reverse_iterator cur = file.Line.rbegin(); cur != file.Line.rend(); ++cur) { for (EntryList::reverse_iterator cur = file.Line.rbegin(); cur != file.Line.rend(); ++cur) {
if (AssDialogue *prev = dynamic_cast<AssDialogue*>(*cur)) { if (AssDialogue *prev = dynamic_cast<AssDialogue*>(&*cur)) {
lastTime = prev->End; lastTime = prev->End;
break; break;
} }
@ -279,5 +279,5 @@ void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
AssDialogue *diag = new AssDialogue; AssDialogue *diag = new AssDialogue;
diag->Start = lastTime; diag->Start = lastTime;
diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt(); diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt();
file.Line.push_back(diag); file.Line.push_back(*diag);
} }

View file

@ -47,7 +47,7 @@ class TTXTSubtitleFormat : public SubtitleFormat {
void ProcessHeader(wxXmlNode *node) const; void ProcessHeader(wxXmlNode *node) const;
void WriteHeader(wxXmlNode *root) const; void WriteHeader(wxXmlNode *root) const;
void WriteLine(wxXmlNode *root, AssDialogue *prev, AssDialogue *line) const; void WriteLine(wxXmlNode *root, const AssDialogue *prev, const AssDialogue *line) const;
void ConvertToTTXT(AssFile &file) const; void ConvertToTTXT(AssFile &file) const;

View file

@ -43,9 +43,9 @@
#include "main.h" #include "main.h"
#include "text_file_reader.h" #include "text_file_reader.h"
#include "text_file_writer.h" #include "text_file_writer.h"
#include "utils.h"
#include "version.h" #include "version.h"
TXTSubtitleFormat::TXTSubtitleFormat() TXTSubtitleFormat::TXTSubtitleFormat()
: SubtitleFormat("Plain-Text") : SubtitleFormat("Plain-Text")
{ {
@ -121,7 +121,7 @@ void TXTSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxSt
line->End = 0; line->End = 0;
// Adds line // Adds line
target->Line.push_back(line); target->Line.push_back(*line);
} }
} }
@ -129,8 +129,8 @@ void TXTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename,
size_t num_actor_names = 0, num_dialogue_lines = 0; size_t num_actor_names = 0, num_dialogue_lines = 0;
// Detect number of lines with Actor field filled out // Detect number of lines with Actor field filled out
for (LineList::const_iterator l = src->Line.begin(); l != src->Line.end(); ++l) { for (constEntryIter l = src->Line.begin(); l != src->Line.end(); ++l) {
AssDialogue *dia = dynamic_cast<AssDialogue*>(*l); const AssDialogue *dia = dynamic_cast<const AssDialogue*>(&*l);
if (dia && !dia->Comment) { if (dia && !dia->Comment) {
num_dialogue_lines++; num_dialogue_lines++;
if (!dia->Actor.empty()) if (!dia->Actor.empty())
@ -146,43 +146,34 @@ void TXTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename,
file.WriteLineToFile(wxString("# Exported by Aegisub ") + GetAegisubShortVersionString()); file.WriteLineToFile(wxString("# Exported by Aegisub ") + GetAegisubShortVersionString());
// Write the file // Write the file
for (LineList::const_iterator l = src->Line.begin(); l != src->Line.end(); ++l) { for (constEntryIter l = src->Line.begin(); l != src->Line.end(); ++l) {
AssDialogue *dia = dynamic_cast<AssDialogue*>(*l); const AssDialogue *dia = dynamic_cast<const AssDialogue*>(&*l);
if (!dia) continue;
if (dia) { wxString out_line;
wxString out_line;
if (dia->Comment) { if (dia->Comment)
out_line = "# "; out_line = "# ";
}
if (write_actors) { if (write_actors)
out_line += dia->Actor + ": "; out_line += dia->Actor + ": ";
}
wxString out_text; wxString out_text;
if (strip_formatting) { if (strip_formatting) {
dia->ParseAssTags(); std::vector<AssDialogueBlock*> blocks = dia->ParseTags();
for (std::vector<AssDialogueBlock*>::iterator block = dia->Blocks.begin(); block != dia->Blocks.end(); ++block) { for (std::vector<AssDialogueBlock*>::iterator block = blocks.begin(); block != blocks.end(); ++block) {
if ((*block)->GetType() == BLOCK_PLAIN) { if ((*block)->GetType() == BLOCK_PLAIN) {
out_text += (*block)->GetText(); out_text += (*block)->GetText();
}
} }
dia->ClearBlocks();
}
else {
out_text = dia->Text;
}
out_line += out_text;
if (!out_text.empty()) {
file.WriteLineToFile(out_line);
} }
delete_clear(blocks);
} }
else { else {
// Not a dialogue line out_text = dia->Text;
// TODO: should any non-dia lines cause blank lines in output?
//file.WriteLineToFile("");
} }
out_line += out_text;
if (!out_text.empty())
file.WriteLineToFile(out_line);
} }
} }

View file

@ -35,8 +35,10 @@
#include "threaded_frame_source.h" #include "threaded_frame_source.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <iterator>
#include <functional> #include <functional>
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/algorithm_ext.hpp>
#endif #endif
#include "ass_dialogue.h" #include "ass_dialogue.h"
@ -49,11 +51,11 @@
#include "video_provider_manager.h" #include "video_provider_manager.h"
// Test if a line is a dialogue line which is not visible at the given time // Test if a line is a dialogue line which is not visible at the given time
struct invisible_line : public std::unary_function<const AssEntry*, bool> { struct invisible_line : public std::unary_function<AssEntry const&, bool> {
double time; double time;
invisible_line(double time) : time(time * 1000.) { } invisible_line(double time) : time(time * 1000.) { }
bool operator()(const AssEntry *entry) const { bool operator()(AssEntry const& entry) const {
const AssDialogue *diag = dynamic_cast<const AssDialogue*>(entry); const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&entry);
return diag && (diag->Start > time || diag->End <= time); return diag && (diag->Start > time || diag->End <= time);
} }
}; };
@ -101,17 +103,20 @@ std::tr1::shared_ptr<AegiVideoFrame> ThreadedFrameSource::ProcFrame(int frameNum
// Copying a nontrivially sized AssFile is fairly slow, so // Copying a nontrivially sized AssFile is fairly slow, so
// instead muck around with its innards to just temporarily // instead muck around with its innards to just temporarily
// remove the non-visible lines without deleting them // remove the non-visible lines without deleting them
std::list<AssEntry*> visible; std::deque<AssEntry*> full;
std::remove_copy_if(subs->Line.begin(), subs->Line.end(), for (entryIter it = subs->Line.begin(); it != subs->Line.end(); ++it)
std::back_inserter(visible), full.push_back(&*it);
invisible_line(time)); subs->Line.remove_if(invisible_line(time));
try { try {
std::swap(subs->Line, visible);
provider->LoadSubtitles(subs.get()); provider->LoadSubtitles(subs.get());
std::swap(subs->Line, visible);
subs->Line.clear();
boost::push_back(subs->Line, full | boost::adaptors::indirected);
} }
catch(...) { catch(...) {
std::swap(subs->Line, visible); subs->Line.clear();
boost::push_back(subs->Line, full | boost::adaptors::indirected);
throw; throw;
} }
} }

View file

@ -138,8 +138,7 @@ void SetClipboard(wxBitmap const& new_value);
/// Polymorphic delete functor /// Polymorphic delete functor
struct delete_ptr { struct delete_ptr {
template<class T> template<class T> void operator()(T* ptr) const {
void operator()(T* ptr) const {
delete ptr; delete ptr;
} }
}; };
@ -158,7 +157,7 @@ template<class Container>
class BackgroundDeleter : public wxThread { class BackgroundDeleter : public wxThread {
Container cont; Container cont;
wxThread::ExitCode Entry() { wxThread::ExitCode Entry() {
delete_clear(cont); cont.clear_and_dispose(delete_ptr());
return (wxThread::ExitCode)0; return (wxThread::ExitCode)0;
} }
public: public:
@ -186,7 +185,12 @@ void background_delete_clear(T& container) {
template<class Out> template<class Out>
struct cast { struct cast {
template<class In> template<class In>
Out operator()(In in) const { Out operator()(In *in) const {
return dynamic_cast<Out>(in); return dynamic_cast<Out>(in);
} }
template<class In>
Out operator()(In &in) const {
return dynamic_cast<Out>(&in);
}
}; };

View file

@ -116,7 +116,7 @@ void VisualToolDrag::OnFileChanged() {
active_feature = features.end(); active_feature = features.end();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (diag && IsDisplayed(diag)) if (diag && IsDisplayed(diag))
MakeFeatures(diag); MakeFeatures(diag);
} }
@ -132,7 +132,7 @@ void VisualToolDrag::OnFrameChanged() {
feature_iterator end = features.end(); feature_iterator end = features.end();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) { for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it); AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (!diag) continue; if (!diag) continue;
if (IsDisplayed(diag)) { if (IsDisplayed(diag)) {