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