15
15
// Aegisub Project http://www.aegisub.org/
17
/// @file dialog_selection.cpp
18
/// @brief Select Lines dialogue box and logic
19
/// @ingroup secondary_ui
24
#include "dialog_selection.h"
26
17
#include "ass_dialogue.h"
27
18
#include "ass_file.h"
28
19
#include "compat.h"
20
#include "dialog_manager.h"
22
#include "frame_main.h"
29
23
#include "help_button.h"
30
24
#include "include/aegisub/context.h"
31
25
#include "libresrc/libresrc.h"
32
26
#include "options.h"
33
27
#include "search_replace_engine.h"
34
28
#include "selection_controller.h"
37
#include <libaegisub/of_type_adaptor.h>
40
#include <boost/algorithm/string/find.hpp>
41
#include <boost/algorithm/string/predicate.hpp>
30
#include <boost/range/algorithm/set_algorithm.hpp>
43
32
#include <wx/checkbox.h>
44
33
#include <wx/combobox.h>
34
#include <wx/dialog.h>
45
35
#include <wx/msgdlg.h>
46
36
#include <wx/radiobox.h>
47
37
#include <wx/radiobut.h>
48
38
#include <wx/sizer.h>
49
39
#include <wx/textctrl.h>
64
static std::set<AssDialogue*> process(std::string const& match_text, bool match_case, int mode, bool invert, bool comments, bool dialogue, int field_n, AssFile *ass) {
42
class DialogSelection final : public wxDialog {
43
agi::Context *con; ///< Project context
45
wxTextCtrl *match_text; ///< Text to search for
46
wxCheckBox *case_sensitive; ///< Should the search be case-sensitive
47
wxCheckBox *apply_to_dialogue; ///< Select/deselect uncommented lines
48
wxCheckBox *apply_to_comments; ///< Select/deselect commented lines
49
wxRadioButton *select_unmatching_lines; ///< Select lines which don't match instead
50
wxRadioBox *selection_change_type; ///< What sort of action to take on the selection
51
wxRadioBox *dialogue_field; ///< Which dialogue field to look at
52
wxRadioBox *match_mode;
54
void Process(wxCommandEvent&);
56
/// Dialogue/Comment check handler to ensure at least one is always checked
57
/// @param chk The checkbox to check if both are clear
58
void OnDialogueCheckbox(wxCheckBox *chk);
61
DialogSelection(agi::Context *c);
78
std::set<AssDialogue*> process(std::string const& match_text, bool match_case, Mode mode, bool invert, bool comments, bool dialogue, int field_n, AssFile *ass) {
65
79
SearchReplaceSettings settings = {
68
82
static_cast<SearchReplaceSettings::Field>(field_n),
69
83
SearchReplaceSettings::Limit::ALL,
77
91
auto predicate = SearchReplaceEngine::GetMatcher(settings);
79
93
std::set<AssDialogue*> matches;
80
for (auto diag : ass->Line | agi::of_type<AssDialogue>()) {
81
if (diag->Comment && !comments) continue;
82
if (!diag->Comment && !dialogue) continue;
94
for (auto& diag : ass->Events) {
95
if (diag.Comment && !comments) continue;
96
if (!diag.Comment && !dialogue) continue;
84
if (invert != predicate(diag, 0))
98
if (invert != predicate(&diag, 0))
99
matches.insert(&diag);
174
188
matches = process(
175
189
from_wx(match_text->GetValue()), case_sensitive->IsChecked(),
176
match_mode->GetSelection(), select_unmatching_lines->GetValue(),
190
static_cast<Mode>(match_mode->GetSelection()), select_unmatching_lines->GetValue(),
177
191
apply_to_comments->IsChecked(), apply_to_dialogue->IsChecked(),
178
dialogue_field->GetSelection(), con->ass);
192
dialogue_field->GetSelection(), con->ass.get());
180
194
catch (agi::Exception const&) {
185
int action = selection_change_type->GetSelection();
199
auto action = static_cast<Action>(selection_change_type->GetSelection());
187
SubtitleSelection old_sel, new_sel;
188
if (action != ACTION_SET)
189
con->selectionController->GetSelectedSet(old_sel);
201
Selection old_sel, new_sel;
202
if (action != Action::SET)
203
old_sel = con->selectionController->GetSelectedSet();
191
205
wxString message;
192
206
size_t count = 0;
193
207
switch (action) {
196
switch (count = new_sel.size()) {
197
case 0: message = _("Selection was set to no lines"); break;
198
case 1: message = _("Selection was set to one line"); break;
199
default: message = wxString::Format(_("Selection was set to %u lines"), (unsigned)count);
204
set_union(old_sel.begin(), old_sel.end(), matches.begin(), matches.end(), inserter(new_sel, new_sel.begin()));
205
switch (count = new_sel.size() - old_sel.size()) {
206
case 0: message = _("No lines were added to selection"); break;
207
case 1: message = _("One line was added to selection"); break;
208
default: message = wxString::Format(_("%u lines were added to selection"), (unsigned)count);
213
set_difference(old_sel.begin(), old_sel.end(), matches.begin(), matches.end(), inserter(new_sel, new_sel.begin()));
214
switch (count = old_sel.size() - new_sel.size()) {
215
case 0: message = _("No lines were removed from selection"); break;
216
case 1: message = _("One line was removed from selection"); break;
217
default: message = wxString::Format(_("%u lines were removed from selection"), (unsigned)count);
221
case ACTION_INTERSECT:
222
set_intersection(old_sel.begin(), old_sel.end(), matches.begin(), matches.end(), inserter(new_sel, new_sel.begin()));
223
switch (count = old_sel.size() - new_sel.size()) {
224
case 0: message = _("No lines were removed from selection"); break;
225
case 1: message = _("One line was removed from selection"); break;
226
default: message = wxString::Format(_("%u lines were removed from selection"), (unsigned)count);
209
new_sel = std::move(matches);
210
message = (count = new_sel.size())
211
? fmt_plural(count, "Selection was set to one line", "Selection was set to %u lines", count)
212
: _("Selection was set to no lines");
216
boost::set_union(old_sel, matches, inserter(new_sel, new_sel.begin()));
217
message = (count = new_sel.size() - old_sel.size())
218
? fmt_plural(count, "One line was added to selection", "%u lines were added to selection", count)
219
: _("No lines were added to selection");
223
boost::set_difference(old_sel, matches, inserter(new_sel, new_sel.begin()));
226
case Action::INTERSECT:
227
boost::set_intersection(old_sel, matches, inserter(new_sel, new_sel.begin()));
229
message = (count = old_sel.size() - new_sel.size())
230
? fmt_plural(count, "One line was removed from selection", "%u lines were removed from selection", count)
231
: _("No lines were removed from selection");
232
236
wxMessageBox(message, _("Selection"), wxOK | wxCENTER, this);
234
StatusTimeout(message);
236
if (new_sel.size() && !new_sel.count(con->selectionController->GetActiveLine()))
237
con->selectionController->SetActiveLine(*new_sel.begin());
238
con->selectionController->SetSelectedSet(new_sel);
238
con->frame->StatusTimeout(message);
240
240
AssDialogue *new_active = con->selectionController->GetActiveLine();
241
241
if (new_sel.size() && !new_sel.count(new_active))
242
242
new_active = *new_sel.begin();
243
con->selectionController->SetSelectionAndActive(new_sel, new_active);
243
con->selectionController->SetSelectionAndActive(std::move(new_sel), new_active);