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