Add a checked iterator_to() to AssFile

iterator_to requires that the object be in the list, which is sometimes
not the case when processing a commit which removed the active line or a
selected line. To handle this, add a checked version that returns
Events.end() when it is not in the list rather than crashing.
This commit is contained in:
Thomas Goyne 2014-04-04 08:11:09 -07:00
parent 9c4574ed34
commit df762b5b99
13 changed files with 29 additions and 18 deletions

View File

@ -57,7 +57,10 @@ AssDialogue::AssDialogue() {
Id = ++next_id;
}
AssDialogue::AssDialogue(AssDialogue const& that) : AssDialogueBase(that) {
AssDialogue::AssDialogue(AssDialogue const& that)
: AssDialogueBase(that)
, AssEntryListHook(that)
{
Id = ++next_id;
}

View File

@ -77,6 +77,12 @@ AssFile& AssFile::operator=(AssFile from) {
return *this;
}
EntryList<AssDialogue>::iterator AssFile::iterator_to(AssDialogue& line) {
using l = EntryList<AssDialogue>;
bool in_list = !l::node_algorithms::inited(l::value_traits::to_node_ptr(line));
return in_list ? Events.iterator_to(line) : Events.end();
}
void AssFile::InsertAttachment(agi::fs::path const& filename) {
AssEntryGroup group = AssEntryGroup::GRAPHIC;

View File

@ -72,6 +72,8 @@ public:
AssFile& operator=(AssFile from);
~AssFile();
EntryList<AssDialogue>::iterator iterator_to(AssDialogue& line);
/// @brief Load default file
/// @param defline Add a blank line to the file
void LoadDefault(bool defline=true);

View File

@ -735,7 +735,7 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
case 2: // Previous and next lines
if (AssDialogue *line = context->selectionController->GetActiveLine())
{
auto current_line = context->ass->Events.iterator_to(*line);
auto current_line = context->ass->iterator_to(*line);
if (current_line == context->ass->Events.end())
break;

View File

@ -780,7 +780,7 @@ static bool try_paste_lines(agi::Context *c) {
for (auto& line : parsed)
new_selection.insert(&line);
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
auto pos = c->ass->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(std::move(new_selection), new_active);
@ -811,7 +811,7 @@ struct edit_line_paste final : public Command {
ctrl->Paste();
}
else {
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
auto pos = c->ass->iterator_to(*c->selectionController->GetActiveLine());
paste_lines(c, false, [=](AssDialogue *new_line) -> AssDialogue * {
c->ass->Events.insert(pos, *new_line);
return new_line;
@ -842,7 +842,7 @@ struct edit_line_paste_over final : public Command {
// Only one line selected, so paste over downwards from the active line
if (sel.size() < 2) {
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
auto pos = c->ass->iterator_to(*c->selectionController->GetActiveLine());
paste_lines(c, true, [&](AssDialogue *new_line) -> AssDialogue * {
std::unique_ptr<AssDialogue> deleter(new_line);
@ -1008,7 +1008,7 @@ void split_lines(agi::Context *c, Func&& set_time) {
AssDialogue *n1 = c->selectionController->GetActiveLine();
auto n2 = new AssDialogue(*n1);
c->ass->Events.insert(++c->ass->Events.iterator_to(*n1), *n2);
c->ass->Events.insert(++c->ass->iterator_to(*n1), *n2);
std::string orig = n1->Text;
n1->Text = boost::trim_right_copy(orig.substr(0, pos));

View File

@ -80,7 +80,7 @@ struct grid_line_next_create final : public Command {
newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt();
newline->Style = cur->Style;
auto pos = c->ass->Events.iterator_to(*cur);
auto pos = c->ass->iterator_to(*cur);
c->ass->Events.insert(++pos, *newline);
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
c->selectionController->NextLine();

View File

@ -124,7 +124,7 @@ 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;
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
auto pos = c->ass->iterator_to(*c->selectionController->GetActiveLine());
if (after) ++pos;
c->ass->Events.insert(pos, *def);

View File

@ -682,11 +682,11 @@ static AssDialogue *find_next(Iterator from, Iterator to, std::string const& sty
AssDialogue *DialogKanjiTimer::FindNextStyleMatch(AssDialogue *search_from, const std::string &search_style)
{
if (!search_from) return search_from;
return find_next(++subs->Events.iterator_to(*search_from), subs->Events.end(), search_style);
return find_next(++subs->iterator_to(*search_from), subs->Events.end(), search_style);
}
AssDialogue *DialogKanjiTimer::FindPrevStyleMatch(AssDialogue *search_from, const std::string &search_style)
{
if (!search_from) return search_from;
return find_next(EntryList<AssDialogue>::reverse_iterator(subs->Events.iterator_to(*search_from)), subs->Events.rend(), search_style);
return find_next(EntryList<AssDialogue>::reverse_iterator(subs->iterator_to(*search_from)), subs->Events.rend(), search_style);
}

View File

@ -212,7 +212,7 @@ bool DialogSpellChecker::FindNext() {
if (CheckLine(active_line, start_pos, &commit_id))
return true;
auto it = context->ass->Events.iterator_to(*active_line);
auto it = context->ass->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

View File

@ -311,7 +311,7 @@ std::vector<AssDialogue*> DialogTimingProcessor::SortDialogues() {
// Check if rows are valid
for (auto diag : sorted) {
if (diag->Start > diag->End) {
int line = std::distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*diag));
int line = std::distance(c->ass->Events.begin(), c->ass->iterator_to(*diag));
wxMessageBox(
wxString::Format(_("One of the lines in the file (%i) has negative duration. Aborting."), line),
_("Invalid script"),

View File

@ -67,7 +67,7 @@ DialogTranslation::DialogTranslation(agi::Context *c)
, active_line_connection(c->selectionController->AddActiveLineListener(&DialogTranslation::OnActiveLineChanged, this))
, active_line(c->selectionController->GetActiveLine())
, line_count(c->ass->Events.size())
, line_number(std::distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*active_line)) + 1)
, line_number(std::distance(c->ass->Events.begin(), c->ass->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 = std::distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*new_line)) + 1;
line_number = std::distance(c->ass->Events.begin(), c->ass->iterator_to(*new_line)) + 1;
if (bad_block(blocks[cur_block]) && !NextBlock()) {
wxMessageBox(_("No more lines to translate."));

View File

@ -229,7 +229,7 @@ bool SearchReplaceEngine::FindReplace(bool replace) {
auto matches = GetMatcher(settings);
AssDialogue *line = context->selectionController->GetActiveLine();
auto it = context->ass->Events.iterator_to(*line);
auto it = context->ass->iterator_to(*line);
size_t pos = 0;
MatchState replace_ms;

View File

@ -46,7 +46,7 @@ void SelectionController::OnSubtitlesOpen() {
void SelectionController::OnSubtitlesSave() {
if (active_line)
context->ass->SaveUIState("Active Line", std::to_string(std::distance(
context->ass->Events.begin(), context->ass->Events.iterator_to(*active_line))));
context->ass->Events.begin(), context->ass->iterator_to(*active_line))));
}
void SelectionController::SetSelectedSet(Selection new_selection) {
@ -68,7 +68,7 @@ void SelectionController::SetSelectionAndActive(Selection new_selection, AssDial
void SelectionController::PrevLine() {
if (!active_line) return;
auto it = context->ass->Events.iterator_to(*active_line);
auto it = context->ass->iterator_to(*active_line);
if (it != context->ass->Events.begin()) {
--it;
SetSelectionAndActive({&*it}, &*it);
@ -77,7 +77,7 @@ void SelectionController::PrevLine() {
void SelectionController::NextLine() {
if (!active_line) return;
auto it = context->ass->Events.iterator_to(*active_line);
auto it = context->ass->iterator_to(*active_line);
if (++it != context->ass->Events.end())
SetSelectionAndActive({&*it}, &*it);
}