Split AssFile into separate lists for each section

This commit is contained in:
Thomas Goyne 2014-03-07 09:02:24 -08:00
parent 222b6ee099
commit 805481315e
45 changed files with 288 additions and 341 deletions

View file

@ -42,78 +42,55 @@
#include "options.h"
#include "utils.h"
#include <libaegisub/dispatch.h>
#include <libaegisub/of_type_adaptor.h>
#include <algorithm>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/filesystem/path.hpp>
namespace std {
template<>
void swap(AssFile &lft, AssFile &rgt) {
lft.swap(rgt);
}
}
AssFile::~AssFile() {
auto copy = new EntryList;
copy->swap(Line);
agi::dispatch::Background().Async([=]{
copy->clear_and_dispose([](AssEntry *e) { delete e; });
delete copy;
});
Info.clear_and_dispose([](AssEntry *e) { delete e; });
Styles.clear_and_dispose([](AssEntry *e) { delete e; });
Events.clear_and_dispose([](AssEntry *e) { delete e; });
Attachments.clear_and_dispose([](AssEntry *e) { delete e; });
}
void AssFile::LoadDefault(bool defline) {
Line.push_back(*new AssInfo("Title", "Default Aegisub file"));
Line.push_back(*new AssInfo("ScriptType", "v4.00+"));
Line.push_back(*new AssInfo("WrapStyle", "0"));
Line.push_back(*new AssInfo("ScaledBorderAndShadow", "yes"));
Info.push_back(*new AssInfo("Title", "Default Aegisub file"));
Info.push_back(*new AssInfo("ScriptType", "v4.00+"));
Info.push_back(*new AssInfo("WrapStyle", "0"));
Info.push_back(*new AssInfo("ScaledBorderAndShadow", "yes"));
if (!OPT_GET("Subtitle/Default Resolution/Auto")->GetBool()) {
Line.push_back(*new AssInfo("PlayResX", std::to_string(OPT_GET("Subtitle/Default Resolution/Width")->GetInt())));
Line.push_back(*new AssInfo("PlayResY", std::to_string(OPT_GET("Subtitle/Default Resolution/Height")->GetInt())));
Info.push_back(*new AssInfo("PlayResX", std::to_string(OPT_GET("Subtitle/Default Resolution/Width")->GetInt())));
Info.push_back(*new AssInfo("PlayResY", std::to_string(OPT_GET("Subtitle/Default Resolution/Height")->GetInt())));
}
Line.push_back(*new AssInfo("YCbCr Matrix", "None"));
Info.push_back(*new AssInfo("YCbCr Matrix", "None"));
Line.push_back(*new AssStyle);
Styles.push_back(*new AssStyle);
if (defline)
Line.push_back(*new AssDialogue);
}
void AssFile::swap(AssFile &that) throw() {
Line.swap(that.Line);
Events.push_back(*new AssDialogue);
}
AssFile::AssFile(const AssFile &from) {
Line.clone_from(from.Line, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
Info.clone_from(from.Info, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
Styles.clone_from(from.Styles, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
Events.clone_from(from.Events, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
Attachments.clone_from(from.Attachments, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
}
void AssFile::swap(AssFile& from) throw() {
Info.swap(from.Info);
Styles.swap(from.Styles);
Events.swap(from.Events);
Attachments.swap(from.Attachments);
}
AssFile& AssFile::operator=(AssFile from) {
std::swap(*this, from);
swap(from);
return *this;
}
void AssFile::InsertLine(AssEntry *entry) {
if (Line.empty()) {
Line.push_back(*entry);
return;
}
// Search for insertion point
entryIter it = Line.end();
do {
--it;
if (it->Group() <= entry->Group()) {
Line.insert(++it, *entry);
return;
}
} while (it != Line.begin());
Line.push_front(*entry);
}
void AssFile::InsertAttachment(agi::fs::path const& filename) {
AssEntryGroup group = AssEntryGroup::GRAPHIC;
@ -121,11 +98,11 @@ void AssFile::InsertAttachment(agi::fs::path const& filename) {
if (ext == ".ttf" || ext == ".ttc" || ext == ".pfb")
group = AssEntryGroup::FONT;
InsertLine(new AssAttachment(filename, group));
Attachments.push_back(*new AssAttachment(filename, group));
}
std::string AssFile::GetScriptInfo(std::string const& key) const {
for (const auto info : Line | agi::of_type<AssInfo>()) {
for (const auto info : Info | agi::of_type<AssInfo>()) {
if (boost::iequals(key, info->Key()))
return info->Value();
}
@ -154,7 +131,7 @@ void AssFile::SaveUIState(std::string const& key, std::string const& value) {
}
void AssFile::SetScriptInfo(std::string const& key, std::string const& value) {
for (auto info : Line | agi::of_type<AssInfo>()) {
for (auto info : Info | agi::of_type<AssInfo>()) {
if (boost::iequals(key, info->Key())) {
if (value.empty())
delete info;
@ -165,7 +142,7 @@ void AssFile::SetScriptInfo(std::string const& key, std::string const& value) {
}
if (!value.empty())
InsertLine(new AssInfo(key, value));
Info.push_back(*new AssInfo(key, value));
}
void AssFile::GetResolution(int &sw,int &sh) const {
@ -192,13 +169,13 @@ void AssFile::GetResolution(int &sw,int &sh) const {
std::vector<std::string> AssFile::GetStyles() const {
std::vector<std::string> styles;
for (auto style : Line | agi::of_type<AssStyle>())
for (auto style : Styles | agi::of_type<AssStyle>())
styles.push_back(style->name);
return styles;
}
AssStyle *AssFile::GetStyle(std::string const& name) {
for (auto style : Line | agi::of_type<AssStyle>()) {
for (auto style : Styles | agi::of_type<AssStyle>()) {
if (boost::iequals(style->name, name))
return style;
}
@ -237,7 +214,7 @@ bool AssFile::CompLayer(const AssDialogue* lft, const AssDialogue* rgt) {
}
void AssFile::Sort(CompFunc comp, std::set<AssDialogue*> const& limit) {
Sort(Line, comp, limit);
Sort(Events, comp, limit);
}
namespace {
inline bool is_dialogue(AssEntry *e, std::set<AssDialogue*> const& limit) {

View file

@ -62,7 +62,10 @@ class AssFile {
agi::signal::Signal<AssFileCommit> PushState;
public:
/// The lines in the file
EntryList Line;
EntryList Info;
EntryList Styles;
EntryList Events;
EntryList Attachments;
AssFile() { }
AssFile(const AssFile &from);
@ -72,8 +75,6 @@ public:
/// @brief Load default file
/// @param defline Add a blank line to the file
void LoadDefault(bool defline=true);
/// Add a line to the file at the end of the appropriate section
void InsertLine(AssEntry *line);
/// Attach a file to the ass file
void InsertAttachment(agi::fs::path const& filename);
/// Get the names of all of the styles available

View file

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

View file

@ -33,7 +33,6 @@ AssParser::AssParser(AssFile *target, int version)
, version(version)
, state(&AssParser::ParseScriptInfoLine)
{
std::fill(begin(insertion_positions), end(insertion_positions), nullptr);
}
AssParser::~AssParser() {
@ -52,7 +51,7 @@ void AssParser::ParseAttachmentLine(std::string const& data) {
// Data is over, add attachment to the file
if (!valid_data || is_filename) {
InsertLine(attach.release());
target->Attachments.push_back(*attach.release());
AddLine(data);
}
else {
@ -60,7 +59,7 @@ void AssParser::ParseAttachmentLine(std::string const& data) {
// Done building
if (data.size() < 80)
InsertLine(attach.release());
target->Attachments.push_back(*attach.release());
}
}
@ -91,17 +90,17 @@ void AssParser::ParseScriptInfoLine(std::string const& data) {
size_t pos = data.find(':');
if (pos == data.npos) return;
InsertLine(new AssInfo(data.substr(0, pos), boost::trim_left_copy(data.substr(pos + 1))));
target->Info.push_back(*new AssInfo(data.substr(0, pos), boost::trim_left_copy(data.substr(pos + 1))));
}
void AssParser::ParseEventLine(std::string const& data) {
if (boost::starts_with(data, "Dialogue:") || boost::starts_with(data, "Comment:"))
InsertLine(new AssDialogue(data));
target->Events.push_back(*new AssDialogue(data));
}
void AssParser::ParseStyleLine(std::string const& data) {
if (boost::starts_with(data, "Style:"))
InsertLine(new AssStyle(data, version));
target->Styles.push_back(*new AssStyle(data, version));
}
void AssParser::ParseFontLine(std::string const& data) {
@ -152,12 +151,3 @@ void AssParser::AddLine(std::string const& data) {
(this->*state)(data);
}
void AssParser::InsertLine(AssEntry *entry) {
AssEntry *position = insertion_positions[(size_t)entry->Group()];
if (position)
target->Line.insert(++target->Line.iterator_to(*position), *entry);
else
target->Line.push_back(*entry);
insertion_positions[(size_t)entry->Group()] = entry;
}

View file

@ -16,8 +16,6 @@
#include <map>
#include <memory>
#include "ass_entry.h"
class AssAttachment;
class AssFile;
@ -26,9 +24,6 @@ class AssParser {
int version;
std::unique_ptr<AssAttachment> attach;
void (AssParser::*state)(std::string const&);
std::array<AssEntry*, (size_t)AssEntryGroup::GROUP_MAX> insertion_positions;
void InsertLine(AssEntry *entry);
void ParseAttachmentLine(std::string const& data);
void ParseEventLine(std::string const& data);

View file

@ -742,20 +742,20 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
case 2: // Previous and next lines
if (AssDialogue *line = context->selectionController->GetActiveLine())
{
entryIter current_line = context->ass->Line.iterator_to(*line);
if (current_line == context->ass->Line.end())
entryIter current_line = context->ass->Events.iterator_to(*line);
if (current_line == context->ass->Events.end())
break;
entryIter prev = current_line;
while (--prev != context->ass->Line.begin() && !predicate(*prev)) ;
if (prev != context->ass->Line.begin())
while (--prev != context->ass->Events.begin() && !predicate(*prev)) ;
if (prev != context->ass->Events.begin())
AddInactiveLine(sel, static_cast<AssDialogue*>(&*prev));
if (mode == 2)
{
entryIter next =
find_if(++current_line, context->ass->Line.end(), predicate);
if (next != context->ass->Line.end())
find_if(++current_line, context->ass->Events.end(), predicate);
if (next != context->ass->Events.end())
AddInactiveLine(sel, static_cast<AssDialogue*>(&*next));
}
}
@ -763,7 +763,7 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
case 3: // All inactive lines
{
AssDialogue *active_line = context->selectionController->GetActiveLine();
for (auto& line : context->ass->Line)
for (auto& line : context->ass->Events)
{
if (&line != active_line && predicate(line))
AddInactiveLine(sel, static_cast<AssDialogue*>(&line));

View file

@ -37,6 +37,7 @@
#include "auto4_lua.h"
#include "auto4_lua_utils.h"
#include "ass_attachment.h"
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_style.h"
@ -838,13 +839,11 @@ namespace Automation4 {
lua_newtable(L);
int active_idx = -1;
int row = 0;
int row = c->ass->Info.size() + c->ass->Styles.size();
int idx = 1;
for (auto& line : c->ass->Line) {
for (auto& line : c->ass->Events) {
++row;
AssDialogue *diag = dynamic_cast<AssDialogue*>(&line);
if (!diag) continue;
auto diag = static_cast<AssDialogue*>(&line);
if (diag == active_line) active_idx = row;
if (sel.count(diag)) {
push_value(L, row);
@ -901,7 +900,7 @@ namespace Automation4 {
try {
LuaThreadedCall(L, 3, 2, from_wx(StrDisplay(c)), c->parent, true);
subsobj->ProcessingComplete(StrDisplay(c));
auto lines = subsobj->ProcessingComplete(StrDisplay(c));
AssDialogue *active_line = nullptr;
int active_idx = 0;
@ -909,8 +908,8 @@ namespace Automation4 {
// Check for a new active row
if (lua_isnumber(L, -1)) {
active_idx = lua_tointeger(L, -1);
if (active_idx < 1 || active_idx > (int)c->ass->Line.size()) {
wxLogError("Active row %d is out of bounds (must be 1-%u)", active_idx, c->ass->Line.size());
if (active_idx < 1 || active_idx > (int)lines.size()) {
wxLogError("Active row %d is out of bounds (must be 1-%u)", active_idx, lines.size());
active_idx = 0;
}
}
@ -921,26 +920,21 @@ namespace Automation4 {
// top of stack will be selected lines array, if any was returned
if (lua_istable(L, -1)) {
std::set<AssDialogue*> sel;
entryIter it = c->ass->Line.begin();
int last_idx = 1;
lua_for_each(L, [&] {
if (lua_isnumber(L, -1)) {
int cur = lua_tointeger(L, -1);
if (cur < 1 || cur > (int)c->ass->Line.size()) {
wxLogError("Selected row %d is out of bounds (must be 1-%u)", cur, c->ass->Line.size());
if (cur < 1 || cur > (int)lines.size()) {
wxLogError("Selected row %d is out of bounds (must be 1-%u)", cur, lines.size());
throw LuaForEachBreak();
}
advance(it, cur - last_idx);
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
AssDialogue *diag = dynamic_cast<AssDialogue*>(lines[cur - 1]);
if (!diag) {
wxLogError("Selected row %d is not a dialogue line", cur);
throw LuaForEachBreak();
}
sel.insert(diag);
last_idx = cur;
if (!active_line || active_idx == cur)
active_line = diag;
}

View file

@ -115,7 +115,7 @@ namespace Automation4 {
/// @param set_undo If there's any uncommitted changes to the file,
/// they will be automatically committed with this
/// description
void ProcessingComplete(wxString const& undo_description = wxString());
std::vector<AssEntry *> ProcessingComplete(wxString const& undo_description = wxString());
/// End processing without applying any changes made
void Cancel();

View file

@ -121,9 +121,7 @@ namespace {
{
case AssEntryGroup::DIALOGUE: return AssFile::COMMIT_DIAG_ADDREM;
case AssEntryGroup::STYLE: return AssFile::COMMIT_STYLES;
case AssEntryGroup::FONT: return AssFile::COMMIT_ATTACHMENT;
case AssEntryGroup::GRAPHIC: return AssFile::COMMIT_ATTACHMENT;
default: return AssFile::COMMIT_SCRIPTINFO;
default: return AssFile::COMMIT_SCRIPTINFO;
}
}
}
@ -217,8 +215,7 @@ namespace Automation4 {
set_field(L, "class", "style");
}
else {
// Attachments
set_field(L, "class", "unknown");
assert(false);
}
}
@ -593,27 +590,40 @@ namespace Automation4 {
return *((LuaAssFile**)ud);
}
void LuaAssFile::ProcessingComplete(wxString const& undo_description)
std::vector<AssEntry *> LuaAssFile::ProcessingComplete(wxString const& undo_description)
{
auto apply_lines = [&](std::vector<AssEntry *> const& lines) {
ass->Info.clear();
ass->Styles.clear();
ass->Events.clear();
for (auto line : lines) {
switch (line->Group()) {
case AssEntryGroup::INFO: ass->Info.push_back(*static_cast<AssInfo *>(line)); break;
case AssEntryGroup::STYLE: ass->Styles.push_back(*static_cast<AssStyle *>(line)); break;
case AssEntryGroup::DIALOGUE: ass->Events.push_back(*static_cast<AssDialogue *>(line)); break;
default: break;
}
}
};
// Apply any pending commits
for (auto const& pc : pending_commits) {
ass->Line.clear();
boost::push_back(ass->Line, pc.lines | boost::adaptors::indirected);
apply_lines(pc.lines);
ass->Commit(pc.mesage, pc.modification_type);
}
// Commit any changes after the last undo point was set
if (modification_type) {
ass->Line.clear();
boost::push_back(ass->Line, lines | boost::adaptors::indirected);
}
if (modification_type)
apply_lines(lines);
if (modification_type && can_set_undo && !undo_description.empty())
ass->Commit(undo_description, modification_type);
lines_to_delete.clear();
auto ret = std::move(lines);
references--;
if (!references) delete this;
return ret;
}
void LuaAssFile::Cancel()
@ -631,7 +641,11 @@ namespace Automation4 {
, modification_type(0)
, references(2)
{
for (auto& line : ass->Line)
for (auto& line : ass->Info)
lines.push_back(&line);
for (auto& line : ass->Styles)
lines.push_back(&line);
for (auto& line : ass->Events)
lines.push_back(&line);
// prepare userdata object

View file

@ -265,7 +265,7 @@ void BaseGrid::UpdateMaps() {
index_line_map.clear();
line_index_map.clear();
for (auto curdiag : context->ass->Line | agi::of_type<AssDialogue>()) {
for (auto curdiag : context->ass->Events | agi::of_type<AssDialogue>()) {
line_index_map[curdiag] = (int)index_line_map.size();
index_line_map.push_back(curdiag);
}

View file

@ -488,7 +488,7 @@ struct edit_find_replace : public Command {
static std::string get_entry_data(AssDialogue *d) { return d->GetEntryData(); }
static void copy_lines(agi::Context *c) {
SubtitleSelection sel = c->selectionController->GetSelectedSet();
SetClipboard(join(c->ass->Line
SetClipboard(join(c->ass->Events
| agi::of_type<AssDialogue>()
| filtered([&](AssDialogue *d) { return sel.count(d); })
| transformed(get_entry_data),
@ -503,7 +503,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
AssDialogue *post_sel = nullptr;
bool hit_selection = false;
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
if (sel.count(diag))
hit_selection = true;
else if (hit_selection && !post_sel) {
@ -519,7 +519,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
// need to create a new dialogue line for it, and we can't select dialogue
// lines until after they're committed.
std::vector<std::unique_ptr<AssEntry>> to_delete;
c->ass->Line.remove_and_dispose_if([&sel](AssEntry const& e) {
c->ass->Events.remove_and_dispose_if([&sel](AssEntry const& e) {
return sel.count(const_cast<AssDialogue *>(static_cast<const AssDialogue*>(&e)));
}, [&](AssEntry *e) {
to_delete.emplace_back(e);
@ -532,7 +532,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
// lines, so make a new one
if (!new_active) {
new_active = new AssDialogue;
c->ass->InsertLine(new_active);
c->ass->Events.push_back(*new_active);
}
c->ass->Commit(commit_message, AssFile::COMMIT_DIAG_ADDREM);
@ -605,8 +605,8 @@ static void duplicate_lines(agi::Context *c, int shift) {
SubtitleSelectionController::Selection new_sel;
AssDialogue *new_active = nullptr;
entryIter start = c->ass->Line.begin();
entryIter end = c->ass->Line.end();
entryIter start = c->ass->Events.begin();
entryIter end = c->ass->Events.end();
while (start != end) {
// Find the first line in the selection
start = find_if(start, end, sel);
@ -622,7 +622,7 @@ static void duplicate_lines(agi::Context *c, int shift) {
auto old_diag = static_cast<AssDialogue*>(&*start);
auto new_diag = new AssDialogue(*old_diag);
c->ass->Line.insert(insert_pos, *new_diag);
c->ass->Events.insert(insert_pos, *new_diag);
new_sel.insert(new_diag);
if (!new_active)
new_active = new_diag;
@ -703,7 +703,7 @@ static void combine_lines(agi::Context *c, void (*combiner)(AssDialogue *, AssDi
SubtitleSelection sel = c->selectionController->GetSelectedSet();
AssDialogue *first = nullptr;
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ) {
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it++);
if (!diag || !sel.count(diag))
continue;
@ -790,8 +790,8 @@ static bool try_paste_lines(agi::Context *c) {
for (auto& line : parsed)
new_selection.insert(static_cast<AssDialogue *>(&line));
auto pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
c->ass->Line.splice(pos, parsed, parsed.begin(), parsed.end());
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
c->ass->Events.splice(pos, parsed, parsed.begin(), parsed.end());
c->ass->Commit(_("paste"), AssFile::COMMIT_DIAG_ADDREM);
c->selectionController->SetSelectionAndActive(new_selection, new_active);
@ -821,9 +821,9 @@ struct edit_line_paste : public Command {
ctrl->Paste();
}
else {
auto pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
paste_lines(c, false, [=](AssDialogue *new_line) -> AssDialogue * {
c->ass->Line.insert(pos, *new_line);
c->ass->Events.insert(pos, *new_line);
return new_line;
});
}
@ -852,15 +852,15 @@ struct edit_line_paste_over : public Command {
// Only one line selected, so paste over downwards from the active line
if (sel.size() < 2) {
auto pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
paste_lines(c, true, [&](AssDialogue *new_line) -> AssDialogue * {
std::unique_ptr<AssDialogue> deleter(new_line);
if (pos == c->ass->Line.end()) return nullptr;
if (pos == c->ass->Events.end()) return nullptr;
AssDialogue *ret = paste_over(c->parent, pasteOverOptions, new_line, static_cast<AssDialogue*>(&*pos));
if (ret)
pos = find_if(next(pos), c->ass->Line.end(), cast<AssDialogue*>());
pos = find_if(next(pos), c->ass->Events.end(), cast<AssDialogue*>());
return ret;
});
}
@ -870,7 +870,7 @@ struct edit_line_paste_over : public Command {
// Sort the selection by grid order
std::vector<AssDialogue*> sorted_selection;
sorted_selection.reserve(sel.size());
for (auto& line : c->ass->Line) {
for (auto& line : c->ass->Events) {
if (sel.count(static_cast<AssDialogue*>(&line)))
sorted_selection.push_back(static_cast<AssDialogue*>(&line));
}
@ -983,7 +983,7 @@ struct edit_line_recombine : public validate_sel_multiple {
// Remove now non-existent lines from the selection
SubtitleSelection lines, new_sel;
boost::copy(c->ass->Line | agi::of_type<AssDialogue>(), inserter(lines, lines.begin()));
boost::copy(c->ass->Events | agi::of_type<AssDialogue>(), inserter(lines, lines.begin()));
boost::set_intersection(lines, sel_set, inserter(new_sel, new_sel.begin()));
if (new_sel.empty())
@ -1015,7 +1015,7 @@ void split_lines(agi::Context *c, Func&& set_time) {
AssDialogue *n1 = c->selectionController->GetActiveLine();
auto n2 = new AssDialogue(*n1);
c->ass->Line.insert(++c->ass->Line.iterator_to(*n1), *n2);
c->ass->Events.insert(++c->ass->Events.iterator_to(*n1), *n2);
std::string orig = n1->Text;
n1->Text = boost::trim_right_copy(orig.substr(0, pos));

View file

@ -79,8 +79,8 @@ struct grid_line_next_create : public Command {
newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt();
newline->Style = cur->Style;
entryIter pos = c->ass->Line.iterator_to(*cur);
c->ass->Line.insert(++pos, *newline);
entryIter pos = c->ass->Events.iterator_to(*cur);
c->ass->Events.insert(++pos, *newline);
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
c->selectionController->NextLine();
}
@ -356,7 +356,7 @@ struct grid_move_up : public Command {
}
void operator()(agi::Context *c) override {
if (move_one(c->ass->Line.begin(), c->ass->Line.end(), c->selectionController->GetSelectedSet(), 1))
if (move_one(c->ass->Events.begin(), c->ass->Events.end(), c->selectionController->GetSelectedSet(), 1))
c->ass->Commit(_("move lines"), AssFile::COMMIT_ORDER);
}
};
@ -373,7 +373,7 @@ struct grid_move_down : public Command {
}
void operator()(agi::Context *c) override {
if (move_one(--c->ass->Line.end(), c->ass->Line.begin(), c->selectionController->GetSelectedSet(), -1))
if (move_one(--c->ass->Events.end(), c->ass->Events.begin(), c->selectionController->GetSelectedSet(), -1))
c->ass->Commit(_("move lines"), AssFile::COMMIT_ORDER);
}
};

View file

@ -54,6 +54,7 @@
#include "../video_context.h"
#include <libaegisub/charset_conv.h>
#include <libaegisub/of_type_adaptor.h>
#include <libaegisub/util.h>
#include <wx/msgdlg.h>
@ -123,10 +124,10 @@ static void insert_subtitle_at_video(agi::Context *c, bool after) {
def->End = video_ms + OPT_GET("Timing/Default Duration")->GetInt();
def->Style = c->selectionController->GetActiveLine()->Style;
entryIter pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
entryIter pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
if (after) ++pos;
c->ass->Line.insert(pos, *def);
c->ass->Events.insert(pos, *def);
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
c->selectionController->SetSelectionAndActive({ def }, def);
@ -146,17 +147,17 @@ struct subtitle_insert_after : public validate_nonempty_selection {
new_line->Start = active_line->End;
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) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) {
AssDialogue *diag = static_cast<AssDialogue*>(&*it);
// Limit the line to the available time
if (diag && diag->Start >= new_line->Start)
if (diag->Start >= new_line->Start)
new_line->End = std::min(new_line->End, diag->Start);
// If we just hit the active line, insert the new line after it
if (diag == active_line) {
++it;
c->ass->Line.insert(it, *new_line);
c->ass->Events.insert(it, *new_line);
--it;
}
}
@ -191,16 +192,16 @@ struct subtitle_insert_before : public validate_nonempty_selection {
new_line->End = active_line->Start;
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) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) {
auto diag = static_cast<AssDialogue*>(&*it);
// Limit the line to the available time
if (diag && diag->End <= new_line->End)
if (diag->End <= new_line->End)
new_line->Start = std::max(new_line->Start, diag->End);
// If we just hit the active line, insert the new line before it
if (diag == active_line)
c->ass->Line.insert(it, *new_line);
c->ass->Events.insert(it, *new_line);
}
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
@ -371,7 +372,7 @@ struct subtitle_select_all : public Command {
void operator()(agi::Context *c) override {
SubtitleSelection sel;
transform(c->ass->Line.begin(), c->ass->Line.end(),
transform(c->ass->Events.begin(), c->ass->Events.end(),
inserter(sel, sel.begin()), cast<AssDialogue*>());
sel.erase(nullptr);
c->selectionController->SetSelectedSet(sel);
@ -393,10 +394,8 @@ struct subtitle_select_visible : public Command {
SubtitleSelectionController::Selection new_selection;
int frame = c->videoController->GetFrameN();
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
if (diag &&
c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame &&
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
if (c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame &&
c->videoController->FrameAtTime(diag->End, agi::vfr::END) >= frame)
{
if (new_selection.empty())

View file

@ -67,7 +67,7 @@ namespace {
if (sel.size() < 2) return !sel.empty();
size_t found = 0;
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
if (sel.count(diag)) {
if (++found == sel.size())
return true;
@ -84,7 +84,7 @@ static void adjoin_lines(agi::Context *c, bool set_start) {
AssDialogue *prev = nullptr;
size_t seen = 0;
bool prev_sel = false;
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
bool cur_sel = !!sel.count(diag);
if (prev) {
// One row selections act as if the previous or next line was selected

View file

@ -99,7 +99,7 @@ void DialogAttachments::UpdateList() {
listView->InsertColumn(1, _("Size"), wxLIST_FORMAT_LEFT, 100);
listView->InsertColumn(2, _("Group"), wxLIST_FORMAT_LEFT, 100);
for (auto attach : ass->Line | agi::of_type<AssAttachment>()) {
for (auto attach : ass->Attachments | agi::of_type<AssAttachment>()) {
int row = listView->GetItemCount();
listView->InsertItem(row, to_wx(attach->GetFileName(true)));
listView->SetItem(row, 1, PrettySize(attach->GetSize()));

View file

@ -557,8 +557,8 @@ void DialogKanjiTimer::OnStart(wxCommandEvent &) {
else if (SourceStyle->GetValue() == DestStyle->GetValue())
wxMessageBox(_("The source and destination styles must be different."),_("Error"),wxICON_EXCLAMATION | wxOK);
else {
currentSourceLine = FindNextStyleMatch(&*subs->Line.begin(), from_wx(SourceStyle->GetValue()));
currentDestinationLine = FindNextStyleMatch(&*subs->Line.begin(), from_wx(DestStyle->GetValue()));
currentSourceLine = FindNextStyleMatch(&*subs->Events.begin(), from_wx(SourceStyle->GetValue()));
currentDestinationLine = FindNextStyleMatch(&*subs->Events.begin(), from_wx(DestStyle->GetValue()));
ResetForNewLine();
}
LinesToChange.clear();
@ -686,11 +686,11 @@ static AssEntry *find_next(Iterator from, Iterator to, std::string const& style_
AssEntry *DialogKanjiTimer::FindNextStyleMatch(AssEntry *search_from, const std::string &search_style)
{
if (!search_from) return search_from;
return find_next(++subs->Line.iterator_to(*search_from), subs->Line.end(), search_style);
return find_next(++subs->Events.iterator_to(*search_from), subs->Events.end(), search_style);
}
AssEntry *DialogKanjiTimer::FindPrevStyleMatch(AssEntry *search_from, const std::string &search_style)
{
if (!search_from) return search_from;
return find_next(EntryList::reverse_iterator(subs->Line.iterator_to(*search_from)), subs->Line.rend(), search_style);
return find_next(EntryList::reverse_iterator(subs->Events.iterator_to(*search_from)), subs->Events.rend(), search_style);
}

View file

@ -77,7 +77,7 @@ static std::set<AssDialogue*> process(std::string const& match_text, bool match_
auto predicate = SearchReplaceEngine::GetMatcher(settings);
std::set<AssDialogue*> matches;
for (auto diag : ass->Line | agi::of_type<AssDialogue>()) {
for (auto diag : ass->Events | agi::of_type<AssDialogue>()) {
if (diag->Comment && !comments) continue;
if (!diag->Comment && !dialogue) continue;

View file

@ -354,7 +354,7 @@ void DialogShiftTimes::Process(wxCommandEvent &) {
int block_start = 0;
json::Array shifted_blocks;
for (auto line : context->ass->Line | agi::of_type<AssDialogue>()) {
for (auto line : context->ass->Events | agi::of_type<AssDialogue>()) {
++row_number;
if (!sel.count(line)) {

View file

@ -212,7 +212,7 @@ bool DialogSpellChecker::FindNext() {
if (CheckLine(active_line, start_pos, &commit_id))
return true;
entryIter it = context->ass->Line.iterator_to(*active_line);
entryIter it = context->ass->Events.iterator_to(*active_line);
// 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
@ -220,8 +220,8 @@ bool DialogSpellChecker::FindNext() {
while(!has_looped || active_line != start_line) {
do {
// Wrap around to the beginning if we hit the end
if (++it == context->ass->Line.end()) {
it = context->ass->Line.begin();
if (++it == context->ass->Events.end()) {
it = context->ass->Events.begin();
has_looped = true;
}
} while (!(active_line = dynamic_cast<AssDialogue*>(&*it)));

View file

@ -86,7 +86,7 @@ class StyleRenamer {
found_any = false;
do_replace = replace;
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
if (diag->Style == source_name) {
if (replace)
diag->Style = new_name;
@ -437,7 +437,7 @@ void DialogStyleEditor::Apply(bool apply, bool close) {
if (store)
store->push_back(std::unique_ptr<AssStyle>(style));
else
c->ass->InsertLine(style);
c->ass->Styles.push_back(*style);
is_new = false;
}
if (!store)

View file

@ -288,7 +288,7 @@ void DialogStyleManager::LoadCurrentStyles(int commit_type) {
CurrentList->Clear();
styleMap.clear();
for (auto style : c->ass->Line | agi::of_type<AssStyle>()) {
for (auto style : c->ass->Styles | agi::of_type<AssStyle>()) {
CurrentList->Append(to_wx(style->name));
styleMap.push_back(style);
}
@ -448,7 +448,7 @@ void DialogStyleManager::OnCopyToCurrent() {
}
}
else {
c->ass->InsertLine(new AssStyle(*Store[selections[i]]));
c->ass->Styles.push_back(*new AssStyle(*Store[selections[i]]));
copied.push_back(styleName);
}
}
@ -480,7 +480,7 @@ void DialogStyleManager::CopyToClipboard(wxListBox *list, T const& v) {
void DialogStyleManager::PasteToCurrent() {
add_styles(
std::bind(&AssFile::GetStyle, c->ass, _1),
std::bind(&AssFile::InsertLine, c->ass, _1));
[=](AssStyle *s) { c->ass->Styles.push_back(*s); });
c->ass->Commit(_("style paste"), AssFile::COMMIT_STYLES);
}
@ -630,7 +630,7 @@ void DialogStyleManager::OnCurrentImport() {
// Copy
modified = true;
c->ass->InsertLine(temp.GetStyle(styles[sel])->Clone());
c->ass->Styles.push_back(*temp.GetStyle(styles[sel])->Clone());
}
// Update
@ -779,10 +779,10 @@ void DialogStyleManager::MoveStyles(bool storage, int type) {
// Replace styles
size_t curn = 0;
for (auto it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
for (auto it = c->ass->Styles.begin(); it != c->ass->Styles.end(); ++it) {
if (!dynamic_cast<AssStyle*>(&*it)) continue;
auto new_style_at_pos = c->ass->Line.iterator_to(*styleMap[curn]);
auto new_style_at_pos = c->ass->Styles.iterator_to(*styleMap[curn]);
EntryList::node_algorithms::swap_nodes(it.pointed_node(), new_style_at_pos.pointed_node());
if (++curn == styleMap.size()) break;
it = new_style_at_pos;

View file

@ -307,14 +307,14 @@ std::vector<AssDialogue*> DialogTimingProcessor::SortDialogues() {
[&](AssDialogue *d) { return !d->Comment && styles.count(d->Style); });
}
else {
transform(c->ass->Line.begin(), c->ass->Line.end(), back_inserter(sorted), cast<AssDialogue*>());
transform(c->ass->Events.begin(), c->ass->Events.end(), back_inserter(sorted), cast<AssDialogue*>());
sorted.erase(boost::remove_if(sorted, bind(bad_line, &styles, _1)), sorted.end());
}
// Check if rows are valid
for (auto diag : sorted) {
if (diag->Start > diag->End) {
int line = count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*diag), cast<const AssDialogue*>());
int line = distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*diag));
wxMessageBox(
wxString::Format(_("One of the lines in the file (%i) has negative duration. Aborting."), line),
_("Invalid script"),

View file

@ -66,8 +66,8 @@ DialogTranslation::DialogTranslation(agi::Context *c)
, file_change_connection(c->ass->AddCommitListener(&DialogTranslation::OnExternalCommit, this))
, active_line_connection(c->selectionController->AddActiveLineListener(&DialogTranslation::OnActiveLineChanged, this))
, active_line(c->selectionController->GetActiveLine())
, line_count(count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>()))
, line_number(count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*active_line), cast<AssDialogue*>()) + 1)
, line_count(c->ass->Events.size())
, line_number(distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*active_line)) + 1)
{
SetIcon(GETICON(translation_toolbutton_16));
@ -175,7 +175,7 @@ void DialogTranslation::OnActiveLineChanged(AssDialogue *new_line) {
active_line = new_line;
blocks = active_line->ParseTags();
cur_block = 0;
line_number = count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*new_line), cast<AssDialogue*>()) + 1;
line_number = distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*new_line)) + 1;
if (bad_block(blocks[cur_block]) && !NextBlock()) {
wxMessageBox(_("No more lines to translate."));
@ -185,7 +185,7 @@ void DialogTranslation::OnActiveLineChanged(AssDialogue *new_line) {
void DialogTranslation::OnExternalCommit(int commit_type) {
if (commit_type == AssFile::COMMIT_NEW || commit_type & AssFile::COMMIT_DIAG_ADDREM) {
line_count = count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>());
line_count = c->ass->Events.size();
line_number_display->SetLabel(wxString::Format(_("Current line: %d/%d"), (int)line_number, (int)line_count));
}

View file

@ -57,7 +57,7 @@ void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *) {
for_each(begin(styles), end(styles), [](std::string& str) { boost::to_lower(str); });
sort(begin(styles), end(styles));
for (auto diag : subs->Line | agi::of_type<AssDialogue>()) {
for (auto diag : subs->Events | agi::of_type<AssDialogue>()) {
if (!binary_search(begin(styles), end(styles), boost::to_lower_copy(diag->Style.get())))
diag->Style = "Default";
}

View file

@ -201,7 +201,7 @@ void AssTransformFramerateFilter::TransformTimeTags(std::string const& name, Ass
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
if (!Input->IsLoaded() || !Output->IsLoaded()) return;
for (auto curDialogue : subs->Line | agi::of_type<AssDialogue>()) {
for (auto curDialogue : subs->Events | agi::of_type<AssDialogue>()) {
line = curDialogue;
newK = 0;
oldK = 0;

View file

@ -182,7 +182,7 @@ std::vector<agi::fs::path> FontCollector::GetFontPaths(const AssFile *file) {
status_callback(_("Parsing file\n"), 0);
for (auto style : file->Line | agi::of_type<const AssStyle>()) {
for (auto style : file->Styles | agi::of_type<const AssStyle>()) {
StyleInfo &info = styles[style->name];
info.facename = style->font;
info.bold = style->bold;
@ -191,7 +191,7 @@ std::vector<agi::fs::path> FontCollector::GetFontPaths(const AssFile *file) {
}
int index = 0;
for (auto diag : file->Line | agi::of_type<const AssDialogue>())
for (auto diag : file->Events | agi::of_type<const AssDialogue>())
ProcessDialogueLine(diag, ++index);
status_callback(_("Searching for font files\n"), 0);

View file

@ -172,7 +172,9 @@ void ResampleResolution(AssFile *ass, ResampleSettings const& settings) {
if (settings.change_ar)
state.ar = state.rx / state.ry;
for (auto& line : ass->Line)
for (auto& line : ass->Styles)
resample_line(&