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