diff --git a/aegisub/src/command/edit.cpp b/aegisub/src/command/edit.cpp
index 4c7c9ab56707efbca11d74f6f2225771ca54651c..ab1da7307a5f7f12e194fe478946fc305a53fedf 100644
--- a/aegisub/src/command/edit.cpp
+++ b/aegisub/src/command/edit.cpp
@@ -49,7 +49,9 @@
 #include "../ass_dialogue.h"
 #include "../ass_file.h"
 #include "../ass_karaoke.h"
+#include "../dialog_paste_over.h"
 #include "../dialog_search_replace.h"
+#include "../main.h"
 #include "../include/aegisub/context.h"
 #include "../subs_edit_ctrl.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.
 struct edit_find_replace : public Command {
 	CMD_NAME("edit/find_replace")
@@ -322,7 +412,7 @@ struct edit_line_paste : public Command {
 		if (wxTextEntryBase *ctrl = dynamic_cast<wxTextEntryBase*>(c->parent->FindFocus()))
 			ctrl->Paste();
 		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) {
-		c->subsGrid->PasteLines(c->subsGrid->GetFirstSelRow(),true);
+		paste_lines(c, true);
 	}
 };
 
diff --git a/aegisub/src/subs_grid.cpp b/aegisub/src/subs_grid.cpp
index b8bbdaca4452079e2d6a823962147df265c565ce..08d865ee851b1dad927249a60dfe4b6a75be9422 100644
--- a/aegisub/src/subs_grid.cpp
+++ b/aegisub/src/subs_grid.cpp
@@ -52,7 +52,6 @@
 
 #include "ass_dialogue.h"
 #include "ass_file.h"
-#include "dialog_paste_over.h"
 #include "main.h"
 #include "utils.h"
 #include "video_context.h"
@@ -210,106 +209,6 @@ void SubtitlesGrid::CutLines(wxArrayInt target) {
 	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) {
 	entryIter before_first = std::find_if(context->ass->Line.begin(), context->ass->Line.end(), cast<AssDialogue*>()); --before_first;
 
diff --git a/aegisub/src/subs_grid.h b/aegisub/src/subs_grid.h
index 558871daa1548a1b6fb9cdaf753ca23a2ef4ccee..9ac9538d1bfd8d23ccf10166a18d6c4eb9d5d513 100644
--- a/aegisub/src/subs_grid.h
+++ b/aegisub/src/subs_grid.h
@@ -70,7 +70,6 @@ public:
 	/// @brief Cut to clipboard
 	/// @param target Lines to cut
 	void CutLines(wxArrayInt lines);
-	void PasteLines(int pos,bool over=false);
 
 	void RecombineLines();