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

Generated by: LCOV version 1.10