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