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.
This commit is contained in:
Daniel Ramoeller 2020-10-15 16:40:20 +02:00 committed by Jean-Marc Lasgouttes
parent 61d68d05bd
commit f5e66ba3c2

View File

@ -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()) {