From f5e66ba3c2ff14cdf03a864336d670b446357db7 Mon Sep 17 00:00:00 2001 From: Daniel Ramoeller Date: Thu, 15 Oct 2020 16:40:20 +0200 Subject: [PATCH] Improved layout adoption on paste The layout from the paste content is adopted only if - the paragraph is empty (ie. empty after the selection has been erased) and Standard or Plain Layout, or - empty and multiple lines are pasted, or - multiple lines are pasted at the beginning of a paragraph As for what other applications do: - MS Word decides the adoption of a layout depending on whether the end of line character is copied - Libre Writer adopts the paste content layout only if the paragraph is empty (otherwise it makes *all* pasted paragraph the target layout) In LyX, as in Libre Writer, one cannot copy the end of line character by selecting a single line. However, the Libre Writer solution is problematic because one always has to make sure that a paragraph is in Standard layout if one wants to paste several lines with their source layout. The implemented behaviour differs from Libre Writer in that the source format is kept when end of line characters are pasted, i.e. several lines are pasted, and hence does what MS Word does in that situation. Fix for bug #11023: Copy and paste from one list into another often leads to undesired result. --- src/CutAndPaste.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index f127f1b1f6..0446175e69 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -289,12 +289,25 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, Change::INSERTED : Change::UNCHANGED)); } - bool const empty = pars[pit].empty(); - if (!empty) { - // Make the buf exactly the same layout as the cursor - // paragraph. + bool const target_empty = pars[pit].empty(); + // Use the paste content's layout, if... + bool const paste_layout = + // if target paragraph is empty + (target_empty + // ... and its layout is default + && (pars[pit].layout() == defaultLayout + // ... or plain + || pars[pit].layout() == plainLayout + // ... or the paste content spans several paragraphs + || insertion.size() > 1)) + // or if pasting is done at the beginning of paragraph + || (pos == 0 + // and the paste content spans several paragraphs + && insertion.size() > 1); + if (!paste_layout) + // Give the first paragraph to insert the same layout as the + // target paragraph. insertion.begin()->makeSameLayout(pars[pit]); - } // Prepare the paragraphs and insets for insertion. insertion.swap(in.paragraphs()); @@ -458,11 +471,17 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, insertion.swap(in.paragraphs()); // Split the paragraph for inserting the buf if necessary. - if (!empty) + if (!target_empty) breakParagraphConservative(buffer.params(), pars, pit, pos); + // If multiple paragraphs are inserted before the target paragraph, + // the cursor is now in a new paragraph before it, + // so use layout from paste content in that case. + if (pos == 0 && insertion.size() > 1) + pars[pit].makeSameLayout(* insertion.begin()); + // Paste it! - if (empty) { + if (target_empty) { pars.insert(pars.iterator_at(pit), insertion.begin(), insertion.end()); @@ -491,7 +510,7 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, // Join (conditionally) last pasted paragraph with next one, i.e., // the tail of the spliced document paragraph - if (!empty && last_paste + 1 != pit_type(pars.size())) { + if (!target_empty && last_paste + 1 != pit_type(pars.size())) { if (pars[last_paste + 1].hasSameLayout(pars[last_paste])) { mergeParagraph(buffer.params(), pars, last_paste); } else if (pars[last_paste + 1].empty()) {