mirror of https://github.com/odrling/Aegisub
337 lines
10 KiB
C++
337 lines
10 KiB
C++
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * 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.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
//
|
|
// AEGISUB
|
|
//
|
|
// Website: http://aegisub.cellosoft.com
|
|
// Contact: mailto:zeratul@cellosoft.com
|
|
//
|
|
|
|
|
|
///////////
|
|
// Headers
|
|
#include "config.h"
|
|
|
|
#include <wx/wxprec.h>
|
|
#include <wx/string.h>
|
|
#include <wx/regex.h>
|
|
#include "dialog_selection.h"
|
|
#include "subs_grid.h"
|
|
#include "ass_dialogue.h"
|
|
#include "options.h"
|
|
#include "help_button.h"
|
|
|
|
|
|
///////////////
|
|
// Constructor
|
|
DialogSelection::DialogSelection(wxWindow *parent, SubtitlesGrid *_grid) :
|
|
wxDialog (parent,-1,_("Select"),wxDefaultPosition,wxDefaultSize,wxCAPTION)
|
|
{
|
|
// Variables
|
|
grid = _grid;
|
|
|
|
// 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,Options.AsText(_T("Select Text")),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"));
|
|
|
|
// 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);
|
|
|
|
// Dialogues/comments box
|
|
MatchDialogues = new wxCheckBox(this,MATCH_DIALOGUES_CHECKBOX,_("Dialogues"));
|
|
MatchComments = new wxCheckBox(this,MATCH_COMMENTS_CHECKBOX,_("Comments"));
|
|
|
|
// 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);
|
|
|
|
// 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);
|
|
|
|
// 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();
|
|
|
|
// 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);
|
|
CenterOnParent();
|
|
|
|
// Load settings
|
|
Field->SetSelection(Options.AsInt(_T("Select Field")));
|
|
Action->SetSelection(Options.AsInt(_T("Select Action")));
|
|
MatchCase->SetValue(Options.AsBool(_T("Select Match case")));
|
|
MatchDialogues->SetValue(Options.AsBool(_T("Select Match dialogues")));
|
|
MatchComments->SetValue(Options.AsBool(_T("Select Match comments")));
|
|
int condition = Options.AsInt(_T("Select Condition"));
|
|
int mode = Options.AsInt(_T("Select Mode"));
|
|
if (condition == 1) DoesntMatch->SetValue(true);
|
|
if (mode == 1) Contains->SetValue(true);
|
|
else if (mode == 2) RegExp->SetValue(true);
|
|
}
|
|
|
|
|
|
/////////////////////
|
|
// Matching function
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Exact
|
|
else if (Exact->GetValue()) {
|
|
if (text == matching) result = true;
|
|
}
|
|
|
|
// Contains
|
|
else if (Contains->GetValue()) {
|
|
if (text.Contains(matching)) result = true;
|
|
}
|
|
|
|
// Regular expression
|
|
else if (isReg) {
|
|
wxRegEx regex (matching,regFlags);
|
|
if (regex.IsValid()) {
|
|
if (regex.Matches(text)) {
|
|
result = true;
|
|
}
|
|
}
|
|
else result = false;
|
|
}
|
|
|
|
// wtf?
|
|
else {
|
|
throw _T("Invalid mode");
|
|
}
|
|
|
|
// Result
|
|
if (Matches->GetValue()) return result;
|
|
else return !result;
|
|
}
|
|
|
|
|
|
///////////
|
|
// Process
|
|
void DialogSelection::Process() {
|
|
// Prepare
|
|
AssDialogue *current;
|
|
int rows = grid->GetRows();
|
|
int action = Action->GetSelection();
|
|
bool replaceSel = false;
|
|
if (action == 0) replaceSel = true;
|
|
int count = 0;
|
|
|
|
// Build current selection list
|
|
wxArrayInt sels;
|
|
if (action == 2 || action == 3) {
|
|
sels = grid->GetSelection();
|
|
}
|
|
|
|
// Iterate
|
|
for (int i=0;i<rows;i++) {
|
|
current = grid->GetDialogue(i);
|
|
if (StringMatches(current)) {
|
|
// Set/Add to selection
|
|
if (action == 0 || action == 1) {
|
|
grid->SelectRow(i,!replaceSel);
|
|
replaceSel = false;
|
|
count++;
|
|
}
|
|
|
|
// Subtract from selection
|
|
if (action == 2) {
|
|
if (sels.Index(i) != wxNOT_FOUND) {
|
|
sels.Remove(i);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Intersect with selection
|
|
if (action == 3) {
|
|
if (sels.Index(i) != wxNOT_FOUND) {
|
|
sels.Remove(i);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Select for modes 2 and 3
|
|
if (action == 2 || action == 3) {
|
|
grid->ClearSelection();
|
|
int count = sels.Count();
|
|
for (int i=0;i<count;i++) {
|
|
grid->SelectRow(sels[i],true);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
|
|
/////////////////
|
|
// 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
|
|
Options.SetText(_T("Select Text"),Match->GetValue());
|
|
Options.SetInt(_T("Select Condition"),condition);
|
|
Options.SetInt(_T("Select Field"),field);
|
|
Options.SetInt(_T("Select Action"),action);
|
|
Options.SetInt(_T("Select Mode"),mode);
|
|
Options.SetBool(_T("Select Match case"),MatchCase->IsChecked());
|
|
Options.SetBool(_T("Select Match dialogues"),MatchDialogues->IsChecked());
|
|
Options.SetBool(_T("Select Match comments"),MatchComments->IsChecked());
|
|
}
|
|
|
|
|
|
///////////////
|
|
// 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()
|
|
|
|
|
|
|
|
//////////////////////////////
|
|
// Dialogue/Comment checkboxes
|
|
void DialogSelection::OnDialogueCheckbox(wxCommandEvent &event) {
|
|
if(!event.IsChecked() && !MatchComments->GetValue())
|
|
MatchComments->SetValue(true);
|
|
}
|
|
|
|
void DialogSelection::OnCommentCheckbox(wxCommandEvent &event) {
|
|
if(!event.IsChecked() && !MatchDialogues->GetValue())
|
|
MatchDialogues->SetValue(true);
|
|
}
|
|
|
|
//////////////
|
|
// OK pressed
|
|
void DialogSelection::OnOK(wxCommandEvent &event) {
|
|
Process();
|
|
SaveSettings();
|
|
EndModal(0);
|
|
}
|
|
|
|
|
|
//////////////////
|
|
// Cancel pressed
|
|
void DialogSelection::OnCancel(wxCommandEvent &event) {
|
|
SaveSettings();
|
|
EndModal(0);
|
|
}
|