summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stahl <Michael.Stahl@cib.de>2020-11-20 17:16:35 +0100
committerMichael Stahl <michael.stahl@cib.de>2020-11-24 12:09:23 +0100
commit7ab349296dac79dad3fec09f60348efcbb9ea17e (patch)
tree7ac058e03eaa0020f93ad185937b0010ee0cbd74
parent93eb6a87e30c8716b5e65ce71e3d1d9deffb6425 (diff)
sw: fix copying and deleting of section content via API
The problem happens if a section starts or ends with a table: SwXTextSection::getAnchor() may return a SwXTextRange with one position in a table cell and another position in a different table cell, or outside the table, neither of which is valid to set the cursor via SwXTextViewCurosor::gotoRange(). Introduce a new special mode for SwXTextRange, RANGE_IS_SECTION, analogous to RANGE_IS_TABLE but actually working. Only SwXTextView can be used to create XTransferables, and it requires selecting first via either the SwXTextViewCursor or select(). It's currently not possible to select the content of a section in the ViewShell in these problematic cases, and would be some effort to add. So add a new interface XTransferableTextSupplier that can be used to create XTransferable from the SwXTextRange with RANGE_IS_SECTION. The core CopyRange() and DeleteRange() functions can deal with SwPaMs that start or end in non-text-nodes, so pass the whole section content to these in SwXTextRange::setString() and in SwXTextView::getTransferableFromTextRange(). Change-Id: If7e3210e8a26f5618317c294f2b2f3ed5c217f1c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/106293 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@cib.de>
-rw-r--r--offapi/UnoApi_offapi.mk1
-rw-r--r--offapi/com/sun/star/datatransfer/XTransferableTextSupplier.idl44
-rw-r--r--sw/inc/unotextrange.hxx16
-rw-r--r--sw/qa/extras/uiwriter/uiwriter.cxx9
-rw-r--r--sw/qa/extras/unowriter/data/tdf134250.fodt86
-rw-r--r--sw/qa/extras/unowriter/data/tdf134252.fodt95
-rw-r--r--sw/qa/extras/unowriter/unowriter.cxx122
-rw-r--r--sw/source/core/unocore/unoobj2.cxx163
-rw-r--r--sw/source/core/unocore/unosect.cxx25
-rw-r--r--sw/source/core/unocore/unotbl.cxx3
-rw-r--r--sw/source/uibase/dochdl/swdtflvr.cxx95
-rw-r--r--sw/source/uibase/inc/swdtflvr.hxx2
-rw-r--r--sw/source/uibase/inc/unotxvw.hxx5
-rw-r--r--sw/source/uibase/uno/unotxvw.cxx29
14 files changed, 654 insertions, 41 deletions
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 8d6e21d00a9b..eabb1272588a 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -2132,6 +2132,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/datatransfer,\
XTransferableEx \
XTransferableSource \
XTransferableSupplier \
+ XTransferableTextSupplier \
))
$(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/datatransfer/clipboard,\
ClipboardEvent \
diff --git a/offapi/com/sun/star/datatransfer/XTransferableTextSupplier.idl b/offapi/com/sun/star/datatransfer/XTransferableTextSupplier.idl
new file mode 100644
index 000000000000..7d91ec9f0c41
--- /dev/null
+++ b/offapi/com/sun/star/datatransfer/XTransferableTextSupplier.idl
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef __com_sun_star_datatransfer_XTransferableTextSupplier_idl__
+#define __com_sun_star_datatransfer_XTransferableTextSupplier_idl__
+
+#include <com/sun/star/datatransfer/XTransferable.idl>
+#include <com/sun/star/text/XTextRange.idl>
+
+
+module com { module sun { module star { module datatransfer {
+
+/** @since LO 7.2
+ */
+interface XTransferableTextSupplier
+{
+ /** Provide access to a transferable representation of a given text
+ range.
+
+ @param xRange a text range known to the supplier.
+
+ @returns
+ a transferable object representing the given text range.
+
+ @see com::sun::star::datatransfer::XTransferable
+ */
+ XTransferable getTransferableForTextRange(
+ [in] com::sun::star::text::XTextRange xRange);
+
+};
+
+
+}; }; }; };
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/unotextrange.hxx b/sw/inc/unotextrange.hxx
index 41a69049fc5e..471a9ae8bc3e 100644
--- a/sw/inc/unotextrange.hxx
+++ b/sw/inc/unotextrange.hxx
@@ -55,10 +55,16 @@ public:
namespace sw {
+ enum class TextRangeMode {
+ RequireTextNode,
+ AllowNonTextNode
+ };
+
void DeepCopyPaM(SwPaM const & rSource, SwPaM & rTarget);
SW_DLLPUBLIC bool XTextRangeToSwPaM(SwUnoInternalPaM& rToFill,
- const css::uno::Reference< css::text::XTextRange > & xTextRange);
+ const css::uno::Reference<css::text::XTextRange> & xTextRange,
+ TextRangeMode eMode = TextRangeMode::RequireTextNode);
css::uno::Reference< css::text::XText >
CreateParentXText(SwDoc & rDoc, const SwPosition& rPos);
@@ -95,6 +101,7 @@ private:
RANGE_IN_TEXT, // "ordinary" css::text::TextRange
RANGE_IN_CELL, // position created with a cell that has no uno object
RANGE_IS_TABLE, // anchor of a table
+ RANGE_IS_SECTION, // anchor of a section
};
void SetPositions(SwPaM const& rPam);
@@ -112,11 +119,14 @@ public:
const css::uno::Reference< css::text::XText > & xParent,
const enum RangePosition eRange = RANGE_IN_TEXT);
// only for RANGE_IS_TABLE
- SwXTextRange(SwFrameFormat& rTableFormat);
+ SwXTextRange(SwTableFormat& rTableFormat);
+ // only for RANGE_IS_SECTION
+ SwXTextRange(SwSectionFormat& rSectionFormat);
const SwDoc& GetDoc() const;
SwDoc& GetDoc();
- bool GetPositions(SwPaM & rToFill) const;
+ bool GetPositions(SwPaM & rToFill,
+ ::sw::TextRangeMode eMode = ::sw::TextRangeMode::RequireTextNode) const;
static css::uno::Reference< css::text::XTextRange > CreateXTextRange(
SwDoc & rDoc,
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx
index 9e88e37f2aaa..8190ef8834ca 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -1374,7 +1374,8 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf134250)
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
uno::Reference<text::XTextContent> xTextContent(xSections->getByIndex(0), uno::UNO_QUERY);
- CPPUNIT_ASSERT(xTextContent->getAnchor()->getString().endsWith("bar"));
+ CPPUNIT_ASSERT_EQUAL(OUString("foo" SAL_NEWLINE_STRING "bar"),
+ xTextContent->getAnchor()->getString());
// select all with table at start -> 3 times
dispatchCommand(mxComponent, ".uno:SelectAll", {});
@@ -1403,7 +1404,8 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf134250)
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
// Without the fix in place, section's content would have been gone after undo
- CPPUNIT_ASSERT(xTextContent->getAnchor()->getString().endsWith("bar"));
+ CPPUNIT_ASSERT_EQUAL(OUString("foo" SAL_NEWLINE_STRING "bar"),
+ xTextContent->getAnchor()->getString());
dispatchCommand(mxComponent, ".uno:Redo", {});
Scheduler::ProcessEventsToIdle();
@@ -1416,7 +1418,8 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf134250)
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
- CPPUNIT_ASSERT(xTextContent->getAnchor()->getString().endsWith("bar"));
+ CPPUNIT_ASSERT_EQUAL(OUString("foo" SAL_NEWLINE_STRING "bar"),
+ xTextContent->getAnchor()->getString());
dispatchCommand(mxComponent, ".uno:Redo", {});
Scheduler::ProcessEventsToIdle();
diff --git a/sw/qa/extras/unowriter/data/tdf134250.fodt b/sw/qa/extras/unowriter/data/tdf134250.fodt
new file mode 100644
index 000000000000..86aaa140c9e7
--- /dev/null
+++ b/sw/qa/extras/unowriter/data/tdf134250.fodt
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:officeooo="http://openoffice.org/2009/office" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field: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:xforms="http://www.w3.org/2002/xforms" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+ <style:font-face style:name="Liberation Serif" svg:font-family="&apos;Liberation Serif&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-face style:name="Lohit Devanagari" svg:font-family="&apos;Lohit Devanagari&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
+ <style:font-face style:name="Source Han Serif CN" svg:font-family="&apos;Source Han Serif CN&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="#3465a4" draw:fill-color="#729fcf" 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:writing-mode="lr-tb" style:font-independent-line-spacing="false">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" 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:orphans="2" fo:widows="2" 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" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" 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" loext:hyphenation-no-caps="false"/>
+ </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="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties fo:orphans="0" fo:widows="0" text:number-lines="false" text:line-number="0"/>
+ </style:style>
+
+ <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
+ <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
+ <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="17cm" table:align="margins"/>
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:table-column-properties style:column-width="17cm" style:rel-column-width="65535*"/>
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:padding="0.097cm" fo:border="0.05pt solid #000000"/>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
+ <style:text-properties officeooo:rsid="001fe5a9" officeooo:paragraph-rsid="001fe5a9"/>
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:text-properties officeooo:rsid="001fe5a9" officeooo:paragraph-rsid="001fe5a9"/>
+ </style:style>
+ <style:style style:name="T1" style:family="text">
+ <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
+ </style:style>
+ <style:style style:name="Sect1" style:family="section">
+ <style:section-properties style:editable="false">
+ <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+ </style:section-properties>
+ </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: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="solid" 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:section text:style-name="Sect1" text:name="Section1">
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P2">foo</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="P1">b<text:span text:style-name="T1">a</text:span><text:bookmark text:name="Bookmark 1"/>r</text:p>
+ </text:section>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/unowriter/data/tdf134252.fodt b/sw/qa/extras/unowriter/data/tdf134252.fodt
new file mode 100644
index 000000000000..6e19ac847dd8
--- /dev/null
+++ b/sw/qa/extras/unowriter/data/tdf134252.fodt
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:officeooo="http://openoffice.org/2009/office" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field: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:xforms="http://www.w3.org/2002/xforms" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+ <style:font-face style:name="Liberation Serif" svg:font-family="&apos;Liberation Serif&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-face style:name="Lohit Devanagari" svg:font-family="&apos;Lohit Devanagari&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
+ <style:font-face style:name="Source Han Serif CN" svg:font-family="&apos;Source Han Serif CN&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="#3465a4" draw:fill-color="#729fcf" 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:writing-mode="lr-tb" style:font-independent-line-spacing="false">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" 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:orphans="2" fo:widows="2" 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" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" 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" loext:hyphenation-no-caps="false"/>
+ </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"/>
+ <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
+ <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
+ <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="17cm" table:align="margins"/>
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:table-column-properties style:column-width="17cm" style:rel-column-width="65535*"/>
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:padding="0.097cm" fo:border="0.05pt solid #000000"/>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
+ <style:text-properties officeooo:rsid="00078615" officeooo:paragraph-rsid="00078615"/>
+ </style:style>
+ <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:text-properties officeooo:rsid="00095b34" officeooo:paragraph-rsid="00095b34"/>
+ </style:style>
+ <style:style style:name="Sect1" style:family="section">
+ <style:section-properties fo:background-color="#81d41a" style:editable="false">
+ <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+ <style:background-image/>
+ </style:section-properties>
+ </style:style>
+ <style:style style:name="Sect2" style:family="section">
+ <style:section-properties style:editable="false">
+ <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+ </style:section-properties>
+ </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="solid" 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: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:section text:style-name="Sect1" text:name="Section1">
+ <text:p text:style-name="P1">bar</text:p>
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P3">baz</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ </text:section>
+ <text:section text:style-name="Sect2" text:name="Section2">
+ <text:p text:style-name="P1">foo</text:p>
+ </text:section>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/unowriter/unowriter.cxx b/sw/qa/extras/unowriter/unowriter.cxx
index a316f3485777..a3cf7afaa37e 100644
--- a/sw/qa/extras/unowriter/unowriter.cxx
+++ b/sw/qa/extras/unowriter/unowriter.cxx
@@ -10,6 +10,8 @@
#include <swmodeltestbase.hxx>
#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/datatransfer/XTransferableSupplier.hpp>
+#include <com/sun/star/datatransfer/XTransferableTextSupplier.hpp>
#include <com/sun/star/table/XCellRange.hpp>
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <com/sun/star/text/AutoTextContainer.hpp>
@@ -374,6 +376,126 @@ CPPUNIT_TEST_FIXTURE(SwUnoWriter, testXAutoTextGroup)
xAutoTextContainer->removeByName(sGroupName);
}
+CPPUNIT_TEST_FIXTURE(SwUnoWriter, testSectionAnchorCopyTableAtStart)
+{
+ // this contains a section that starts with a table
+ load(DATA_DIRECTORY, "tdf134250.fodt");
+
+ uno::Reference<text::XTextTablesSupplier> const xTextTablesSupplier(mxComponent,
+ uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> const xTables(xTextTablesSupplier->getTextTables(),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
+
+ uno::Reference<text::XTextSectionsSupplier> const xTextSectionsSupplier(mxComponent,
+ uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> const xSections(
+ xTextSectionsSupplier->getTextSections(), uno::UNO_QUERY);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+
+ uno::Reference<text::XTextContent> const xSection(xSections->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> const xAnchor(xSection->getAnchor());
+ CPPUNIT_ASSERT_EQUAL(OUString("foo" SAL_NEWLINE_STRING "bar"), xAnchor->getString());
+
+ // copy the content of the section to a clipboard document
+ uno::Reference<datatransfer::XTransferableSupplier> const xTS(
+ uno::Reference<frame::XModel>(mxComponent, uno::UNO_QUERY_THROW)->getCurrentController(),
+ uno::UNO_QUERY);
+ uno::Reference<datatransfer::XTransferableTextSupplier> const xTTS(xTS, uno::UNO_QUERY);
+ uno::Reference<datatransfer::XTransferable> const xTransferable(
+ xTTS->getTransferableForTextRange(xAnchor));
+
+ // check this doesn't throw
+ CPPUNIT_ASSERT(xAnchor->getStart().is());
+ CPPUNIT_ASSERT(xAnchor->getEnd().is());
+
+ // replace section content
+ xAnchor->setString("quux");
+
+ // table in section was deleted, but not section itself
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables->getCount());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("\""
+ "quux" /*SAL_NEWLINE_STRING*/ "\""),
+ OUString("\"" + xAnchor->getString() + "\""));
+
+ // now paste it
+ uno::Reference<text::XTextViewCursorSupplier> const xTVCS(xTS, uno::UNO_QUERY);
+ uno::Reference<text::XTextViewCursor> const xCursor(xTVCS->getViewCursor());
+ xCursor->gotoEnd(false);
+ xTS->insertTransferable(xTransferable);
+
+ // table in section was pasted, but not section itself
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ xCursor->gotoStart(true);
+ CPPUNIT_ASSERT_EQUAL(OUString("quux" SAL_NEWLINE_STRING "foo" SAL_NEWLINE_STRING "bar"),
+ xCursor->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUnoWriter, testSectionAnchorCopyTableAtEnd)
+{
+ // this contains a section that ends with a table (plus another section)
+ load(DATA_DIRECTORY, "tdf134252.fodt");
+
+ uno::Reference<text::XTextTablesSupplier> const xTextTablesSupplier(mxComponent,
+ uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> const xTables(xTextTablesSupplier->getTextTables(),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
+
+ uno::Reference<text::XTextSectionsSupplier> const xTextSectionsSupplier(mxComponent,
+ uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> const xSections(
+ xTextSectionsSupplier->getTextSections(), uno::UNO_QUERY);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections->getCount());
+
+ uno::Reference<text::XTextContent> const xSection(xSections->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> const xAnchor(xSection->getAnchor());
+ CPPUNIT_ASSERT_EQUAL(OUString("bar" SAL_NEWLINE_STRING "baz" SAL_NEWLINE_STRING),
+ xAnchor->getString());
+
+ // copy the content of the section to a clipboard document
+ uno::Reference<datatransfer::XTransferableSupplier> const xTS(
+ uno::Reference<frame::XModel>(mxComponent, uno::UNO_QUERY_THROW)->getCurrentController(),
+ uno::UNO_QUERY);
+ uno::Reference<datatransfer::XTransferableTextSupplier> const xTTS(xTS, uno::UNO_QUERY);
+ uno::Reference<datatransfer::XTransferable> const xTransferable(
+ xTTS->getTransferableForTextRange(xAnchor));
+
+ // check this doesn't throw
+ CPPUNIT_ASSERT(xAnchor->getStart().is());
+ CPPUNIT_ASSERT(xAnchor->getEnd().is());
+
+ // replace section content
+ xAnchor->setString("quux");
+
+ // table in section was deleted, but not section itself
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables->getCount());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections->getCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("\""
+ "quux" /*SAL_NEWLINE_STRING*/ "\""),
+ OUString("\"" + xAnchor->getString() + "\""));
+
+ // now paste it
+ uno::Reference<text::XTextViewCursorSupplier> const xTVCS(xTS, uno::UNO_QUERY);
+ uno::Reference<text::XTextViewCursor> const xCursor(xTVCS->getViewCursor());
+ xCursor->gotoEnd(false);
+ xTS->insertTransferable(xTransferable);
+
+ // table in section was pasted, but not section itself
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections->getCount());
+ // note: this selects the 2nd section because it calls StartOfSection()
+ // not SttEndDoc() like it should?
+ xCursor->gotoStart(true);
+ CPPUNIT_ASSERT_EQUAL(OUString(/*"quux" SAL_NEWLINE_STRING */
+ "foobar" SAL_NEWLINE_STRING "baz" SAL_NEWLINE_STRING),
+ xCursor->getString());
+}
+
CPPUNIT_TEST_FIXTURE(SwUnoWriter, testXURI)
{
uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
diff --git a/sw/source/core/unocore/unoobj2.cxx b/sw/source/core/unocore/unoobj2.cxx
index e364bb353f92..63dc5a50d392 100644
--- a/sw/source/core/unocore/unoobj2.cxx
+++ b/sw/source/core/unocore/unoobj2.cxx
@@ -650,20 +650,23 @@ public:
const enum RangePosition m_eRangePosition;
SwDoc& m_rDoc;
uno::Reference<text::XText> m_xParentText;
- const SwFrameFormat* m_pTableFormat;
+ const SwFrameFormat* m_pTableOrSectionFormat;
const ::sw::mark::IMark* m_pMark;
Impl(SwDoc& rDoc, const enum RangePosition eRange,
- SwFrameFormat* const pTableFormat,
+ SwFrameFormat* const pTableOrSectionFormat,
const uno::Reference<text::XText>& xParent = nullptr)
: m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR))
, m_eRangePosition(eRange)
, m_rDoc(rDoc)
, m_xParentText(xParent)
- , m_pTableFormat(pTableFormat)
+ , m_pTableOrSectionFormat(pTableOrSectionFormat)
, m_pMark(nullptr)
{
- m_pTableFormat && StartListening(pTableFormat->GetNotifier());
+ if (m_pTableOrSectionFormat)
+ {
+ StartListening(pTableOrSectionFormat->GetNotifier());
+ }
}
virtual ~Impl() override
@@ -679,7 +682,7 @@ public:
m_rDoc.getIDocumentMarkAccess()->deleteMark(m_pMark);
m_pMark = nullptr;
}
- m_pTableFormat = nullptr;
+ m_pTableOrSectionFormat = nullptr;
EndListeningAll();
}
@@ -687,7 +690,7 @@ public:
void SetMark(::sw::mark::IMark& rMark)
{
EndListeningAll();
- m_pTableFormat = nullptr;
+ m_pTableOrSectionFormat = nullptr;
m_pMark = &rMark;
StartListening(rMark.GetNotifier());
}
@@ -701,7 +704,7 @@ void SwXTextRange::Impl::Notify(const SfxHint& rHint)
if(rHint.GetId() == SfxHintId::Dying)
{
EndListeningAll();
- m_pTableFormat = nullptr;
+ m_pTableOrSectionFormat = nullptr;
m_pMark = nullptr;
}
}
@@ -714,7 +717,7 @@ SwXTextRange::SwXTextRange(SwPaM const & rPam,
SetPositions(rPam);
}
-SwXTextRange::SwXTextRange(SwFrameFormat& rTableFormat)
+SwXTextRange::SwXTextRange(SwTableFormat& rTableFormat)
: m_pImpl(
new SwXTextRange::Impl(*rTableFormat.GetDoc(), RANGE_IS_TABLE, &rTableFormat) )
{
@@ -726,6 +729,13 @@ SwXTextRange::SwXTextRange(SwFrameFormat& rTableFormat)
SetPositions( aPam );
}
+SwXTextRange::SwXTextRange(SwSectionFormat& rSectionFormat)
+ : m_pImpl(
+ new SwXTextRange::Impl(*rSectionFormat.GetDoc(), RANGE_IS_SECTION, &rSectionFormat) )
+{
+ // no SetPositions here for now
+}
+
SwXTextRange::~SwXTextRange()
{
}
@@ -753,6 +763,18 @@ void SwXTextRange::SetPositions(const SwPaM& rPam)
m_pImpl->SetMark(*pMark);
}
+static void DeleteTable(SwDoc & rDoc, SwTable& rTable)
+{
+ SwSelBoxes aSelBoxes;
+ for (auto& rBox : rTable.GetTabSortBoxes())
+ {
+ aSelBoxes.insert(rBox);
+ }
+ // note: if the table is the content in the section, this will create
+ // a new text node - that's desirable here
+ rDoc.DeleteRowCol(aSelBoxes);
+}
+
void SwXTextRange::DeleteAndInsert(
const OUString& rText, const bool bForceExpandHints)
{
@@ -764,11 +786,80 @@ void SwXTextRange::DeleteAndInsert(
const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent());
SwCursor aCursor(aPos, nullptr);
- if (!GetPositions(aCursor))
- return;
UnoActionContext aAction(& m_pImpl->m_rDoc);
- m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr);
+
+ if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition)
+ {
+ if (!m_pImpl->m_pTableOrSectionFormat)
+ {
+ throw uno::RuntimeException("disposed?");
+ }
+ m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr);
+ SwSectionFormat const& rFormat(
+ *static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat));
+ SwNodeIndex const start(*rFormat.GetSectionNode());
+ SwNodeIndex const end(*start.GetNode().EndOfSectionNode());
+
+ // delete tables at start
+ for (SwNodeIndex i = start; i < end; )
+ {
+ SwNode & rNode(i.GetNode());
+ if (rNode.IsSectionNode())
+ {
+ ++i;
+ continue;
+ }
+ else if (SwTableNode *const pTableNode = rNode.GetTableNode())
+ {
+ DeleteTable(m_pImpl->m_rDoc, pTableNode->GetTable());
+ // where does that leave index? presumably behind?
+ }
+ else
+ {
+ assert(rNode.IsTextNode());
+ break;
+ }
+ }
+ // delete tables at end
+ for (SwNodeIndex i = end; start <= i; )
+ {
+ --i;
+ SwNode & rNode(i.GetNode());
+ if (rNode.IsEndNode())
+ {
+ if (SwTableNode *const pTableNode = rNode.StartOfSectionNode()->GetTableNode())
+ {
+ DeleteTable(m_pImpl->m_rDoc, pTableNode->GetTable());
+ }
+ else
+ {
+ assert(rNode.StartOfSectionNode()->IsSectionNode());
+ continue;
+ }
+ }
+ else
+ {
+ assert(rNode.IsTextNode());
+ break;
+ }
+ }
+ // now there should be a text node at the start and end of it!
+ *aCursor.GetPoint() = SwPosition(start);
+ aCursor.Move( fnMoveForward, GoInContent );
+ assert(aCursor.GetPoint()->nNode <= end);
+ aCursor.SetMark();
+ *aCursor.GetPoint() = SwPosition(end);
+ aCursor.Move( fnMoveBackward, GoInContent );
+ assert(start <= aCursor.GetPoint()->nNode);
+ }
+ else
+ {
+ if (!GetPositions(aCursor))
+ return;
+ m_pImpl->m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr);
+ }
+
if (aCursor.HasMark())
{
m_pImpl->m_rDoc.getIDocumentContentOperations().DeleteAndJoin(aCursor);
@@ -836,9 +927,9 @@ SwXTextRange::getText()
if (!m_pImpl->m_xParentText.is())
{
if (m_pImpl->m_eRangePosition == RANGE_IS_TABLE &&
- m_pImpl->m_pTableFormat)
+ m_pImpl->m_pTableOrSectionFormat)
{
- SwTable const*const pTable = SwTable::FindTable( m_pImpl->m_pTableFormat );
+ SwTable const*const pTable = SwTable::FindTable( m_pImpl->m_pTableOrSectionFormat );
SwTableNode const*const pTableNode = pTable->GetTableNode();
const SwPosition aPosition( *pTableNode );
m_pImpl->m_xParentText =
@@ -870,6 +961,15 @@ SwXTextRange::getStart()
// start and end are this, if it's a table
xRet = this;
}
+ else if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition
+ && m_pImpl->m_pTableOrSectionFormat)
+ {
+ auto const pSectFormat(static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat));
+ SwPaM aPaM(*pSectFormat->GetContent().GetContentIdx());
+ aPaM.Move( fnMoveForward, GoInContent );
+ assert(aPaM.GetPoint()->nNode < *pSectFormat->GetContent().GetContentIdx()->GetNode().EndOfSectionNode());
+ xRet = new SwXTextRange(aPaM, m_pImpl->m_xParentText);
+ }
else
{
throw uno::RuntimeException("disposed?");
@@ -898,6 +998,15 @@ SwXTextRange::getEnd()
// start and end are this, if it's a table
xRet = this;
}
+ else if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition
+ && m_pImpl->m_pTableOrSectionFormat)
+ {
+ auto const pSectFormat(static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat));
+ SwPaM aPaM(*pSectFormat->GetContent().GetContentIdx()->GetNode().EndOfSectionNode());
+ aPaM.Move( fnMoveBackward, GoInContent );
+ assert(*pSectFormat->GetContent().GetContentIdx() < aPaM.GetPoint()->nNode);
+ xRet = new SwXTextRange(aPaM, m_pImpl->m_xParentText);
+ }
else
{
throw uno::RuntimeException("disposed?");
@@ -913,7 +1022,7 @@ OUString SAL_CALL SwXTextRange::getString()
// for tables there is no bookmark, thus also no text
// one could export the table as ASCII here maybe?
SwPaM aPaM(GetDoc().GetNodes());
- if (GetPositions(aPaM) && aPaM.HasMark())
+ if (GetPositions(aPaM, sw::TextRangeMode::AllowNonTextNode) && aPaM.HasMark())
{
SwUnoCursorHelper::GetTextFromPam(aPaM, sRet);
}
@@ -927,8 +1036,27 @@ void SAL_CALL SwXTextRange::setString(const OUString& rString)
DeleteAndInsert(rString, false);
}
-bool SwXTextRange::GetPositions(SwPaM& rToFill) const
+bool SwXTextRange::GetPositions(SwPaM& rToFill, ::sw::TextRangeMode const eMode) const
{
+ if (RANGE_IS_SECTION == m_pImpl->m_eRangePosition
+ && eMode == ::sw::TextRangeMode::AllowNonTextNode)
+ {
+ if (auto const pSectFormat = static_cast<SwSectionFormat const*>(m_pImpl->m_pTableOrSectionFormat))
+ {
+ SwNodeIndex const*const pSectionNode(pSectFormat->GetContent().GetContentIdx());
+ assert(pSectionNode);
+ assert(pSectionNode->GetNodes().IsDocNodes());
+ rToFill.GetPoint()->nNode = *pSectionNode;
+ ++rToFill.GetPoint()->nNode;
+ rToFill.GetPoint()->nContent.Assign(rToFill.GetPoint()->nNode.GetNode().GetContentNode(), 0);
+ rToFill.SetMark();
+ rToFill.GetMark()->nNode = *pSectionNode->GetNode().EndOfSectionNode();
+ --rToFill.GetMark()->nNode;
+ rToFill.GetMark()->nContent.Assign(rToFill.GetMark()->nNode.GetNode().GetContentNode(),
+ rToFill.GetMark()->nNode.GetNode().GetContentNode() ? rToFill.GetMark()->nNode.GetNode().GetContentNode()->Len() : 0);
+ return true;
+ }
+ }
::sw::mark::IMark const * const pBkmk = m_pImpl->GetBookmark();
if(pBkmk)
{
@@ -950,7 +1078,8 @@ bool SwXTextRange::GetPositions(SwPaM& rToFill) const
namespace sw {
bool XTextRangeToSwPaM( SwUnoInternalPaM & rToFill,
- const uno::Reference< text::XTextRange > & xTextRange)
+ const uno::Reference<text::XTextRange> & xTextRange,
+ ::sw::TextRangeMode const eMode)
{
bool bRet = false;
@@ -984,7 +1113,7 @@ bool XTextRangeToSwPaM( SwUnoInternalPaM & rToFill,
}
if(pRange && &pRange->GetDoc() == &rToFill.GetDoc())
{
- bRet = pRange->GetPositions(rToFill);
+ bRet = pRange->GetPositions(rToFill, eMode);
}
else
{
diff --git a/sw/source/core/unocore/unosect.cxx b/sw/source/core/unocore/unosect.cxx
index 3c0eb298b079..a0c158cc2897 100644
--- a/sw/source/core/unocore/unosect.cxx
+++ b/sw/source/core/unocore/unosect.cxx
@@ -457,14 +457,35 @@ SwXTextSection::getAnchor()
nullptr != ( pIdx = pSectFormat->GetContent().GetContentIdx() ) &&
pIdx->GetNode().GetNodes().IsDocNodes() )
{
+ bool isMoveIntoTable(false);
SwPaM aPaM(*pIdx);
aPaM.Move( fnMoveForward, GoInContent );
+ assert(pIdx->GetNode().IsSectionNode());
+ if (aPaM.GetPoint()->nNode.GetNode().FindTableNode() != pIdx->GetNode().FindTableNode()
+ || aPaM.GetPoint()->nNode.GetNode().FindSectionNode() != &pIdx->GetNode())
+ {
+ isMoveIntoTable = true;
+ }
const SwEndNode* pEndNode = pIdx->GetNode().EndOfSectionNode();
SwPaM aEnd(*pEndNode);
aEnd.Move( fnMoveBackward, GoInContent );
- xRet = SwXTextRange::CreateXTextRange(*pSectFormat->GetDoc(),
- *aPaM.Start(), aEnd.Start());
+ if (aEnd.GetPoint()->nNode.GetNode().FindTableNode() != pIdx->GetNode().FindTableNode()
+ || aEnd.GetPoint()->nNode.GetNode().FindSectionNode() != &pIdx->GetNode())
+ {
+ isMoveIntoTable = true;
+ }
+ if (isMoveIntoTable)
+ {
+ uno::Reference<text::XText> const xParentText(
+ ::sw::CreateParentXText(*pSectFormat->GetDoc(), SwPosition(*pIdx)));
+ xRet = new SwXTextRange(*pSectFormat);
+ }
+ else // for compatibility, keep the old way in this case
+ {
+ xRet = SwXTextRange::CreateXTextRange(*pSectFormat->GetDoc(),
+ *aPaM.Start(), aEnd.Start());
+ }
}
}
return xRet;
diff --git a/sw/source/core/unocore/unotbl.cxx b/sw/source/core/unocore/unotbl.cxx
index 35f3eea3ad0c..c28a6a38f325 100644
--- a/sw/source/core/unocore/unotbl.cxx
+++ b/sw/source/core/unocore/unotbl.cxx
@@ -2179,7 +2179,8 @@ SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange)
uno::Reference<text::XTextRange> SwXTextTable::getAnchor()
{
SolarMutexGuard aGuard;
- SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
+ SwTableFormat *const pFormat = static_cast<SwTableFormat*>(
+ lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
return new SwXTextRange(*pFormat);
}
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index da8c13e04caa..9200cd67df9f 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -82,6 +82,7 @@
#include <IDocumentUndoRedo.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
#include <IDocumentState.hxx>
#include <IMark.hxx>
#include <section.hxx>
@@ -867,6 +868,84 @@ void SwTransferable::DeleteSelection()
m_pWrtShell->EndUndo( SwUndoId::END );
}
+static void DeleteDDEMarks(SwDoc & rDest)
+{
+ IDocumentMarkAccess *const pMarkAccess = rDest.getIDocumentMarkAccess();
+ std::vector< ::sw::mark::IMark* > vDdeMarks;
+ // find all DDE-Bookmarks
+ for (IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
+ ppMark != pMarkAccess->getAllMarksEnd();
+ ++ppMark)
+ {
+ if (IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
+ {
+ vDdeMarks.push_back(*ppMark);
+ }
+ }
+ // remove all DDE-Bookmarks, they are invalid inside the clipdoc!
+ for (const auto& rpMark : vDdeMarks)
+ {
+ pMarkAccess->deleteMark(rpMark);
+ }
+}
+
+void SwTransferable::PrepareForCopyTextRange(SwPaM & rPaM)
+{
+ std::unique_ptr<SwWait> pWait;
+ if (m_pWrtShell->ShouldWait())
+ {
+ pWait.reset(new SwWait( *m_pWrtShell->GetView().GetDocShell(), true ));
+ }
+
+ m_pClpDocFac.reset(new SwDocFac);
+
+ SwDoc& rDest(lcl_GetDoc(*m_pClpDocFac));
+ rDest.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
+ {
+ SwDoc const& rSrc(*m_pWrtShell->GetDoc());
+ assert(&rSrc == &rPaM.GetDoc());
+
+ rDest.ReplaceCompatibilityOptions(rSrc);
+ rDest.ReplaceDefaults(rSrc);
+
+ //It would probably make most sense here to only insert the styles used
+ //by the selection, e.g. apply SwDoc::IsUsed on styles ?
+ rDest.ReplaceStyles(rSrc, false);
+
+ // relevant bits of rSrcWrtShell.Copy(rDest);
+ rDest.GetIDocumentUndoRedo().DoUndo(false); // always false!
+ rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
+
+ SwNodeIndex const aIdx(rDest.GetNodes().GetEndOfContent(), -1);
+ SwContentNode *const pContentNode(aIdx.GetNode().GetContentNode());
+ SwPosition aPos(aIdx,
+ SwIndex(pContentNode, pContentNode ? pContentNode->Len() : 0));
+
+ rSrc.getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly);
+
+ rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
+
+ rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
+ }
+
+ DeleteDDEMarks(rDest);
+
+ // a new one was created in core (OLE objects copied!)
+ m_aDocShellRef = rDest.GetTmpDocShell();
+ if (m_aDocShellRef.Is())
+ SwTransferable::InitOle( m_aDocShellRef );
+ rDest.SetTmpDocShell( nullptr );
+
+ // let's add some formats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::RTF );
+#if HAVE_FEATURE_DESKTOP
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ AddFormat( SotClipboardFormatId::HTML );
+#endif
+ AddFormat( SotClipboardFormatId::STRING );
+}
+
int SwTransferable::PrepareForCopy( bool bIsCut )
{
int nRet = 1;
@@ -974,21 +1053,7 @@ int SwTransferable::PrepareForCopy( bool bIsCut )
rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
- {
- IDocumentMarkAccess* const pMarkAccess = rTmpDoc.getIDocumentMarkAccess();
- std::vector< ::sw::mark::IMark* > vDdeMarks;
- // find all DDE-Bookmarks
- for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
- ppMark != pMarkAccess->getAllMarksEnd();
- ++ppMark)
- {
- if(IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
- vDdeMarks.push_back(*ppMark);
- }
- // remove all DDE-Bookmarks, they are invalid inside the clipdoc!
- for(const auto& rpMark : vDdeMarks)
- pMarkAccess->deleteMark(rpMark);
- }
+ DeleteDDEMarks(rTmpDoc);
// a new one was created in CORE (OLE objects copied!)
m_aDocShellRef = rTmpDoc.GetTmpDocShell();
diff --git a/sw/source/uibase/inc/swdtflvr.hxx b/sw/source/uibase/inc/swdtflvr.hxx
index e231269e7297..cdd3e2124e1e 100644
--- a/sw/source/uibase/inc/swdtflvr.hxx
+++ b/sw/source/uibase/inc/swdtflvr.hxx
@@ -40,6 +40,7 @@ class INetImage;
class SfxAbstractPasteDialog;
class SwDoc;
class SwDocFac;
+class SwPaM;
class SwTextBlocks;
class SwWrtShell;
class SvxClipboardFormatItem;
@@ -181,6 +182,7 @@ public:
int Cut();
int Copy( bool bIsCut = false );
int PrepareForCopy( bool bIsCut = false );
+ void PrepareForCopyTextRange(SwPaM & rPaM);
void CalculateAndCopy(); // special for Calculator
bool CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr );
diff --git a/sw/source/uibase/inc/unotxvw.hxx b/sw/source/uibase/inc/unotxvw.hxx
index db2f6eae398f..b31760d8f9fe 100644
--- a/sw/source/uibase/inc/unotxvw.hxx
+++ b/sw/source/uibase/inc/unotxvw.hxx
@@ -36,6 +36,7 @@
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/datatransfer/XTransferableSupplier.hpp>
+#include <com/sun/star/datatransfer/XTransferableTextSupplier.hpp>
#include <cppuhelper/implbase.hxx>
#include <svl/itemprop.hxx>
#include <TextCursorHelper.hxx>
@@ -55,6 +56,7 @@ class SwXTextView :
public css::view::XViewSettingsSupplier,
public css::beans::XPropertySet,
public css::datatransfer::XTransferableSupplier,
+ public css::datatransfer::XTransferableTextSupplier,
public SfxBaseController
{
::comphelper::OInterfaceContainerHelper2 m_SelChangedListeners;
@@ -129,6 +131,9 @@ public:
virtual css::uno::Reference< css::datatransfer::XTransferable > SAL_CALL getTransferable( ) override;
virtual void SAL_CALL insertTransferable( const css::uno::Reference< css::datatransfer::XTransferable >& xTrans ) override;
+ // XTransferableTextSupplier
+ virtual css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getTransferableForTextRange(css::uno::Reference<css::text::XTextRange> const& xTextRange) override;
+
void NotifySelChanged();
void NotifyDBChanged();
diff --git a/sw/source/uibase/uno/unotxvw.cxx b/sw/source/uibase/uno/unotxvw.cxx
index 6a0aa7edde25..589ad2fc8644 100644
--- a/sw/source/uibase/uno/unotxvw.cxx
+++ b/sw/source/uibase/uno/unotxvw.cxx
@@ -137,6 +137,7 @@ Sequence< uno::Type > SAL_CALL SwXTextView::getTypes( )
cppu::UnoType<XRubySelection>::get(),
cppu::UnoType<XPropertySet>::get(),
cppu::UnoType<datatransfer::XTransferableSupplier>::get(),
+ cppu::UnoType<datatransfer::XTransferableTextSupplier>::get(),
SfxBaseController::getTypes()
).getTypes();
}
@@ -204,6 +205,11 @@ uno::Any SAL_CALL SwXTextView::queryInterface( const uno::Type& aType )
uno::Reference<datatransfer::XTransferableSupplier> xRet = this;
aRet <<= xRet;
}
+ else if(aType == cppu::UnoType<datatransfer::XTransferableTextSupplier>::get())
+ {
+ uno::Reference<datatransfer::XTransferableTextSupplier> xRet = this;
+ aRet <<= xRet;
+ }
else
aRet = SfxBaseController::queryInterface(aType);
return aRet;
@@ -1704,6 +1710,29 @@ SwPaM* SwXTextViewCursor::GetPaM()
return rSh.GetCursor();
}
+uno::Reference<datatransfer::XTransferable> SAL_CALL
+SwXTextView::getTransferableForTextRange(uno::Reference<text::XTextRange> const& xTextRange)
+{
+ SolarMutexGuard aGuard;
+
+ // the point is we can copy PaM that wouldn't be legal as shell cursor
+ SwUnoInternalPaM aPam(*m_pView->GetDocShell()->GetDoc());
+ if (!::sw::XTextRangeToSwPaM(aPam, xTextRange, ::sw::TextRangeMode::AllowNonTextNode))
+ {
+ throw uno::RuntimeException("invalid text range");
+ }
+
+ //force immediate shell update
+ GetView()->StopShellTimer();
+ SwWrtShell& rSh = GetView()->GetWrtShell();
+ SwTransferable *const pTransfer = new SwTransferable(rSh);
+ const bool bLockedView = rSh.IsViewLocked();
+ rSh.LockView( true );
+ pTransfer->PrepareForCopyTextRange(aPam);
+ rSh.LockView( bLockedView );
+ return uno::Reference<datatransfer::XTransferable>(pTransfer);
+}
+
uno::Reference< datatransfer::XTransferable > SAL_CALL SwXTextView::getTransferable()
{
SolarMutexGuard aGuard;