From 1cc5d4001ae569e7888ec3e228d4ae282b65d43e Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 15 Sep 2011 05:16:47 +0000 Subject: [PATCH] Rewrite the selection dialog, detangling it from SubtitlesGrid and making it modeless Originally committed to SVN as r5592. --- aegisub/src/command/tool.cpp | 7 +- aegisub/src/dialog_selection.cpp | 536 ++++++++++------------- aegisub/src/dialog_selection.h | 130 ++---- aegisub/src/libresrc/default_config.json | 10 +- 4 files changed, 263 insertions(+), 420 deletions(-) diff --git a/aegisub/src/command/tool.cpp b/aegisub/src/command/tool.cpp index 7a1f78a98..b0f9d477b 100644 --- a/aegisub/src/command/tool.cpp +++ b/aegisub/src/command/tool.cpp @@ -105,16 +105,15 @@ struct tool_font_collector : public Command { }; -/// Selects lines based on defined criterea. +/// Selects lines based on defined criteria. struct tool_line_select : public Command { CMD_NAME("tool/line/select") STR_MENU("Select Lines..") STR_DISP("Select Lines") - STR_HELP("Selects lines based on defined criterea.") + STR_HELP("Selects lines based on defined criteria.") void operator()(agi::Context *c) { - c->videoController->Stop(); - DialogSelection(c->parent, c->subsGrid).ShowModal(); + (new DialogSelection(c))->Show(); } }; diff --git a/aegisub/src/dialog_selection.cpp b/aegisub/src/dialog_selection.cpp index e8f4cadfd..bb1342213 100644 --- a/aegisub/src/dialog_selection.cpp +++ b/aegisub/src/dialog_selection.cpp @@ -1,29 +1,16 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2011, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ // @@ -34,336 +21,261 @@ /// @ingroup secondary_ui /// - -/////////// -// Headers #include "config.h" +#include "dialog_selection.h" + #ifndef AGI_PRE +#include +#include +#include +#include #include -#include +#include #endif #include "ass_dialogue.h" +#include "ass_file.h" #include "compat.h" -#include "dialog_selection.h" +#include "frame_main.h" #include "help_button.h" +#include "include/aegisub/context.h" #include "main.h" #include "selection_controller.h" -#include "subs_grid.h" -#include "subs_edit_box.h" +enum { + ACTION_SET = 0, + ACTION_ADD, + ACTION_SUB, + ACTION_INTERSECT +}; -/// @brief Constructor -/// @param parent -/// @param _grid -/// -DialogSelection::DialogSelection(wxWindow *parent, SubtitlesGrid *_grid) : -wxDialog (parent,-1,_("Select"),wxDefaultPosition,wxDefaultSize,wxCAPTION) +enum { + FIELD_TEXT = 0, + FIELD_STYLE, + FIELD_ACTOR, + FIELD_EFFECT +}; + +enum { + MODE_EXACT = 0, + MODE_CONTAINS, + MODE_REGEXP +}; + +DEFINE_SIMPLE_EXCEPTION(BadRegex, agi::InvalidInputException, "bad_regex") + +static wxString AssDialogue::* get_field(int field_n) { + switch(field_n) { + case FIELD_TEXT: return &AssDialogue::Text; break; + case FIELD_STYLE: return &AssDialogue::Style; break; + case FIELD_ACTOR: return &AssDialogue::Actor; break; + case FIELD_EFFECT: return &AssDialogue::Effect; break; + default: throw agi::InternalError("Bad field", 0); + } +} + +std::tr1::function get_predicate(int mode, wxRegEx *re, bool match_case, wxString const& match_text) { + using std::tr1::placeholders::_1; + + switch (mode) { + case MODE_REGEXP: + return bind(&wxRegEx::Matches, re, _1, 0); + case MODE_EXACT: + if (match_case) + return bind(std::equal_to(), match_text, _1); + else + return bind(std::equal_to(), match_text.Lower(), bind(&wxString::Lower, _1)); + case MODE_CONTAINS: + if (match_case) + return bind(&wxString::Contains, _1, match_text); + else + return bind(&wxString::Contains, bind(&wxString::Lower, _1), match_text.Lower()); + break; + default: throw agi::InternalError("Bad mode", 0); + } +} + +static std::set process(wxString match_text, bool match_case, int mode, bool invert, bool comments, bool dialogue, int field_n, AssFile *ass) { + wxRegEx re; + if (mode == MODE_REGEXP) { + int flags = wxRE_ADVANCED; + if (!match_case) + flags |= wxRE_ICASE; + if (!re.Compile(match_text)) + throw BadRegex("Syntax error in regular expression", 0); + match_case = false; + } + + wxString AssDialogue::*field = get_field(field_n); + std::tr1::function pred = get_predicate(mode, &re, match_case, match_text); + + std::set matches; + for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ++it) { + AssDialogue *diag = dynamic_cast(*it); + if (!diag) continue; + if (diag->Comment && !comments) continue; + if (!diag->Comment && !dialogue) continue; + + if (pred(diag->*field) != invert) + matches.insert(diag); + } + + return matches; +} + +DialogSelection::DialogSelection(agi::Context *c) : +wxDialog (c->parent, -1, _("Select"), wxDefaultPosition, wxDefaultSize, wxCAPTION) +, con(c) { - // Variables - grid = _grid; + wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); - // Static-box sizers before anything else - wxSizer *MatchSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Match")); - wxSizer *MatchTopSizer = new wxBoxSizer(wxHORIZONTAL); - wxSizer *DialogueSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Match dialogues/comments")); - - // Matches box - Matches = new wxRadioButton(this,-1,_("Matches"),wxDefaultPosition,wxDefaultSize,wxRB_GROUP); - DoesntMatch = new wxRadioButton(this,-1,_("Doesn't Match"),wxDefaultPosition,wxDefaultSize,0); - Match = new wxTextCtrl(this,-1,lagi_wxString(OPT_GET("Tool/Select Lines/Text")->GetString()),wxDefaultPosition,wxSize(200,-1)); - MatchCase = new wxCheckBox(this,-1,_("Match case")); - Exact = new wxRadioButton(this,-1,_("Exact match"),wxDefaultPosition,wxDefaultSize,wxRB_GROUP); - Contains = new wxRadioButton(this,-1,_("Contains")); - RegExp = new wxRadioButton(this,-1,_("Regular Expression match")); + wxSizerFlags main_flags = wxSizerFlags().Expand().Border(); - // Fields box - wxArrayString field; - field.Add(_("Text")); - field.Add(_("Style")); - field.Add(_("Actor")); - field.Add(_("Effect")); - Field = new wxRadioBox(this,-1,_("In Field"),wxDefaultPosition,wxDefaultSize,field); + { + wxSizer *match_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Match")); + { + wxSizerFlags radio_flags = wxSizerFlags().Border(wxLEFT | wxRIGHT); + wxSizer *match_radio_line = new wxBoxSizer(wxHORIZONTAL); + match_radio_line->Add(new wxRadioButton(this, -1, _("Matches"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP), radio_flags); + match_radio_line->Add(select_unmatching_lines = new wxRadioButton(this, -1, _("Doesn't Match")), radio_flags); + match_radio_line->Add(case_sensitive = new wxCheckBox(this, -1, _("Match case")), radio_flags); + match_sizer->Add(match_radio_line); + } + match_sizer->Add(match_text = new wxTextCtrl(this, -1, lagi_wxString(OPT_GET("Tool/Select Lines/Text")->GetString())), main_flags); - // Dialogues/comments box - MatchDialogues = new wxCheckBox(this,MATCH_DIALOGUES_CHECKBOX,_("Dialogues")); - MatchComments = new wxCheckBox(this,MATCH_COMMENTS_CHECKBOX,_("Comments")); + main_sizer->Add(match_sizer, main_flags); + } - // Action box - wxArrayString actions; - actions.Add(_("Set selection")); - actions.Add(_("Add to selection")); - actions.Add(_("Subtract from selection")); - actions.Add(_("Intersect with selection")); - Action = new wxRadioBox(this,-1,_("Action"),wxDefaultPosition,wxDefaultSize,actions,1); + { + wxString modes[] = { _("Exact match"), _("Contains"), _("Regular Expression match") }; + main_sizer->Add(match_mode = new wxRadioBox(this, -1, _("Mode"), wxDefaultPosition, wxDefaultSize, 3, modes, 1), main_flags); + } - // Matches box sizer - MatchTopSizer->Add(Matches,0,wxEXPAND|wxRIGHT,5); - MatchTopSizer->Add(DoesntMatch,0,wxEXPAND,0); - MatchTopSizer->AddStretchSpacer(1); - MatchSizer->Add(MatchTopSizer,0,wxEXPAND,0); - MatchSizer->Add(Match,1,wxTOP|wxEXPAND,5); - MatchSizer->Add(MatchCase,0,wxTOP|wxEXPAND,5); - MatchSizer->Add(Exact,0,wxTOP|wxEXPAND,5); - MatchSizer->Add(Contains,0,wxTOP|wxEXPAND,5); - MatchSizer->Add(RegExp,0,wxTOP|wxEXPAND,5); + { + wxString fields[] = { _("Text"), _("Style"), _("Actor"), _("Effect") }; + main_sizer->Add(dialogue_field = new wxRadioBox(this, -1, _("In Field"), wxDefaultPosition, wxDefaultSize, 4, fields), main_flags); + } - // Dialogues / Comments box - DialogueSizer->Add(MatchDialogues,0, wxRIGHT|wxEXPAND,5); - DialogueSizer->Add(MatchComments,0, wxEXPAND); - - // Buttons sizer - wxStdDialogButtonSizer *ButtonSizer = new wxStdDialogButtonSizer(); - ButtonSizer->AddButton(new wxButton(this,wxID_OK)); - ButtonSizer->AddButton(new wxButton(this,wxID_CANCEL)); - ButtonSizer->AddButton(new HelpButton(this,_T("Select Lines"))); - ButtonSizer->Realize(); + { + wxSizer *comment_sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Match dialogues/comments")); + comment_sizer->Add(apply_to_dialogue = new wxCheckBox(this, -1, _("Dialogues")), wxSizerFlags().Border()); + comment_sizer->Add(apply_to_comments = new wxCheckBox(this, -1, _("Comments")), wxSizerFlags().Border()); + main_sizer->Add(comment_sizer, main_flags); + } - // Main sizer - wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL); - MainSizer->Add(MatchSizer,0,wxEXPAND|wxLEFT|wxTOP|wxRIGHT,5); - MainSizer->Add(Field,0,wxEXPAND|wxLEFT|wxRIGHT|wxTOP,5); - MainSizer->Add(DialogueSizer,0,wxEXPAND|wxLEFT|wxRIGHT|wxTOP,5); - MainSizer->Add(Action,0,wxEXPAND|wxLEFT|wxRIGHT|wxTOP,5); - MainSizer->Add(ButtonSizer,0,wxEXPAND|wxALL,5); - MainSizer->SetSizeHints(this); - SetSizer(MainSizer); + { + wxString actions[] = { _("Set selection"), _("Add to selection"), _("Subtract from selection"), _("Intersect with selection") }; + main_sizer->Add(selection_change_type = new wxRadioBox(this, -1, _("Action"), wxDefaultPosition, wxDefaultSize, 4, actions, 1), main_flags); + } + + main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL | wxHELP), main_flags); + + SetSizerAndFit(main_sizer); CenterOnParent(); - // Load settings - Field->SetSelection(OPT_GET("Tool/Select/Field")->GetInt()); - Action->SetSelection(OPT_GET("Tool/Select/Action")->GetInt()); - MatchCase->SetValue(OPT_GET("Tool/Select Lines/Match/Case")->GetBool()); - MatchDialogues->SetValue(OPT_GET("Tool/Select Lines/Match/Dialogue")->GetBool()); - MatchComments->SetValue(OPT_GET("Tool/Select Lines/Match/Comment")->GetBool()); - int condition = OPT_GET("Tool/Select/Condition")->GetInt(); - int mode = OPT_GET("Tool/Select/Mode")->GetInt(); - if (condition == 1) DoesntMatch->SetValue(true); - if (mode == 1) Contains->SetValue(true); - else if (mode == 2) RegExp->SetValue(true); + dialogue_field->SetSelection(OPT_GET("Tool/Select Lines/Field")->GetInt()); + selection_change_type->SetSelection(OPT_GET("Tool/Select Lines/Action")->GetInt()); + case_sensitive->SetValue(OPT_GET("Tool/Select Lines/Match/Case")->GetBool()); + apply_to_dialogue->SetValue(OPT_GET("Tool/Select Lines/Match/Dialogue")->GetBool()); + apply_to_comments->SetValue(OPT_GET("Tool/Select Lines/Match/Comment")->GetBool()); + select_unmatching_lines->SetValue(!!OPT_GET("Tool/Select Lines/Condition")->GetInt()); + match_mode->SetSelection(OPT_GET("Tool/Select Lines/Mode")->GetInt()); + + Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSelection::Process, this, wxID_OK); + Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSelection::OnClose, this, wxID_CANCEL); + Bind(wxEVT_COMMAND_BUTTON_CLICKED, std::tr1::bind(&HelpButton::OpenPage, "Select Lines"), wxID_HELP); + apply_to_comments->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, std::tr1::bind(&DialogSelection::OnDialogueCheckbox, this, apply_to_dialogue)); + apply_to_dialogue->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, std::tr1::bind(&DialogSelection::OnDialogueCheckbox, this, apply_to_comments)); } +void DialogSelection::Process(wxCommandEvent&) { + std::set matches; - -/// @brief Matching function -/// @param diag -/// @return -/// -bool DialogSelection::StringMatches(AssDialogue *diag) { - // Variables - wxString text; - wxString matching = Match->GetValue(); - bool result = false; - int field = Field->GetSelection(); - - // Get text - if (field == 0) text = diag->Text; - else if (field == 1) text = diag->Style; - else if (field == 2) text = diag->Actor; - else if (field == 3) text = diag->Effect; - - // RegExp? - bool isReg = false; - if (RegExp->GetValue()) { - isReg = true; + try { + matches = process( + match_text->GetValue(), case_sensitive->IsChecked(), + match_mode->GetSelection(), select_unmatching_lines->GetValue(), + apply_to_comments->IsChecked(), apply_to_dialogue->IsChecked(), + dialogue_field->GetSelection(), con->ass); + } + catch (agi::Exception const&) { + Close(); + return; } - // Case sensitivity - int regFlags = wxRE_ADVANCED; - if (!MatchCase->IsChecked()) { - if (isReg) regFlags |= wxRE_ICASE; - else { - text.LowerCase(); - matching.LowerCase(); - } - } - - // Dialogue/Comment - bool dial = MatchDialogues->GetValue(); - bool comm = MatchComments->GetValue(); - if ((diag->Comment && !comm) || (!diag->Comment && !dial)) { - result = false; - } + int action = selection_change_type->GetSelection(); - // Exact - else if (Exact->GetValue()) { - if (text == matching) result = true; - } - - // Contains - else if (Contains->GetValue()) { - if (text.Contains(matching)) result = true; - } + SelectionController::Selection old_sel, new_sel; + if (action != ACTION_SET) + con->selectionController->GetSelectedSet(old_sel); - // Regular expression - else if (isReg) { - wxRegEx regex (matching,regFlags); - if (regex.IsValid()) { - if (regex.Matches(text)) { - result = true; + wxString message; + size_t count; + switch (action) { + case ACTION_SET: + new_sel = matches; + switch (count = new_sel.size()) { + case 0: message = _("Selection was set to no lines"); break; + case 1: message = _("Selection was set to one line"); break; + default: message = wxString::Format(_("Selection was set to %u lines"), count); } + break; + + case ACTION_ADD: + set_union(old_sel.begin(), old_sel.end(), matches.begin(), matches.end(), inserter(new_sel, new_sel.begin())); + switch (count = new_sel.size() - old_sel.size()) { + case 0: message = _("No lines were added to selection"); break; + case 1: message = _("One line was added to selection"); break; + default: message = wxString::Format(_("%u lines were were added to selection"), count); } - else result = false; - } + break; - // wtf? - else { - throw _T("Invalid mode"); - } - - // Result - if (Matches->GetValue()) return result; - else return !result; -} - - - -/// @brief Process -/// -void DialogSelection::Process() { - // Prepare - AssDialogue *current; - int rows = grid->GetRows(); - int action = Action->GetSelection(); - bool replaceSel = (action == 0); - int firstSel = -1; - int count = 0; - - // Build current selection list - wxArrayInt sels; - if (action == 2 || action == 3) { - sels = grid->GetSelection(); - } - - // Iterate - for (int i=0;iGetDialogue(i); - if (StringMatches(current)) { - // Set/Add to selection - if (action == 0 || action == 1) { - grid->SelectRow(i,!replaceSel); - if (replaceSel) firstSel = i; - replaceSel = false; - count++; + case ACTION_SUB: + set_difference(old_sel.begin(), old_sel.end(), matches.begin(), matches.end(), inserter(new_sel, new_sel.begin())); + switch (count = old_sel.size() - new_sel.size()) { + case 0: message = _("No lines were removed from selection"); break; + case 1: message = _("One line was removed from selection"); break; + default: message = wxString::Format(_("%u lines were were removed from selection"), count); } + break; - // Subtract from selection - if (action == 2) { - if (sels.Index(i) != wxNOT_FOUND) { - sels.Remove(i); - count++; - } + case ACTION_INTERSECT: + set_intersection(old_sel.begin(), old_sel.end(), matches.begin(), matches.end(), inserter(new_sel, new_sel.begin())); + switch (count = old_sel.size() - new_sel.size()) { + case 0: message = _("No lines were removed from selection"); break; + case 1: message = _("One line was removed from selection"); break; + default: message = wxString::Format(_("%u lines were were removed from selection"), count); } - } - else { - // Intersect with selection - if (action == 3) { - if (sels.Index(i) != wxNOT_FOUND) { - sels.Remove(i); - count++; - } - } - } + break; } - // Select for modes 2 and 3 - if (action == 2 || action == 3) { - SubtitleSelectionController::Selection newsel; - int count = sels.Count(); - for (int i=0;iGetDialogue(sels[i])); - } - grid->SetSelectedSet(newsel); - if (count) { - grid->SetActiveLine(grid->GetDialogue(sels[0])); - } - } - else if (firstSel > -1) { - grid->SetActiveLine(grid->GetDialogue(firstSel)); - } + if (count == 0) + wxMessageBox(message, _("Selection"), wxOK); + else + wxGetApp().frame->StatusTimeout(message); - // Message saying number selected - if (action == 0) wxMessageBox(wxString::Format(_("Selection was set to %i lines"),count), _("Selection"), wxOK); - else if (action == 1) wxMessageBox(wxString::Format(_("%i lines were added to selection"),count), _("Selection"), wxOK); - else wxMessageBox(wxString::Format(_("%i lines were removed from selection"),count), _("Selection"), wxOK); + if (new_sel.size() && !new_sel.count(con->selectionController->GetActiveLine())) + con->selectionController->SetActiveLine(*new_sel.begin()); + con->selectionController->SetSelectedSet(new_sel); + + Close(); } +void DialogSelection::OnClose(wxCommandEvent&) { + OPT_SET("Tool/Select Lines/Text")->SetString(STD_STR(match_text->GetValue())); + OPT_SET("Tool/Select Lines/Condition")->SetInt(select_unmatching_lines->GetValue()); + OPT_SET("Tool/Select Lines/Field")->SetInt(dialogue_field->GetSelection()); + OPT_SET("Tool/Select Lines/Action")->SetInt(selection_change_type->GetSelection()); + OPT_SET("Tool/Select Lines/Mode")->SetInt(match_mode->GetSelection()); + OPT_SET("Tool/Select Lines/Match/Case")->SetBool(case_sensitive->IsChecked()); + OPT_SET("Tool/Select Lines/Match/Dialogue")->SetBool(apply_to_dialogue->IsChecked()); + OPT_SET("Tool/Select Lines/Match/Comment")->SetBool(apply_to_comments->IsChecked()); - -/// @brief Save settings -/// -void DialogSelection::SaveSettings() { - // Prepare settings - int action = Action->GetSelection(); - int mode; - if (Exact->GetValue()) mode = 0; - else if (Contains->GetValue()) mode = 1; - else mode = 2; - int field = Field->GetSelection(); - int condition; - if (Matches->GetValue()) condition = 0; - else condition = 1; - - // Store - OPT_SET("Tool/Select Lines/Text")->SetString(STD_STR(Match->GetValue())); - OPT_SET("Tool/Select/Condition")->SetInt(condition); - OPT_SET("Tool/Select/Field")->SetInt(field); - OPT_SET("Tool/Select/Action")->SetInt(action); - OPT_SET("Tool/Select/Mode")->SetInt(mode); - OPT_SET("Tool/Select Lines/Match/Case")->SetBool(MatchCase->IsChecked()); - OPT_SET("Tool/Select Lines/Match/Dialogue")->SetBool(MatchDialogues->IsChecked()); - OPT_SET("Tool/Select Lines/Match/Comment")->SetBool(MatchComments->IsChecked()); + Destroy(); } - -/////////////// -// Event table -BEGIN_EVENT_TABLE(DialogSelection,wxDialog) - EVT_BUTTON(wxID_OK,DialogSelection::OnOK) - EVT_BUTTON(wxID_CANCEL,DialogSelection::OnCancel) - EVT_CHECKBOX(MATCH_DIALOGUES_CHECKBOX, DialogSelection::OnDialogueCheckbox) - EVT_CHECKBOX(MATCH_COMMENTS_CHECKBOX, DialogSelection::OnCommentCheckbox) -END_EVENT_TABLE() - - - - -/// @brief Dialogue/Comment checkboxes -/// @param event -/// -void DialogSelection::OnDialogueCheckbox(wxCommandEvent &event) { - if(!event.IsChecked() && !MatchComments->GetValue()) - MatchComments->SetValue(true); +void DialogSelection::OnDialogueCheckbox(wxCheckBox *chk) { + if(!apply_to_dialogue->IsChecked() && !apply_to_comments->GetValue()) + chk->SetValue(true); } - - -/// @brief DOCME -/// @param event -/// -void DialogSelection::OnCommentCheckbox(wxCommandEvent &event) { - if(!event.IsChecked() && !MatchDialogues->GetValue()) - MatchDialogues->SetValue(true); -} - - -/// @brief OK pressed -/// @param event -/// -void DialogSelection::OnOK(wxCommandEvent &event) { - Process(); - SaveSettings(); - EndModal(0); -} - - - -/// @brief Cancel pressed -/// @param event -/// -void DialogSelection::OnCancel(wxCommandEvent &event) { - SaveSettings(); - EndModal(0); -} - - diff --git a/aegisub/src/dialog_selection.h b/aegisub/src/dialog_selection.h index 0d9547e69..edc6a6049 100644 --- a/aegisub/src/dialog_selection.h +++ b/aegisub/src/dialog_selection.h @@ -1,29 +1,16 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2011, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ // @@ -34,28 +21,16 @@ /// @ingroup secondary_ui /// - - - -/////////// -// Headers #ifndef AGI_PRE -#include -#include #include -#include -#include -#include -#include #endif - -////////////// -// Prototypes -class SubtitlesGrid; +namespace agi { struct Context; } class AssDialogue; - - +class wxCheckBox; +class wxRadioBox; +class wxRadioButton; +class wxTextCtrl; /// DOCME /// @class DialogSelection @@ -63,67 +38,26 @@ class AssDialogue; /// /// DOCME class DialogSelection : public wxDialog { -private: + agi::Context *con; ///< Project context - /// DOCME - SubtitlesGrid *grid; + wxTextCtrl *match_text; ///< Text to search for + wxCheckBox *case_sensitive; ///< Should the search be case-sensitive + wxCheckBox *apply_to_dialogue; ///< Select/deselect uncommented lines + wxCheckBox *apply_to_comments; ///< Select/deselect commented lines + wxRadioButton *select_unmatching_lines; ///< Select lines which don't match instead + wxRadioBox *selection_change_type; ///< What sort of action to take on the selection + wxRadioBox *dialogue_field; ///< Which dialogue field to look at + wxRadioBox *match_mode; - /// DOCME - wxTextCtrl *Match; + void Process(wxCommandEvent&); - /// DOCME - wxCheckBox *MatchCase; + /// Close event handler to save settings and destroy + void OnClose(wxCommandEvent&); - /// DOCME - wxCheckBox *MatchDialogues; - - /// DOCME - wxCheckBox *MatchComments; - - /// DOCME - wxRadioButton *Matches; - - /// DOCME - wxRadioButton *DoesntMatch; - - /// DOCME - wxRadioBox *Action; - - /// DOCME - wxRadioBox *Field; - - /// DOCME - wxRadioButton *Exact; - - /// DOCME - wxRadioButton *Contains; - - /// DOCME - wxRadioButton *RegExp; - - void Process(); - void SaveSettings(); - bool StringMatches (AssDialogue *diag); - - void OnOK (wxCommandEvent &event); - void OnCancel (wxCommandEvent &event); - void OnDialogueCheckbox(wxCommandEvent &event); - void OnCommentCheckbox(wxCommandEvent &event); + /// Dialogue/Comment check handler to ensure at least one is always checked + /// @param chk The checkbox to check if both are clear + void OnDialogueCheckbox(wxCheckBox *chk); public: - DialogSelection(wxWindow *parent, SubtitlesGrid *grid); - - DECLARE_EVENT_TABLE() -}; - - -/////// -// IDs -enum { - - /// DOCME - MATCH_DIALOGUES_CHECKBOX = 3000, - - /// DOCME - MATCH_COMMENTS_CHECKBOX + DialogSelection(agi::Context *c); }; diff --git a/aegisub/src/libresrc/default_config.json b/aegisub/src/libresrc/default_config.json index 2de316e92..47d9bcade 100644 --- a/aegisub/src/libresrc/default_config.json +++ b/aegisub/src/libresrc/default_config.json @@ -323,19 +323,17 @@ "Video Update" : false }, "Select Lines" : { + "Action" : 0, + "Condition" : 0, + "Field" : 0, "Match" : { "Case" : false, "Comment" : false, "Dialogue" : true }, + "Mode" : 1, "Text" : "" }, - "Select" : { - "Action" : 0, - "Condition" : 0, - "Field" : 0, - "Mode" : 1 - }, "Shift Times" : { "Affect" : 0, "ByTime" : true,