summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamás Zolnai <tamas.zolnai@collabora.com>2017-11-04 16:26:23 +0100
committerTamás Zolnai <tamas.zolnai@collabora.com>2017-11-04 19:11:00 +0100
commit98bc7215935f1eb2e0dc6f1db826d8e729430c13 (patch)
tree677dc15a3800537b25738b35f0dac82a54e5bc9e
parentffb5ad4681f7f68b3b50dc4d94ea7ea8127da5e0 (diff)
tdf#42346: DOCX export of cross-references to objects
* Objects means tables, images, text frames and shapes * Implementation ** MSO uses simple bookmark references as cross-references to objects ** So generate bookmarks in export time if a caption is referenced ** In some cases we also need to split some of the runs ** Implemented all types of cross-references, except the chapter reference Change-Id: I3b17753123d94a04e4f28783ad5663831e7c6c84 Reviewed-on: https://gerrit.libreoffice.org/44294 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
-rw-r--r--sw/CppunitTest_sw_ooxmlexport10.mk97
-rwxr-xr-xsw/qa/extras/ooxmlexport/data/object_cross_reference.odtbin0 -> 35685 bytes
-rwxr-xr-xsw/qa/extras/ooxmlexport/data/table_cross_reference.odtbin0 -> 10243 bytes
-rwxr-xr-xsw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odtbin0 -> 12089 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport10.cxx578
-rw-r--r--sw/source/filter/ww8/attributeoutputbase.hxx2
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx216
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx8
-rw-r--r--sw/source/filter/ww8/docxexport.hxx2
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.hxx1
-rw-r--r--sw/source/filter/ww8/rtfexport.hxx2
-rw-r--r--sw/source/filter/ww8/wrtw8nds.cxx23
-rw-r--r--sw/source/filter/ww8/wrtww8.hxx7
-rw-r--r--sw/source/filter/ww8/ww8atr.cxx64
-rw-r--r--sw/source/filter/ww8/ww8attributeoutput.hxx2
15 files changed, 897 insertions, 105 deletions
diff --git a/sw/CppunitTest_sw_ooxmlexport10.mk b/sw/CppunitTest_sw_ooxmlexport10.mk
index 0dd1596a615e..4976da4ac605 100644
--- a/sw/CppunitTest_sw_ooxmlexport10.mk
+++ b/sw/CppunitTest_sw_ooxmlexport10.mk
@@ -9,101 +9,6 @@
#
#*************************************************************************
-$(eval $(call gb_CppunitTest_CppunitTest,sw_ooxmlexport10))
-
-$(eval $(call gb_CppunitTest_add_exception_objects,sw_ooxmlexport10, \
- sw/qa/extras/ooxmlexport/ooxmlexport10 \
-))
-
-$(eval $(call gb_CppunitTest_use_libraries,sw_ooxmlexport10, \
- basegfx \
- comphelper \
- cppu \
- cppuhelper \
- sal \
- test \
- unotest \
- utl \
- sfx \
- sw \
- tl \
- vcl \
- svxcore \
-))
-
-$(eval $(call gb_CppunitTest_use_externals,sw_ooxmlexport10,\
- boost_headers \
- libxml2 \
-))
-
-$(eval $(call gb_CppunitTest_set_include,sw_ooxmlexport10,\
- -I$(SRCDIR)/sw/inc \
- -I$(SRCDIR)/sw/source/core/inc \
- -I$(SRCDIR)/sw/qa/extras/inc \
- $$(INCLUDE) \
-))
-
-ifeq ($(OS),MACOSX)
-
-$(eval $(call gb_CppunitTest_add_cxxflags,sw_ooxmlexport10,\
- $(gb_OBJCXXFLAGS) \
-))
-
-$(eval $(call gb_CppunitTest_use_system_darwin_frameworks,sw_ooxmlexport10,\
- AppKit \
-))
-
-endif
-
-$(eval $(call gb_CppunitTest_use_sdk_api,sw_ooxmlexport10))
-
-$(eval $(call gb_CppunitTest_use_ure,sw_ooxmlexport10))
-$(eval $(call gb_CppunitTest_use_vcl,sw_ooxmlexport10))
-
-$(eval $(call gb_CppunitTest_use_components,sw_ooxmlexport10,\
- basic/util/sb \
- chart2/source/controller/chartcontroller \
- chart2/source/chartcore \
- canvas/source/factory/canvasfactory \
- comphelper/util/comphelp \
- configmgr/source/configmgr \
- drawinglayer/drawinglayer \
- embeddedobj/util/embobj \
- emfio/emfio \
- filter/source/config/cache/filterconfig1 \
- forms/util/frm \
- framework/util/fwk \
- i18npool/util/i18npool \
- linguistic/source/lng \
- oox/util/oox \
- package/source/xstor/xstor \
- package/util/package2 \
- sax/source/expatwrap/expwrap \
- sw/util/sw \
- sw/util/swd \
- sw/util/msword \
- sfx2/util/sfx \
- starmath/util/sm \
- svl/source/fsstor/fsstorage \
- svl/util/svl \
- svtools/util/svt \
- svx/util/svx \
- svx/util/svxcore \
- toolkit/util/tk \
- ucb/source/core/ucb1 \
- ucb/source/ucp/file/ucpfile1 \
- unotools/util/utl \
- unoxml/source/service/unoxml \
- unoxml/source/rdf/unordf \
- uui/util/uui \
- writerfilter/util/writerfilter \
- xmloff/util/xo \
-))
-
-$(eval $(call gb_CppunitTest_use_configuration,sw_ooxmlexport10))
-
-$(eval $(call gb_CppunitTest_use_uiconfigs,sw_ooxmlexport10,\
- modules/swriter \
-))
+$(eval $(call sw_ooxmlexport_test,10))
# vim: set noet sw=4 ts=4:
diff --git a/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt b/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt
new file mode 100755
index 000000000000..18b02a38c2a9
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt b/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt
new file mode 100755
index 000000000000..bd9c84016157
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt b/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt
new file mode 100755
index 000000000000..cbf03d34ed9f
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index 2c9812c121cf..a4265728e0ff 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -10,13 +10,6 @@
#include <memory>
#include <config_test.h>
-#ifdef MACOSX
-#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
-#include <premac.h>
-#include <AppKit/AppKit.h>
-#include <postmac.h>
-#endif
-
#include <swmodeltestbase.hxx>
#include <com/sun/star/awt/XBitmap.hpp>
@@ -41,6 +34,7 @@
#include <com/sun/star/text/XPageCursor.hpp>
#include <com/sun/star/text/XTextColumns.hpp>
#include <com/sun/star/text/XTextFrame.hpp>
+#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/text/XTextFramesSupplier.hpp>
#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
@@ -1146,6 +1140,576 @@ DECLARE_OOXMLEXPORT_TEST( testTdf107359, "tdf107359-char-pitch.docx" )
CPPUNIT_ASSERT_EQUAL( sal_Int32(convertTwipToMm100(24 * 20)), nBaseWidth );
}
+DECLARE_OOXMLEXPORT_TEST( testTableCrossReference, "table_cross_reference.odt" )
+{
+ // tdf#42346: Cross references to tables were not saved
+ // MSO uses simple bookmarks for referencing table caption, so we do the same by export
+ if (!mbExported)
+ return;
+
+ // Check whether we have all the neccessary bookmarks exported and imported back
+ uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), xBookmarksByIdx->getCount());
+ uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_number_only"));
+
+ // Check bookmark text ranges
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table 1: Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table 1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+ }
+
+ // Check reference fields
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+ uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+ CPPUNIT_ASSERT(xFields->hasMoreElements());
+
+ sal_uInt16 nIndex = 0;
+ while (xFields->hasMoreElements())
+ {
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xFields->nextElement(), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(xServiceInfo, uno::UNO_QUERY);
+ switch (nIndex)
+ {
+ // Full reference to table caption
+ case 0:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Table 1: Table caption"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ // Page style reference / exported as simple page reference
+ case 1:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ // Reference to table number
+ case 2:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_number_only"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ // Reference to caption only
+ case 3:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_caption_only"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ // Reference to category and number
+ case 4:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Table 1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_label_and_number"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ // Reference to page of the table
+ case 5:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ // Above / bellow reference
+ case 6:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ sal_Int16 nValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("above"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Table0_full"), sValue);
+ xPropertySet->getPropertyValue("SequenceNumber") >>= nValue;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nValue);
+ break;
+ }
+ default:
+ break;
+ }
+ ++nIndex;
+ }
+}
+
+DECLARE_OOXMLEXPORT_TEST( testTableCrossReferenceCustomFormat, "table_cross_reference_custom_format.odt" )
+{
+ // tdf#42346: Cross references to tables were not saved
+ // Check also captions with custom formatting
+ if (!mbExported)
+ return;
+
+ // Check whether we have all the neccessary bookmarks exported and imported back
+ uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(16), xBookmarksByIdx->getCount());
+ uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table0_number_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table1_number_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table2_number_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Table3_number_only"));
+
+ // Check bookmark text ranges
+ // First table's caption
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1. Table: Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1. Table"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table0_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+ }
+ // Second table's caption
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("2. TableTable caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("2. Table"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table1_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("2"), xRange->getString());
+ }
+ // Third table's caption
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("3) Table Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("3) Table"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table2_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("3"), xRange->getString());
+ }
+ // Fourth table's caption
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table 4- Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table 4"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table caption"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Table3_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("4"), xRange->getString());
+ }
+}
+
+DECLARE_OOXMLEXPORT_TEST( testObjectCrossReference, "object_cross_reference.odt" )
+{
+ // tdf#42346: Cross references to objects were not saved
+ // MSO uses simple bookmarks for referencing table caption, so we do the same by export
+ if (!mbExported)
+ return;
+
+ // Check whether we have all the neccessary bookmarks exported and imported back
+ uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(15), xBookmarksByIdx->getCount());
+ uno::Reference<container::XNameAccess> xBookmarksByName(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing0_number_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Drawing1_full"));
+
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration0_number_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Illustration1_caption_only"));
+
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_full"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_label_and_number"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_caption_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text0_number_only"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("Ref_Text1_label_and_number"));
+
+ // Check bookmark text ranges
+ // Cross references to shapes
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1: A rectangle"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("A rectangle"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing0_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Drawing1_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Drawing 2: a circle"), xRange->getString());
+ }
+
+ // Cross references to pictures
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1: A picture"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("A picture"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration0_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Illustration1_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("an other image"), xRange->getString());
+ }
+
+ // Cross references to text frames
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_full"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Text 1: A frame"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Text 1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_caption_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("A frame"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text0_number_only"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), xRange->getString());
+ }
+ {
+ uno::Reference<text::XTextContent> xContent(xBookmarksByName->getByName("Ref_Text1_label_and_number"), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xRange(xContent->getAnchor(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Text 2"), xRange->getString());
+ }
+
+ // Check reference fields
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+ uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+ CPPUNIT_ASSERT(xFields->hasMoreElements());
+
+ sal_uInt16 nIndex = 0;
+ while (xFields->hasMoreElements())
+ {
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xFields->nextElement(), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(xServiceInfo, uno::UNO_QUERY);
+ switch (nIndex)
+ {
+ // Reference to image number
+ case 0:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_number_only"), sValue);
+ break;
+ }
+ // Full reference to the circle shape
+ case 1:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Drawing 2: a circle"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing1_full"), sValue);
+ break;
+ }
+ // Caption only reference to the second picture
+ case 2:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("an other image"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration1_caption_only"), sValue);
+ break;
+ }
+ // Category and number reference to second text frame
+ case 3:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Text 2"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text1_label_and_number"), sValue);
+ break;
+ }
+ // Full reference to rectangle shape
+ case 4:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1: A rectangle"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_full"), sValue);
+ break;
+ }
+ // Caption only reference to rectangle shape
+ case 5:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("A rectangle"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_caption_only"), sValue);
+ break;
+ }
+ // Category and number reference to rectangle shape
+ case 6:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Drawing 1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_label_and_number"), sValue);
+ break;
+ }
+ // Reference to rectangle shape's number
+ case 7:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Drawing0_number_only"), sValue);
+ break;
+ }
+ // Full reference to first text frame
+ case 8:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Text 1: A frame"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_full"), sValue);
+ break;
+ }
+ // Caption only reference to first text frame
+ case 9:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("A frame"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_caption_only"), sValue);
+ break;
+ }
+ // Category and number reference to first text frame
+ case 10:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Text 1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_label_and_number"), sValue);
+ break;
+ }
+ // Number only reference to first text frame
+ case 11:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Text0_number_only"), sValue);
+ break;
+ }
+ // Full reference to first picture
+ case 12:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1: A picture"), sValue.trim()); // failes on MAC without trim
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_full"), sValue);
+ break;
+ }
+ // Reference to first picture' caption
+ case 13:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("A picture"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_caption_only"), sValue);
+ break;
+ }
+ // Category and number reference to first picture
+ case 14:
+ {
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.GetReference"));
+ OUString sValue;
+ xPropertySet->getPropertyValue("CurrentPresentation") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Illustration 1"), sValue);
+ xPropertySet->getPropertyValue("SourceName") >>= sValue;
+ CPPUNIT_ASSERT_EQUAL(OUString("Ref_Illustration0_label_and_number"), sValue);
+ break;
+ }
+ default:
+ break;
+ }
+ ++nIndex;
+ }
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx
index 5327be3a819a..b2a7605a9330 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -209,6 +209,8 @@ public:
virtual void FieldVanish( const OUString& rText, ww::eField eType ) = 0;
+ virtual void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter) = 0;
+
void StartTOX( const SwSection& rSect );
void EndTOX( const SwSection& rSect,bool bCareEnd=true );
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 57e182dc34ac..4bf1b1c3dc27 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -125,6 +125,8 @@
#include <IDocumentSettingAccess.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <reffld.hxx>
#include <osl/file.hxx>
#include <vcl/embeddedfontshelper.hxx>
@@ -594,6 +596,10 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
if( !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen() )
m_bParagraphOpened = false;
+ // Clear gererated bookmarks
+ m_aBookmarksWithPosStart.clear();
+ m_aBookmarksWithPosEnd.clear();
+
}
void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken,
@@ -1278,6 +1284,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
m_endPageRef = true;
}
+ DoWriteBookmarkStartIfExist(nPos);
+
m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
if(GetExport().m_bTabInTOC && m_pHyperlinkAttrList.is())
{
@@ -1377,6 +1385,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
}
m_nFieldsInHyperlink = 0;
}
+
+ DoWriteBookmarkEndIfExist(nPos);
}
void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString & bookmarkName)
@@ -1404,6 +1414,34 @@ void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString & bookmarkName)
}
}
+void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nPos)
+{
+ auto aRange = m_aBookmarksWithPosStart.equal_range(nPos);
+ for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+ {
+ DoWriteBookmarkTagStart(aIter->second);
+ m_rOpenedBookmarksIds[aIter->second] = m_nNextBookmarkId;
+ m_sLastOpenedBookmark = OUStringToOString(BookmarkToWord(aIter->second), RTL_TEXTENCODING_UTF8).getStr();
+ m_nNextBookmarkId++;
+ }
+}
+
+void DocxAttributeOutput::DoWriteBookmarkEndIfExist(sal_Int32 nPos)
+{
+ auto aRange = m_aBookmarksWithPosEnd.equal_range(nPos);
+ for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+ {
+ // Get the id of the bookmark
+ auto pPos = m_rOpenedBookmarksIds.find(aIter->second);
+ if (pPos != m_rOpenedBookmarksIds.end())
+ {
+ // Output the bookmark
+ DoWriteBookmarkTagEnd(aIter->second);
+ m_rOpenedBookmarksIds.erase(aIter->second);
+ }
+ }
+}
+
/// Write the start bookmarks
void DocxAttributeOutput::DoWriteBookmarksStart()
{
@@ -1662,7 +1700,7 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
else
{
// Write the field start
- if ( rInfos.pField && rInfos.pField->GetSubType() & FIXEDFLD )
+ if ( rInfos.pField && (rInfos.pField->Which() == SwFieldIds::DateTime) && rInfos.pField->GetSubType() & FIXEDFLD )
{
m_pSerializer->startElementNS( XML_w, XML_fldChar,
FSNS( XML_w, XML_fldCharType ), "begin",
@@ -7143,6 +7181,176 @@ bool DocxAttributeOutput::PlaceholderField( const SwField* pField )
return false; // do not expand
}
+void DocxAttributeOutput::GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter)
+{
+ if (const SwpHints* pTextAttrs = rNode.GetpSwpHints())
+ {
+ for( size_t i = 0; i < pTextAttrs->Count(); ++i )
+ {
+ const SwTextAttr* pHt = pTextAttrs->Get(i);
+ if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
+ {
+ const SwFormatField& rField = static_cast<const SwFormatField&>(pHt->GetAttr());
+ const SwField* pField = rField.GetField();
+ // Need to have bookmarks only for sequence fields
+ if (pField && pField->GetTyp()->Which() == SwFieldIds::SetExp && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
+ {
+ const sal_uInt16 nSeqFieldNumber = static_cast<const SwSetExpField*>(pField)->GetSeqNumber();
+ const OUString sObjectName = static_cast<const SwSetExpFieldType*>(pField->GetTyp())->GetName();
+ const SwFieldTypes* pFieldTypes = m_rExport.m_pDoc->getIDocumentFieldsAccess().GetFieldTypes();
+ bool bHaveFullBkm = false;
+ bool bHaveLabelAndNumberBkm = false;
+ bool bHaveCaptionOnlyBkm = false;
+ bool bHaveNumberOnlyBkm = false;
+ bool bRunSplittedAtSep = false;
+ for( auto pFieldType : *pFieldTypes )
+ {
+ if( SwFieldIds::GetRef == pFieldType->Which() )
+ {
+ SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
+ for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
+ {
+ SwGetRefField* pRefField = static_cast<SwGetRefField*>(pFormatField->GetField());
+ // If we have a reference to the current sequence field
+ if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
+ {
+ // Need to create a seperate run for separator character
+ SwWW8AttrIter aLocalAttrIter( m_rExport, rNode );
+ const OUString aText = rNode.GetText();
+ const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
+ const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
+ bool bCategoryFirst = nCategoryStart < pHt->GetStart();
+ sal_Int32 nSeparatorPos = 0;
+ if (bCategoryFirst)
+ {
+ nSeparatorPos = aLocalAttrIter.WhereNext();
+ while (nSeparatorPos <= nPosBeforeSeparator)
+ {
+ aLocalAttrIter.NextPos();
+ nSeparatorPos = aLocalAttrIter.WhereNext();
+ }
+ }
+ else
+ {
+ nSeparatorPos = nCategoryStart + pRefField->GetSetRefName().getLength();
+ }
+ sal_Int32 nRefTextPos = 0;
+ if(nSeparatorPos < aText.getLength())
+ {
+ nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), *m_rExport.m_pDoc, nSeparatorPos);
+ if(nRefTextPos != nSeparatorPos)
+ {
+ if(!bRunSplittedAtSep)
+ {
+ if(!bCategoryFirst)
+ rAttrIter.SplitRun(nSeparatorPos);
+ rAttrIter.SplitRun(nRefTextPos);
+ bRunSplittedAtSep = true;
+ }
+ if(!bCategoryFirst)
+ aLocalAttrIter.SplitRun(nSeparatorPos);
+ aLocalAttrIter.SplitRun(nRefTextPos);
+ }
+ else if (bCategoryFirst)
+ {
+ if(!bRunSplittedAtSep)
+ {
+ rAttrIter.SplitRun(nSeparatorPos);
+ bRunSplittedAtSep = true;
+ }
+ aLocalAttrIter.SplitRun(nSeparatorPos);
+ }
+ }
+ // Generate bookmarks on the right position
+ OUString sName("Ref_" + pRefField->GetSetRefName());
+ sName += OUString::number(pRefField->GetSeqNo());
+ switch (pRefField->GetFormat())
+ {
+ case REF_PAGE:
+ case REF_PAGE_PGDESC:
+ case REF_CONTENT:
+ case REF_UPDOWN:
+ sName += "_full";
+ if(!bHaveFullBkm)
+ {
+ sal_Int32 nLastAttrStart = 0;
+ sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
+ while (nActAttr < rNode.GetText().getLength())
+ {
+ nLastAttrStart = nActAttr;
+ aLocalAttrIter.NextPos();
+ nActAttr = aLocalAttrIter.WhereNext();
+ }
+ WriteBookmarks_Impl( sName, std::min(nCategoryStart, pHt->GetStart()), nLastAttrStart );
+ bHaveFullBkm = true;
+ }
+ break;
+ case REF_ONLYNUMBER:
+ {
+ sName += "_label_and_number";
+ if(!bHaveLabelAndNumberBkm)
+ {
+ if(bCategoryFirst)
+ WriteBookmarks_Impl( sName, std::min(nCategoryStart, pHt->GetStart()), std::max(nCategoryStart, pHt->GetStart()) );
+ else
+ {
+ // Find the last run which contains category text
+ SwWW8AttrIter aLocalAttrIter2( m_rExport, rNode );
+ sal_Int32 nCatLastRun = 0;
+ sal_Int32 nNextAttr = aLocalAttrIter2.WhereNext();
+ while (nNextAttr < nSeparatorPos)
+ {
+ nCatLastRun = nNextAttr;
+ aLocalAttrIter2.NextPos();
+ nNextAttr = aLocalAttrIter2.WhereNext();
+ }
+ WriteBookmarks_Impl( sName, pHt->GetStart(), nCatLastRun );
+ }
+ bHaveLabelAndNumberBkm = true;
+ }
+ break;
+ }
+ case REF_ONLYCAPTION:
+ {
+ sName += "_caption_only";
+ if(!bHaveCaptionOnlyBkm)
+ {
+ // Find last run
+ sal_Int32 nLastAttrStart = 0;
+ sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
+ while (nActAttr < rNode.GetText().getLength())
+ {
+ nLastAttrStart = nActAttr;
+ aLocalAttrIter.NextPos();
+ nActAttr = aLocalAttrIter.WhereNext();
+ }
+ WriteBookmarks_Impl( sName, nRefTextPos, nLastAttrStart );
+ bHaveCaptionOnlyBkm = true;
+ }
+ break;
+ }
+ case REF_ONLYSEQNO:
+ {
+ sName += "_number_only";
+ if(!bHaveNumberOnlyBkm)
+ {
+ WriteBookmarks_Impl( sName, pHt->GetStart(), pHt->GetStart() );
+ bHaveNumberOnlyBkm = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+ }
+ }
+ }
+ }
+}
+
void DocxAttributeOutput::WritePendingPlaceholder()
{
if( pendingPlaceholder == nullptr )
@@ -7248,6 +7456,12 @@ void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts,
rEnds.clear();
}
+void DocxAttributeOutput::WriteBookmarks_Impl( const OUString& rName, sal_Int32 nWithStartPos, sal_Int32 nWithEndPos )
+{
+ m_aBookmarksWithPosStart.insert(std::pair<sal_Int32, OUString>(nWithStartPos, rName));
+ m_aBookmarksWithPosEnd.insert(std::pair<sal_Int32, OUString>(nWithEndPos, rName));
+}
+
void DocxAttributeOutput::WriteAnnotationMarks_Impl( std::vector< OUString >& rStarts,
std::vector< OUString >& rEnds )
{
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 8822d523dec3..eb9dcf4d6791 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -370,6 +370,7 @@ public:
void WriteFormData_Impl( const ::sw::mark::IFieldmark& rFieldmark );
void WriteBookmarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds );
+ void WriteBookmarks_Impl( const OUString& rName, sal_Int32 nWithStartPos, sal_Int32 nWithEndPos );
void WriteAnnotationMarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds );
void PushRelIdCache();
void PopRelIdCache();
@@ -699,6 +700,8 @@ private:
void DoWriteBookmarkTagEnd(const OUString & bookmarkName);
void DoWriteBookmarksStart();
void DoWriteBookmarksEnd();
+ void DoWriteBookmarkStartIfExist(sal_Int32 nPos);
+ void DoWriteBookmarkEndIfExist(sal_Int32 nPos);
void DoWritePermissionTagStart(const OUString & permission);
void DoWritePermissionTagEnd(const OUString & permission);
@@ -730,6 +733,7 @@ private:
void CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun );
void EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos );
void DoWriteFieldRunProperties( const SwTextNode* pNode, sal_Int32 nPos );
+ virtual void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter) override;
static void AddToAttrList( rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue );
static void AddToAttrList( rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nArgs, ... );
@@ -787,6 +791,10 @@ private:
std::vector<OUString> m_rBookmarksStart;
std::vector<OUString> m_rBookmarksEnd;
+ /// Bookmarks with position to output
+ std::multimap<sal_Int32, OUString> m_aBookmarksWithPosStart;
+ std::multimap<sal_Int32, OUString> m_aBookmarksWithPosEnd;
+
/// Permissions to output
std::vector<OUString> m_rPermissionsStart;
std::vector<OUString> m_rPermissionsEnd;
diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx
index de017201ed78..df65f3d39e93 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -186,6 +186,8 @@ public:
void WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp);
+ virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOCX; }
+
protected:
/// Format-dependent part of the actual export.
virtual void ExportDocument_Impl() override;
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 1520569a7dd3..0f25754927c4 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -218,6 +218,7 @@ public:
void WriteBookmarks_Impl(std::vector< OUString >& rStarts, std::vector< OUString >& rEnds);
void WriteAnnotationMarks_Impl(std::vector< OUString >& rStarts, std::vector< OUString >& rEnds);
void WriteHeaderFooter_Impl(const SwFrameFormat& rFormat, bool bHeader, const sal_Char* pStr, bool bTitlepg);
+ void GenerateBookmarksForSequenceField(const SwTextNode& /*rNode*/, SwWW8AttrIter& /*rAttrIter*/) override {};
protected:
/// Output frames - the implementation.
diff --git a/sw/source/filter/ww8/rtfexport.hxx b/sw/source/filter/ww8/rtfexport.hxx
index 0b58e27392ae..64cceef9b333 100644
--- a/sw/source/filter/ww8/rtfexport.hxx
+++ b/sw/source/filter/ww8/rtfexport.hxx
@@ -124,6 +124,8 @@ public:
sal_uLong ReplaceCr(sal_uInt8 nChar) override;
+ ExportFormat GetExportFormat() const override { return ExportFormat::RTF; }
+
protected:
/// Format-dependent part of the actual export.
void ExportDocument_Impl() override;
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 87c27db44c89..23208e90a8fc 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -1173,6 +1173,25 @@ void SwWW8AttrIter::OutSwFormatRefMark(const SwFormatRefMark& rAttr)
&rAttr.GetRefName(), 0 ));
}
+void SwWW8AttrIter::SplitRun( sal_Int32 nSplitEndPos )
+{
+ for(auto aIter = maCharRuns.begin(); aIter != maCharRuns.end(); ++aIter)
+ {
+ if(aIter->mnEndPos == nSplitEndPos)
+ return;
+ else if (aIter->mnEndPos > nSplitEndPos)
+ {
+ CharRunEntry aNewEntry = *aIter;
+ aIter->mnEndPos = nSplitEndPos;
+ maCharRuns.insert( ++aIter, aNewEntry);
+ maCharRunIter = maCharRuns.begin();
+ IterToCurrent();
+ nAktSwPos = SearchNext(1);
+ break;
+ }
+ }
+}
+
void WW8AttributeOutput::FieldVanish( const OUString& rText, ww::eField /*eType*/ )
{
ww::bytes aItems;
@@ -2163,6 +2182,10 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
AppendBookmark( BookmarkToWord( sBkmkName ) );
}
+ // Call this before write out fields and runs
+ if(GetExportFormat() == ExportFormat::DOCX)
+ AttrOutput().GenerateBookmarksForSequenceField(rNode, aAttrIter);
+
const OUString& aStr( rNode.GetText() );
sal_Int32 nAktPos = 0;
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index c3f05caad3c9..c96dcd8299b0 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -783,6 +783,9 @@ public:
/// Returns the index of a picture bullet, used in numberings.
int GetGrfIndex(const SvxBrushItem& rBrush);
+ enum ExportFormat { DOC = 0, RTF = 1, DOCX = 2};
+ virtual ExportFormat GetExportFormat() const = 0;
+
protected:
/// Format-dependent part of the actual export.
virtual void ExportDocument_Impl() = 0;
@@ -1145,6 +1148,8 @@ public:
const SwFrameFormat& rFormat, const SwFrameFormat& rLeftFormat, const SwFrameFormat& rFirstPageFormat,
sal_uInt8 nBreakCode) override;
+ virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOC; }
+
protected:
/// Output SwGrfNode
virtual void OutputGrfNode( const SwGrfNode& ) override;
@@ -1508,6 +1513,8 @@ public:
bool IsWatermarkFrame();
bool IsAnchorLinkedToThisNode( sal_uLong nNodePos );
+
+ void SplitRun( sal_Int32 nSplitEndPos );
};
/// Class to collect and output the styles table.
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index dfa4c2d29aa2..ad4c300b0350 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -899,7 +899,12 @@ OUString MSWordExportBase::GetBookmarkName( sal_uInt16 nTyp, const OUString* pNa
}
break;
case REF_SEQUENCEFLD:
- break; // ???
+ {
+ assert(pName);
+ sRet += "Ref_";
+ sRet += *pName;
+ break;
+ }
case REF_BOOKMARK:
if ( pName )
sRet = *pName;
@@ -2779,6 +2784,63 @@ void AttributeOutputBase::TextField( const SwFormatField& rField )
break;
}
break;
+ case REF_SEQUENCEFLD:
+ {
+ // Have this only for DOCX format by now
+ if(!(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::DOCX))
+ break;
+
+ switch (pField->GetFormat())
+ {
+ case REF_PAGE:
+ case REF_PAGE_PGDESC:
+ eField = ww::ePAGEREF;
+ break;
+ default:
+ eField = ww::eREF;
+ break;
+ }
+ // Generate a unique bookmark name
+ {
+ OUString sName(rRField.GetSetRefName());
+ sName += OUString::number(rRField.GetSeqNo());
+ switch (pField->GetFormat())
+ {
+ case REF_PAGE:
+ case REF_PAGE_PGDESC:
+ case REF_CONTENT:
+ case REF_UPDOWN:
+ sName += "_full";
+ break;
+ case REF_ONLYNUMBER:
+ sName += "_label_and_number";
+ break;
+ case REF_ONLYCAPTION:
+ sName += "_caption_only";
+ break;
+ case REF_ONLYSEQNO:
+ sName += "_number_only";
+ break;
+ default: // Ingore other types of reference fields
+ eField = ww::eNONE;
+ break;
+ }
+ sStr = FieldString(eField) + MSWordExportBase::GetBookmarkName(nSubType, &sName, 0);
+ }
+ switch (pField->GetFormat())
+ {
+ case REF_NUMBER:
+ sStr += " \\r";
+ break;
+ case REF_NUMBER_NO_CONTEXT:
+ sStr += " \\n";
+ break;
+ case REF_NUMBER_FULL_CONTEXT:
+ sStr += " \\w";
+ break;
+ }
+ break;
+ }
case REF_FOOTNOTE:
case REF_ENDNOTE:
switch (pField->GetFormat())
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index 9a4701d49199..d814fff62805 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -84,6 +84,8 @@ public:
virtual void FieldVanish( const OUString& rText, ww::eField eType ) override;
+ virtual void GenerateBookmarksForSequenceField(const SwTextNode& /*rNode*/, SwWW8AttrIter& /*rAttrIter*/) override {};
+
/// Output redlining.
virtual void Redline( const SwRedlineData* pRedline ) override;