summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stahl <Michael.Stahl@cib.de>2019-12-05 16:49:33 +0100
committerMiklos Vajna <vmiklos@collabora.com>2020-02-20 18:52:24 +0100
commit1c31d13fe0b74336b242f8ee41c28b3fe672e44c (patch)
treefab8907f2e8c77d69b8c1cbaff4b8d068217e902
parent783ff7aacf72d907b43b26926131966b199ebb90 (diff)
tdf#121300 sw: consistent fly at-pargraph selection
As a follow-up to commit 28b77c89dfcafae82cf2a6d85731b643ff9290e5, add IsSelectFrameAnchoredAtPara() function and use it to harmonize at-para fly selection across all relevant operations: * CopyImpl: - it had a pre-existing bugs that would lose a fly anchored to the 2nd (1st fully selected) node of a redline - remove a bunch of code for finding the last node of the body content, which doesn't matter for the remaining at-fly checks - flys that already existed at the insert position need to have their anchors corrected * DeleteRange: - get rid of the bDelFwrd checks * MoveRange: - the ALLFLYS flag would be obsoleted by the new selection, were it not for the writerfiler "special hack", see below * also adapt A11y and UI selection, SwRootFrame::CalcFrameRects() The selection behavior is changed: * the bDelFwrd case is quite odd, some code was checking whether a deletion was "forward" or "backward" and removing only the flys at the point node while retaining the flys at the mark node; this worked in a very non-obvious way relying on sw_GetJoinFlags actually calling Exchange() on the cursor, and then SwUndoDelete stored it in m_bJoinNext, but it turns out that only SwUndoMove also has a m_bJoinNext and it's dead, and no other Undo has such a flag, so this only worked for "delete". It's not obvious what the value of this is, let's just ignore the "direction". * Selections exclude the start and end position except if it's a fully selected node or at the start or end of a section (i.e. Ctrl+A should also select every at-para fly). * An exception is made in case the selection looks like it's a backspace/delete joining 2 paragraphs; flys are not deleted in that case because it seemed annoying (and as it happens, Word does not appear to delete flys in that case), particularly if both of the nodes are already empty. This is done with a heuristic, it's conceivable to pass down some flag from DelLeft()/DelRight() but probably this is good enough. A special hack is needed to keep writerfilter happy for now; it likes to anchor flys at nodes which it then deletes in RemoveLastParagraph(), which likely could be improved there. The ALLFLYS usage in SwRangeRedline::MoveFromSection() could be removed (because the end-of-section check already handles the case) except for this, because it turns out that the ODF import runs SetRedlineFlags with a temporarily reset IsInXMLImport() flag because of its effect in thints.cxx, so during the move IsSelectFrameAnchoredAtPara() can't check it. tdf#108124 scenario works better, now everything that's selected is both copied and deleted. Fixes the problem where an at-para fly at the 2nd node of a redline where the 1st node is partially deleted was lost on ODF export. (cherry picked from commit 91b2325808a75174f284c48c8b8afc118fad74e4) Conflicts: sw/source/core/undo/undobj.cxx sw/source/core/undo/untblk.cxx Change-Id: I168013665e70ff0a5f198e09f3fa3afc06ba0449 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89098 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r--sw/inc/undobj.hxx6
-rw-r--r--sw/qa/core/uwriter.cxx3
-rw-r--r--sw/qa/extras/uiwriter/data/redline_fly_at_para_one_paragraph.odtbin0 -> 9251 bytes
-rw-r--r--sw/qa/extras/uiwriter/data/redline_fly_duplication_at_para_2nd_paragraph.fodt222
-rw-r--r--sw/qa/extras/uiwriter/uiwriter.cxx16
-rw-r--r--sw/qa/uitest/writer_tests4/tdf108124.py15
-rw-r--r--sw/source/core/access/accframebase.cxx3
-rw-r--r--sw/source/core/access/accmap.cxx12
-rw-r--r--sw/source/core/doc/DocumentContentOperationsManager.cxx45
-rw-r--r--sw/source/core/doc/docedt.cxx57
-rw-r--r--sw/source/core/edit/edglbldc.cxx2
-rw-r--r--sw/source/core/layout/trvlfrm.cxx17
-rw-r--r--sw/source/core/undo/undobj.cxx96
-rw-r--r--sw/source/core/undo/untblk.cxx17
14 files changed, 371 insertions, 140 deletions
diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx
index 2d8b02ce6e12..2008c1926275 100644
--- a/sw/inc/undobj.hxx
+++ b/sw/inc/undobj.hxx
@@ -135,7 +135,7 @@ enum class DelContentType : sal_uInt16
Fly = 0x02,
Bkm = 0x08,
AllMask = 0x0b,
- ExcludeAtCharFlyAtStartEnd = 0x40,
+ ExcludeFlyAtStartEnd = 0x40,
CheckNoCntnt = 0x80,
};
namespace o3tl {
@@ -146,6 +146,10 @@ namespace o3tl {
bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos,
SwPosition const & rStart, SwPosition const & rEnd,
DelContentType const nDelContentType = DelContentType::AllMask);
+/// is a fly anchored at paragraph at rAnchorPos selected?
+bool IsSelectFrameAnchoredAtPara(SwPosition const & rAnchorPos,
+ SwPosition const & rStart, SwPosition const & rEnd,
+ DelContentType const nDelContentType = DelContentType::AllMask);
// This class has to be inherited into an Undo-object if it saves content
// for Redo/Undo...
diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index ac06585c0efe..f97a41042f57 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -1157,8 +1157,7 @@ void SwDocTest::randomTest()
SwMoveFlags nFlags =
getRand(1) // FIXME: puterb this more ?
? SwMoveFlags::DEFAULT
- : SwMoveFlags::ALLFLYS |
- SwMoveFlags::CREATEUNDOOBJ |
+ : SwMoveFlags::CREATEUNDOOBJ |
SwMoveFlags::REDLINES |
SwMoveFlags::NO_DELFRMS;
SwPosition aTo(getRandomPosition(m_pDoc, i/10));
diff --git a/sw/qa/extras/uiwriter/data/redline_fly_at_para_one_paragraph.odt b/sw/qa/extras/uiwriter/data/redline_fly_at_para_one_paragraph.odt
new file mode 100644
index 000000000000..a4b41e4ec25d
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/redline_fly_at_para_one_paragraph.odt
Binary files differ
diff --git a/sw/qa/extras/uiwriter/data/redline_fly_duplication_at_para_2nd_paragraph.fodt b/sw/qa/extras/uiwriter/data/redline_fly_duplication_at_para_2nd_paragraph.fodt
new file mode 100644
index 000000000000..230159513ba0
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/redline_fly_duplication_at_para_2nd_paragraph.fodt
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+ <style:font-face style:name="Wingdings" svg:font-family="Wingdings" style:font-pitch="variable" style:font-charset="x-symbol"/>
+ <style:font-face style:name="Symbol" svg:font-family="Symbol" style:font-family-generic="roman" style:font-pitch="variable" style:font-charset="x-symbol"/>
+ <style:font-face style:name="Arial" svg:font-family="Arial"/>
+ <style:font-face style:name="Scala-Regular" svg:font-family="Scala-Regular"/>
+ <style:font-face style:name="ScalaPro-Regular" svg:font-family="ScalaPro-Regular"/>
+ <style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/>
+ <style:font-face style:name="Courier New" svg:font-family="&apos;Courier New&apos;" style:font-family-generic="modern"/>
+ <style:font-face style:name="ScalaPro-Bold" svg:font-family="ScalaPro-Bold" style:font-family-generic="roman"/>
+ <style:font-face style:name="Arial4" svg:font-family="Arial, Arial" style:font-family-generic="swiss"/>
+ <style:font-face style:name="Arial1" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ <style:font-face style:name="Arial2" svg:font-family="Arial" style:font-adornments="Fett" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ <style:font-face style:name="Arial3" svg:font-family="Arial" style:font-adornments="Standard" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ <style:font-face style:name="Arial Unicode MS" svg:font-family="&apos;Arial Unicode MS&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
+ <style:font-face style:name="DejaVu Sans" svg:font-family="&apos;DejaVu Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="graphic">
+ <style:graphic-properties svg:stroke-color="#000000" draw:fill-color="#99ccff" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
+ <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:font-independent-line-spacing="false">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true" style:font-name="Arial" fo:font-size="11pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="DejaVu Sans" style:font-size-asian="12pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="DejaVu Sans" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/>
+ </style:default-style>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
+ <style:text-properties style:use-window-font-color="true" style:font-name="Arial" fo:font-size="11pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="DejaVu Sans" style:font-size-asian="12pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="DejaVu Sans" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/>
+ </style:default-style>
+ <style:default-style style:family="table">
+ <style:table-properties table:border-model="collapsing"/>
+ </style:default-style>
+ <style:default-style style:family="table-row">
+ <style:table-row-properties fo:keep-together="auto"/>
+ </style:default-style>
+ <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
+ <style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.212cm" loext:contextual-spacing="false"/>
+ </style:style>
+ <style:style style:name="RGUgliederung" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="WW8Num6">
+ <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.529cm" loext:contextual-spacing="false" style:line-height-at-least="0.529cm" fo:text-indent="0cm" style:auto-text-indent="false" style:text-autospace="none" style:punctuation-wrap="simple" style:vertical-align="baseline">
+ <style:tab-stops>
+ <style:tab-stop style:position="0.751cm"/>
+ <style:tab-stop style:position="16.277cm"/>
+ </style:tab-stops>
+ </style:paragraph-properties>
+ <style:text-properties style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="Bullet_20_Symbols" style:display-name="Bullet Symbols" style:family="text">
+ <style:text-properties style:font-name="StarSymbol" fo:font-family="StarSymbol" fo:font-size="9pt" style:font-name-asian="StarSymbol" style:font-family-asian="StarSymbol" style:font-size-asian="9pt" style:font-name-complex="StarSymbol" style:font-family-complex="StarSymbol" style:font-size-complex="9pt"/>
+ </style:style>
+ <style:style style:name="WW8Num6z1" style:family="text">
+ <style:text-properties style:font-name="Courier New" fo:font-family="&apos;Courier New&apos;" style:font-family-generic="modern"/>
+ </style:style>
+ <style:style style:name="WW8Num6z0" style:family="text">
+ <style:text-properties style:font-name="Wingdings" fo:font-family="Wingdings" style:font-pitch="variable" style:font-charset="x-symbol"/>
+ </style:style>
+ <style:style style:name="WW8Num6z3" style:family="text">
+ <style:text-properties style:font-name="Symbol" fo:font-family="Symbol" style:font-family-generic="roman" style:font-pitch="variable" style:font-charset="x-symbol"/>
+ </style:style>
+ <style:style style:name="Graphics" style:family="graphic">
+ <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" style:wrap="none" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph"/>
+ </style:style>
+ <text:list-style style:name="WW8Num6" text:consecutive-numbering="true">
+ <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.635cm" text:min-label-width="0.635cm"/>
+ <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2" text:style-name="WW8Num6z1" text:bullet-char="o">
+ <style:list-level-properties text:space-before="1.905cm" text:min-label-width="0.635cm"/>
+ <style:text-properties fo:font-family="&apos;Courier New&apos;" style:font-family-generic="modern" style:font-pitch="fixed"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3" text:style-name="WW8Num6z0" text:bullet-char="">
+ <style:list-level-properties text:space-before="3.175cm" text:min-label-width="0.635cm"/>
+ <style:text-properties style:font-name="Wingdings"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4" text:style-name="WW8Num6z3" text:bullet-char="">
+ <style:list-level-properties text:space-before="4.445cm" text:min-label-width="0.635cm"/>
+ <style:text-properties style:font-name="Symbol"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5" text:style-name="WW8Num6z1" text:bullet-char="o">
+ <style:list-level-properties text:space-before="5.715cm" text:min-label-width="0.635cm"/>
+ <style:text-properties fo:font-family="&apos;Courier New&apos;" style:font-family-generic="modern" style:font-pitch="fixed"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6" text:style-name="WW8Num6z0" text:bullet-char="">
+ <style:list-level-properties text:space-before="6.985cm" text:min-label-width="0.635cm"/>
+ <style:text-properties style:font-name="Wingdings"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7" text:style-name="WW8Num6z3" text:bullet-char="">
+ <style:list-level-properties text:space-before="8.255cm" text:min-label-width="0.635cm"/>
+ <style:text-properties style:font-name="Symbol"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8" text:style-name="WW8Num6z1" text:bullet-char="o">
+ <style:list-level-properties text:space-before="9.525cm" text:min-label-width="0.635cm"/>
+ <style:text-properties fo:font-family="&apos;Courier New&apos;" style:font-family-generic="modern" style:font-pitch="fixed"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9" text:style-name="WW8Num6z0" text:bullet-char="">
+ <style:list-level-properties text:space-before="10.795cm" text:min-label-width="0.635cm"/>
+ <style:text-properties style:font-name="Wingdings"/>
+ </text:list-level-style-bullet>
+ <text:list-level-style-number text:level="10" style:num-suffix="." style:num-format="1">
+ <style:list-level-properties text:space-before="6.35cm" text:min-label-width="0.635cm"/>
+ </text:list-level-style-number>
+ </text:list-style>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="RGUgliederung" style:list-style-name="WW8Num6">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.229cm" loext:contextual-spacing="false"/>
+ <style:text-properties fo:color="#000000"/>
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="RGUgliederung" style:list-style-name="">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.229cm" loext:contextual-spacing="false"/>
+ <style:text-properties fo:color="#000000"/>
+ </style:style>
+ <style:style style:name="P3" style:family="paragraph" style:parent-style-name="RGUgliederung" style:list-style-name="">
+ <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"/>
+ <style:text-properties fo:color="#000000" style:font-name="Arial1" fo:font-size="11pt" fo:font-weight="normal" officeooo:rsid="0036e634" officeooo:paragraph-rsid="002d5bb4" style:font-name-asian="Scala-Regular" style:font-size-asian="11pt" style:font-weight-asian="normal" style:font-name-complex="Scala-Regular" style:font-size-complex="11pt" style:font-weight-complex="normal"/>
+ </style:style>
+ <style:style style:name="P5" style:family="paragraph" style:parent-style-name="RGUgliederung" style:list-style-name="">
+ <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"/>
+ <style:text-properties fo:color="#000000" style:font-name="Arial2" fo:font-size="11pt" fo:font-weight="normal" officeooo:rsid="0036e634" officeooo:paragraph-rsid="002d5bb4" style:font-name-asian="Scala-Regular" style:font-size-asian="11pt" style:font-weight-asian="normal" style:font-name-complex="Scala-Regular" style:font-size-complex="11pt" style:font-weight-complex="normal"/>
+ </style:style>
+ <style:style style:name="P6" style:family="paragraph" style:parent-style-name="RGUgliederung" style:list-style-name="">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.229cm" loext:contextual-spacing="false"/>
+ <style:text-properties fo:color="#000000"/>
+ </style:style>
+ <style:style style:name="T1" style:family="text">
+ <style:text-properties fo:color="#231f20" style:font-name="Arial3" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal" style:font-name-asian="ScalaPro-Regular" style:font-size-asian="10pt" style:font-name-complex="ScalaPro-Regular" style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="T2" style:family="text">
+ <style:text-properties fo:color="#231f20" style:font-name="Arial3" fo:font-size="10pt" fo:font-style="normal" fo:font-weight="normal" style:font-name-asian="ScalaPro-Bold" style:font-size-asian="10pt" style:font-name-complex="ScalaPro-Bold" style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="T3" style:family="text">
+ <style:text-properties style:font-name="Arial1" fo:font-size="11pt" style:text-underline-style="none" fo:font-weight="bold" style:font-name-asian="ScalaPro-Regular" style:font-size-asian="11pt" style:font-weight-asian="bold" style:font-name-complex="ScalaPro-Regular" style:font-size-complex="11pt" style:font-weight-complex="bold"/>
+ </style:style>
+ <style:style style:name="T4" style:family="text">
+ <style:text-properties style:font-name="Arial1" fo:font-size="11pt" style:text-underline-style="none" fo:font-weight="bold" style:font-name-asian="Arial4" style:font-size-asian="11pt" style:font-weight-asian="bold" style:font-name-complex="Arial1" style:font-size-complex="11pt" style:font-weight-complex="bold"/>
+ </style:style>
+ <style:style style:name="T5" style:family="text">
+ <style:text-properties style:font-name="Arial2" style:font-name-asian="ScalaPro-Regular" style:font-name-complex="ScalaPro-Regular"/>
+ </style:style>
+ <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics">
+ <style:graphic-properties style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm">
+ <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="none" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+ </style:page-layout-properties>
+ <style:header-style/>
+ <style:footer-style/>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:tracked-changes>
+ <text:changed-region xml:id="ct121341168" text:id="ct121341168">
+ <text:deletion>
+ <office:change-info>
+ <dc:creator>Unknown Author</dc:creator>
+ <dc:date>2019-12-04T18:05:04</dc:date>
+ </office:change-info>
+ <text:p text:style-name="P1">x</text:p>
+ <text:p text:style-name="P1"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="paragraph" svg:width="0.67cm" svg:height="0.67cm" draw:z-index="0"><draw:image loext:mime-type="image/png">
+ <office:binary-data>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
+ SUVORK5CYII=
+ </office:binary-data>
+ </draw:image></draw:frame>x</text:p>
+ <text:p text:style-name="P1"/>
+ </text:deletion>
+ </text:changed-region>
+ </text:tracked-changes>
+ <text:sequence-decls>
+ <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+ </text:sequence-decls>
+ <text:p text:style-name="P1">x<text:change text:change-id="ct121341168"/></text:p>
+ <text:p text:style-name="P1"></text:p>
+ </office:text>
+ </office:body>
+</office:document>
+
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx
index c734ba823f6e..a9687593ef10 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -158,6 +158,8 @@ public:
void testRedlineFrameAtCharStartInside();
void testRedlineFrameAtParaStartOutside();
void testRedlineFrameAtParaEndInside();
+ void testRedlineFrameAtParaOneParagraph();
+ void testRedlineFrameAtPara2ndParagraph();
void testThreadedException();
void testBookmarkCopy();
void testFdo69893();
@@ -359,6 +361,8 @@ public:
CPPUNIT_TEST(testRedlineFrameAtCharStartInside);
CPPUNIT_TEST(testRedlineFrameAtParaStartOutside);
CPPUNIT_TEST(testRedlineFrameAtParaEndInside);
+ CPPUNIT_TEST(testRedlineFrameAtParaOneParagraph);
+ CPPUNIT_TEST(testRedlineFrameAtPara2ndParagraph);
CPPUNIT_TEST(testThreadedException);
CPPUNIT_TEST(testBookmarkCopy);
CPPUNIT_TEST(testFdo69893);
@@ -676,6 +680,18 @@ void SwUiWriterTest::testRedlineFrameAtParaEndInside()
testRedlineFrame("redline_fly_duplication_at_para_end_inside.fodt");
}
+void SwUiWriterTest::testRedlineFrameAtParaOneParagraph()
+{
+ // test ALLFLYS flag: oddly enough it didn't fail as fodt but failed as odt...
+ testRedlineFrame("redline_fly_at_para_one_paragraph.odt");
+}
+
+void SwUiWriterTest::testRedlineFrameAtPara2ndParagraph()
+{
+ // lost via the buggy increment in Copy
+ testRedlineFrame("redline_fly_duplication_at_para_2nd_paragraph.fodt");
+}
+
void SwUiWriterTest::testThreadedException()
{
SvFileStream aFileStream(m_directories.getURLFromSrc(DATA_DIRECTORY) + "threadedException.fodt", StreamMode::READ);
diff --git a/sw/qa/uitest/writer_tests4/tdf108124.py b/sw/qa/uitest/writer_tests4/tdf108124.py
index 168f51bff33a..929a3d7b498d 100644
--- a/sw/qa/uitest/writer_tests4/tdf108124.py
+++ b/sw/qa/uitest/writer_tests4/tdf108124.py
@@ -28,11 +28,22 @@ class tdf108124(UITestCase):
xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"CTRL+a"})) # select all
xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"CTRL+c"})) # copy
xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"CTRL+v"})) # paste
- self.assertEqual(document.GraphicObjects.getCount(), 4)
+ self.assertEqual(document.GraphicObjects.getCount(), 2)
+ xObj1Old = document.GraphicObjects[0]
+ xObj2Old = document.GraphicObjects[1]
self.xUITest.executeCommand(".uno:Undo") #Undo
self.assertEqual(document.GraphicObjects.getCount(), 2)
+ xObj1New = document.GraphicObjects[0]
+ xObj2New = document.GraphicObjects[1]
+ # there should be 2 different objects now but they have the same names,
+ # so rely on the object identity for testing...
+ self.assertNotEqual(xObj1Old, xObj1New)
+ self.assertNotEqual(xObj1Old, xObj2New)
+ self.assertNotEqual(xObj2Old, xObj1New)
+ self.assertNotEqual(xObj2Old, xObj2New)
self.xUITest.executeCommand(".uno:Redo") #Redo
- self.assertEqual(document.GraphicObjects.getCount(), 4)
+ self.assertEqual(document.GraphicObjects.getCount(), 2)
self.ui_test.close_doc()
+
# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/access/accframebase.cxx b/sw/source/core/access/accframebase.cxx
index c08e255a6725..bf23ed4a15e9 100644
--- a/sw/source/core/access/accframebase.cxx
+++ b/sw/source/core/access/accframebase.cxx
@@ -340,8 +340,7 @@ bool SwAccessibleFrameBase::GetSelectedState( )
}
else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
{
- if( ((nHere > nStartIndex) || pStart->nContent.GetIndex() ==0 )
- && (nHere < nEndIndex ) )
+ if (IsSelectFrameAnchoredAtPara(*pPos, *pStart, *pEnd))
return true;
}
else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
diff --git a/sw/source/core/access/accmap.cxx b/sw/source/core/access/accmap.cxx
index 5b42a664f0c2..017bb00ab336 100644
--- a/sw/source/core/access/accmap.cxx
+++ b/sw/source/core/access/accmap.cxx
@@ -1215,21 +1215,19 @@ void SwAccessibleMap::InvalidateShapeInParaSelection()
}
else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
{
- if (((nStartIndex < nFirstNode) ||
- (nFirstNode == nStartIndex && pStart->nContent.GetIndex() == 0))
- && (nLastNode < nEndIndex))
- {
- uno::Reference < XAccessible > xAcc( (*aIter).second );
+ uno::Reference<XAccessible> const xAcc((*aIter).second);
if( xAcc.is() )
+ {
+ if (IsSelectFrameAnchoredAtPara(*pPos, *pStart, *pEnd))
+ {
static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
}
else
{
- uno::Reference < XAccessible > xAcc( (*aIter).second );
- if(xAcc.is())
static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
}
}
+ }
else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
{
uno::Reference<XAccessible> const xAcc((*aIter).second);
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 137eb9a593ec..650c324dfb7a 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3441,9 +3441,11 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
++nStart;
break;
case RndStdIds::FLY_AT_PARA:
- // FIXME TODO why exclude start node, this seems very questionable and causes data loss on export
- if(m_rDoc.getIDocumentRedlineAccess().IsRedlineMove())
- ++nStart;
+ {
+ bAdd = IsSelectFrameAnchoredAtPara(*pAPos,
+ pCopiedPaM ? *pCopiedPaM->Start() : SwPosition(rRg.aStart),
+ pCopiedPaM ? *pCopiedPaM->End() : SwPosition(rRg.aEnd));
+ }
break;
case RndStdIds::FLY_AT_CHAR:
{
@@ -3455,7 +3457,7 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
default:
continue;
}
- if (RndStdIds::FLY_AT_CHAR != pAnchor->GetAnchorId())
+ if (RndStdIds::FLY_AT_FLY == pAnchor->GetAnchorId())
{
if (nStart > nSkipAfter)
continue;
@@ -3470,31 +3472,6 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
bAdd = true;
if (!bAdd && !m_rDoc.getIDocumentRedlineAccess().IsRedlineMove()) // fdo#40599: not for redline move
{
- bool bEmptyNode = false;
- bool bLastNode = false;
- // is the node empty?
- const SwNodes& rNodes = pAPos->nNode.GetNodes();
- SwTextNode *const pTextNode = pAPos->nNode.GetNode().GetTextNode();
- if (nullptr != pTextNode)
- {
- bEmptyNode = pTextNode->GetText().isEmpty();
- if (bEmptyNode)
- {
- //last node information is only necessary to know for the last TextNode
- SwNodeIndex aTmp( pAPos->nNode );
- ++aTmp;//goto next node
- while (aTmp.GetNode().IsEndNode())
- {
- if (aTmp == rNodes.GetEndOfContent().GetIndex())
- {
- bLastNode = true;
- break;
- }
- ++aTmp;
- }
- }
- }
- bAdd = bLastNode && bEmptyNode;
if (!bAdd)
{
// technically old code checked nContent of AT_FLY which is pointless
@@ -4753,6 +4730,8 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
// at-char anchors post SplitNode are on index 0 of 2nd node and will
// remain there - move them back to the start (end would also work?)
+ // ... also for at-para anchors; here start is preferable because
+ // it's consistent with SplitNode from SwUndoInserts::RedoImpl()
if (pFlysAtInsPos)
{
// init *again* - because CopyWithFlyInFly moved startPos
@@ -4765,6 +4744,8 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
startPos = *temp.GetPoint();
}
assert(startPos.nNode.GetNode().IsContentNode());
+ SwPosition startPosAtPara(startPos);
+ startPosAtPara.nContent.Assign(nullptr, 0);
for (SwFrameFormat * pFly : *pFlysAtInsPos)
{
@@ -4775,6 +4756,12 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
anchor.SetAnchor( &startPos );
pFly->SetFormatAttr(anchor);
}
+ if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PARA)
+ {
+ SwFormatAnchor anchor(*pAnchor);
+ anchor.SetAnchor( &startPosAtPara );
+ pFly->SetFormatAttr(anchor);
+ }
}
}
diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index 7b35c948c31f..169a24cfec2b 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -145,14 +145,14 @@ void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
const SwPosition* pPos = rPam.Start();
const SwNodeIndex& rSttNdIdx = pPos->nNode;
- short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsContentNode() &&
- pPos->nContent.GetIndex()) ? 1 : 0;
- pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
- const SwNodeIndex& rEndNdIdx = pPos->nNode;
- short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsContentNode() &&
- pPos->nContent == rEndNdIdx.GetNode().GetContentNode()->Len() ))
- ? 0 : 1;
+ SwPosition atParaEnd(*rPam.End());
+ if (bMoveAllFlys)
+ {
+ assert(rPam.End()->nContent.GetIndex() == rPam.End()->nNode.GetNode().GetTextNode()->Len());
+ ++atParaEnd.nNode;
+ atParaEnd.nContent.Assign(atParaEnd.nNode.GetNode().GetContentNode(), 0);
+ }
for( SwFrameFormats::size_type n = 0; n < rFormats.size(); ++n )
{
@@ -170,27 +170,13 @@ void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
{
bool bInsPos = false;
- if (!bMoveAllFlys
- && RndStdIds::FLY_AT_CHAR != pAnchor->GetAnchorId()
- && rEndNdIdx == pAPos->nNode)
- {
- // Do not touch Anchor, if only a part of the EndNode
- // or the whole EndNode is identical with the SttNode
- if( rSttNdIdx != pAPos->nNode )
- {
- // Only attach an anchor to the beginning or end
- SwPosition aPos( rSttNdIdx );
- SwFormatAnchor aAnchor( *pAnchor );
- aAnchor.SetAnchor( &aPos );
- pFormat->SetFormatAttr( aAnchor );
- }
- }
- else if ( (//bMoveAllFlys ... no do not check - all callers are actually from redline code, from the MoveToSection case; so check bMoveAllFlys only for AT_PARA!
- (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())
+ if ( (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
&& IsDestroyFrameAnchoredAtChar(*pAPos, *rPam.Start(), *rPam.End()))
|| (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()
- && rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
- && pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff)
+ && IsSelectFrameAnchoredAtPara(*pAPos, *rPam.Start(), atParaEnd,
+ bMoveAllFlys
+ ? DelContentType::CheckNoCntnt|DelContentType::AllMask
+ : DelContentType::AllMask))
|| (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()
&& (bInsPos = (rInsPos.nNode == pAPos->nNode)))
|| (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
@@ -231,7 +217,6 @@ void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
: SwPosition(rMkNdIdx));
SwPosition const& rStart = mark <= point ? mark : point;
SwPosition const& rEnd = mark <= point ? point : mark;
- const bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
SwFrameFormats& rTable = *pDoc->GetSpzFrameFormats();
@@ -242,25 +227,14 @@ void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
SwPosition const*const pAPos = rAnch.GetContentAnchor();
if (pAPos &&
(((rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
- && (bDelFwrd
- ? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
- : rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx))
+ && IsSelectFrameAnchoredAtPara(*pAPos, rStart, rEnd, pPtIdx
+ ? DelContentType::AllMask
+ : DelContentType::AllMask|DelContentType::CheckNoCntnt))
|| ((rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
&& IsDestroyFrameAnchoredAtChar(*pAPos, rStart, rEnd, pPtIdx
? DelContentType::AllMask
: DelContentType::AllMask|DelContentType::CheckNoCntnt))))
{
- // Only move the Anchor??
- if ((rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
- && rPtNdIdx == pAPos->nNode )
- {
- SwFormatAnchor aAnch( pFormat->GetAnchor() );
- SwPosition aPos( rMkNdIdx );
- aAnch.SetAnchor( &aPos );
- pFormat->SetFormatAttr( aAnch );
- }
- else
- {
// If the Fly is deleted, all Flys in its content have to be deleted too.
const SwFormatContent &rContent = pFormat->GetContent();
// But only fly formats own their content, not draw formats.
@@ -284,7 +258,6 @@ void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
}
}
}
-}
// #i59534: Redo of insertion of multiple text nodes runs into trouble
// because of unnecessary expanded redlines
diff --git a/sw/source/core/edit/edglbldc.cxx b/sw/source/core/edit/edglbldc.cxx
index ec14ef48661d..309cc7aabd50 100644
--- a/sw/source/core/edit/edglbldc.cxx
+++ b/sw/source/core/edit/edglbldc.cxx
@@ -326,7 +326,7 @@ bool SwEditShell::MoveGlobalDocContent( const SwGlblDocContents& rArr ,
aInsPos = pMyDoc->GetNodes().GetEndOfContent();
bool bRet = pMyDoc->getIDocumentContentOperations().MoveNodeRange( aRg, aInsPos,
- SwMoveFlags::ALLFLYS | SwMoveFlags::CREATEUNDOOBJ );
+ SwMoveFlags::CREATEUNDOOBJ );
EndAllAction();
return bRet;
diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx
index 5c466862c816..b4a76d09b839 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -2583,22 +2583,7 @@ void SwRootFrame::CalcFrameRects(SwShellCursor &rCursor)
&& ( (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR
&& IsDestroyFrameAnchoredAtChar(*anchoredAt, *pStartPos, *pEndPos))
|| (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
- && *pStartPos <= *anchoredAt
- && *anchoredAt < *pEndPos)));
- if (anchoredAt != nullptr
- && rAnchor.GetAnchorId() != RndStdIds::FLY_AT_CHAR
- && *anchoredAt == *pEndPos)
- {
- const SwNodes& nodes = anchoredAt->GetDoc()->GetNodes();
- if( *pEndPos == SwPosition( nodes.GetEndOfContent()))
- inSelection = true;
- else
- {
- SwNodeIndex idx( nodes.GetEndOfContent());
- if( SwContentNode* last = SwNodes::GoPrevious( &idx ))
- inSelection = *pEndPos == SwPosition( *last, last->Len());
- }
- }
+ && IsSelectFrameAnchoredAtPara(*anchoredAt, *pStartPos, *pEndPos))));
if( inSelection )
Add( aRegion, pFly->getFrameArea() );
else if ( !pFly->IsAnLower( pStartFrame ) &&
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index dcbe3a4a04cc..a062f168acb0 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -932,7 +932,6 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
const SwFrameFormats& rSpzArr = *pDoc->GetSpzFrameFormats();
if( !rSpzArr.empty() )
{
- const bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex();
SwFrameFormat* pFormat;
const SwFormatAnchor* pAnchor;
size_t n = rSpzArr.size();
@@ -966,28 +965,25 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
case RndStdIds::FLY_AT_PARA:
{
pAPos = pAnchor->GetContentAnchor();
- if( pAPos )
- {
- bool bTmp;
- if( DelContentType::CheckNoCntnt & nDelContentType )
- bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode;
- else
- {
- if (bDelFwrd)
- bTmp = rMark.nNode < pAPos->nNode &&
- pAPos->nNode <= rPoint.nNode;
- else
- bTmp = rPoint.nNode <= pAPos->nNode &&
- pAPos->nNode < rMark.nNode;
- }
-
- if (bTmp)
+ if (pAPos &&
+ pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode)
{
if( !pHistory )
pHistory.reset( new SwHistory );
+ if (IsSelectFrameAnchoredAtPara(*pAPos, *pStt, *pEnd, nDelContentType))
+ {
+ pHistory->AddDeleteFly(*pFormat, nChainInsPos);
+ // reset n so that no Format is skipped
+ n = n >= rSpzArr.size()
+ ? rSpzArr.size() : n+1;
+ }
// Moving the anchor?
- if( !( DelContentType::CheckNoCntnt & nDelContentType ) &&
+ else if (!((DelContentType::CheckNoCntnt|DelContentType::ExcludeFlyAtStartEnd)
+ & nDelContentType) &&
+ // at least for calls from SwUndoDelete,
+ // this should work - other Undos don't
+ // remember the order of the cursor
(rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex())
// Do not try to move the anchor to a table!
&& rMark.nNode.GetNode().IsTextNode())
@@ -998,14 +994,6 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
aAnch.SetAnchor( &aPos );
pFormat->SetFormatAttr( aAnch );
}
- else
- {
- pHistory->AddDeleteFly(*pFormat, nChainInsPos );
- // reset n so that no Format is skipped
- n = n >= rSpzArr.size() ?
- rSpzArr.size() : n+1;
- }
- }
}
}
break;
@@ -1022,7 +1010,7 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
}
else if (!((DelContentType::CheckNoCntnt |
- DelContentType::ExcludeAtCharFlyAtStartEnd)
+ DelContentType::ExcludeFlyAtStartEnd)
& nDelContentType))
{
if( *pStt <= *pAPos && *pAPos < *pEnd )
@@ -1540,6 +1528,15 @@ static bool IsAtStartOfSection(SwPosition const& rAnchorPos)
return node == rAnchorPos.nNode && rAnchorPos.nContent == 0;
}
+static bool IsNotBackspaceHeuristic(
+ SwPosition const& rStart, SwPosition const& rEnd)
+{
+ // check if the selection is backspace/delete created by DelLeft/DelRight
+ return rStart.nNode.GetIndex() + 1 != rEnd.nNode.GetIndex()
+ || rEnd.nContent != 0
+ || rStart.nContent != rStart.nNode.GetNode().GetTextNode()->Len();
+}
+
bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos,
SwPosition const & rStart, SwPosition const & rEnd,
DelContentType const nDelContentType)
@@ -1559,16 +1556,57 @@ bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos,
// in general, exclude the start and end position
return ((rStart < rAnchorPos)
|| (rStart == rAnchorPos
- && !(nDelContentType & DelContentType::ExcludeAtCharFlyAtStartEnd)
+ && !(nDelContentType & DelContentType::ExcludeFlyAtStartEnd)
// special case: fully deleted node
&& ((rStart.nNode != rEnd.nNode && rStart.nContent == 0)
|| IsAtStartOfSection(rAnchorPos))))
&& ((rAnchorPos < rEnd)
|| (rAnchorPos == rEnd
- && !(nDelContentType & DelContentType::ExcludeAtCharFlyAtStartEnd)
+ && !(nDelContentType & DelContentType::ExcludeFlyAtStartEnd)
// special case: fully deleted node
&& ((rEnd.nNode != rStart.nNode && rEnd.nContent == rEnd.nNode.GetNode().GetTextNode()->Len())
|| IsAtEndOfSection(rAnchorPos))));
}
+bool IsSelectFrameAnchoredAtPara(SwPosition const & rAnchorPos,
+ SwPosition const & rStart, SwPosition const & rEnd,
+ DelContentType const nDelContentType)
+{
+ assert(rStart <= rEnd);
+
+ // CheckNoCntnt means DelFullPara which is obvious to handle
+ if (DelContentType::CheckNoCntnt & nDelContentType)
+ { // exclude selection end node because it won't be deleted
+ return (rAnchorPos.nNode < rEnd.nNode)
+ && (rStart.nNode <= rAnchorPos.nNode);
+ }
+
+ if (rAnchorPos.GetDoc()->IsInReading())
+ { // FIXME hack for writerfilter RemoveLastParagraph(); can't test file format more specific?
+ // but it MUST NOT be done during the SetRedlineFlags at the end of ODF
+ // import, where the IsInXMLImport() cannot be checked because the
+ // stupid code temp. overrides it - instead rely on setting the ALLFLYS
+ // flag in MoveFromSection() and converting that to CheckNoCntnt with
+ // adjusted cursor!
+ return (rStart.nNode < rAnchorPos.nNode) && (rAnchorPos.nNode < rEnd.nNode);
+ }
+
+ // in general, exclude the start and end position
+ return ((rStart.nNode < rAnchorPos.nNode)
+ || (rStart.nNode == rAnchorPos.nNode
+ && !(nDelContentType & DelContentType::ExcludeFlyAtStartEnd)
+ // special case: fully deleted node
+ && ((rStart.nNode != rEnd.nNode && rStart.nContent == 0
+ // but not if the selection is backspace/delete!
+ && IsNotBackspaceHeuristic(rStart, rEnd))
+ || IsAtStartOfSection(rStart))))
+ && ((rAnchorPos.nNode < rEnd.nNode)
+ || (rAnchorPos.nNode == rEnd.nNode
+ && !(nDelContentType & DelContentType::ExcludeFlyAtStartEnd)
+ // special case: fully deleted node
+ && ((rEnd.nNode != rStart.nNode && rEnd.nContent == rEnd.nNode.GetNode().GetTextNode()->Len()
+ && IsNotBackspaceHeuristic(rStart, rEnd))
+ || IsAtEndOfSection(rEnd))));
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/undo/untblk.cxx b/sw/source/core/undo/untblk.cxx
index 01d2970be4d1..9e61a945e5fb 100644
--- a/sw/source/core/undo/untblk.cxx
+++ b/sw/source/core/undo/untblk.cxx
@@ -201,15 +201,14 @@ SwUndoInserts::~SwUndoInserts()
// But storing absolute indices leads to crashes if some action in Undo fails to roll back some modifications.
// Has following main steps:
-// 1. DelContentIndex to delete footnotes, flys, bookmarks (see comment for this function)
+// 1. m_FlyUndos removes flys anchored to first and last paragraph in Undo range.
+// This array may be empty.
+// 2. DelContentIndex to delete footnotes, flys, bookmarks (see comment for this function)
// Deleted flys are stored in pHistory array.
-// First and last paragraphs flys are handled later in this function! They are not deleted by DelContentIndex!
-// For flys anchored to last paragraph, DelContentIndex re-anchors them to the last paragraph that will remain after Undo.
-// This is not fully correct, as everything between nSttNode and nEndNode should be deleted (these nodes marks range of inserted nodes).
-// But due to bug in paste (probably there), during paste all flys are anchored to last paragraph (see https://bugs.documentfoundation.org/show_bug.cgi?id=94225#c38).
-// So they should be re-anchored.
-// 2. MoveToUndoNds moves nodes to Undo nodes array and removes them from document.
-// 3. m_FlyUndos removes flys anchored to first and last paragraph in Undo range. This array may be empty.
+// First and last paragraphs flys are not deleted by DelContentIndex!
+// For flys anchored to last paragraph, DelContentIndex re-anchors them to
+// the last paragraph that will remain after Undo.
+// 3. MoveToUndoNds moves nodes to Undo nodes array and removes them from document.
// 4. Lastly (starting from if(pTextNode)), text from last paragraph is joined to last remaining paragraph and FormatColl for last paragraph is restored.
// Format coll for last paragraph is removed during execution of UndoImpl
@@ -266,7 +265,7 @@ void SwUndoInserts::UndoImpl(::sw::UndoRedoContext & rContext)
nSetPos = pHistory->Count();
sal_uLong nTmp = rPam.GetMark()->nNode.GetIndex();
DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(),
- DelContentType::AllMask|DelContentType::ExcludeAtCharFlyAtStartEnd);
+ DelContentType::AllMask|DelContentType::ExcludeFlyAtStartEnd);
nNdDiff += nTmp - rPam.GetMark()->nNode.GetIndex();
if( *rPam.GetPoint() != *rPam.GetMark() )
{