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