LCOV - code coverage report
Current view: top level - sfx2/source/doc - Metadatable.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 404 479 84.3 %
Date: 2014-11-03 Functions: 79 94 84.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <sfx2/Metadatable.hxx>
      22             : #include <sfx2/XmlIdRegistry.hxx>
      23             : 
      24             : #include <osl/mutex.hxx>
      25             : #include <vcl/svapp.hxx>
      26             : 
      27             : #include <rtl/random.h>
      28             : 
      29             : #include <boost/bind.hpp>
      30             : 
      31             : #include <memory>
      32             : #include <boost/unordered_map.hpp>
      33             : #include <list>
      34             : #include <algorithm>
      35             : #if OSL_DEBUG_LEVEL > 0
      36             : #include <typeinfo>
      37             : #endif
      38             : 
      39             : 
      40             : /** XML ID handling.
      41             : 
      42             :     There is an abstract base class <type>XmlIdRegistry</type>, with
      43             :     2 subclasses <type>XmlIdRegistryDocument</type> for "normal" documents,
      44             :     and <type>XmlIdRegistryClipboard</type> for clipboard documents.
      45             :     These classes are responsible for managing XML IDs for all elements
      46             :     of the model. Only the implementation of the <type>Metadatable</type>
      47             :     base class needs to know the registries, so they are not in the header.
      48             : 
      49             :     The handling of XML IDs differs between clipboard and non-clipboard
      50             :     documents in several aspects. Most importantly, non-clipboard documents
      51             :     can have several elements associated with one XML ID.
      52             :     This is necessary because of the weird undo implementation:
      53             :     deleting a text node moves the deleted node to the undo array, but
      54             :     executing undo will then create a <em>copy</em> of that node in the
      55             :     document array. These 2 nodes must have the same XML ID, because
      56             :     we cannot know whether the user will do a redo next, or something else.
      57             : 
      58             :     Because we need to have a mechanism for several objects per XML ID anyway,
      59             :     we use that also to enable some usability features:
      60             :     The document registry has a list of Metadatables per XML ID.
      61             :     This list is sorted by priority, i.e., the first element has highest
      62             :     priority. When inserting copies, care must be taken that they are inserted
      63             :     at the right position: either before or after the source.
      64             :     This is done by <method>Metadatable::RegisterAsCopyOf</method>.
      65             :     When a text node is split, then both resulting text nodes are inserted
      66             :     into the list. If the user then deletes one text node, the other one
      67             :     will have the XML ID.
      68             :     Also, when a Metadatable is copied to the clipboard and then pasted,
      69             :     the copy is inserted into the list. If the user then deletes the source,
      70             :     the XML ID is not lost.
      71             :     The goal is that it should be hard to lose an XML ID by accident, which
      72             :     is especially important as long as we do not have an UI that displays them.
      73             : 
      74             :     There are two subclasses of <type>Metadatable</type>:
      75             :     <ul><li><type>MetadatableClipboard</type>: for copies in the clipboard</li>
      76             :         <li><type>MetadatableUndo</type>: for undo, because a Metadatable
      77             :         may be destroyed on delete and a new one created on undo.</li></ul>
      78             :     These serve only to track the position in an XML ID list in a document
      79             :     registry, so that future actions can insert objects at the right position.
      80             :     Unfortunately, inserting dummy objects seems to be necessary:
      81             :     <ul><li>it is not sufficient to just remember the saved id, because then
      82             :             the relative priorities might change when executing the undo</li>
      83             :         <li>it is not sufficient to record the position as an integer, because
      84             :             if we delete a text node and then undo, the node will be copied(!),
      85             :             and we will have one more node in the list.<li>
      86             :         <li>it is not sufficient to record the pointer of the previous/next
      87             :             Metadatable, because if we delete a text node, undo, and then
      88             :             do something to clear the redo array, the original text node is
      89             :             destroyed, and is replaced by the copy created by undo</li></ul>
      90             : 
      91             :     If content from a non-clipboard document is copied into a clipboard
      92             :     document, a dummy <type>MetadatableClipboard</type> is inserted into the
      93             :     non-clipboard document registry in order to track the position of the
      94             :     source element.  When the clipboard content is pasted back into the source
      95             :     document, this dummy object is used to associate the pasted element with
      96             :     that same XML ID.
      97             : 
      98             :     If a <type>Metadatable</type> is deleted or merged,
      99             :     <method>Metadatable::CreateUndo</method> is called, and returns a
     100             :     <type>MetadatableUndo<type> instance, which can be used to undo the action
     101             :     by passing it to <method>Metadatable::RestoreMetadata</method>.
     102             : 
     103             :     @author mst
     104             :  */
     105             : 
     106             : 
     107             : using namespace ::com::sun::star;
     108             : 
     109             : using ::sfx2::isValidXmlId;
     110             : 
     111             : 
     112             : namespace sfx2 {
     113             : 
     114             : static const char s_content [] = "content.xml";
     115             : static const char s_styles  [] = "styles.xml";
     116             : static const char s_prefix  [] = "id";  // prefix for generated xml:id
     117             : 
     118        2448 : static bool isContentFile(OUString const & i_rPath)
     119             : {
     120        2448 :     return i_rPath == s_content;
     121             : }
     122             : 
     123           2 : static bool isStylesFile (OUString const & i_rPath)
     124             : {
     125           2 :     return i_rPath == s_styles;
     126             : }
     127             : 
     128             : 
     129             : 
     130             : // XML ID handling ---------------------------------------------------
     131             : 
     132             : /** handles registration of XMetadatable.
     133             : 
     134             :     This class is responsible for guaranteeing that XMetadatable objects
     135             :     always have XML IDs that are unique within a stream.
     136             : 
     137             :     This is an abstract base class; see subclasses XmlIdRegistryDocument and
     138             :     XmlIdRegistryClipboard.
     139             : 
     140             :     @see SwDoc::GetXmlIdRegistry
     141             :     @see SwDocShell::GetXmlIdRegistry
     142             :  */
     143             : class XmlIdRegistry : public sfx2::IXmlIdRegistry
     144             : {
     145             : 
     146             : public:
     147             :     XmlIdRegistry();
     148             : 
     149             :     virtual ~XmlIdRegistry();
     150             : 
     151             :     /** get the ODF element with the given metadata reference. */
     152             :     virtual ::com::sun::star::uno::Reference<
     153             :             ::com::sun::star::rdf::XMetadatable >
     154             :         GetElementByMetadataReference(
     155             :             const ::com::sun::star::beans::StringPair & i_rReference) const
     156             :         SAL_OVERRIDE;
     157             : 
     158             :     /** register an ODF element at a newly generated, unique metadata reference.
     159             : 
     160             :         <p>
     161             :         Find a fresh XML ID, and register it for the element.
     162             :         The generated ID does not occur in any stream of the document.
     163             :         </p>
     164             :      */
     165             :     virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject) = 0;
     166             : 
     167             :     /** try to register an ODF element at a given XML ID, or update its
     168             :         registation to a different XML ID.
     169             : 
     170             :         <p>
     171             :         If the given new metadata reference is not already occupied in the
     172             :         document, unregister the element at its old metadata reference if
     173             :         it has one, and register the new metadata reference for the element.
     174             :         Note that this method only ensures that XML IDs are unique per stream,
     175             :         so using the same XML ID in both content.xml and styles.xml is allowed.
     176             :         </p>
     177             : 
     178             :         @returns
     179             :             true iff the element has successfully been registered
     180             :      */
     181             :     virtual bool TryRegisterMetadatable(Metadatable& i_xObject,
     182             :         OUString const& i_rStreamName, OUString const& i_rIdref)
     183             :         = 0;
     184             : 
     185             :     /** unregister an ODF element.
     186             : 
     187             :         <p>
     188             :         Unregister the element at its metadata reference.
     189             :         Does not remove the metadata reference from the element.
     190             :         </p>
     191             : 
     192             :         @see RemoveXmlIdForElement
     193             :      */
     194             :     virtual void UnregisterMetadatable(Metadatable const&) = 0;
     195             : 
     196             :     /** get the metadata reference for the given element. */
     197             :     ::com::sun::star::beans::StringPair
     198             :         GetXmlIdForElement(Metadatable const&) const;
     199             : 
     200             :     /** remove the metadata reference for the given element. */
     201             :     virtual void RemoveXmlIdForElement(Metadatable const&) = 0;
     202             : 
     203             : protected:
     204             : 
     205             :     virtual bool LookupXmlId(const Metadatable& i_xObject,
     206             :         OUString & o_rStream, OUString & o_rIdref) const = 0;
     207             : 
     208             :     virtual Metadatable* LookupElement(const OUString & i_rStreamName,
     209             :         const OUString & i_rIdref) const = 0;
     210             : };
     211             : 
     212             : // XmlIdRegistryDocument ---------------------------------------------
     213             : 
     214             : /** non-clipboard documents */
     215             : class XmlIdRegistryDocument : public XmlIdRegistry
     216             : {
     217             : 
     218             : public:
     219             :     XmlIdRegistryDocument();
     220             : 
     221             :     virtual ~XmlIdRegistryDocument();
     222             : 
     223             :     virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject) SAL_OVERRIDE;
     224             : 
     225             :     virtual bool TryRegisterMetadatable(Metadatable& i_xObject,
     226             :         OUString const& i_rStreamName, OUString const& i_rIdref) SAL_OVERRIDE;
     227             : 
     228             :     virtual void UnregisterMetadatable(Metadatable const&) SAL_OVERRIDE;
     229             : 
     230             :     virtual void RemoveXmlIdForElement(Metadatable const&) SAL_OVERRIDE;
     231             : 
     232             :     /** register i_rCopy as a copy of i_rSource,
     233             :         with precedence iff i_bCopyPrecedesSource is true */
     234             :     void RegisterCopy(Metadatable const& i_rSource, Metadatable & i_rCopy,
     235             :         const bool i_bCopyPrecedesSource);
     236             : 
     237             :     /** create a Undo Metadatable for i_rObject. */
     238             :     ::boost::shared_ptr<MetadatableUndo> CreateUndo(
     239             :         Metadatable const& i_rObject);
     240             : 
     241             :     /** merge i_rMerged and i_rOther into i_rMerged. */
     242             :     void JoinMetadatables(Metadatable & i_rMerged, Metadatable const& i_rOther);
     243             : 
     244             :     // unfortunately public, Metadatable::RegisterAsCopyOf needs this
     245             :     virtual bool LookupXmlId(const Metadatable& i_xObject,
     246             :         OUString & o_rStream, OUString & o_rIdref) const SAL_OVERRIDE;
     247             : 
     248             : private:
     249             : 
     250             :     virtual Metadatable* LookupElement(const OUString & i_rStreamName,
     251             :         const OUString & i_rIdref) const SAL_OVERRIDE;
     252             : 
     253             :     struct XmlIdRegistry_Impl;
     254             :     ::std::unique_ptr<XmlIdRegistry_Impl> m_pImpl;
     255             : };
     256             : 
     257             : // MetadatableUndo ---------------------------------------------------
     258             : 
     259             : /** the horrible Undo Metadatable: is inserted into lists to track position */
     260           0 : class MetadatableUndo : public Metadatable
     261             : {
     262             :     /// as determined by the stream of the source in original document
     263             :     const bool m_isInContent;
     264             : public:
     265           0 :     MetadatableUndo(const bool i_isInContent)
     266           0 :         : m_isInContent(i_isInContent) { }
     267           0 :     virtual ::sfx2::XmlIdRegistry& GetRegistry() SAL_OVERRIDE
     268             :     {
     269             :         // N.B. for Undo, m_pReg is initialized by registering this as copy in
     270             :         // CreateUndo; it is never cleared
     271             :         OSL_ENSURE(m_pReg, "no m_pReg in MetadatableUndo ?");
     272           0 :         return *m_pReg;
     273             :     }
     274           0 :     virtual bool IsInClipboard() const SAL_OVERRIDE { return false; }
     275           0 :     virtual bool IsInUndo() const SAL_OVERRIDE { return true; }
     276           0 :     virtual bool IsInContent() const SAL_OVERRIDE { return m_isInContent; }
     277             :     virtual ::com::sun::star::uno::Reference<
     278           0 :         ::com::sun::star::rdf::XMetadatable > MakeUnoObject() SAL_OVERRIDE
     279           0 :     { OSL_FAIL("MetadatableUndo::MakeUnoObject"); throw; }
     280             : };
     281             : 
     282             : // MetadatableClipboard ----------------------------------------------
     283             : 
     284             : /** the horrible Clipboard Metadatable: inserted into lists to track position */
     285           8 : class MetadatableClipboard : public Metadatable
     286             : {
     287             :     /// as determined by the stream of the source in original document
     288             :     const bool m_isInContent;
     289             : public:
     290           4 :     MetadatableClipboard(const bool i_isInContent)
     291           4 :         : m_isInContent(i_isInContent) { }
     292           4 :     virtual ::sfx2::XmlIdRegistry& GetRegistry() SAL_OVERRIDE
     293             :     {
     294             :         // N.B. for Clipboard, m_pReg is initialized by registering this as copy in
     295             :         // RegisterAsCopyOf; it is only cleared by OriginNoLongerInBusinessAnymore
     296             :         assert(m_pReg && "no m_pReg in MetadatableClipboard ?");
     297           4 :         return *m_pReg;
     298             :     }
     299           4 :     virtual bool IsInClipboard() const SAL_OVERRIDE { return true; }
     300           4 :     virtual bool IsInUndo() const SAL_OVERRIDE { return false; }
     301           4 :     virtual bool IsInContent() const SAL_OVERRIDE { return m_isInContent; }
     302             :     virtual ::com::sun::star::uno::Reference<
     303           0 :         ::com::sun::star::rdf::XMetadatable > MakeUnoObject() SAL_OVERRIDE
     304           0 :     { OSL_FAIL("MetadatableClipboard::MakeUnoObject"); throw; }
     305           0 :     void OriginNoLongerInBusinessAnymore() { m_pReg = 0; }
     306             : };
     307             : 
     308             : // XmlIdRegistryClipboard --------------------------------------------
     309             : 
     310             : class XmlIdRegistryClipboard : public XmlIdRegistry
     311             : {
     312             : 
     313             : public:
     314             :     XmlIdRegistryClipboard();
     315             :     virtual ~XmlIdRegistryClipboard();
     316             : 
     317             :     virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject) SAL_OVERRIDE;
     318             : 
     319             :     virtual bool TryRegisterMetadatable(Metadatable& i_xObject,
     320             :         OUString const& i_rStreamName, OUString const& i_rIdref) SAL_OVERRIDE;
     321             : 
     322             :     virtual void UnregisterMetadatable(Metadatable const&) SAL_OVERRIDE;
     323             : 
     324             :     virtual void RemoveXmlIdForElement(Metadatable const&) SAL_OVERRIDE;
     325             : 
     326             :     /** register i_rCopy as a copy of i_rSource */
     327             :     MetadatableClipboard & RegisterCopyClipboard(Metadatable & i_rCopy,
     328             :         beans::StringPair const & i_rReference,
     329             :         const bool i_isLatent);
     330             : 
     331             :     /** get the Metadatable that links i_rObject to its origin registry */
     332             :     MetadatableClipboard const* SourceLink(Metadatable const& i_rObject);
     333             : 
     334             : private:
     335             :     virtual bool LookupXmlId(const Metadatable& i_xObject,
     336             :         OUString & o_rStream, OUString & o_rIdref) const SAL_OVERRIDE;
     337             : 
     338             :     virtual Metadatable* LookupElement(const OUString & i_rStreamName,
     339             :         const OUString & i_rIdref) const SAL_OVERRIDE;
     340             : 
     341             :     /** create a Clipboard Metadatable for i_rObject. */
     342             :     ::boost::shared_ptr<MetadatableClipboard> CreateClipboard(
     343             :         const bool i_isInContent);
     344             : 
     345             :     struct XmlIdRegistry_Impl;
     346             :     ::std::unique_ptr<XmlIdRegistry_Impl> m_pImpl;
     347             : };
     348             : 
     349             : 
     350             : 
     351             : // XmlIdRegistry
     352             : 
     353          72 : ::sfx2::IXmlIdRegistry * createXmlIdRegistry(const bool i_DocIsClipboard)
     354             : {
     355             :     return i_DocIsClipboard
     356           2 :         ? static_cast<XmlIdRegistry*>( new XmlIdRegistryClipboard )
     357          74 :         : static_cast<XmlIdRegistry*>( new XmlIdRegistryDocument );
     358             : }
     359             : 
     360          72 : XmlIdRegistry::XmlIdRegistry()
     361             : {
     362          72 : }
     363             : 
     364          72 : XmlIdRegistry::~XmlIdRegistry()
     365             : {
     366          72 : }
     367             : 
     368             : ::com::sun::star::uno::Reference< ::com::sun::star::rdf::XMetadatable >
     369           2 : XmlIdRegistry::GetElementByMetadataReference(
     370             :     const beans::StringPair & i_rReference) const
     371             : {
     372             :     Metadatable* pObject( LookupElement(i_rReference.First,
     373           2 :         i_rReference.Second) );
     374           2 :     return pObject ? pObject->MakeUnoObject() : 0;
     375             : }
     376             : 
     377             : beans::StringPair
     378        1336 : XmlIdRegistry::GetXmlIdForElement(const Metadatable& i_rObject) const
     379             : {
     380        1336 :     OUString path;
     381        2672 :     OUString idref;
     382        1336 :     if (LookupXmlId(i_rObject, path, idref))
     383             :     {
     384        1336 :         if (LookupElement(path, idref) == &i_rObject)
     385             :         {
     386        1312 :             return beans::StringPair(path, idref);
     387             :         }
     388             :     }
     389        1360 :     return beans::StringPair();
     390             : }
     391             : 
     392             : 
     393             : /// generate unique xml:id
     394             : template< typename T >
     395          44 : /*static*/ OUString create_id(const
     396             :     ::boost::unordered_map< OUString, T, OUStringHash > & i_rXmlIdMap)
     397             : {
     398          44 :     static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
     399          44 :     const OUString prefix(s_prefix);
     400             :     typename ::boost::unordered_map< OUString, T, OUStringHash >
     401          44 :         ::const_iterator iter;
     402          44 :     OUString id;
     403             : 
     404          44 :     if (bHack)
     405             :     {
     406             :         static sal_Int64 nIdCounter = SAL_CONST_INT64(4000000000);
     407           0 :         do
     408             :         {
     409           0 :             id = prefix + OUString::number(nIdCounter++);
     410           0 :             iter = i_rXmlIdMap.find(id);
     411             :         }
     412           0 :         while (iter != i_rXmlIdMap.end());
     413             :     }
     414             :     else
     415             :     {
     416          44 :         static rtlRandomPool s_Pool( rtl_random_createPool() );
     417          88 :         do
     418             :         {
     419             :             sal_Int32 n;
     420          44 :             rtl_random_getBytes(s_Pool, & n, sizeof(n));
     421          44 :             id = prefix + OUString::number(abs(n));
     422          44 :             iter = i_rXmlIdMap.find(id);
     423             :         }
     424          88 :         while (iter != i_rXmlIdMap.end());
     425             :     }
     426          44 :     return id;
     427             : }
     428             : 
     429             : 
     430             : // Document XML ID Registry (_Impl)
     431             : 
     432             : /// element list
     433             : typedef ::std::list< Metadatable* > XmlIdList_t;
     434             : 
     435             : /// Idref -> (content.xml element list, styles.xml element list)
     436             : typedef ::boost::unordered_map< OUString,
     437             :     ::std::pair< XmlIdList_t, XmlIdList_t >, OUStringHash > XmlIdMap_t;
     438             : 
     439             : /// pointer hash template
     440             : template<typename T> struct PtrHash
     441             : {
     442        2902 :     size_t operator() (T const * i_pT) const
     443             :     {
     444        2902 :         return reinterpret_cast<size_t>(i_pT);
     445             :     }
     446             : };
     447             : 
     448             : /// element -> (stream name, idref)
     449             : typedef ::boost::unordered_map< const Metadatable*,
     450             :     ::std::pair< OUString, OUString>, PtrHash<Metadatable> >
     451             :     XmlIdReverseMap_t;
     452             : 
     453          70 : struct XmlIdRegistryDocument::XmlIdRegistry_Impl
     454             : {
     455          70 :     XmlIdRegistry_Impl()
     456          70 :         : m_XmlIdMap(), m_XmlIdReverseMap() { }
     457             : 
     458             :     bool TryInsertMetadatable(Metadatable& i_xObject,
     459             :         const OUString & i_rStream, const OUString & i_rIdref);
     460             : 
     461             :     bool LookupXmlId(const Metadatable& i_xObject,
     462             :         OUString & o_rStream, OUString & o_rIdref) const;
     463             : 
     464             :     Metadatable* LookupElement(const OUString & i_rStreamName,
     465             :         const OUString & i_rIdref) const;
     466             : 
     467             :     const XmlIdList_t * LookupElementList(
     468             :         const OUString & i_rStreamName,
     469             :         const OUString & i_rIdref) const;
     470             : 
     471         324 :           XmlIdList_t * LookupElementList(
     472             :         const OUString & i_rStreamName,
     473             :         const OUString & i_rIdref)
     474             :     {
     475             :         return const_cast<XmlIdList_t*>(
     476             :             const_cast<const XmlIdRegistry_Impl*>(this)
     477         324 :                 ->LookupElementList(i_rStreamName, i_rIdref));
     478             :     }
     479             : 
     480             :     XmlIdMap_t m_XmlIdMap;
     481             :     XmlIdReverseMap_t m_XmlIdReverseMap;
     482             : };
     483             : 
     484             : 
     485             : 
     486             : static void
     487         670 : rmIter(XmlIdMap_t & i_rXmlIdMap, XmlIdMap_t::iterator const& i_rIter,
     488             :     OUString const & i_rStream, Metadatable const& i_rObject)
     489             : {
     490         670 :     if (i_rIter != i_rXmlIdMap.end())
     491             :     {
     492         364 :         XmlIdList_t & rList( isContentFile(i_rStream)
     493         364 :             ? i_rIter->second.first : i_rIter->second.second );
     494         364 :         rList.remove(&const_cast<Metadatable&>(i_rObject));
     495         364 :         if (i_rIter->second.first.empty() && i_rIter->second.second.empty())
     496             :         {
     497         350 :             i_rXmlIdMap.erase(i_rIter);
     498             :         }
     499             :     }
     500         670 : }
     501             : 
     502             : 
     503             : 
     504             : const XmlIdList_t *
     505        1726 : XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupElementList(
     506             :     const OUString & i_rStreamName,
     507             :     const OUString & i_rIdref) const
     508             : {
     509        1726 :     const XmlIdMap_t::const_iterator iter( m_XmlIdMap.find(i_rIdref) );
     510        1726 :     if (iter != m_XmlIdMap.end())
     511             :     {
     512             :         OSL_ENSURE(!iter->second.first.empty() || !iter->second.second.empty(),
     513             :             "null entry in m_XmlIdMap");
     514        1418 :         return (isContentFile(i_rStreamName))
     515        1416 :             ?  &iter->second.first
     516        2834 :             :  &iter->second.second;
     517             :     }
     518             :     else
     519             :     {
     520         308 :         return 0;
     521             :     }
     522             : }
     523             : 
     524             : Metadatable*
     525        1402 : XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupElement(
     526             :     const OUString & i_rStreamName,
     527             :     const OUString & i_rIdref) const
     528             : {
     529        1402 :     if (!isValidXmlId(i_rStreamName, i_rIdref))
     530             :     {
     531             :         throw lang::IllegalArgumentException(OUString(
     532           0 :             "illegal XmlId"), 0, 0);
     533             :     }
     534             : 
     535        1402 :     const XmlIdList_t * pList( LookupElementList(i_rStreamName, i_rIdref) );
     536        1402 :     if (pList)
     537             :     {
     538             :         const XmlIdList_t::const_iterator iter(
     539             :             ::std::find_if(pList->begin(), pList->end(),
     540             :                 ::boost::bind(
     541             :                     ::std::logical_not<bool>(),
     542             :                         ::boost::bind(
     543             :                             ::std::logical_or<bool>(),
     544             :                                 ::boost::bind( &Metadatable::IsInUndo, _1 ),
     545             :                                 ::boost::bind( &Metadatable::IsInClipboard, _1 )
     546        1402 :             ) ) ) );
     547        1402 :         if (iter != pList->end())
     548             :         {
     549        1400 :             return *iter;
     550             :         }
     551             :     }
     552           2 :     return 0;
     553             : }
     554             : 
     555             : bool
     556        2124 : XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupXmlId(
     557             :     const Metadatable& i_rObject,
     558             :     OUString & o_rStream, OUString & o_rIdref) const
     559             : {
     560             :     const XmlIdReverseMap_t::const_iterator iter(
     561        2124 :         m_XmlIdReverseMap.find(&i_rObject) );
     562        2124 :     if (iter != m_XmlIdReverseMap.end())
     563             :     {
     564             :         OSL_ENSURE(!iter->second.first.isEmpty(),
     565             :             "null stream in m_XmlIdReverseMap");
     566             :         OSL_ENSURE(!iter->second.second.isEmpty(),
     567             :             "null id in m_XmlIdReverseMap");
     568        1776 :         o_rStream = iter->second.first;
     569        1776 :         o_rIdref  = iter->second.second;
     570        1776 :         return true;
     571             :     }
     572             :     else
     573             :     {
     574         348 :         return false;
     575             :     }
     576             : }
     577             : 
     578             : bool
     579         312 : XmlIdRegistryDocument::XmlIdRegistry_Impl::TryInsertMetadatable(
     580             :     Metadatable & i_rObject,
     581             :     const OUString & i_rStreamName, const OUString & i_rIdref)
     582             : {
     583         312 :     const bool bContent( isContentFile(i_rStreamName) );
     584             :     OSL_ENSURE(isContentFile(i_rStreamName) || isStylesFile(i_rStreamName),
     585             :         "invalid stream");
     586             : 
     587         312 :     XmlIdList_t * pList( LookupElementList(i_rStreamName, i_rIdref) );
     588         312 :     if (pList)
     589             :     {
     590           4 :         if (pList->empty())
     591             :         {
     592           0 :             pList->push_back( &i_rObject );
     593           0 :             return true;
     594             :         }
     595             :         else
     596             :         {
     597             :             // this is only called from TryRegister now, so check
     598             :             // if all elements in the list are deleted (in undo) or
     599             :             // placeholders, then "steal" the id from them
     600           8 :             if ( pList->end() == ::std::find_if(pList->begin(), pList->end(),
     601             :                 ::boost::bind(
     602             :                     ::std::logical_not<bool>(),
     603             :                         ::boost::bind(
     604             :                             ::std::logical_or<bool>(),
     605             :                                 ::boost::bind( &Metadatable::IsInUndo, _1 ),
     606             :                                 ::boost::bind( &Metadatable::IsInClipboard, _1 )
     607           8 :                 ) ) ) )
     608             :             {
     609           2 :                 pList->push_front( &i_rObject );
     610           2 :                 return true;
     611             :             }
     612             :             else
     613             :             {
     614           2 :                 return false;
     615             :             }
     616             :         }
     617             :     }
     618             :     else
     619             :     {
     620             :         m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent
     621             :             ? ::std::make_pair( XmlIdList_t( 1, &i_rObject ), XmlIdList_t() )
     622         308 :             : ::std::make_pair( XmlIdList_t(), XmlIdList_t( 1, &i_rObject ) )));
     623         308 :         return true;
     624             :     }
     625             : }
     626             : 
     627             : 
     628             : // Document XML ID Registry
     629             : 
     630             : 
     631          70 : XmlIdRegistryDocument::XmlIdRegistryDocument()
     632          70 :     :   m_pImpl( new XmlIdRegistry_Impl )
     633             : {
     634          70 : }
     635             : 
     636             : static void
     637           0 : removeLink(Metadatable* i_pObject)
     638             : {
     639             :     OSL_ENSURE(i_pObject, "null in list ???");
     640           0 :     if (!i_pObject) return;
     641           0 :     if (i_pObject->IsInClipboard())
     642             :     {
     643             :         MetadatableClipboard* pLink(
     644           0 :             dynamic_cast<MetadatableClipboard*>( i_pObject ) );
     645             :         OSL_ENSURE(pLink, "IsInClipboard, but no MetadatableClipboard ?");
     646           0 :         if (pLink)
     647             :         {
     648           0 :             pLink->OriginNoLongerInBusinessAnymore();
     649             :         }
     650             :     }
     651             : }
     652             : 
     653         210 : XmlIdRegistryDocument::~XmlIdRegistryDocument()
     654             : {
     655             :     // notify all list elements that are actually in the clipboard
     656         210 :     for (XmlIdMap_t::iterator iter(m_pImpl->m_XmlIdMap.begin());
     657         140 :         iter != m_pImpl->m_XmlIdMap.end(); ++iter)
     658             :     {
     659           0 :         ::std::for_each(iter->second.first.begin(), iter->second.first.end(),
     660           0 :             removeLink);
     661           0 :         ::std::for_each(iter->second.second.begin(), iter->second.second.end(),
     662           0 :             removeLink);
     663             :     }
     664         140 : }
     665             : 
     666             : bool
     667        1322 : XmlIdRegistryDocument::LookupXmlId(
     668             :     const Metadatable& i_rObject,
     669             :     OUString & o_rStream, OUString & o_rIdref) const
     670             : {
     671        1322 :     return m_pImpl->LookupXmlId(i_rObject, o_rStream, o_rIdref);
     672             : }
     673             : 
     674             : Metadatable*
     675        1322 : XmlIdRegistryDocument::LookupElement(
     676             :     const OUString & i_rStreamName,
     677             :     const OUString & i_rIdref) const
     678             : {
     679        1322 :     return m_pImpl->LookupElement(i_rStreamName, i_rIdref);
     680             : }
     681             : 
     682             : bool
     683         314 : XmlIdRegistryDocument::TryRegisterMetadatable(Metadatable & i_rObject,
     684             :     OUString const& i_rStreamName, OUString const& i_rIdref)
     685             : {
     686             :     OSL_TRACE("TryRegisterMetadatable: %p (%s#%s)\n", &i_rObject,
     687             :         OUStringToOString(i_rStreamName, RTL_TEXTENCODING_UTF8).getStr(),
     688             :         OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8).getStr());
     689             : 
     690             :     OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject),
     691             :         "TryRegisterMetadatable called for MetadatableUndo?");
     692             :     OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject),
     693             :         "TryRegisterMetadatable called for MetadatableClipboard?");
     694             : 
     695         314 :     if (!isValidXmlId(i_rStreamName, i_rIdref))
     696             :     {
     697             :         throw lang::IllegalArgumentException(OUString(
     698           0 :             "illegal XmlId"), 0, 0);
     699             :     }
     700         628 :     if (i_rObject.IsInContent()
     701         312 :         ?   !isContentFile(i_rStreamName)
     702           2 :         :   !isStylesFile(i_rStreamName))
     703             :     {
     704             :         throw lang::IllegalArgumentException(OUString(
     705           0 :             "illegal XmlId: wrong stream"), 0, 0);
     706             :     }
     707             : 
     708         314 :     OUString old_path;
     709         628 :     OUString old_idref;
     710         314 :     m_pImpl->LookupXmlId(i_rObject, old_path, old_idref);
     711         314 :     if (old_path  == i_rStreamName && old_idref == i_rIdref)
     712             :     {
     713           2 :         return (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject);
     714             :     }
     715         312 :     XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() );
     716         312 :     if (!old_idref.isEmpty())
     717             :     {
     718           4 :         old_id = m_pImpl->m_XmlIdMap.find(old_idref);
     719             :         OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found");
     720             :     }
     721         312 :     if (m_pImpl->TryInsertMetadatable(i_rObject, i_rStreamName, i_rIdref))
     722             :     {
     723         310 :         rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject);
     724         620 :         m_pImpl->m_XmlIdReverseMap[&i_rObject] =
     725         310 :             ::std::make_pair(i_rStreamName, i_rIdref);
     726         310 :         return true;
     727             :     }
     728             :     else
     729             :     {
     730           2 :         return false;
     731         314 :     }
     732             : }
     733             : 
     734             : void
     735         118 : XmlIdRegistryDocument::RegisterMetadatableAndCreateID(Metadatable & i_rObject)
     736             : {
     737             :     OSL_TRACE("RegisterMetadatableAndCreateID: %p", &i_rObject);
     738             : 
     739             :     OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject),
     740             :         "RegisterMetadatableAndCreateID called for MetadatableUndo?");
     741             :     OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject),
     742             :         "RegisterMetadatableAndCreateID called for MetadatableClipboard?");
     743             : 
     744         118 :     const bool isInContent( i_rObject.IsInContent() );
     745             :     const OUString stream( OUString::createFromAscii(
     746         118 :         isInContent ? s_content : s_styles ) );
     747             :     // check if we have a latent xmlid, and if yes, remove it
     748         160 :     OUString old_path;
     749         160 :     OUString old_idref;
     750         118 :     m_pImpl->LookupXmlId(i_rObject, old_path, old_idref);
     751             : 
     752         118 :     XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() );
     753         118 :     if (!old_idref.isEmpty())
     754             :     {
     755          78 :         old_id = m_pImpl->m_XmlIdMap.find(old_idref);
     756             :         OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found");
     757          78 :         if (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject)
     758             :         {
     759         194 :             return;
     760             :         }
     761             :         else
     762             :         {
     763             :             // remove latent xmlid
     764           2 :             rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject);
     765             :         }
     766             :     }
     767             : 
     768             :     // create id
     769          84 :     const OUString id( create_id(m_pImpl->m_XmlIdMap) );
     770             :     OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(),
     771             :         "created id is in use");
     772          42 :     m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent
     773             :         ? ::std::make_pair( XmlIdList_t( 1, &i_rObject ), XmlIdList_t() )
     774          84 :         : ::std::make_pair( XmlIdList_t(), XmlIdList_t( 1, &i_rObject ) )));
     775          84 :     m_pImpl->m_XmlIdReverseMap[&i_rObject] = ::std::make_pair(stream, id);
     776             : }
     777             : 
     778         358 : void XmlIdRegistryDocument::UnregisterMetadatable(const Metadatable& i_rObject)
     779             : {
     780             :     OSL_TRACE("UnregisterMetadatable: %p", &i_rObject);
     781             : 
     782         358 :     OUString path;
     783         716 :     OUString idref;
     784         358 :     if (!m_pImpl->LookupXmlId(i_rObject, path, idref))
     785             :     {
     786             :         OSL_FAIL("unregister: no xml id?");
     787         358 :         return;
     788             :     }
     789         358 :     const XmlIdMap_t::iterator iter( m_pImpl->m_XmlIdMap.find(idref) );
     790         358 :     if (iter != m_pImpl->m_XmlIdMap.end())
     791             :     {
     792         358 :         rmIter(m_pImpl->m_XmlIdMap, iter, path, i_rObject);
     793         358 :     }
     794             : }
     795             : 
     796         358 : void XmlIdRegistryDocument::RemoveXmlIdForElement(const Metadatable& i_rObject)
     797             : {
     798             :     OSL_TRACE("RemoveXmlIdForElement: %p", &i_rObject);
     799             : 
     800             :     const XmlIdReverseMap_t::iterator iter(
     801         358 :         m_pImpl->m_XmlIdReverseMap.find(&i_rObject) );
     802         358 :     if (iter != m_pImpl->m_XmlIdReverseMap.end())
     803             :     {
     804             :         OSL_ENSURE(!iter->second.second.isEmpty(),
     805             :             "null id in m_XmlIdReverseMap");
     806         358 :         m_pImpl->m_XmlIdReverseMap.erase(iter);
     807             :     }
     808         358 : }
     809             : 
     810             : 
     811             : 
     812          12 : void XmlIdRegistryDocument::RegisterCopy(Metadatable const& i_rSource,
     813             :     Metadatable & i_rCopy, const bool i_bCopyPrecedesSource)
     814             : {
     815             :     OSL_TRACE("RegisterCopy: %p -> %p (%d)\n",
     816             :         &i_rSource, &i_rCopy, i_bCopyPrecedesSource);
     817             : 
     818             :     // potential sources: clipboard, undo array, splitNode
     819             :     // assumption: stream change can only happen via clipboard, and is handled
     820             :     // by Metadatable::RegisterAsCopyOf
     821             :     OSL_ENSURE(i_rSource.IsInUndo() || i_rCopy.IsInUndo() ||
     822             :         (i_rSource.IsInContent() == i_rCopy.IsInContent()),
     823             :         "RegisterCopy: not in same stream?");
     824             : 
     825          12 :     OUString path;
     826          24 :     OUString idref;
     827          12 :     if (!m_pImpl->LookupXmlId( i_rSource, path, idref ))
     828             :     {
     829             :         OSL_FAIL("no xml id?");
     830           0 :         return;
     831             :     }
     832          12 :     XmlIdList_t * pList ( m_pImpl->LookupElementList(path, idref) );
     833             :     OSL_ENSURE( ::std::find( pList->begin(), pList->end(), &i_rCopy )
     834             :         == pList->end(), "copy already registered???");
     835             :     XmlIdList_t::iterator srcpos(
     836          12 :         ::std::find( pList->begin(), pList->end(), &i_rSource ) );
     837             :     OSL_ENSURE(srcpos != pList->end(), "source not in list???");
     838          12 :     if (srcpos == pList->end())
     839             :     {
     840           0 :         return;
     841             :     }
     842          12 :     if (i_bCopyPrecedesSource)
     843             :     {
     844           4 :         pList->insert( srcpos, &i_rCopy );
     845             :     }
     846             :     else
     847             :     {
     848             :         // for undo push_back does not work! must insert right after source
     849           8 :         pList->insert( ++srcpos, &i_rCopy );
     850             :     }
     851          12 :     m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy,
     852          36 :         ::std::make_pair(path, idref)));
     853             : }
     854             : 
     855             : ::boost::shared_ptr<MetadatableUndo>
     856           0 : XmlIdRegistryDocument::CreateUndo(Metadatable const& i_rObject)
     857             : {
     858             :     OSL_TRACE("CreateUndo: %p", &i_rObject);
     859             : 
     860             :     return ::boost::shared_ptr<MetadatableUndo>(
     861           0 :                 new MetadatableUndo(i_rObject.IsInContent()) );
     862             : }
     863             : 
     864             : /*
     865             : i_rMerged is both a source and the target node of the merge
     866             : i_rOther is the other source, and will be deleted after the merge
     867             : 
     868             : dimensions: none|latent|actual empty|nonempty
     869             : i_rMerged(1)    i_rOther(2)        result
     870             :      *|empty         *|empty    => 1|2 (arbitrary)
     871             :      *|empty         *|nonempty => 2
     872             :      *|nonempty      *|empty    => 1
     873             :   none|nonempty   none|nonempty => none
     874             :   none|nonempty latent|nonempty => 2
     875             : latent|nonempty   none|nonempty => 1
     876             : latent|nonempty latent|nonempty => 1|2
     877             :      *|nonempty actual|nonempty => 2
     878             : actual|nonempty      *|nonempty => 1
     879             : actual|nonempty actual|nonempty => 1|2
     880             : */
     881             : void
     882           0 : XmlIdRegistryDocument::JoinMetadatables(
     883             :     Metadatable & i_rMerged, Metadatable const & i_rOther)
     884             : {
     885             :     OSL_TRACE("JoinMetadatables: %p <- %p", &i_rMerged, &i_rOther);
     886             : 
     887             :     bool mergedOwnsRef;
     888           0 :     OUString path;
     889           0 :     OUString idref;
     890           0 :     if (m_pImpl->LookupXmlId(i_rMerged, path, idref))
     891             :     {
     892           0 :         mergedOwnsRef = (m_pImpl->LookupElement(path, idref) == &i_rMerged);
     893             :     }
     894             :     else
     895             :     {
     896             :         OSL_FAIL("JoinMetadatables: no xmlid?");
     897           0 :         return;
     898             :     }
     899           0 :     if (!mergedOwnsRef)
     900             :     {
     901           0 :         i_rMerged.RemoveMetadataReference();
     902           0 :         i_rMerged.RegisterAsCopyOf(i_rOther, true);
     903           0 :         return;
     904           0 :     }
     905             :     // other cases: merged has actual ref and is nonempty,
     906             :     // other has latent/actual ref and is nonempty: other loses => nothing to do
     907             : }
     908             : 
     909             : 
     910             : 
     911             : // Clipboard XML ID Registry (_Impl)
     912             : 
     913          40 : struct RMapEntry
     914             : {
     915           4 :     RMapEntry() : m_pLink() { }
     916           8 :     RMapEntry(OUString const& i_rStream,
     917             :             OUString const& i_rXmlId,
     918             :             ::boost::shared_ptr<MetadatableClipboard> const& i_pLink
     919             :                 = ::boost::shared_ptr<MetadatableClipboard>())
     920           8 :         :   m_Stream(i_rStream), m_XmlId(i_rXmlId), m_pLink(i_pLink)
     921           8 :         {}
     922             :     OUString m_Stream;
     923             :     OUString m_XmlId;
     924             :     // this would have been an auto_ptr, if only that would have compiled...
     925             :     ::boost::shared_ptr<MetadatableClipboard> m_pLink;
     926             : };
     927             : 
     928             : /// element -> (stream name, idref, source)
     929             : typedef ::boost::unordered_map< const Metadatable*,
     930             :     struct RMapEntry,
     931             :     PtrHash<Metadatable> >
     932             :     ClipboardXmlIdReverseMap_t;
     933             : 
     934             : /// Idref -> (content.xml element, styles.xml element)
     935             : typedef ::boost::unordered_map< OUString,
     936             :     ::std::pair< Metadatable*, Metadatable* >, OUStringHash >
     937             :     ClipboardXmlIdMap_t;
     938             : 
     939           2 : struct XmlIdRegistryClipboard::XmlIdRegistry_Impl
     940             : {
     941           2 :     XmlIdRegistry_Impl()
     942           2 :         : m_XmlIdMap(), m_XmlIdReverseMap() { }
     943             : 
     944             :     bool TryInsertMetadatable(Metadatable& i_xObject,
     945             :         const OUString & i_rStream, const OUString & i_rIdref);
     946             : 
     947             :     bool LookupXmlId(const Metadatable& i_xObject,
     948             :         OUString & o_rStream, OUString & o_rIdref,
     949             :         MetadatableClipboard const* &o_rpLink) const;
     950             : 
     951             :     Metadatable* LookupElement(const OUString & i_rStreamName,
     952             :         const OUString & i_rIdref) const;
     953             : 
     954             :     Metadatable* const* LookupEntry(const OUString & i_rStreamName,
     955             :         const OUString & i_rIdref) const;
     956             : 
     957           6 :     Metadatable*      * LookupEntry(const OUString & i_rStreamName,
     958             :         const OUString & i_rIdref)
     959             :     {
     960             :         return const_cast<Metadatable**>(
     961             :             const_cast<const XmlIdRegistry_Impl*>(this)
     962           6 :                 ->LookupEntry(i_rStreamName, i_rIdref));
     963             :     }
     964             : 
     965             :     ClipboardXmlIdMap_t m_XmlIdMap;
     966             :     ClipboardXmlIdReverseMap_t m_XmlIdReverseMap;
     967             : };
     968             : 
     969             : 
     970             : 
     971             : static void
     972           8 : rmIter(ClipboardXmlIdMap_t & i_rXmlIdMap,
     973             :     ClipboardXmlIdMap_t::iterator const& i_rIter,
     974             :     OUString const & i_rStream, Metadatable const& i_rObject)
     975             : {
     976           8 :     if (i_rIter != i_rXmlIdMap.end())
     977             :     {
     978           6 :         Metadatable *& rMeta = isContentFile(i_rStream)
     979           6 :             ? i_rIter->second.first : i_rIter->second.second;
     980           6 :         if (rMeta == &i_rObject)
     981             :         {
     982           6 :             rMeta = 0;
     983             :         }
     984           6 :         if (!i_rIter->second.first && !i_rIter->second.second)
     985             :         {
     986           6 :             i_rXmlIdMap.erase(i_rIter);
     987             :         }
     988             :     }
     989           8 : }
     990             : 
     991             : 
     992             : 
     993             : Metadatable* const*
     994          28 : XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupEntry(
     995             :     const OUString & i_rStreamName,
     996             :     const OUString & i_rIdref) const
     997             : {
     998          28 :     if (!isValidXmlId(i_rStreamName, i_rIdref))
     999             :     {
    1000             :         throw lang::IllegalArgumentException(OUString(
    1001           0 :             "illegal XmlId"), 0, 0);
    1002             :     }
    1003             : 
    1004          28 :     const ClipboardXmlIdMap_t::const_iterator iter( m_XmlIdMap.find(i_rIdref) );
    1005          28 :     if (iter != m_XmlIdMap.end())
    1006             :     {
    1007             :         OSL_ENSURE(iter->second.first || iter->second.second,
    1008             :             "null entry in m_XmlIdMap");
    1009          20 :         return (isContentFile(i_rStreamName))
    1010          20 :             ?  &iter->second.first
    1011          40 :             :  &iter->second.second;
    1012             :     }
    1013             :     else
    1014             :     {
    1015           8 :         return 0;
    1016             :     }
    1017             : }
    1018             : 
    1019             : Metadatable*
    1020          22 : XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupElement(
    1021             :     const OUString & i_rStreamName,
    1022             :     const OUString & i_rIdref) const
    1023             : {
    1024          22 :     Metadatable * const * ppEntry = LookupEntry(i_rStreamName, i_rIdref);
    1025          22 :     return ppEntry ? *ppEntry : 0;
    1026             : }
    1027             : 
    1028             : bool
    1029          40 : XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupXmlId(
    1030             :     const Metadatable& i_rObject,
    1031             :     OUString & o_rStream, OUString & o_rIdref,
    1032             :     MetadatableClipboard const* &o_rpLink) const
    1033             : {
    1034             :     const ClipboardXmlIdReverseMap_t::const_iterator iter(
    1035          40 :         m_XmlIdReverseMap.find(&i_rObject) );
    1036          40 :     if (iter != m_XmlIdReverseMap.end())
    1037             :     {
    1038             :         OSL_ENSURE(!iter->second.m_Stream.isEmpty(),
    1039             :             "null stream in m_XmlIdReverseMap");
    1040             :         OSL_ENSURE(!iter->second.m_XmlId.isEmpty(),
    1041             :             "null id in m_XmlIdReverseMap");
    1042          34 :         o_rStream = iter->second.m_Stream;
    1043          34 :         o_rIdref  = iter->second.m_XmlId;
    1044          34 :         o_rpLink  = iter->second.m_pLink.get();
    1045          34 :         return true;
    1046             :     }
    1047             :     else
    1048             :     {
    1049           6 :         return false;
    1050             :     }
    1051             : }
    1052             : 
    1053             : bool
    1054           6 : XmlIdRegistryClipboard::XmlIdRegistry_Impl::TryInsertMetadatable(
    1055             :     Metadatable & i_rObject,
    1056             :     const OUString & i_rStreamName, const OUString & i_rIdref)
    1057             : {
    1058           6 :     bool bContent( isContentFile(i_rStreamName) );
    1059             :     OSL_ENSURE(isContentFile(i_rStreamName) || isStylesFile(i_rStreamName),
    1060             :         "invalid stream");
    1061             : 
    1062           6 :     Metadatable ** ppEntry = LookupEntry(i_rStreamName, i_rIdref);
    1063           6 :     if (ppEntry)
    1064             :     {
    1065           2 :         if (*ppEntry)
    1066             :         {
    1067           2 :             return false;
    1068             :         }
    1069             :         else
    1070             :         {
    1071           0 :             *ppEntry = &i_rObject;
    1072           0 :             return true;
    1073             :         }
    1074             :     }
    1075             :     else
    1076             :     {
    1077             :         m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent
    1078          16 :             ? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(0) )
    1079          12 :             : ::std::make_pair( static_cast<Metadatable*>(0), &i_rObject )));
    1080           4 :         return true;
    1081             :     }
    1082             : }
    1083             : 
    1084             : 
    1085             : // Clipboard XML ID Registry
    1086             : 
    1087             : 
    1088           2 : XmlIdRegistryClipboard::XmlIdRegistryClipboard()
    1089           2 :     :   m_pImpl( new XmlIdRegistry_Impl )
    1090             : {
    1091           2 : }
    1092             : 
    1093           4 : XmlIdRegistryClipboard::~XmlIdRegistryClipboard()
    1094             : {
    1095           4 : }
    1096             : 
    1097             : bool
    1098          22 : XmlIdRegistryClipboard::LookupXmlId(
    1099             :     const Metadatable& i_rObject,
    1100             :     OUString & o_rStream, OUString & o_rIdref) const
    1101             : {
    1102             :     const MetadatableClipboard * pLink;
    1103          22 :     return m_pImpl->LookupXmlId(i_rObject, o_rStream, o_rIdref, pLink);
    1104             : }
    1105             : 
    1106             : Metadatable*
    1107          16 : XmlIdRegistryClipboard::LookupElement(
    1108             :     const OUString & i_rStreamName,
    1109             :     const OUString & i_rIdref) const
    1110             : {
    1111          16 :     return m_pImpl->LookupElement(i_rStreamName, i_rIdref);
    1112             : }
    1113             : 
    1114             : bool
    1115           6 : XmlIdRegistryClipboard::TryRegisterMetadatable(Metadatable & i_rObject,
    1116             :     OUString const& i_rStreamName, OUString const& i_rIdref)
    1117             : {
    1118             :     OSL_TRACE("TryRegisterMetadatable: %p (%s#%s)\n", &i_rObject,
    1119             :         OUStringToOString(i_rStreamName, RTL_TEXTENCODING_UTF8).getStr(),
    1120             :         OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8).getStr());
    1121             : 
    1122             :     OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject),
    1123             :         "TryRegisterMetadatable called for MetadatableUndo?");
    1124             :     OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject),
    1125             :         "TryRegisterMetadatable called for MetadatableClipboard?");
    1126             : 
    1127           6 :     if (!isValidXmlId(i_rStreamName, i_rIdref))
    1128             :     {
    1129             :         throw lang::IllegalArgumentException(OUString(
    1130           0 :             "illegal XmlId"), 0, 0);
    1131             :     }
    1132          12 :     if (i_rObject.IsInContent()
    1133           6 :         ?   !isContentFile(i_rStreamName)
    1134           0 :         :   !isStylesFile(i_rStreamName))
    1135             :     {
    1136             :         throw lang::IllegalArgumentException(OUString(
    1137           0 :             "illegal XmlId: wrong stream"), 0, 0);
    1138             :     }
    1139             : 
    1140           6 :     OUString old_path;
    1141          12 :     OUString old_idref;
    1142             :     const MetadatableClipboard * pLink;
    1143           6 :     m_pImpl->LookupXmlId(i_rObject, old_path, old_idref, pLink);
    1144           6 :     if (old_path  == i_rStreamName && old_idref == i_rIdref)
    1145             :     {
    1146           2 :         return (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject);
    1147             :     }
    1148           4 :     ClipboardXmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() );
    1149           4 :     if (!old_idref.isEmpty())
    1150             :     {
    1151           0 :         old_id = m_pImpl->m_XmlIdMap.find(old_idref);
    1152             :         OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found");
    1153             :     }
    1154           4 :     if (m_pImpl->TryInsertMetadatable(i_rObject, i_rStreamName, i_rIdref))
    1155             :     {
    1156           2 :         rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject);
    1157           4 :         m_pImpl->m_XmlIdReverseMap[&i_rObject] =
    1158           2 :             RMapEntry(i_rStreamName, i_rIdref);
    1159           2 :         return true;
    1160             :     }
    1161             :     else
    1162             :     {
    1163           2 :         return false;
    1164           6 :     }
    1165             : }
    1166             : 
    1167             : void
    1168           6 : XmlIdRegistryClipboard::RegisterMetadatableAndCreateID(Metadatable & i_rObject)
    1169             : {
    1170             :     OSL_TRACE("RegisterMetadatableAndCreateID: %p", &i_rObject);
    1171             : 
    1172             :     OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject),
    1173             :         "RegisterMetadatableAndCreateID called for MetadatableUndo?");
    1174             :     OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject),
    1175             :         "RegisterMetadatableAndCreateID called for MetadatableClipboard?");
    1176             : 
    1177           6 :     bool isInContent( i_rObject.IsInContent() );
    1178             :     OUString stream( OUString::createFromAscii(
    1179           6 :         isInContent ? s_content : s_styles ) );
    1180             : 
    1181           8 :     OUString old_path;
    1182           8 :     OUString old_idref;
    1183           6 :     LookupXmlId(i_rObject, old_path, old_idref);
    1184          10 :     if (!old_idref.isEmpty() &&
    1185           4 :         (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject))
    1186             :     {
    1187          10 :         return;
    1188             :     }
    1189             : 
    1190             :     // create id
    1191           4 :     const OUString id( create_id(m_pImpl->m_XmlIdMap) );
    1192             :     OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(),
    1193             :         "created id is in use");
    1194           2 :     m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent
    1195           8 :         ? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(0) )
    1196           8 :         : ::std::make_pair( static_cast<Metadatable*>(0), &i_rObject )));
    1197             :     // N.B.: if i_rObject had a latent XmlId, then we implicitly delete the
    1198             :     // MetadatableClipboard and thus the latent XmlId here
    1199           4 :     m_pImpl->m_XmlIdReverseMap[&i_rObject] = RMapEntry(stream, id);
    1200             : }
    1201             : 
    1202           8 : void XmlIdRegistryClipboard::UnregisterMetadatable(const Metadatable& i_rObject)
    1203             : {
    1204             :     OSL_TRACE("UnregisterMetadatable: %p", &i_rObject);
    1205             : 
    1206           8 :     OUString path;
    1207          16 :     OUString idref;
    1208             :     const MetadatableClipboard * pLink;
    1209           8 :     if (!m_pImpl->LookupXmlId(i_rObject, path, idref, pLink))
    1210             :     {
    1211             :         OSL_FAIL("unregister: no xml id?");
    1212           8 :         return;
    1213             :     }
    1214           8 :     const ClipboardXmlIdMap_t::iterator iter( m_pImpl->m_XmlIdMap.find(idref) );
    1215           8 :     if (iter != m_pImpl->m_XmlIdMap.end())
    1216             :     {
    1217           6 :         rmIter(m_pImpl->m_XmlIdMap, iter, path, i_rObject);
    1218           8 :     }
    1219             : }
    1220             : 
    1221             : 
    1222           8 : void XmlIdRegistryClipboard::RemoveXmlIdForElement(const Metadatable& i_rObject)
    1223             : {
    1224             :     OSL_TRACE("RemoveXmlIdForElement: %p", &i_rObject);
    1225             : 
    1226             :     ClipboardXmlIdReverseMap_t::iterator iter(
    1227           8 :         m_pImpl->m_XmlIdReverseMap.find(&i_rObject) );
    1228           8 :     if (iter != m_pImpl->m_XmlIdReverseMap.end())
    1229             :     {
    1230             :         OSL_ENSURE(!iter->second.m_XmlId.isEmpty(),
    1231             :             "null id in m_XmlIdReverseMap");
    1232           8 :         m_pImpl->m_XmlIdReverseMap.erase(iter);
    1233             :     }
    1234           8 : }
    1235             : 
    1236             : 
    1237             : 
    1238             : ::boost::shared_ptr<MetadatableClipboard>
    1239           4 : XmlIdRegistryClipboard::CreateClipboard(const bool i_isInContent)
    1240             : {
    1241             :     OSL_TRACE("CreateClipboard:");
    1242             : 
    1243             :     return ::boost::shared_ptr<MetadatableClipboard>(
    1244           4 :         new MetadatableClipboard(i_isInContent) );
    1245             : }
    1246             : 
    1247             : MetadatableClipboard &
    1248           4 : XmlIdRegistryClipboard::RegisterCopyClipboard(Metadatable & i_rCopy,
    1249             :     beans::StringPair const & i_rReference,
    1250             :     const bool i_isLatent)
    1251             : {
    1252             :     OSL_TRACE("RegisterCopyClipboard: %p -> "/*"%p"*/"(%s#%s) (%d)\n",
    1253             :         /*&i_rSource,*/ &i_rCopy,
    1254             :         OUStringToOString(i_rReference.First,
    1255             :             RTL_TEXTENCODING_UTF8).getStr(),
    1256             :         OUStringToOString(i_rReference.Second,
    1257             :             RTL_TEXTENCODING_UTF8).getStr(),
    1258             :         i_isLatent);
    1259             : 
    1260             :     // N.B.: when copying to the clipboard, the selection is always inserted
    1261             :     //       into the body, even if the source is a header/footer!
    1262             :     //       so we do not check whether the stream is right in this function
    1263             : 
    1264           4 :     if (!isValidXmlId(i_rReference.First, i_rReference.Second))
    1265             :     {
    1266             :         throw lang::IllegalArgumentException(OUString(
    1267           0 :             "illegal XmlId"), 0, 0);
    1268             :     }
    1269             : 
    1270           4 :     if (!i_isLatent)
    1271             :     {
    1272             :         // this should succeed assuming clipboard has a single source document
    1273             :         const bool success( m_pImpl->TryInsertMetadatable(i_rCopy,
    1274           2 :                 i_rReference.First, i_rReference.Second) );
    1275             :         OSL_ENSURE(success, "RegisterCopyClipboard: TryInsert failed?");
    1276             :         (void) success;
    1277             :     }
    1278             :     const ::boost::shared_ptr<MetadatableClipboard> pLink(
    1279           4 :         CreateClipboard( isContentFile(i_rReference.First)) );
    1280           4 :     m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy,
    1281           8 :         RMapEntry(i_rReference.First, i_rReference.Second, pLink)));
    1282           4 :     return *pLink.get();
    1283             : }
    1284             : 
    1285             : MetadatableClipboard const*
    1286           4 : XmlIdRegistryClipboard::SourceLink(Metadatable const& i_rObject)
    1287             : {
    1288           4 :     OUString path;
    1289           8 :     OUString idref;
    1290           4 :     const MetadatableClipboard * pLink( 0 );
    1291           4 :     m_pImpl->LookupXmlId(i_rObject, path, idref, pLink);
    1292           8 :     return pLink;
    1293             : }
    1294             : 
    1295             : 
    1296             : 
    1297             : // Metadatable mixin
    1298             : 
    1299             : 
    1300      101647 : Metadatable::~Metadatable()
    1301             : {
    1302      101647 :     RemoveMetadataReference();
    1303      101647 : }
    1304             : 
    1305      103181 : void Metadatable::RemoveMetadataReference()
    1306             : {
    1307             :     try
    1308             :     {
    1309      103181 :         if (m_pReg)
    1310             :         {
    1311         366 :             m_pReg->UnregisterMetadatable( *this );
    1312         366 :             m_pReg->RemoveXmlIdForElement( *this );
    1313         366 :             m_pReg = 0;
    1314             :         }
    1315             :     }
    1316           0 :     catch (const uno::Exception &)
    1317             :     {
    1318             :         OSL_FAIL("Metadatable::RemoveMetadataReference: exception");
    1319             :     }
    1320      103181 : }
    1321             : 
    1322             : // ::com::sun::star::rdf::XMetadatable:
    1323             : beans::StringPair
    1324        6028 : Metadatable::GetMetadataReference() const
    1325             : {
    1326        6028 :     if (m_pReg)
    1327             :     {
    1328        1332 :         return m_pReg->GetXmlIdForElement(*this);
    1329             :     }
    1330        4696 :     return beans::StringPair();
    1331             : }
    1332             : 
    1333             : void
    1334         322 : Metadatable::SetMetadataReference(
    1335             :     const ::com::sun::star::beans::StringPair & i_rReference)
    1336             : {
    1337         322 :     if (i_rReference.Second.isEmpty())
    1338             :     {
    1339           2 :         RemoveMetadataReference();
    1340             :     }
    1341             :     else
    1342             :     {
    1343         320 :         OUString streamName( i_rReference.First );
    1344         320 :         if (streamName.isEmpty())
    1345             :         {
    1346             :             // handle empty stream name as auto-detect.
    1347             :             // necessary for importing flat file format.
    1348           8 :             streamName = OUString::createFromAscii(
    1349           8 :                             IsInContent() ? s_content : s_styles );
    1350             :         }
    1351         320 :         XmlIdRegistry & rReg( dynamic_cast<XmlIdRegistry&>( GetRegistry() ) );
    1352         320 :         if (rReg.TryRegisterMetadatable(*this, streamName, i_rReference.Second))
    1353             :         {
    1354         316 :             m_pReg = &rReg;
    1355             :         }
    1356             :         else
    1357             :         {
    1358             :             throw lang::IllegalArgumentException(
    1359             :                 OUString("Metadatable::"
    1360           4 :                     "SetMetadataReference: argument is invalid"), /*this*/0, 0);
    1361         320 :         }
    1362             :     }
    1363         318 : }
    1364             : 
    1365         124 : void Metadatable::EnsureMetadataReference()
    1366             : {
    1367             :     XmlIdRegistry& rReg(
    1368         124 :         m_pReg ? *m_pReg : dynamic_cast<XmlIdRegistry&>( GetRegistry() ) );
    1369         124 :     rReg.RegisterMetadatableAndCreateID( *this );
    1370         124 :     m_pReg = &rReg;
    1371         124 : }
    1372             : 
    1373           4 : const ::sfx2::IXmlIdRegistry& GetRegistryConst(Metadatable const& i_rObject)
    1374             : {
    1375           4 :     return const_cast< Metadatable& >( i_rObject ).GetRegistry();
    1376             : }
    1377             : 
    1378             : void
    1379       11100 : Metadatable::RegisterAsCopyOf(Metadatable const & i_rSource,
    1380             :     const bool i_bCopyPrecedesSource)
    1381             : {
    1382             :     OSL_ENSURE(typeid(*this) == typeid(i_rSource)
    1383             :         || typeid(i_rSource) == typeid(MetadatableUndo)
    1384             :         || typeid(*this)     == typeid(MetadatableUndo)
    1385             :         || typeid(i_rSource) == typeid(MetadatableClipboard)
    1386             :         || typeid(*this)     == typeid(MetadatableClipboard),
    1387             :         "RegisterAsCopyOf element with different class?");
    1388             :     OSL_ENSURE(!this->m_pReg, "RegisterAsCopyOf called on element with XmlId?");
    1389             : 
    1390       11100 :     if (this->m_pReg)
    1391             :     {
    1392           0 :         RemoveMetadataReference();
    1393             :     }
    1394             : 
    1395             :     try
    1396             :     {
    1397       11100 :         if (i_rSource.m_pReg)
    1398             :         {
    1399             :             XmlIdRegistry & rReg(
    1400          12 :                 dynamic_cast<XmlIdRegistry&>( GetRegistry() ) );
    1401          12 :             if (i_rSource.m_pReg == &rReg)
    1402             :             {
    1403             :                 OSL_ENSURE(!IsInClipboard(),
    1404             :                     "RegisterAsCopy: both in clipboard?");
    1405           4 :                 if (!IsInClipboard())
    1406             :                 {
    1407             :                     XmlIdRegistryDocument & rRegDoc(
    1408           4 :                         dynamic_cast<XmlIdRegistryDocument&>( rReg ) );
    1409             :                     rRegDoc.RegisterCopy(i_rSource, *this,
    1410           4 :                         i_bCopyPrecedesSource);
    1411           4 :                     this->m_pReg = &rRegDoc;
    1412             :                 }
    1413           4 :                 return;
    1414             :             }
    1415             :             // source is in different document
    1416             :             XmlIdRegistryDocument  * pRegDoc(
    1417           8 :                 dynamic_cast<XmlIdRegistryDocument *>(&rReg) );
    1418             :             XmlIdRegistryClipboard * pRegClp(
    1419           8 :                 dynamic_cast<XmlIdRegistryClipboard*>(&rReg) );
    1420             : 
    1421           8 :             if (pRegClp)
    1422             :             {
    1423             :                 beans::StringPair SourceRef(
    1424           4 :                     i_rSource.m_pReg->GetXmlIdForElement(i_rSource) );
    1425           4 :                 bool isLatent( SourceRef.Second.isEmpty() );
    1426             :                 XmlIdRegistryDocument * pSourceRegDoc(
    1427           4 :                     dynamic_cast<XmlIdRegistryDocument*>(i_rSource.m_pReg) );
    1428             :                 OSL_ENSURE(pSourceRegDoc, "RegisterAsCopyOf: 2 clipboards?");
    1429           4 :                 if (!pSourceRegDoc) return;
    1430             :                 // this is a copy _to_ the clipboard
    1431           4 :                 if (isLatent)
    1432             :                 {
    1433             :                     pSourceRegDoc->LookupXmlId(i_rSource,
    1434           2 :                         SourceRef.First, SourceRef.Second);
    1435             :                 }
    1436             :                 Metadatable & rLink(
    1437           4 :                     pRegClp->RegisterCopyClipboard(*this, SourceRef, isLatent));
    1438           4 :                 this->m_pReg = pRegClp;
    1439             :                 // register as copy in the non-clipboard registry
    1440             :                 pSourceRegDoc->RegisterCopy(i_rSource, rLink,
    1441           4 :                     false); // i_bCopyPrecedesSource);
    1442           4 :                 rLink.m_pReg = pSourceRegDoc;
    1443             :             }
    1444           4 :             else if (pRegDoc)
    1445             :             {
    1446             :                 XmlIdRegistryClipboard * pSourceRegClp(
    1447           4 :                     dynamic_cast<XmlIdRegistryClipboard*>(i_rSource.m_pReg) );
    1448             :                 OSL_ENSURE(pSourceRegClp,
    1449             :                     "RegisterAsCopyOf: 2 non-clipboards?");
    1450           4 :                 if (!pSourceRegClp) return;
    1451             :                 const MetadatableClipboard * pLink(
    1452           4 :                     pSourceRegClp->SourceLink(i_rSource) );
    1453             :                 // may happen if src got its id via UNO call
    1454           4 :                 if (!pLink) return;
    1455             :                 // only register copy if clipboard content is from this SwDoc!
    1456           4 :                 if (pLink && (&GetRegistryConst(*pLink) == pRegDoc))
    1457             :                 {
    1458             :                     // this is a copy _from_ the clipboard; check if the
    1459             :                     // element is still in the same stream
    1460             :                     // N.B.: we check the stream of pLink, not of i_rSource!
    1461           4 :                     bool srcInContent( pLink->IsInContent() );
    1462           4 :                     bool tgtInContent( this->IsInContent() );
    1463           4 :                     if (srcInContent == tgtInContent)
    1464             :                     {
    1465             :                         pRegDoc->RegisterCopy(*pLink, *this,
    1466           4 :                             true); // i_bCopyPrecedesSource);
    1467           4 :                         this->m_pReg = pRegDoc;
    1468             :                     }
    1469             :                     // otherwise: stream change! do not register!
    1470             :                 }
    1471             :             }
    1472             :             else
    1473             :             {
    1474             :                 OSL_FAIL("neither RegDoc nor RegClp cannot happen");
    1475             :             }
    1476             :         }
    1477             :     }
    1478           0 :     catch (const uno::Exception &)
    1479             :     {
    1480             :         OSL_FAIL("Metadatable::RegisterAsCopyOf: exception");
    1481             :     }
    1482             : }
    1483             : 
    1484        2832 : ::boost::shared_ptr<MetadatableUndo> Metadatable::CreateUndo() const
    1485             : {
    1486             :     OSL_ENSURE(!IsInUndo(), "CreateUndo called for object in undo?");
    1487             :     OSL_ENSURE(!IsInClipboard(), "CreateUndo called for object in clipboard?");
    1488             :     try
    1489             :     {
    1490        2832 :         if (!IsInClipboard() && !IsInUndo() && m_pReg)
    1491             :         {
    1492             :             XmlIdRegistryDocument * pRegDoc(
    1493           0 :                 dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) );
    1494             :             ::boost::shared_ptr<MetadatableUndo> pUndo(
    1495           0 :                 pRegDoc->CreateUndo(*this) );
    1496           0 :             pRegDoc->RegisterCopy(*this, *pUndo, false);
    1497           0 :             pUndo->m_pReg = pRegDoc;
    1498           0 :             return pUndo;
    1499             :         }
    1500             :     }
    1501           0 :     catch (const uno::Exception &)
    1502             :     {
    1503             :         OSL_FAIL("Metadatable::CreateUndo: exception");
    1504             :     }
    1505        2832 :     return ::boost::shared_ptr<MetadatableUndo>();
    1506             : }
    1507             : 
    1508         226 : ::boost::shared_ptr<MetadatableUndo> Metadatable::CreateUndoForDelete()
    1509             : {
    1510         226 :     ::boost::shared_ptr<MetadatableUndo> const pUndo( CreateUndo() );
    1511         226 :     RemoveMetadataReference();
    1512         226 :     return pUndo;
    1513             : }
    1514             : 
    1515           2 : void Metadatable::RestoreMetadata(
    1516             :     ::boost::shared_ptr<MetadatableUndo> const& i_pUndo)
    1517             : {
    1518             :     OSL_ENSURE(!IsInUndo(), "RestoreMetadata called for object in undo?");
    1519             :     OSL_ENSURE(!IsInClipboard(),
    1520             :         "RestoreMetadata called for object in clipboard?");
    1521           4 :     if (IsInClipboard() || IsInUndo()) return;
    1522           2 :     RemoveMetadataReference();
    1523           2 :     if (i_pUndo)
    1524             :     {
    1525           0 :         this->RegisterAsCopyOf(*i_pUndo, true);
    1526             :     }
    1527             : }
    1528             : 
    1529             : void
    1530        5484 : Metadatable::JoinMetadatable(Metadatable const & i_rOther,
    1531             :     const bool i_isMergedEmpty, const bool i_isOtherEmpty)
    1532             : {
    1533             :     OSL_ENSURE(!IsInUndo(), "JoinMetadatables called for object in undo?");
    1534             :     OSL_ENSURE(!IsInClipboard(),
    1535             :         "JoinMetadatables called for object in clipboard?");
    1536        5484 :     if (IsInClipboard() || IsInUndo()) return;
    1537             : 
    1538        5484 :     if (i_isOtherEmpty && !i_isMergedEmpty)
    1539             :     {
    1540             :         // other is empty, thus loses => nothing to do
    1541        2832 :         return;
    1542             :     }
    1543        2652 :     if (i_isMergedEmpty && !i_isOtherEmpty)
    1544             :     {
    1545          80 :         this->RemoveMetadataReference();
    1546          80 :         this->RegisterAsCopyOf(i_rOther, true);
    1547          80 :         return;
    1548             :     }
    1549             : 
    1550        2572 :     if (!i_rOther.m_pReg)
    1551             :     {
    1552             :         // other doesn't have xmlid, thus loses => nothing to do
    1553        2572 :         return;
    1554             :     }
    1555           0 :     if (!m_pReg)
    1556             :     {
    1557           0 :         this->RegisterAsCopyOf(i_rOther, true);
    1558             :         // assumption: i_rOther will be deleted, so don't unregister it here
    1559           0 :         return;
    1560             :     }
    1561             :     try
    1562             :     {
    1563             :         XmlIdRegistryDocument * pRegDoc(
    1564           0 :             dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) );
    1565             :         OSL_ENSURE(pRegDoc, "JoinMetadatable: no pRegDoc?");
    1566           0 :         if (pRegDoc)
    1567             :         {
    1568           0 :             pRegDoc->JoinMetadatables(*this, i_rOther);
    1569             :         }
    1570             :     }
    1571           0 :     catch (const uno::Exception &)
    1572             :     {
    1573             :         OSL_FAIL("Metadatable::JoinMetadatable: exception");
    1574             :     }
    1575             : }
    1576             : 
    1577             : 
    1578             : 
    1579             : // XMetadatable mixin
    1580             : 
    1581             : // ::com::sun::star::rdf::XNode:
    1582         194 : OUString SAL_CALL MetadatableMixin::getStringValue()
    1583             :     throw (::com::sun::star::uno::RuntimeException, std::exception)
    1584             : {
    1585         194 :     return getNamespace() + getLocalName();
    1586             : }
    1587             : 
    1588             : // ::com::sun::star::rdf::XURI:
    1589         194 : OUString SAL_CALL MetadatableMixin::getLocalName()
    1590             :     throw (::com::sun::star::uno::RuntimeException, std::exception)
    1591             : {
    1592         194 :     SolarMutexGuard aGuard;
    1593         388 :     beans::StringPair mdref( getMetadataReference() );
    1594         194 :     if (mdref.Second.isEmpty())
    1595             :     {
    1596           2 :         ensureMetadataReference(); // N.B.: side effect!
    1597           2 :         mdref = getMetadataReference();
    1598             :     }
    1599         388 :     OUStringBuffer buf;
    1600         194 :     buf.append(mdref.First);
    1601         194 :     buf.append('#');
    1602         194 :     buf.append(mdref.Second);
    1603         388 :     return buf.makeStringAndClear();
    1604             : }
    1605             : 
    1606         194 : OUString SAL_CALL MetadatableMixin::getNamespace()
    1607             :     throw (::com::sun::star::uno::RuntimeException, std::exception)
    1608             : {
    1609         194 :     SolarMutexGuard aGuard;
    1610         388 :     const uno::Reference< frame::XModel > xModel( GetModel() );
    1611         388 :     const uno::Reference< rdf::XURI > xDMA( xModel, uno::UNO_QUERY_THROW );
    1612         388 :     return xDMA->getStringValue();
    1613             : }
    1614             : 
    1615             : // ::com::sun::star::rdf::XMetadatable:
    1616             : beans::StringPair SAL_CALL
    1617        5950 : MetadatableMixin::getMetadataReference()
    1618             : throw (uno::RuntimeException, std::exception)
    1619             : {
    1620        5950 :     SolarMutexGuard aGuard;
    1621             : 
    1622        5950 :     Metadatable *const pObject( GetCoreObject() );
    1623        5950 :     if (!pObject)
    1624             :     {
    1625             :         throw uno::RuntimeException(
    1626             :             OUString(
    1627             :                 "MetadatableMixin: cannot get core object; not inserted?"),
    1628           0 :             *this);
    1629             :     }
    1630        5950 :     return pObject->GetMetadataReference();
    1631             : }
    1632             : 
    1633             : void SAL_CALL
    1634         302 : MetadatableMixin::setMetadataReference(
    1635             :     const beans::StringPair & i_rReference)
    1636             : throw (uno::RuntimeException, lang::IllegalArgumentException, std::exception)
    1637             : {
    1638         302 :     SolarMutexGuard aGuard;
    1639             : 
    1640         302 :     Metadatable *const pObject( GetCoreObject() );
    1641         302 :     if (!pObject)
    1642             :     {
    1643             :         throw uno::RuntimeException(
    1644             :             OUString(
    1645             :                 "MetadatableMixin: cannot get core object; not inserted?"),
    1646           0 :             *this);
    1647             :     }
    1648         302 :     return pObject->SetMetadataReference(i_rReference);
    1649             : }
    1650             : 
    1651         110 : void SAL_CALL MetadatableMixin::ensureMetadataReference()
    1652             : throw (uno::RuntimeException, std::exception)
    1653             : {
    1654         110 :     SolarMutexGuard aGuard;
    1655             : 
    1656         110 :     Metadatable *const pObject( GetCoreObject() );
    1657         110 :     if (!pObject)
    1658             :     {
    1659             :         throw uno::RuntimeException(
    1660             :             OUString(
    1661             :                 "MetadatableMixin: cannot get core object; not inserted?"),
    1662           0 :             *this);
    1663             :     }
    1664         110 :     return pObject->EnsureMetadataReference();
    1665             : }
    1666             : 
    1667         951 : } // namespace sfx2
    1668             : 
    1669             : 
    1670             : 
    1671             : 
    1672             : #if OSL_DEBUG_LEVEL > 1
    1673             : 
    1674             : #include <stdio.h>
    1675             : 
    1676             : static void dump(sfx2::XmlIdList_t * pList)
    1677             : #ifdef __GNUC__
    1678             : __attribute__ ((unused))
    1679             : #endif
    1680             : ;
    1681             : static void dump(sfx2::XmlIdList_t * pList)
    1682             : {
    1683             :     fprintf(stderr, "\nXmlIdList(%p):  ", pList);
    1684             :     for (sfx2::XmlIdList_t::iterator i = pList->begin(); i != pList->end(); ++i)
    1685             :     {
    1686             :         fprintf(stderr, "%p  ", *i);
    1687             :     }
    1688             :     fprintf(stderr, "\n");
    1689             : }
    1690             : 
    1691             : #endif
    1692             : 
    1693             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10