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 "framework/ResourceId.hxx"
22 : #include "framework/FrameworkHelper.hxx"
23 : #include "tools/SdGlobalResourceContainer.hxx"
24 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
25 : #include <com/sun/star/uno/XComponentContext.hpp>
26 : #include <com/sun/star/util/URLTransformer.hpp>
27 : #include <comphelper/processfactory.hxx>
28 : #include <rtl/ref.hxx>
29 :
30 : using namespace ::com::sun::star;
31 : using namespace ::com::sun::star::uno;
32 : using namespace ::com::sun::star::lang;
33 : using namespace ::com::sun::star::drawing::framework;
34 :
35 : /** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations
36 : are activated that work only together with XResourceId objects that are
37 : implemented by the ResourceId class. For other implementations of when
38 : the USE_OPTIMIZATIONS symbol is not defined then alternative code is
39 : used instead.
40 : */
41 : #define USE_OPTIMIZATIONS
42 :
43 : namespace sd { namespace framework {
44 :
45 96 : Reference<XInterface> SAL_CALL ResourceId_createInstance (
46 : const Reference<XComponentContext>& rxContext)
47 : {
48 : (void)rxContext;
49 96 : return Reference<XInterface>(static_cast<XWeak*>(new ::sd::framework::ResourceId()));
50 : }
51 :
52 :
53 :
54 :
55 18 : OUString ResourceId_getImplementationName (void) throw(RuntimeException)
56 : {
57 18 : return OUString("com.sun.star.comp.Draw.framework.ResourceId");
58 : }
59 :
60 :
61 :
62 :
63 8 : Sequence<OUString> SAL_CALL ResourceId_getSupportedServiceNames (void)
64 : throw (RuntimeException)
65 : {
66 8 : static const OUString sServiceName("com.sun.star.drawing.framework.ResourceId");
67 8 : return Sequence<OUString>(&sServiceName, 1);
68 : }
69 :
70 :
71 :
72 :
73 : //===== ResourceId ============================================================
74 :
75 11 : WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak;
76 :
77 801 : ResourceId::ResourceId (void)
78 : : ResourceIdInterfaceBase(),
79 : maResourceURLs(0),
80 801 : mpURL()
81 : {
82 801 : }
83 :
84 :
85 :
86 :
87 0 : ResourceId::ResourceId (
88 : const std::vector<OUString>& rResourceURLs)
89 : : ResourceIdInterfaceBase(),
90 : maResourceURLs(rResourceURLs),
91 0 : mpURL()
92 : {
93 0 : ParseResourceURL();
94 0 : }
95 :
96 :
97 :
98 :
99 3926 : ResourceId::ResourceId (
100 : const OUString& rsResourceURL)
101 : : ResourceIdInterfaceBase(),
102 : maResourceURLs(1, rsResourceURL),
103 3926 : mpURL()
104 : {
105 : // Handle the special case of an empty resource URL.
106 3926 : if (rsResourceURL.isEmpty())
107 0 : maResourceURLs.clear();
108 3926 : ParseResourceURL();
109 3926 : }
110 :
111 :
112 :
113 :
114 284 : ResourceId::ResourceId (
115 : const OUString& rsResourceURL,
116 : const OUString& rsAnchorURL)
117 : : ResourceIdInterfaceBase(),
118 : maResourceURLs(2),
119 284 : mpURL()
120 : {
121 284 : maResourceURLs[0] = rsResourceURL;
122 284 : maResourceURLs[1] = rsAnchorURL;
123 284 : ParseResourceURL();
124 284 : }
125 :
126 :
127 :
128 :
129 26 : ResourceId::ResourceId (
130 : const OUString& rsResourceURL,
131 : const ::std::vector<OUString>& rAnchorURLs)
132 : : ResourceIdInterfaceBase(),
133 26 : maResourceURLs(1+rAnchorURLs.size()),
134 52 : mpURL()
135 : {
136 26 : maResourceURLs[0] = rsResourceURL;
137 78 : for (sal_uInt32 nIndex=0; nIndex<rAnchorURLs.size(); ++nIndex)
138 52 : maResourceURLs[nIndex+1] = rAnchorURLs[nIndex];
139 26 : ParseResourceURL();
140 26 : }
141 :
142 :
143 :
144 :
145 117 : ResourceId::ResourceId (
146 : const OUString& rsResourceURL,
147 : const OUString& rsFirstAnchorURL,
148 : const Sequence<OUString>& rAnchorURLs)
149 : : ResourceIdInterfaceBase(),
150 117 : maResourceURLs(2+rAnchorURLs.getLength()),
151 234 : mpURL()
152 : {
153 117 : maResourceURLs[0] = rsResourceURL;
154 117 : maResourceURLs[1] = rsFirstAnchorURL;
155 117 : for (sal_Int32 nIndex=0; nIndex<rAnchorURLs.getLength(); ++nIndex)
156 0 : maResourceURLs[nIndex+2] = rAnchorURLs[nIndex];
157 117 : ParseResourceURL();
158 117 : }
159 :
160 :
161 :
162 :
163 15228 : ResourceId::~ResourceId (void)
164 : {
165 5076 : mpURL.reset();
166 10152 : }
167 :
168 :
169 :
170 :
171 : OUString SAL_CALL
172 13283 : ResourceId::getResourceURL (void)
173 : throw(com::sun::star::uno::RuntimeException)
174 : {
175 13283 : if (!maResourceURLs.empty())
176 13259 : return maResourceURLs[0];
177 : else
178 24 : return OUString();
179 : }
180 :
181 :
182 :
183 :
184 : util::URL SAL_CALL
185 0 : ResourceId::getFullResourceURL (void)
186 : throw(com::sun::star::uno::RuntimeException)
187 : {
188 0 : if (mpURL.get() != NULL)
189 0 : return *mpURL;
190 :
191 0 : Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
192 0 : if (xURLTransformer.is() && !maResourceURLs.empty() )
193 : {
194 0 : mpURL.reset(new util::URL);
195 0 : mpURL->Complete = maResourceURLs[0];
196 0 : xURLTransformer->parseStrict(*mpURL);
197 0 : return *mpURL;
198 : }
199 :
200 0 : util::URL aURL;
201 0 : if (!maResourceURLs.empty())
202 0 : aURL.Complete = maResourceURLs[0];
203 0 : return aURL;
204 : }
205 :
206 :
207 :
208 :
209 : sal_Bool SAL_CALL
210 0 : ResourceId::hasAnchor (void)
211 : throw (RuntimeException)
212 : {
213 0 : return maResourceURLs.size()>1;
214 : }
215 :
216 :
217 :
218 :
219 : Reference<XResourceId> SAL_CALL
220 705 : ResourceId::getAnchor (void)
221 : throw (RuntimeException)
222 : {
223 705 : ::rtl::Reference<ResourceId> rResourceId (new ResourceId());
224 705 : const sal_Int32 nAnchorCount (maResourceURLs.size()-1);
225 705 : if (nAnchorCount > 0)
226 : {
227 681 : rResourceId->maResourceURLs.resize(nAnchorCount);
228 1421 : for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
229 740 : rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1];
230 : }
231 705 : return Reference<XResourceId>(rResourceId.get());
232 : }
233 :
234 :
235 :
236 :
237 : Sequence<OUString> SAL_CALL
238 117 : ResourceId::getAnchorURLs (void)
239 : throw (RuntimeException)
240 : {
241 117 : const sal_Int32 nAnchorCount (maResourceURLs.size() - 1);
242 117 : if (nAnchorCount > 0)
243 : {
244 0 : Sequence<OUString> aAnchorURLs (nAnchorCount);
245 0 : for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
246 0 : aAnchorURLs[nIndex] = maResourceURLs[nIndex+1];
247 0 : return aAnchorURLs;
248 : }
249 : else
250 117 : return Sequence<OUString>();
251 : }
252 :
253 :
254 :
255 :
256 : OUString SAL_CALL
257 701 : ResourceId::getResourceTypePrefix (void)
258 : throw (RuntimeException)
259 : {
260 701 : if (!maResourceURLs.empty() )
261 : {
262 : // Return the "private:resource/<type>/" prefix.
263 :
264 : // Get the prefix that ends with the second "/".
265 701 : const OUString& rsResourceURL (maResourceURLs[0]);
266 701 : sal_Int32 nPrefixEnd (rsResourceURL.indexOf(sal_Unicode('/'), 0));
267 701 : if (nPrefixEnd >= 0)
268 701 : nPrefixEnd = rsResourceURL.indexOf(sal_Unicode('/'), nPrefixEnd+1) + 1;
269 : else
270 0 : nPrefixEnd = 0;
271 :
272 701 : return rsResourceURL.copy(0,nPrefixEnd);
273 : }
274 : else
275 0 : return OUString();
276 : }
277 :
278 :
279 :
280 :
281 : sal_Int16 SAL_CALL
282 28874 : ResourceId::compareTo (const Reference<XResourceId>& rxResourceId)
283 : throw (RuntimeException)
284 : {
285 28874 : sal_Int16 nResult (0);
286 :
287 28874 : if ( ! rxResourceId.is())
288 : {
289 : // The empty reference is interpreted as empty resource id object.
290 0 : if (!maResourceURLs.empty())
291 0 : nResult = +1;
292 : else
293 0 : nResult = 0;
294 : }
295 : else
296 : {
297 28874 : ResourceId* pId = NULL;
298 : #ifdef USE_OPTIMIZATIONS
299 28874 : pId = dynamic_cast<ResourceId*>(rxResourceId.get());
300 : #endif
301 28874 : if (pId != NULL)
302 : {
303 : // We have direct access to the implementation of the given
304 : // resource id object.
305 28874 : nResult = CompareToLocalImplementation(*pId);
306 : }
307 : else
308 : {
309 : // We have to do the comparison via the UNO interface of the
310 : // given resource id object.
311 0 : nResult = CompareToExternalImplementation(rxResourceId);
312 : }
313 : }
314 :
315 28874 : return nResult;
316 : }
317 :
318 :
319 :
320 :
321 28874 : sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const
322 : {
323 28874 : sal_Int16 nResult (0);
324 :
325 28874 : const sal_uInt32 nLocalURLCount (maResourceURLs.size());
326 28874 : const sal_uInt32 nURLCount(rId.maResourceURLs.size());
327 :
328 : // Start comparison with the top most anchors.
329 60095 : for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
330 45618 : nIndex>=0 && nLocalIndex>=0;
331 : --nIndex,--nLocalIndex)
332 : {
333 39783 : const OUString sLocalURL (maResourceURLs[nLocalIndex]);
334 71004 : const OUString sURL (rId.maResourceURLs[nIndex]);
335 39783 : const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL));
336 39783 : if (nLocalResult != 0)
337 : {
338 8562 : if (nLocalResult < 0)
339 5500 : nResult = -1;
340 : else
341 3062 : nResult = +1;
342 8562 : break;
343 : }
344 31221 : }
345 :
346 28874 : if (nResult == 0)
347 : {
348 : // No difference found yet. When the lengths are the same then the
349 : // two resource ids are equivalent. Otherwise the shorter comes
350 : // first.
351 20312 : if (nLocalURLCount != nURLCount)
352 : {
353 6914 : if (nLocalURLCount < nURLCount)
354 5835 : nResult = -1;
355 : else
356 1079 : nResult = +1;
357 : }
358 : }
359 :
360 28874 : return nResult;
361 : }
362 :
363 :
364 :
365 :
366 0 : sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const
367 : {
368 0 : sal_Int16 nResult (0);
369 :
370 0 : const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs());
371 0 : const sal_uInt32 nLocalURLCount (maResourceURLs.size());
372 0 : const sal_uInt32 nURLCount(1+aAnchorURLs.getLength());
373 :
374 : // Start comparison with the top most anchors.
375 0 : sal_Int32 nLocalResult (0);
376 0 : for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
377 0 : nIndex>=0&&nLocalIndex>=0;
378 : --nIndex,--nLocalIndex)
379 : {
380 0 : if (nIndex == 0 )
381 0 : nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL());
382 : else
383 0 : nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]);
384 0 : if (nLocalResult != 0)
385 : {
386 0 : if (nLocalResult < 0)
387 0 : nResult = -1;
388 : else
389 0 : nResult = +1;
390 0 : break;
391 : }
392 : }
393 :
394 0 : if (nResult == 0)
395 : {
396 : // No difference found yet. When the lengths are the same then the
397 : // two resource ids are equivalent. Otherwise the shorter comes
398 : // first.
399 0 : if (nLocalURLCount != nURLCount)
400 : {
401 0 : if (nLocalURLCount < nURLCount)
402 0 : nResult = -1;
403 : else
404 0 : nResult = +1;
405 : }
406 : }
407 :
408 0 : return nResult;
409 : }
410 :
411 :
412 :
413 :
414 : sal_Bool SAL_CALL
415 33897 : ResourceId::isBoundTo (
416 : const Reference<XResourceId>& rxResourceId,
417 : AnchorBindingMode eMode)
418 : throw (RuntimeException)
419 : {
420 33897 : if ( ! rxResourceId.is())
421 : {
422 : // An empty reference is interpreted as empty resource id.
423 5384 : return IsBoundToAnchor(NULL, NULL, eMode);
424 : }
425 :
426 28513 : ResourceId* pId = NULL;
427 : #ifdef USE_OPTIMIZATIONS
428 28513 : pId = dynamic_cast<ResourceId*>(rxResourceId.get());
429 : #endif
430 28513 : if (pId != NULL)
431 : {
432 28513 : return IsBoundToAnchor(pId->maResourceURLs, eMode);
433 : }
434 : else
435 : {
436 0 : const OUString sResourceURL (rxResourceId->getResourceURL());
437 0 : const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
438 0 : return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode);
439 : }
440 : }
441 :
442 :
443 :
444 :
445 : sal_Bool SAL_CALL
446 1311 : ResourceId::isBoundToURL (
447 : const OUString& rsAnchorURL,
448 : AnchorBindingMode eMode)
449 : throw (RuntimeException)
450 : {
451 1311 : return IsBoundToAnchor(&rsAnchorURL, NULL, eMode);
452 : }
453 :
454 :
455 :
456 :
457 : Reference<XResourceId> SAL_CALL
458 0 : ResourceId::clone (void)
459 : throw(RuntimeException)
460 : {
461 0 : return new ResourceId(maResourceURLs);
462 : }
463 :
464 :
465 :
466 :
467 : //----- XInitialization -------------------------------------------------------
468 :
469 96 : void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments)
470 : throw (RuntimeException)
471 : {
472 96 : sal_uInt32 nCount (aArguments.getLength());
473 192 : for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
474 : {
475 96 : OUString sResourceURL;
476 96 : if (aArguments[nIndex] >>= sResourceURL)
477 96 : maResourceURLs.push_back(sResourceURL);
478 : else
479 : {
480 0 : Reference<XResourceId> xAnchor;
481 0 : if (aArguments[nIndex] >>= xAnchor)
482 : {
483 0 : if (xAnchor.is())
484 : {
485 0 : maResourceURLs.push_back(xAnchor->getResourceURL());
486 0 : Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs());
487 0 : for (sal_Int32 nURLIndex=0; nURLIndex<aAnchorURLs.getLength(); ++nURLIndex)
488 : {
489 0 : maResourceURLs.push_back(aAnchorURLs[nURLIndex]);
490 0 : }
491 : }
492 0 : }
493 : }
494 96 : }
495 96 : ParseResourceURL();
496 96 : }
497 :
498 :
499 :
500 :
501 : //-----------------------------------------------------------------------------
502 :
503 : /** When eMode is DIRECTLY then the anchor of the called object and the
504 : anchor represented by the given sequence of anchor URLs have to be
505 : identical. When eMode is RECURSIVE then the anchor of the called
506 : object has to start with the given anchor URLs.
507 : */
508 6695 : bool ResourceId::IsBoundToAnchor (
509 : const OUString* psFirstAnchorURL,
510 : const Sequence<OUString>* paAnchorURLs,
511 : AnchorBindingMode eMode) const
512 : {
513 6695 : const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
514 6695 : const bool bHasFirstAnchorURL (psFirstAnchorURL!=NULL);
515 : const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0)
516 6695 : + (paAnchorURLs!=NULL ? paAnchorURLs->getLength() : 0));
517 :
518 : // Check the lengths.
519 6695 : if (nLocalAnchorURLCount<nAnchorURLCount ||
520 3171 : (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
521 : {
522 1297 : return false;
523 : }
524 :
525 : // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
526 : // id and the given anchor.
527 5398 : sal_uInt32 nOffset = 0;
528 5398 : if (paAnchorURLs != NULL)
529 : {
530 0 : sal_uInt32 nCount = paAnchorURLs->getLength();
531 0 : while (nOffset < nCount)
532 : {
533 0 : if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals(
534 0 : (*paAnchorURLs)[nCount - 1 - nOffset]))
535 : {
536 0 : return false;
537 : }
538 0 : ++nOffset;
539 : }
540 : }
541 5398 : if (bHasFirstAnchorURL)
542 : {
543 1105 : if ( ! psFirstAnchorURL->equals(maResourceURLs[nLocalAnchorURLCount - nOffset]))
544 572 : return false;
545 : }
546 :
547 4826 : return true;
548 : }
549 :
550 :
551 :
552 :
553 28513 : bool ResourceId::IsBoundToAnchor (
554 : const ::std::vector<OUString>& rAnchorURLs,
555 : AnchorBindingMode eMode) const
556 : {
557 28513 : const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
558 28513 : const sal_uInt32 nAnchorURLCount (rAnchorURLs.size());
559 :
560 : // Check the lengths.
561 28513 : if (nLocalAnchorURLCount<nAnchorURLCount ||
562 11587 : (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
563 : {
564 15857 : return false;
565 : }
566 :
567 : // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
568 : // id and the given anchor.
569 18647 : for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset)
570 : {
571 25420 : if ( ! maResourceURLs[nLocalAnchorURLCount - nOffset].equals(
572 25420 : rAnchorURLs[nAnchorURLCount - 1 - nOffset]))
573 : {
574 6719 : return false;
575 : }
576 : }
577 :
578 5937 : return true;
579 : }
580 :
581 :
582 :
583 :
584 4449 : void ResourceId::ParseResourceURL (void)
585 : {
586 4449 : ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex());
587 8898 : Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
588 4449 : if ( ! xURLTransformer.is())
589 : {
590 : // Create the URL transformer.
591 8 : Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
592 8 : xURLTransformer = Reference<util::XURLTransformer>(util::URLTransformer::create(xContext));
593 8 : mxURLTransformerWeak = xURLTransformer;
594 8 : SdGlobalResourceContainer::Instance().AddResource(
595 16 : Reference<XInterface>(xURLTransformer,UNO_QUERY));
596 : }
597 :
598 4449 : if (xURLTransformer.is() && !maResourceURLs.empty() )
599 : {
600 4449 : mpURL.reset(new util::URL);
601 4449 : mpURL->Complete = maResourceURLs[0];
602 4449 : xURLTransformer->parseStrict(*mpURL);
603 4449 : if (mpURL->Main == maResourceURLs[0])
604 4449 : mpURL.reset();
605 : else
606 0 : maResourceURLs[0] = mpURL->Main;
607 4449 : }
608 4449 : }
609 :
610 :
611 33 : } } // end of namespace sd::framework
612 :
613 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|