Make pasting lines not horribly slow and bad. Closes #1534.

This commit is contained in:
Thomas Goyne 2012-10-13 21:21:43 -07:00
parent 6e90d9498d
commit dcbf644820
3 changed files with 92 additions and 104 deletions

View file

@ -49,7 +49,9 @@
#include "../ass_dialogue.h" #include "../ass_dialogue.h"
#include "../ass_file.h" #include "../ass_file.h"
#include "../ass_karaoke.h" #include "../ass_karaoke.h"
#include "../dialog_paste_over.h"
#include "../dialog_search_replace.h" #include "../dialog_search_replace.h"
#include "../main.h"
#include "../include/aegisub/context.h" #include "../include/aegisub/context.h"
#include "../subs_edit_ctrl.h" #include "../subs_edit_ctrl.h"
#include "../subs_grid.h" #include "../subs_grid.h"
@ -74,6 +76,94 @@ struct validate_sel_multiple : public Command {
} }
}; };
void paste_lines(agi::Context *c, bool paste_over) {
wxString data;
if (wxTheClipboard->Open()) {
if (wxTheClipboard->IsSupported(wxDF_TEXT)) {
wxTextDataObject rawdata;
wxTheClipboard->GetData(rawdata);
data = rawdata.GetText();
}
wxTheClipboard->Close();
}
if (!data) return;
AssDialogue *rel_line = c->selectionController->GetActiveLine();
entryIter pos = find(c->ass->Line.begin(), c->ass->Line.end(), rel_line);
AssDialogue *first = 0;
std::set<AssDialogue *> newsel;
std::vector<bool> pasteOverOptions;
wxStringTokenizer token (data,"\r\n",wxTOKEN_STRTOK);
while (token.HasMoreTokens()) {
// Convert data into an AssDialogue
wxString curdata = token.GetNextToken();
curdata.Trim(true);
curdata.Trim(false);
AssDialogue *curdiag;
try {
// Try to interpret the line as an ASS line
curdiag = new AssDialogue(curdata);
}
catch (...) {
// Line didn't parse correctly, assume it's plain text that
// should be pasted in the Text field only
curdiag = new AssDialogue();
curdiag->Text = curdata;
// Make sure pasted plain-text lines always are blank-timed
curdiag->Start = 0;
curdiag->End = 0;
}
if (!first)
first = curdiag;
if (!paste_over) {
newsel.insert(curdiag);
c->ass->Line.insert(pos, curdiag);
}
else {
// Get list of options to paste over, if not asked yet
if (pasteOverOptions.empty()) {
DialogPasteOver diag(c->parent);
if (diag.ShowModal()) {
delete curdiag;
return;
}
pasteOverOptions = OPT_GET("Tool/Paste Lines Over/Fields")->GetListBool();
}
AssDialogue *line = static_cast<AssDialogue *>(*pos);
if (pasteOverOptions[0]) line->Layer = curdiag->Layer;
if (pasteOverOptions[1]) line->Start = curdiag->Start;
if (pasteOverOptions[2]) line->End = curdiag->End;
if (pasteOverOptions[3]) line->Style = curdiag->Style;
if (pasteOverOptions[4]) line->Actor = curdiag->Actor;
if (pasteOverOptions[5]) line->Margin[0] = curdiag->Margin[0];
if (pasteOverOptions[6]) line->Margin[1] = curdiag->Margin[1];
if (pasteOverOptions[7]) line->Margin[2] = curdiag->Margin[2];
if (pasteOverOptions[8]) line->Effect = curdiag->Effect;
if (pasteOverOptions[9]) line->Text = curdiag->Text;
delete curdiag;
do {
++pos;
} while (pos != c->ass->Line.end() && !dynamic_cast<AssDialogue*>(*pos));
if (pos == c->ass->Line.end())
break;
}
}
if (first) {
c->ass->Commit(_("paste"), paste_over ? AssFile::COMMIT_DIAG_FULL : AssFile::COMMIT_DIAG_ADDREM);
if (!paste_over)
c->selectionController->SetSelectionAndActive(newsel, first);
}
}
/// Find and replace words in subtitles. /// Find and replace words in subtitles.
struct edit_find_replace : public Command { struct edit_find_replace : public Command {
CMD_NAME("edit/find_replace") CMD_NAME("edit/find_replace")
@ -322,7 +412,7 @@ struct edit_line_paste : public Command {
if (wxTextEntryBase *ctrl = dynamic_cast<wxTextEntryBase*>(c->parent->FindFocus())) if (wxTextEntryBase *ctrl = dynamic_cast<wxTextEntryBase*>(c->parent->FindFocus()))
ctrl->Paste(); ctrl->Paste();
else else
c->subsGrid->PasteLines(c->subsGrid->GetFirstSelRow()); paste_lines(c, false);
} }
}; };
@ -345,7 +435,7 @@ struct edit_line_paste_over : public Command {
} }
void operator()(agi::Context *c) { void operator()(agi::Context *c) {
c->subsGrid->PasteLines(c->subsGrid->GetFirstSelRow(),true); paste_lines(c, true);
} }
}; };

View file

@ -52,7 +52,6 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "dialog_paste_over.h"
#include "main.h" #include "main.h"
#include "utils.h" #include "utils.h"
#include "video_context.h" #include "video_context.h"
@ -210,106 +209,6 @@ void SubtitlesGrid::CutLines(wxArrayInt target) {
EndBatch(); EndBatch();
} }
/// @brief Paste lines from clipboard
/// @param n
/// @param pasteOver
void SubtitlesGrid::PasteLines(int n,bool pasteOver) {
BeginBatch();
// Prepare text
wxString data;
// Read from clipboard
if (wxTheClipboard->Open()) {
if (wxTheClipboard->IsSupported(wxDF_TEXT)) {
wxTextDataObject rawdata;
wxTheClipboard->GetData(rawdata);
data = rawdata.GetText();
}
wxTheClipboard->Close();
}
// Check if it actually got anything
if (!data.empty()) {
// Insert data
int inserted = 0;
std::vector<bool> pasteOverOptions;
wxStringTokenizer token (data,"\r\n",wxTOKEN_STRTOK);
while (token.HasMoreTokens()) {
// Convert data into an AssDialogue
wxString curdata = token.GetNextToken();
curdata.Trim(true);
curdata.Trim(false);
AssDialogue *curdiag;
try {
// Try to interpret the line as an ASS line
curdiag = new AssDialogue(curdata);
}
catch (...) {
// Line didn't parse correctly, assume it's plain text that
// should be pasted in the Text field only
curdiag = new AssDialogue();
curdiag->Text = curdata;
// Make sure pasted plain-text lines always are blank-timed
curdiag->Start = 0;
curdiag->End = 0;
}
// Paste over
if (pasteOver) {
if (n+inserted < GetRows()) {
// Get list of options to paste over, if not asked yet
if (pasteOverOptions.empty()) {
DialogPasteOver diag(context->parent);
if (diag.ShowModal()) {
delete curdiag;
EndBatch();
return;
}
pasteOverOptions = OPT_GET("Tool/Paste Lines Over/Fields")->GetListBool();
}
// Paste over
AssDialogue *target = GetDialogue(n+inserted);
if (pasteOverOptions[0]) target->Layer = curdiag->Layer;
if (pasteOverOptions[1]) target->Start = curdiag->Start;
if (pasteOverOptions[2]) target->End = curdiag->End;
if (pasteOverOptions[3]) target->Style = curdiag->Style;
if (pasteOverOptions[4]) target->Actor = curdiag->Actor;
if (pasteOverOptions[5]) target->Margin[0] = curdiag->Margin[0];
if (pasteOverOptions[6]) target->Margin[1] = curdiag->Margin[1];
if (pasteOverOptions[7]) target->Margin[2] = curdiag->Margin[2];
if (pasteOverOptions[8]) target->Effect = curdiag->Effect;
if (pasteOverOptions[9]) target->Text = curdiag->Text;
}
delete curdiag;
}
// Paste normally
else InsertLine(curdiag,n+inserted,false,false);
// Increment insertion
inserted++;
}
// Update data post-insertion
if (inserted > 0) {
context->ass->Commit(_("paste"), pasteOver ? AssFile::COMMIT_DIAG_FULL : AssFile::COMMIT_DIAG_ADDREM);
// Set selection
if (!pasteOver) {
Selection newsel;
for (int i=n;i<n+inserted;i++) {
newsel.insert(GetDialogue(i));
}
SetSelectedSet(newsel);
SetActiveLine(GetDialogue(GetFirstSelRow()));
}
}
}
EndBatch();
}
void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) { void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
entryIter before_first = std::find_if(context->ass->Line.begin(), context->ass->Line.end(), cast<AssDialogue*>()); --before_first; entryIter before_first = std::find_if(context->ass->Line.begin(), context->ass->Line.end(), cast<AssDialogue*>()); --before_first;

View file

@ -70,7 +70,6 @@ public:
/// @brief Cut to clipboard /// @brief Cut to clipboard
/// @param target Lines to cut /// @param target Lines to cut
void CutLines(wxArrayInt lines); void CutLines(wxArrayInt lines);
void PasteLines(int pos,bool over=false);
void RecombineLines(); void RecombineLines();