Rebased ref, commits from common ancestor: commit 42327130ab4455eb4fc6f487873cbf83ce21223b Author: Andreas Brandner <andreas.brand...@cib.de> Date: Sun Nov 5 20:41:31 2017 +0100
tdf#66401 don't lose docx-combined-characters' font props on roundtrip - font-size will now get halfed, if exported within a combined-characters-field in docx - font-property will get exported for every run in a field, this redundancy is required by MS Word Change-Id: Idbdb5bf3066e2ed86b494255d72d66eebf72f755 Reviewed-on: https://gerrit.libreoffice.org/44509 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 467177d013fa..e8cdfc86182c 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -1740,12 +1740,18 @@ void DocxAttributeOutput::DoWriteCmd( const OUString& rCmd ) void DocxAttributeOutput::CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun ) { + bool bWriteCombChars(false); + // Write the Field instruction { if ( bWriteRun ) { m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); - DoWriteFieldRunProperties( pNode, nPos ); + + if (rInfos.eType == ww::eEQ) + bWriteCombChars = true; + + DoWriteFieldRunProperties( pNode, nPos, bWriteCombChars ); } sal_Int32 nNbToken = comphelper::string::getTokenCount(rInfos.sCmd, '\t'); @@ -1829,7 +1835,7 @@ void DocxAttributeOutput::CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos /// <w:fldChar w:fldCharType="end" /> /// </w:r> /// See, tdf#38778 -void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode * pNode, sal_Int32 nPos ) +void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode * pNode, sal_Int32 nPos, bool bWriteCombChars) { if (! pNode) { @@ -1859,7 +1865,17 @@ void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode * pNode, s // 3. output all other character properties SwWW8AttrIter aAttrIt( m_rExport, *pNode ); - aAttrIt.OutAttr( nPos, false ); + aAttrIt.OutAttr( nPos, false, bWriteCombChars ); + + // 4. explicitly write the font-properties, to ensure all runs in the field have them + // see tdf#66401 + if ( m_pFontsAttrList.is() ) + { + XFastAttributeListRef xAttrList( m_pFontsAttrList.get() ); + m_pFontsAttrList.clear(); + + m_pSerializer->singleElementNS( XML_w, XML_rFonts, xAttrList ); + } m_pSerializer->endElementNS( XML_w, XML_rPr ); diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 4c41f83d2f30..64fa4238e617 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -729,7 +729,7 @@ private: void DoWriteCmd( const OUString& rCmd ); 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 ); + void DoWriteFieldRunProperties( const SwTextNode* pNode, sal_Int32 nPos, bool bWriteCombChars = false ); virtual void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter) override; static void AddToAttrList( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue ); diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index e9ba18f40d6f..33b67ea5e627 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -382,7 +382,7 @@ static bool lcl_isFontsizeItem( const SfxPoolItem& rItem ) rItem.Which( ) == RES_CHRATR_CTL_FONTSIZE ); } -void SwWW8AttrIter::OutAttr( sal_Int32 nSwPos, bool bRuby ) +void SwWW8AttrIter::OutAttr( sal_Int32 nSwPos, bool bRuby , bool bWriteCombChars) { m_rExport.AttrOutput().RTLAndCJKState( IsCharRTL(), GetScript() ); @@ -488,7 +488,7 @@ void SwWW8AttrIter::OutAttr( sal_Int32 nSwPos, bool bRuby ) // tdf#38778 Fix output of the font in DOC run for fields const SvxFontItem * pFontToOutput = ( rParentFont != *pFont )? pFont : nullptr; - m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript(), pFontToOutput ); + m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript(), pFontToOutput, bWriteCombChars ); // HasTextItem only allowed in the above range m_rExport.m_aCurrentCharPropStarts.pop(); diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index dafffeaafd44..ff25dedd1c3e 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -584,7 +584,7 @@ public: void WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_uInt8 nTTyp ); /// Export the pool items to attributes (through an attribute output class). - void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont ); + void ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont, bool bWriteCombChars = false ); /// Return the numeric id of the numbering rule sal_uInt16 GetId( const SwNumRule& rNumRule ); @@ -1490,7 +1490,7 @@ public: void NextPos() { if ( nAktSwPos < SAL_MAX_INT32 ) nAktSwPos = SearchNext( nAktSwPos + 1 ); } - void OutAttr( sal_Int32 nSwPos, bool bRuby = false ); + void OutAttr( sal_Int32 nSwPos, bool bRuby = false, bool bWriteCombinedChars = false ); virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const override; virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const override; int OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos); diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index fbb763a1459a..3250808165a8 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -204,7 +204,7 @@ bool WW8Export::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich // Hilfsroutinen fuer Styles -void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont ) +void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont, bool bWriteCombChars ) { ww8::cPoolItemIter aEnd = rItems.end(); for ( ww8::cPoolItemIter aI = rItems.begin(); aI != aEnd; ++aI ) @@ -228,7 +228,21 @@ void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 AttrOutput().OutputItem( *pFont ); } - AttrOutput().OutputItem( *pItem ); + // tdf#66401 For Combined Characters in docx, MS Word uses half the normal font-size for the field's + // font-size, but only for <w:sz>. Therefore, we check if we are currently writing a field of type + // Combined Characters and if so, we half the font size. + if (bWriteCombChars && + nWhich == RES_CHRATR_FONTSIZE) + { + SvxFontHeightItem fontHeight(item_cast<SvxFontHeightItem>( *pItem )); + fontHeight.SetHeight( fontHeight.GetHeight() / 2 ); + + AttrOutput().OutputItem( fontHeight ); + } + else + { + AttrOutput().OutputItem( *pItem ); + } } } } commit 56a1fdbb2b97a5b2f3adb3fc8628b9c12313a6b9 Author: Tamás Zolnai <tamas.zol...@collabora.com> Date: Mon Nov 6 18:46:56 2017 +0100 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 Reviewed-on: https://gerrit.libreoffice.org/44294 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit 98bc7215935f1eb2e0dc6f1db826d8e729430c13) Change-Id: I3b17753123d94a04e4f28783ad5663831e7c6c84 Reviewed-on: https://gerrit.libreoffice.org/44372 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx index e5b1561abd2d..078ef88552fc 100644 --- a/sc/source/ui/view/tabview.cxx +++ b/sc/source/ui/view/tabview.cxx @@ -350,7 +350,7 @@ void ScTabView::DoResize( const Point& rOffset, const Size& rSize, bool bInner ) Size aFontSize = rStyleSettings.GetTabFont().GetFontSize(); - MapMode aPtMapMode(MapUnit::MapPoint); + MapMode aPtMapMode(MapUnit::MAP_POINT); aFontSize = pFrameWin->LogicToPixel(aFontSize, aPtMapMode); sal_Int32 nTabWidth = aFontSize.Height() + WIDTH_MARGIN; 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 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/object_cross_reference.odt 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 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/table_cross_reference.odt 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 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/table_cross_reference_custom_format.odt differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx index b82b39e7c34c..51e3089d9647 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx @@ -9,8 +9,6 @@ #include <swmodeltestbase.hxx> -#if !defined(_WIN32) - #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp> @@ -45,6 +43,8 @@ protected: } }; +#if !defined(_WIN32) + DECLARE_OOXMLEXPORT_TEST( testChildNodesOfCubicBezierTo, "FDO74774.docx") { /* Number of children required by cubicBexTo is 3 of type "pt". @@ -1245,6 +1245,577 @@ DECLARE_OOXMLEXPORT_TEST(testTdf107111, "tdf107111.docx") #endif +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 6e8c0ca0bb26..dc32dd36d8fe 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 45c5ed84cbd3..467177d013fa 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -117,6 +117,8 @@ #include <IDocumentSettingAccess.hxx> #include <IDocumentStylePoolAccess.hxx> #include <IDocumentRedlineAccess.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <reffld.hxx> #include <osl/file.hxx> #include <vcl/embeddedfontshelper.hxx> @@ -601,6 +603,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, @@ -1267,6 +1273,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()) { @@ -1364,6 +1372,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos) } m_nFieldsInHyperlink = 0; } + + DoWriteBookmarkEndIfExist(nPos); } void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString & bookmarkName) @@ -1391,6 +1401,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() { @@ -1655,7 +1693,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() == RES_DATETIMEFLD) && rInfos.pField->GetSubType() & FIXEDFLD ) { m_pSerializer->startElementNS( XML_w, XML_fldChar, FSNS( XML_w, XML_fldCharType ), "begin", @@ -6509,7 +6547,7 @@ void DocxAttributeOutput::CharFont( const SvxFontItem& rFont) const OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8); if (!sFontNameUtf8.isEmpty()) { - if (m_pFontsAttrList && + if (m_pFontsAttrList.is() && ( m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_ascii )) || m_pFontsAttrList->hasAttribute(FSNS( XML_w, XML_hAnsi )) ) ) @@ -6934,6 +6972,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() == RES_SETEXPFLD && 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( RES_GETREFFLD == 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 ) @@ -7040,6 +7248,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 2456fffac0a6..4c41f83d2f30 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(); @@ -696,6 +697,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); @@ -727,6 +730,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( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue ); static void AddToAttrList( css::uno::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nArgs, ... ); @@ -784,6 +788,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 047b497dcce5..2cfd53a866d2 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -177,6 +177,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 e465dbbe8a8f..82e2817e1a03 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.hxx +++ b/sw/source/filter/ww8/rtfattributeoutput.hxx @@ -217,6 +217,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 ecef9ee60217..1c1f4d62c161 100644 --- a/sw/source/filter/ww8/rtfexport.hxx +++ b/sw/source/filter/ww8/rtfexport.hxx @@ -124,6 +124,8 @@ public: virtual sal_uLong ReplaceCr(sal_uInt8 nChar) override; + ExportFormat GetExportFormat() const override { return ExportFormat::RTF; } + protected: /// Format-dependent part of the actual export. virtual void ExportDocument_Impl() override; diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index d04facf6af8c..e9ba18f40d6f 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -1156,6 +1156,25 @@ void SwWW8AttrIter::OutSwFormatRefMark(const SwFormatRefMark& rAttr, bool) &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; @@ -2146,6 +2165,10 @@ void MSWordExportBase::OutputTextNode( const SwTextNode& rNode ) AppendWordBookmark( 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 9ee2645f2d38..dafffeaafd44 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -779,6 +779,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; @@ -1141,6 +1144,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; @@ -1504,6 +1509,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 db888c475a20..fbb763a1459a 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -902,7 +902,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; @@ -2784,6 +2789,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 0d41f0e33fb4..e2a978fcb4ac 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;
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits