1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "framework/ResourceId.hxx"
21 #include "framework/FrameworkHelper.hxx"
22 #include "tools/SdGlobalResourceContainer.hxx"
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 #include <com/sun/star/uno/XComponentContext.hpp>
25 #include <com/sun/star/util/URLTransformer.hpp>
26 #include <comphelper/processfactory.hxx>
27 #include <rtl/ref.hxx>
31 using namespace ::com::sun::star
;
32 using namespace ::com::sun::star::uno
;
33 using namespace ::com::sun::star::lang
;
34 using namespace ::com::sun::star::drawing::framework
;
36 /** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations
37 are activated that work only together with XResourceId objects that are
38 implemented by the ResourceId class. For other implementations of when
39 the USE_OPTIMIZATIONS symbol is not defined then alternative code is
42 #define USE_OPTIMIZATIONS
44 namespace sd
{ namespace framework
{
46 //===== ResourceId ============================================================
48 WeakReference
<util::XURLTransformer
> ResourceId::mxURLTransformerWeak
;
50 ResourceId::ResourceId()
51 : ResourceIdInterfaceBase(),
57 ResourceId::ResourceId (
58 const std::vector
<OUString
>& rResourceURLs
)
59 : ResourceIdInterfaceBase(),
60 maResourceURLs(rResourceURLs
),
66 ResourceId::ResourceId (
67 const OUString
& rsResourceURL
)
68 : ResourceIdInterfaceBase(),
69 maResourceURLs(1, rsResourceURL
),
72 // Handle the special case of an empty resource URL.
73 if (rsResourceURL
.isEmpty())
74 maResourceURLs
.clear();
78 ResourceId::ResourceId (
79 const OUString
& rsResourceURL
,
80 const OUString
& rsAnchorURL
)
81 : ResourceIdInterfaceBase(),
85 maResourceURLs
[0] = rsResourceURL
;
86 maResourceURLs
[1] = rsAnchorURL
;
90 ResourceId::ResourceId (
91 const OUString
& rsResourceURL
,
92 const OUString
& rsFirstAnchorURL
,
93 const Sequence
<OUString
>& rAnchorURLs
)
94 : ResourceIdInterfaceBase(),
95 maResourceURLs(2+rAnchorURLs
.getLength()),
98 maResourceURLs
[0] = rsResourceURL
;
99 maResourceURLs
[1] = rsFirstAnchorURL
;
100 for (sal_Int32 nIndex
=0; nIndex
<rAnchorURLs
.getLength(); ++nIndex
)
101 maResourceURLs
[nIndex
+2] = rAnchorURLs
[nIndex
];
105 ResourceId::~ResourceId()
111 ResourceId::getResourceURL()
112 throw(com::sun::star::uno::RuntimeException
, std::exception
)
114 if (!maResourceURLs
.empty())
115 return maResourceURLs
[0];
121 ResourceId::getFullResourceURL()
122 throw(com::sun::star::uno::RuntimeException
, std::exception
)
124 if (mpURL
.get() != NULL
)
127 Reference
<util::XURLTransformer
> xURLTransformer (mxURLTransformerWeak
);
128 if (xURLTransformer
.is() && !maResourceURLs
.empty() )
130 mpURL
.reset(new util::URL
);
131 mpURL
->Complete
= maResourceURLs
[0];
132 xURLTransformer
->parseStrict(*mpURL
);
137 if (!maResourceURLs
.empty())
138 aURL
.Complete
= maResourceURLs
[0];
143 ResourceId::hasAnchor()
144 throw (RuntimeException
, std::exception
)
146 return maResourceURLs
.size()>1;
149 Reference
<XResourceId
> SAL_CALL
150 ResourceId::getAnchor()
151 throw (RuntimeException
, std::exception
)
153 ::rtl::Reference
<ResourceId
> rResourceId (new ResourceId());
154 const sal_Int32
nAnchorCount (maResourceURLs
.size()-1);
155 if (nAnchorCount
> 0)
157 rResourceId
->maResourceURLs
.resize(nAnchorCount
);
158 for (sal_Int32 nIndex
=0; nIndex
<nAnchorCount
; ++nIndex
)
159 rResourceId
->maResourceURLs
[nIndex
] = maResourceURLs
[nIndex
+1];
161 return Reference
<XResourceId
>(rResourceId
.get());
164 Sequence
<OUString
> SAL_CALL
165 ResourceId::getAnchorURLs()
166 throw (RuntimeException
, std::exception
)
168 const sal_Int32
nAnchorCount (maResourceURLs
.size() - 1);
169 if (nAnchorCount
> 0)
171 Sequence
<OUString
> aAnchorURLs (nAnchorCount
);
172 for (sal_Int32 nIndex
=0; nIndex
<nAnchorCount
; ++nIndex
)
173 aAnchorURLs
[nIndex
] = maResourceURLs
[nIndex
+1];
177 return Sequence
<OUString
>();
181 ResourceId::getResourceTypePrefix()
182 throw (RuntimeException
, std::exception
)
184 if (!maResourceURLs
.empty() )
186 // Return the "private:resource/<type>/" prefix.
188 // Get the prefix that ends with the second "/".
189 const OUString
& rsResourceURL (maResourceURLs
[0]);
190 sal_Int32
nPrefixEnd (rsResourceURL
.indexOf('/', 0));
192 nPrefixEnd
= rsResourceURL
.indexOf('/', nPrefixEnd
+1) + 1;
196 return rsResourceURL
.copy(0,nPrefixEnd
);
203 ResourceId::compareTo (const Reference
<XResourceId
>& rxResourceId
)
204 throw (RuntimeException
, std::exception
)
206 sal_Int16
nResult (0);
208 if ( ! rxResourceId
.is())
210 // The empty reference is interpreted as empty resource id object.
211 if (!maResourceURLs
.empty())
218 ResourceId
* pId
= NULL
;
219 #ifdef USE_OPTIMIZATIONS
220 pId
= dynamic_cast<ResourceId
*>(rxResourceId
.get());
224 // We have direct access to the implementation of the given
225 // resource id object.
226 nResult
= CompareToLocalImplementation(*pId
);
230 // We have to do the comparison via the UNO interface of the
231 // given resource id object.
232 nResult
= CompareToExternalImplementation(rxResourceId
);
239 sal_Int16
ResourceId::CompareToLocalImplementation (const ResourceId
& rId
) const
241 sal_Int16
nResult (0);
243 const sal_uInt32
nLocalURLCount (maResourceURLs
.size());
244 const sal_uInt32
nURLCount(rId
.maResourceURLs
.size());
246 // Start comparison with the top most anchors.
247 for (sal_Int32 nIndex
=nURLCount
-1,nLocalIndex
=nLocalURLCount
-1;
248 nIndex
>=0 && nLocalIndex
>=0;
249 --nIndex
,--nLocalIndex
)
251 const OUString
sLocalURL (maResourceURLs
[nLocalIndex
]);
252 const OUString
sURL (rId
.maResourceURLs
[nIndex
]);
253 const sal_Int32
nLocalResult (sURL
.compareTo(sLocalURL
));
254 if (nLocalResult
!= 0)
256 if (nLocalResult
< 0)
266 // No difference found yet. When the lengths are the same then the
267 // two resource ids are equivalent. Otherwise the shorter comes
269 if (nLocalURLCount
!= nURLCount
)
271 if (nLocalURLCount
< nURLCount
)
281 sal_Int16
ResourceId::CompareToExternalImplementation (const Reference
<XResourceId
>& rxId
) const
283 sal_Int16
nResult (0);
285 const Sequence
<OUString
> aAnchorURLs (rxId
->getAnchorURLs());
286 const sal_uInt32
nLocalURLCount (maResourceURLs
.size());
287 const sal_uInt32
nURLCount(1+aAnchorURLs
.getLength());
289 // Start comparison with the top most anchors.
290 sal_Int32
nLocalResult (0);
291 for (sal_Int32 nIndex
=nURLCount
-1,nLocalIndex
=nLocalURLCount
-1;
292 nIndex
>=0&&nLocalIndex
>=0;
293 --nIndex
,--nLocalIndex
)
296 nLocalResult
= maResourceURLs
[nIndex
].compareTo(rxId
->getResourceURL());
298 nLocalResult
= maResourceURLs
[nIndex
].compareTo(aAnchorURLs
[nIndex
-1]);
299 if (nLocalResult
!= 0)
301 if (nLocalResult
< 0)
311 // No difference found yet. When the lengths are the same then the
312 // two resource ids are equivalent. Otherwise the shorter comes
314 if (nLocalURLCount
!= nURLCount
)
316 if (nLocalURLCount
< nURLCount
)
327 ResourceId::isBoundTo (
328 const Reference
<XResourceId
>& rxResourceId
,
329 AnchorBindingMode eMode
)
330 throw (RuntimeException
, std::exception
)
332 if ( ! rxResourceId
.is())
334 // An empty reference is interpreted as empty resource id.
335 return IsBoundToAnchor(NULL
, NULL
, eMode
);
338 ResourceId
* pId
= NULL
;
339 #ifdef USE_OPTIMIZATIONS
340 pId
= dynamic_cast<ResourceId
*>(rxResourceId
.get());
344 return IsBoundToAnchor(pId
->maResourceURLs
, eMode
);
348 const OUString
sResourceURL (rxResourceId
->getResourceURL());
349 const Sequence
<OUString
> aAnchorURLs (rxResourceId
->getAnchorURLs());
350 return IsBoundToAnchor(&sResourceURL
, &aAnchorURLs
, eMode
);
355 ResourceId::isBoundToURL (
356 const OUString
& rsAnchorURL
,
357 AnchorBindingMode eMode
)
358 throw (RuntimeException
, std::exception
)
360 return IsBoundToAnchor(&rsAnchorURL
, NULL
, eMode
);
363 Reference
<XResourceId
> SAL_CALL
365 throw(RuntimeException
, std::exception
)
367 return new ResourceId(maResourceURLs
);
370 //----- XInitialization -------------------------------------------------------
372 void SAL_CALL
ResourceId::initialize (const Sequence
<Any
>& aArguments
)
373 throw (RuntimeException
, std::exception
)
375 sal_uInt32
nCount (aArguments
.getLength());
376 for (sal_uInt32 nIndex
=0; nIndex
<nCount
; ++nIndex
)
378 OUString sResourceURL
;
379 if (aArguments
[nIndex
] >>= sResourceURL
)
380 maResourceURLs
.push_back(sResourceURL
);
383 Reference
<XResourceId
> xAnchor
;
384 if (aArguments
[nIndex
] >>= xAnchor
)
388 maResourceURLs
.push_back(xAnchor
->getResourceURL());
389 Sequence
<OUString
> aAnchorURLs (xAnchor
->getAnchorURLs());
390 for (sal_Int32 nURLIndex
=0; nURLIndex
<aAnchorURLs
.getLength(); ++nURLIndex
)
392 maResourceURLs
.push_back(aAnchorURLs
[nURLIndex
]);
401 OUString
ResourceId::getImplementationName()
402 throw (css::uno::RuntimeException
, std::exception
)
404 return OUString("com.sun.star.comp.Draw.framework.ResourceId");
407 sal_Bool
ResourceId::supportsService(OUString
const & ServiceName
)
408 throw (css::uno::RuntimeException
, std::exception
)
410 return cppu::supportsService(this, ServiceName
);
413 css::uno::Sequence
<OUString
> ResourceId::getSupportedServiceNames()
414 throw (css::uno::RuntimeException
, std::exception
)
416 return css::uno::Sequence
<OUString
>{
417 "com.sun.star.drawing.framework.ResourceId"};
420 /** When eMode is DIRECTLY then the anchor of the called object and the
421 anchor represented by the given sequence of anchor URLs have to be
422 identical. When eMode is RECURSIVE then the anchor of the called
423 object has to start with the given anchor URLs.
425 bool ResourceId::IsBoundToAnchor (
426 const OUString
* psFirstAnchorURL
,
427 const Sequence
<OUString
>* paAnchorURLs
,
428 AnchorBindingMode eMode
) const
430 const sal_uInt32
nLocalAnchorURLCount (maResourceURLs
.size() - 1);
431 const bool bHasFirstAnchorURL (psFirstAnchorURL
!=NULL
);
432 const sal_uInt32
nAnchorURLCount ((bHasFirstAnchorURL
?1:0)
433 + (paAnchorURLs
!=NULL
? paAnchorURLs
->getLength() : 0));
435 // Check the lengths.
436 if (nLocalAnchorURLCount
<nAnchorURLCount
||
437 (eMode
==AnchorBindingMode_DIRECT
&& nLocalAnchorURLCount
!=nAnchorURLCount
))
442 // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
443 // id and the given anchor.
444 sal_uInt32 nOffset
= 0;
445 if (paAnchorURLs
!= NULL
)
447 sal_uInt32 nCount
= paAnchorURLs
->getLength();
448 while (nOffset
< nCount
)
450 if ( ! maResourceURLs
[nLocalAnchorURLCount
- nOffset
].equals(
451 (*paAnchorURLs
)[nCount
- 1 - nOffset
]))
458 if (bHasFirstAnchorURL
)
460 if ( ! psFirstAnchorURL
->equals(maResourceURLs
[nLocalAnchorURLCount
- nOffset
]))
467 bool ResourceId::IsBoundToAnchor (
468 const ::std::vector
<OUString
>& rAnchorURLs
,
469 AnchorBindingMode eMode
) const
471 const sal_uInt32
nLocalAnchorURLCount (maResourceURLs
.size() - 1);
472 const sal_uInt32
nAnchorURLCount (rAnchorURLs
.size());
474 // Check the lengths.
475 if (nLocalAnchorURLCount
<nAnchorURLCount
||
476 (eMode
==AnchorBindingMode_DIRECT
&& nLocalAnchorURLCount
!=nAnchorURLCount
))
481 // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
482 // id and the given anchor.
483 for (sal_uInt32 nOffset
=0; nOffset
<nAnchorURLCount
; ++nOffset
)
485 if ( ! maResourceURLs
[nLocalAnchorURLCount
- nOffset
].equals(
486 rAnchorURLs
[nAnchorURLCount
- 1 - nOffset
]))
495 void ResourceId::ParseResourceURL()
497 ::osl::Guard
< ::osl::Mutex
> aGuard (::osl::Mutex::getGlobalMutex());
498 Reference
<util::XURLTransformer
> xURLTransformer (mxURLTransformerWeak
);
499 if ( ! xURLTransformer
.is())
501 // Create the URL transformer.
502 Reference
<uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
503 xURLTransformer
= Reference
<util::XURLTransformer
>(util::URLTransformer::create(xContext
));
504 mxURLTransformerWeak
= xURLTransformer
;
505 SdGlobalResourceContainer::Instance().AddResource(
506 Reference
<XInterface
>(xURLTransformer
,UNO_QUERY
));
509 if (xURLTransformer
.is() && !maResourceURLs
.empty() )
511 mpURL
.reset(new util::URL
);
512 mpURL
->Complete
= maResourceURLs
[0];
513 xURLTransformer
->parseStrict(*mpURL
);
514 if (mpURL
->Main
== maResourceURLs
[0])
517 maResourceURLs
[0] = mpURL
->Main
;
521 } } // end of namespace sd::framework
524 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
525 com_sun_star_comp_Draw_framework_ResourceID_get_implementation(::com::sun::star::uno::XComponentContext
*,
526 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
528 return cppu::acquire(new sd::framework::ResourceId());
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */