diff options
-rw-r--r-- | filter/source/msfilter/util.cxx | 19 | ||||
-rw-r--r-- | include/filter/msfilter/util.hxx | 7 | ||||
-rw-r--r-- | sw/CppunitTest_sw_ooxmlexport.mk | 1 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/bnc834035.odt | bin | 0 -> 18557 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport.cxx | 63 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 32 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 7 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 28 |
8 files changed, 133 insertions, 24 deletions
diff --git a/filter/source/msfilter/util.cxx b/filter/source/msfilter/util.cxx index bf612c33c169..a10e4381d510 100644 --- a/filter/source/msfilter/util.cxx +++ b/filter/source/msfilter/util.cxx @@ -427,6 +427,25 @@ const ApiPaperSize& PaperSizeConv::getApiSizeForMSPaperSizeIndex( sal_Int32 nMSO return spPaperSizeTable[ nMSOPaperIndex ]; } +OUString findQuotedText( const OUString& rCommand, + const sal_Char* cStartQuote, const sal_Unicode uEndQuote ) +{ + OUString sRet; + OUString sStartQuote( OUString::createFromAscii(cStartQuote) ); + sal_Int32 nStartIndex = rCommand.indexOf( sStartQuote ); + if( nStartIndex >= 0 ) + { + sal_Int32 nStartLength = sStartQuote.getLength(); + sal_Int32 nEndIndex = rCommand.indexOf( uEndQuote, nStartIndex + nStartLength); + if( nEndIndex > nStartIndex ) + { + sRet = rCommand.copy( nStartIndex + nStartLength, nEndIndex - nStartIndex - nStartLength); + } + } + return sRet; + +} + } } diff --git a/include/filter/msfilter/util.hxx b/include/filter/msfilter/util.hxx index e13419905a0f..38cdf56e7df2 100644 --- a/include/filter/msfilter/util.hxx +++ b/include/filter/msfilter/util.hxx @@ -88,6 +88,13 @@ public: static sal_Int32 getMSPaperSizeIndex( const com::sun::star::awt::Size& rSize ); static const ApiPaperSize& getApiSizeForMSPaperSizeIndex( sal_Int32 nMSOPaperIndex ); }; + +/** + * Finds the quoted text in a field instruction text. + * + * Example: SEQ "Figure" \someoption -> "Figure" + */ +MSFILTER_DLLPUBLIC OUString findQuotedText( const OUString& rCommand, const sal_Char* cStartQuote, const sal_Unicode uEndQuote ); } } diff --git a/sw/CppunitTest_sw_ooxmlexport.mk b/sw/CppunitTest_sw_ooxmlexport.mk index e96961fade5b..2e90beca897c 100644 --- a/sw/CppunitTest_sw_ooxmlexport.mk +++ b/sw/CppunitTest_sw_ooxmlexport.mk @@ -76,6 +76,7 @@ $(eval $(call gb_CppunitTest_use_components,sw_ooxmlexport,\ ucb/source/ucp/file/ucpfile1 \ unotools/util/utl \ unoxml/source/service/unoxml \ + uui/util/uui \ writerfilter/util/writerfilter \ xmloff/util/xo \ )) diff --git a/sw/qa/extras/ooxmlexport/data/bnc834035.odt b/sw/qa/extras/ooxmlexport/data/bnc834035.odt Binary files differnew file mode 100644 index 000000000000..393c960dea63 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/bnc834035.odt diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx index 2ed291fbe183..fd1c30aea46b 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx @@ -10,6 +10,7 @@ #include <com/sun/star/frame/XStorable.hpp> #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/packages/zip/ZipFileAccess.hpp> #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> #include <com/sun/star/text/XTextFrame.hpp> @@ -73,6 +74,7 @@ public: void testN822175(); void testFdo58577(); void testFdo60990(); + void testBnc834035(); CPPUNIT_TEST_SUITE(Test); #if !defined(MACOSX) && !defined(WNT) @@ -82,6 +84,14 @@ public: private: void run(); + /** + * Given that some problem doesn't affect the result in the importer, we + * test the resulting file directly, by opening the zip file, parsing an + * xml stream, and asserting an XPath expression. This method returns the + * xml stream, so that you can do the asserting. + */ + xmlDocPtr parseExport(); + void assertXPath(xmlDocPtr pXmlDoc, OString aXPath, OString aAttribute = OString(), OUString aExpectedValue = OUString()); }; void Test::run() @@ -123,6 +133,7 @@ void Test::run() {"n822175.odt", &Test::testN822175}, {"fdo58577.odt", &Test::testFdo58577}, {"fdo60990.odt", &Test::testFdo60990}, + {"bnc834035.odt", &Test::testBnc834035}, }; // Don't test the first import of these, for some reason those tests fail const char* aBlacklist[] = { @@ -144,6 +155,46 @@ void Test::run() } } +xmlDocPtr Test::parseExport() +{ + // Create the zip file. + utl::TempFile aTempFile; + save("Office Open XML Text", aTempFile); + + // Read the XML stream we're interested in. + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), aTempFile.GetURL()); + uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("word/document.xml"), uno::UNO_QUERY); + boost::shared_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, sal_True)); + pStream->Seek(STREAM_SEEK_TO_END); + sal_Size nSize = pStream->Tell(); + pStream->Seek(0); + OStringBuffer aDocument(nSize); + char ch; + for (sal_Size i = 0; i < nSize; ++i) + { + *pStream >> ch; + aDocument.append(ch); + } + + // Parse the XML. + return xmlParseMemory((const char*)aDocument.getStr(), aDocument.getLength()); +} + +void Test::assertXPath(xmlDocPtr pXmlDoc, OString aXPath, OString aAttribute, OUString aExpectedValue) +{ + xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc); + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main")); + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml")); + xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(aXPath.getStr()), pXmlXpathCtx); + xmlNodeSetPtr pXmlNodes = pXmlXpathObj->nodesetval; + CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlNodes)); + if (aAttribute.isEmpty()) + return; + xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0]; + OUString aValue = OUString::createFromAscii((const char*)xmlGetProp(pXmlNode, BAD_CAST(aAttribute.getStr()))); + CPPUNIT_ASSERT_EQUAL(aExpectedValue, aValue); +} + void Test::testZoom() { uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); @@ -709,6 +760,18 @@ void Test::testFdo60990() CPPUNIT_ASSERT_EQUAL(sal_Int32(0x00FF00), getProperty<sal_Int32>(getRun(xParagraph, 1), "CharColor")); } +void Test::testBnc834035() +{ + // This is tricky, when saving manually, there are 2 hyperlinks, here only + // one, no idea why. That one still shows that we're not using bookmarks, though. + + // Illustration index had wrong hyperlinks: anchor was using Writer's + // <seqname>!<index>|sequence syntax, not a bookmark name. + xmlDocPtr pXmlDoc = parseExport(); + // This was Figure!1|sequence. + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:hyperlink", "anchor", "_Toc363553908"); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 08d79f02118b..0e2ee5e8969e 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -699,6 +699,7 @@ void DocxAttributeOutput::DoWriteBookmarks() FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( nId ) ).getStr( ), FSNS( XML_w, XML_name ), rName.getStr(), FSEND ); + m_sLastOpenedMark = rName; } m_rMarksStart.clear(); @@ -828,6 +829,12 @@ void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun ) void DocxAttributeOutput::DoWriteCmd( String& rCmd ) { + OUString sCmd = OUString(rCmd).trim(); + if (sCmd.startsWith("SEQ")) + { + OUString sSeqName = msfilter::util::findQuotedText(sCmd, "SEQ ", '\\').trim(); + m_aSeqMarksNames[sSeqName].push_back(m_sLastOpenedMark); + } // Write the Field command m_pSerializer->startElementNS( XML_w, XML_instrText, FSEND ); m_pSerializer->writeEscaped( OUString( rCmd ) ); @@ -1313,8 +1320,33 @@ bool DocxAttributeOutput::StartURL( const String& rUrl, const String& rTarget ) m_pHyperlinkAttrList->add( FSNS( XML_r, XML_id), sId.getStr()); } else + { + // Is this a link to a sequence? Then try to replace that with a + // normal bookmark, as Word won't understand our special + // <seqname>!<index>|sequence syntax. + OUString aMark(sMark); + if (aMark.endsWith("|sequence")) + { + sal_Int32 nPos = aMark.indexOf('!'); + if (nPos != -1) + { + // Extract <seqname>, the field instruction text has the name quoted. + OUString aSequenceName = OUString('"') + aMark.copy(0, nPos) + OUString('"'); + // Extract <index>. + sal_uInt32 nIndex = aMark.copy(nPos + 1, aMark.getLength() - nPos - sizeof("|sequence")).toInt32(); + std::map<OUString, std::vector<OString> >::iterator it = m_aSeqMarksNames.find(aSequenceName); + if (it != m_aSeqMarksNames.end()) + { + std::vector<OString>& rNames = it->second; + if (rNames.size() > nIndex) + // We know the bookmark name for this sequence and this index, do the replacement. + sMark = OStringToOUString(rNames[nIndex], RTL_TEXTENCODING_UTF8); + } + } + } m_pHyperlinkAttrList->add( FSNS( XML_w, XML_anchor ), OUStringToOString( OUString( sMark ), RTL_TEXTENCODING_UTF8 ).getStr( ) ); + } OUString sTarget( rTarget ); if ( !sTarget.isEmpty() ) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 0854e46ea662..85014b9ca97f 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -603,6 +603,13 @@ private: /// Maps of the bookmarks ids std::map<OString, sal_uInt16> m_rOpenedMarksIds; + /// Name of the last opened bookmark. + OString m_sLastOpenedMark; + + /// If there are bookmarks around sequence fields, this map contains the + /// names of these bookmarks for each sequence. + std::map<OUString, std::vector<OString> > m_aSeqMarksNames; + /// The current table helper SwWriteTable *m_pTableWrt; diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 467e587616af..6319c7983dec 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -71,6 +71,7 @@ #include <comphelper/stlunosequence.hxx> #include <vcl/svapp.hxx> #include <vcl/outdev.hxx> +#include <filter/msfilter/util.hxx> using namespace ::com::sun::star; using namespace ::rtl; @@ -1797,33 +1798,12 @@ void DomainMapper_Impl::PopShapeContext() } } - -OUString lcl_FindQuotedText( const OUString& rCommand, - const sal_Char* cStartQuote, const sal_Unicode uEndQuote ) -{ - OUString sRet; - OUString sStartQuote( OUString::createFromAscii(cStartQuote) ); - sal_Int32 nStartIndex = rCommand.indexOf( sStartQuote ); - if( nStartIndex >= 0 ) - { - sal_Int32 nStartLength = sStartQuote.getLength(); - sal_Int32 nEndIndex = rCommand.indexOf( uEndQuote, nStartIndex + nStartLength); - if( nEndIndex > nStartIndex ) - { - sRet = rCommand.copy( nStartIndex + nStartLength, nEndIndex - nStartIndex - nStartLength); - } - } - return sRet; - -} - - sal_Int16 lcl_ParseNumberingType( const OUString& rCommand ) { sal_Int16 nRet = style::NumberingType::PAGE_DESCRIPTOR; // The command looks like: " PAGE \* Arabic " - OUString sNumber = lcl_FindQuotedText(rCommand, "\\* ", ' '); + OUString sNumber = msfilter::util::findQuotedText(rCommand, "\\* ", ' '); if( !sNumber.isEmpty() ) { @@ -1918,7 +1898,7 @@ style::NumberingType:: OUString lcl_ParseFormat( const OUString& rCommand ) { // The command looks like: " DATE \@ "dd MMMM yyyy" - return lcl_FindQuotedText(rCommand, "\\@ \"", '\"'); + return msfilter::util::findQuotedText(rCommand, "\\@ \"", '\"'); } /*------------------------------------------------------------------------- extract a parameter (with or without quotes) between the command and the following backslash @@ -3213,7 +3193,7 @@ void DomainMapper_Impl::CloseFieldCommand() // command looks like: " SEQ Table \* ARABIC " OUString sCmd(pContext->GetCommand()); // find the sequence name, e.g. "SEQ" - OUString sSeqName = lcl_FindQuotedText(sCmd, "SEQ ", '\\'); + OUString sSeqName = msfilter::util::findQuotedText(sCmd, "SEQ ", '\\'); sSeqName = sSeqName.trim(); // create a sequence field master using the sequence name |