summaryrefslogtreecommitdiff
path: root/xmloff
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2016-01-08 16:02:43 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-01-11 10:31:28 +0000
commit74c089fe14b82c796692b7600e78c8fea17e33cf (patch)
tree89e87f5325c3512d75768f6d03fbbea85fcfe2b3 /xmloff
parentdd7e6210fa73e201495578c08f5ccbb612eb6456 (diff)
tdf#96480: ODF import: eliminate duplicate cross reference heading bookmarks
7c3c3006deaaaf1bb3f2f4eeeaf11da3bcebe53c is apparently worse than it appeared at first glance since there are numerous assumptions about bookmarks, such as that if they were inserted successfully they may be copied successfully, which isn't the case for duplicate cross reference bookmarks. So fix this differently, by eliminating the duplicates and mapping all reference fields to refer to the surviving bookmark. It was not possible to do this in SwXBookmark by checking the makeMark() return as that would raise interesting problems such as it's currently guaranteed to have 1:1 SwXBoomarks to core Marks so we can't just connect 2 SwXBookmarks to the same core Mark, and we also can't leave the SwXBookmark unconnected after attach. Another alternative would be to temporarily allow inserting the duplicate bookmarks and then eliminate them after the import, but what is implemented now is to check from xmloff for duplicates, which is reasonably simple. Change-Id: I7ee4854d1c9d8bf74201089cbb7287b1bd8ee3b9 (cherry picked from commit 774fb6d2e7cf36b677e66c54278225b1256bd40f) Reviewed-on: https://gerrit.libreoffice.org/21277 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'xmloff')
-rw-r--r--xmloff/source/core/xmlimp.cxx2
-rw-r--r--xmloff/source/text/XMLTextMarkImportContext.cxx46
-rw-r--r--xmloff/source/text/XMLTextMarkImportContext.hxx7
-rw-r--r--xmloff/source/text/txtimp.cxx60
-rw-r--r--xmloff/source/text/txtparai.cxx38
5 files changed, 141 insertions, 12 deletions
diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx
index ad5f58a309a7..2b8c995589cf 100644
--- a/xmloff/source/core/xmlimp.cxx
+++ b/xmloff/source/core/xmlimp.cxx
@@ -545,6 +545,8 @@ void SAL_CALL SvXMLImport::endDocument()
// #i9518# All the stuff that accesses the document has to be done here, not in the dtor,
// because the SvXMLImport dtor might not be called until after the document has been closed.
+ GetTextImport()->MapCrossRefHeadingFieldsHorribly();
+
if (mpImpl->mpRDFaHelper.get())
{
const uno::Reference<rdf::XRepositorySupplier> xRS(mxModel,
diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx
index e28170c1ee71..63d349be8445 100644
--- a/xmloff/source/text/XMLTextMarkImportContext.cxx
+++ b/xmloff/source/text/XMLTextMarkImportContext.cxx
@@ -99,10 +99,12 @@ void XMLFieldParamImportContext::StartElement(const ::com::sun::star::uno::Refer
XMLTextMarkImportContext::XMLTextMarkImportContext(
SvXMLImport& rImport,
XMLTextImportHelper& rHlp,
+ uno::Reference<uno::XInterface> & io_rxCrossRefHeadingBookmark,
sal_uInt16 nPrefix,
const OUString& rLocalName )
: SvXMLImportContext(rImport, nPrefix, rLocalName)
, m_rHelper(rHlp)
+ , m_rxCrossRefHeadingBookmark(io_rxCrossRefHeadingBookmark)
, m_bHaveAbout(false)
{
}
@@ -202,9 +204,23 @@ void XMLTextMarkImportContext::EndElement()
OUString());
break;
- case TypeFieldmark:
case TypeBookmark:
{
+ // tdf#94804: detect duplicate heading cross reference bookmarks
+ if (m_sBookmarkName.startsWith("__RefHeading__"))
+ {
+ if (m_rxCrossRefHeadingBookmark.is())
+ {
+ uno::Reference<container::XNamed> const xNamed(
+ m_rxCrossRefHeadingBookmark, uno::UNO_QUERY);
+ m_rHelper.AddCrossRefHeadingMapping(
+ m_sBookmarkName, xNamed->getName());
+ break; // don't insert
+ }
+ }
+ } // fall through
+ case TypeFieldmark:
+ {
const char *formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName);
bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmark && formFieldmarkName!=nullptr); //@TODO handle abbreviation cases..
// export point bookmark
@@ -225,6 +241,12 @@ void XMLTextMarkImportContext::EndElement()
}
m_rHelper.popFieldCtx();
}
+ if (TypeBookmark == nTmp
+ && m_sBookmarkName.startsWith("__RefHeading__"))
+ {
+ assert(xContent.is());
+ m_rxCrossRefHeadingBookmark = xContent;
+ }
}
break;
@@ -249,8 +271,22 @@ void XMLTextMarkImportContext::EndElement()
}
break;
- case TypeFieldmarkEnd:
case TypeBookmarkEnd:
+ {
+ // tdf#94804: detect duplicate heading cross reference bookmarks
+ if (m_sBookmarkName.startsWith("__RefHeading__"))
+ {
+ if (m_rxCrossRefHeadingBookmark.is())
+ {
+ uno::Reference<container::XNamed> const xNamed(
+ m_rxCrossRefHeadingBookmark, uno::UNO_QUERY);
+ m_rHelper.AddCrossRefHeadingMapping(
+ m_sBookmarkName, xNamed->getName());
+ break; // don't insert
+ }
+ }
+ } // fall through
+ case TypeFieldmarkEnd:
{
// get old range, and construct
Reference<XTextRange> xStartRange;
@@ -333,6 +369,12 @@ void XMLTextMarkImportContext::EndElement()
}
m_rHelper.popFieldCtx();
}
+ if (TypeBookmarkEnd == nTmp
+ && m_sBookmarkName.startsWith("__RefHeading__"))
+ {
+ assert(xContent.is());
+ m_rxCrossRefHeadingBookmark = xContent;
+ }
}
// else: beginning/end in different XText -> ignore!
}
diff --git a/xmloff/source/text/XMLTextMarkImportContext.hxx b/xmloff/source/text/XMLTextMarkImportContext.hxx
index faa963feed28..2e77b8759be8 100644
--- a/xmloff/source/text/XMLTextMarkImportContext.hxx
+++ b/xmloff/source/text/XMLTextMarkImportContext.hxx
@@ -61,8 +61,11 @@ public:
*/
class XMLTextMarkImportContext : public SvXMLImportContext
{
-
+private:
XMLTextImportHelper & m_rHelper;
+
+ css::uno::Reference<css::uno::XInterface> & m_rxCrossRefHeadingBookmark;
+
OUString m_sBookmarkName;
OUString m_sFieldName;
OUString m_sXmlId;
@@ -75,10 +78,10 @@ class XMLTextMarkImportContext : public SvXMLImportContext
public:
-
XMLTextMarkImportContext(
SvXMLImport& rImport,
XMLTextImportHelper& rHlp,
+ css::uno::Reference<css::uno::XInterface> & io_rxCrossRefHeadingBookmark,
sal_uInt16 nPrfx,
const OUString& rLocalName );
diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx
index 8de29693ec40..76c71273f768 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -25,7 +25,9 @@
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/text/ReferenceFieldSource.hpp>
#include <com/sun/star/text/XChapterNumberingSupplier.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
#include <com/sun/star/text/XTextFramesSupplier.hpp>
#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
@@ -576,6 +578,8 @@ struct XMLTextImportHelper::Impl
OUString m_sCellParaStyleDefault;
+ std::unique_ptr<std::map<OUString, OUString>> m_pCrossRefHeadingBookmarkMap;
+
Impl( uno::Reference<frame::XModel> const& rModel,
SvXMLImport & rImport,
bool const bInsertMode, bool const bStylesOnlyMode,
@@ -2798,4 +2802,60 @@ OUString const& XMLTextImportHelper::GetCellParaStyleDefault()
return m_xImpl->m_sCellParaStyleDefault;
}
+void XMLTextImportHelper::AddCrossRefHeadingMapping(OUString const& rFrom, OUString const& rTo)
+{
+ if (!m_xImpl->m_pCrossRefHeadingBookmarkMap)
+ {
+ m_xImpl->m_pCrossRefHeadingBookmarkMap.reset(new std::map<OUString, OUString>);
+ }
+ m_xImpl->m_pCrossRefHeadingBookmarkMap->insert(std::make_pair(rFrom, rTo));
+}
+
+// tdf#94804: hack to map cross reference fiels that reference duplicate marks
+// note that we can't really check meta:generator for this since the file might
+// be round-tripped by different versions preserving duplicates => always map
+void XMLTextImportHelper::MapCrossRefHeadingFieldsHorribly()
+{
+ if (!m_xImpl->m_pCrossRefHeadingBookmarkMap)
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextFieldsSupplier> const xFieldsSupplier(
+ m_xImpl->m_rSvXMLImport.GetModel(), uno::UNO_QUERY);
+ if (!xFieldsSupplier.is())
+ {
+ return;
+ }
+ uno::Reference<container::XEnumerationAccess> const xFieldsEA(
+ xFieldsSupplier->getTextFields());
+ uno::Reference<container::XEnumeration> const xFields(
+ xFieldsEA->createEnumeration());
+ while (xFields->hasMoreElements())
+ {
+ uno::Reference<lang::XServiceInfo> const xFieldInfo(
+ xFields->nextElement(), uno::UNO_QUERY);
+ if (!xFieldInfo->supportsService("com.sun.star.text.textfield.GetReference"))
+ {
+ continue;
+ }
+ uno::Reference<beans::XPropertySet> const xField(
+ xFieldInfo, uno::UNO_QUERY);
+ sal_uInt16 nType(0);
+ xField->getPropertyValue("ReferenceFieldSource") >>= nType;
+ if (text::ReferenceFieldSource::BOOKMARK != nType)
+ {
+ continue;
+ }
+ OUString name;
+ xField->getPropertyValue("SourceName") >>= name;
+ auto const iter(m_xImpl->m_pCrossRefHeadingBookmarkMap->find(name));
+ if (iter == m_xImpl->m_pCrossRefHeadingBookmarkMap->end())
+ {
+ continue;
+ }
+ xField->setPropertyValue("SourceName", uno::makeAny(iter->second));
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx
index ffceba4cfbbf..0d4b7e3c83e1 100644
--- a/xmloff/source/text/txtparai.cxx
+++ b/xmloff/source/text/txtparai.cxx
@@ -68,8 +68,28 @@ using namespace ::xmloff::token;
using ::com::sun::star::container::XEnumerationAccess;
using ::com::sun::star::container::XEnumeration;
-class XMLHints_Impl : public std::vector<std::unique_ptr<XMLHint_Impl>> {};
+class XMLHints_Impl
+{
+private:
+ std::vector<std::unique_ptr<XMLHint_Impl>> m_Hints;
+ uno::Reference<uno::XInterface> m_xCrossRefHeadingBookmark;
+
+public:
+ void push_back(std::unique_ptr<XMLHint_Impl> pHint)
+ {
+ m_Hints.push_back(std::move(pHint));
+ }
+ std::vector<std::unique_ptr<XMLHint_Impl>> const& GetHints()
+ {
+ return m_Hints;
+ }
+
+ uno::Reference<uno::XInterface> & GetCrossRefHeadingBookmark()
+ {
+ return m_xCrossRefHeadingBookmark;
+ }
+};
XMLCharContext::XMLCharContext(
SvXMLImport& rImport,
@@ -253,10 +273,10 @@ XMLEndReferenceContext_Impl::XMLEndReferenceContext_Impl(
if (XMLStartReferenceContext_Impl::FindName(GetImport(), xAttrList, sName))
{
// search for reference start
- sal_uInt16 nCount = rHints.size();
+ sal_uInt16 nCount = rHints.GetHints().size();
for(sal_uInt16 nPos = 0; nPos < nCount; nPos++)
{
- XMLHint_Impl *const pHint = rHints[nPos].get();
+ XMLHint_Impl *const pHint = rHints.GetHints()[nPos].get();
if ( pHint->IsReference() &&
sName.equals( static_cast<XMLReferenceHint_Impl *>(pHint)->GetRefName()) )
{
@@ -1102,10 +1122,10 @@ void XMLIndexMarkImportContext_Impl::StartElement(
if (!sID.isEmpty())
{
// if we have an ID, find the hint and set the end position
- sal_uInt16 nCount = m_rHints.size();
+ sal_uInt16 nCount = m_rHints.GetHints().size();
for(sal_uInt16 nPos = 0; nPos < nCount; nPos++)
{
- XMLHint_Impl *const pHint = m_rHints[nPos].get();
+ XMLHint_Impl *const pHint = m_rHints.GetHints()[nPos].get();
if ( pHint->IsIndexMark() &&
sID.equals(
static_cast<XMLIndexMarkHint_Impl *>(pHint)->GetID()) )
@@ -1629,6 +1649,7 @@ SvXMLImportContext *XMLImpSpanContext_Impl::CreateChildContext(
case XML_TOK_TEXT_BOOKMARK_END:
pContext = new XMLTextMarkImportContext( rImport,
*rImport.GetTextImport().get(),
+ rHints.GetCrossRefHeadingBookmark(),
nPrefix, rLocalName );
break;
@@ -1637,6 +1658,7 @@ SvXMLImportContext *XMLImpSpanContext_Impl::CreateChildContext(
case XML_TOK_TEXT_FIELDMARK_END:
pContext = new XMLTextMarkImportContext( rImport,
*rImport.GetTextImport().get(),
+ rHints.GetCrossRefHeadingBookmark(),
nPrefix, rLocalName );
break;
@@ -2045,11 +2067,11 @@ XMLParaContext::~XMLParaContext()
}
}
- if( pHints && !pHints->empty() )
+ if (pHints && !pHints->GetHints().empty())
{
- for( size_t i=0; i<pHints->size(); i++ )
+ for (size_t i = 0; i < pHints->GetHints().size(); ++i)
{
- XMLHint_Impl *const pHint = (*pHints)[i].get();
+ XMLHint_Impl *const pHint = pHints->GetHints()[i].get();
xAttrCursor->gotoRange( pHint->GetStart(), sal_False );
xAttrCursor->gotoRange( pHint->GetEnd(), sal_True );
switch( pHint->GetType() )