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