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 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_hier.hxx" 26 27 /************************************************************************** 28 TODO 29 ************************************************************************** 30 31 - optimize transfer command. "Move" should be implementable much more 32 efficient! 33 34 ************************************************************************** 35 36 - Root Folder vs. 'normal' Folder 37 - root doesn't support command 'delete' 38 - root doesn't support command 'insert' 39 - root needs not created via XContentCreator - queryContent with root 40 folder id ( HIERARCHY_ROOT_FOLDER_URL ) always returns a value != 0 41 - root has no parent. 42 43 *************************************************************************/ 44 #include <osl/diagnose.h> 45 46 #include "osl/doublecheckedlocking.h" 47 #include <rtl/ustring.h> 48 #include <rtl/ustring.hxx> 49 #include <com/sun/star/beans/PropertyAttribute.hpp> 50 #include <com/sun/star/beans/PropertyState.hpp> 51 #include <com/sun/star/beans/PropertyValue.hpp> 52 #include <com/sun/star/beans/XPropertyAccess.hpp> 53 #include <com/sun/star/lang/IllegalAccessException.hpp> 54 #include <com/sun/star/sdbc/XRow.hpp> 55 #include <com/sun/star/ucb/ContentInfoAttribute.hpp> 56 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 57 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp> 58 #include <com/sun/star/ucb/MissingPropertiesException.hpp> 59 #include <com/sun/star/ucb/NameClash.hpp> 60 #include <com/sun/star/ucb/NameClashException.hpp> 61 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 62 #include <com/sun/star/ucb/TransferInfo.hpp> 63 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp> 64 #include <com/sun/star/ucb/XCommandInfo.hpp> 65 #include <com/sun/star/ucb/XPersistentPropertySet.hpp> 66 #include <com/sun/star/uno/Any.hxx> 67 #include <com/sun/star/uno/Sequence.hxx> 68 #include <ucbhelper/contentidentifier.hxx> 69 #include <ucbhelper/propertyvalueset.hxx> 70 #include <ucbhelper/cancelcommandexecution.hxx> 71 #include "hierarchycontent.hxx" 72 #include "hierarchyprovider.hxx" 73 #include "dynamicresultset.hxx" 74 #include "hierarchyuri.hxx" 75 76 #include "../inc/urihelper.hxx" 77 78 using namespace com::sun::star; 79 using namespace hierarchy_ucp; 80 81 //========================================================================= 82 //========================================================================= 83 // 84 // HierarchyContent Implementation. 85 // 86 //========================================================================= 87 //========================================================================= 88 89 // static ( "virtual" ctor ) 90 HierarchyContent* HierarchyContent::create( 91 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 92 HierarchyContentProvider* pProvider, 93 const uno::Reference< ucb::XContentIdentifier >& Identifier ) 94 { 95 // Fail, if content does not exist. 96 HierarchyContentProperties aProps; 97 if ( !loadData( rxSMgr, pProvider, Identifier, aProps ) ) 98 return 0; 99 100 return new HierarchyContent( rxSMgr, pProvider, Identifier, aProps ); 101 } 102 103 //========================================================================= 104 // static ( "virtual" ctor ) 105 HierarchyContent* HierarchyContent::create( 106 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 107 HierarchyContentProvider* pProvider, 108 const uno::Reference< ucb::XContentIdentifier >& Identifier, 109 const ucb::ContentInfo& Info ) 110 { 111 if ( !Info.Type.getLength() ) 112 return 0; 113 114 if ( !Info.Type.equalsAsciiL( 115 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_FOLDER_CONTENT_TYPE ) ) && 116 !Info.Type.equalsAsciiL( 117 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_LINK_CONTENT_TYPE ) ) ) 118 return 0; 119 120 #if 0 121 // Fail, if content does exist. 122 if ( hasData( rxSMgr, pProvider, Identifier ) ) 123 return 0; 124 #endif 125 126 return new HierarchyContent( rxSMgr, pProvider, Identifier, Info ); 127 } 128 129 //========================================================================= 130 HierarchyContent::HierarchyContent( 131 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 132 HierarchyContentProvider* pProvider, 133 const uno::Reference< ucb::XContentIdentifier >& Identifier, 134 const HierarchyContentProperties& rProps ) 135 : ContentImplHelper( rxSMgr, pProvider, Identifier ), 136 m_aProps( rProps ), 137 m_eState( PERSISTENT ), 138 m_pProvider( pProvider ), 139 m_bCheckedReadOnly( false ), 140 m_bIsReadOnly( true ) 141 { 142 setKind( Identifier ); 143 } 144 145 //========================================================================= 146 HierarchyContent::HierarchyContent( 147 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 148 HierarchyContentProvider* pProvider, 149 const uno::Reference< ucb::XContentIdentifier >& Identifier, 150 const ucb::ContentInfo& Info ) 151 : ContentImplHelper( rxSMgr, pProvider, Identifier ), 152 m_aProps( Info.Type.equalsAsciiL( 153 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_FOLDER_CONTENT_TYPE ) ) 154 ? HierarchyEntryData::FOLDER 155 : HierarchyEntryData::LINK ), 156 m_eState( TRANSIENT ), 157 m_pProvider( pProvider ), 158 m_bCheckedReadOnly( false ), 159 m_bIsReadOnly( true ) 160 { 161 setKind( Identifier ); 162 } 163 164 //========================================================================= 165 // virtual 166 HierarchyContent::~HierarchyContent() 167 { 168 } 169 170 //========================================================================= 171 // 172 // XInterface methods. 173 // 174 //========================================================================= 175 176 // virtual 177 void SAL_CALL HierarchyContent::acquire() 178 throw( ) 179 { 180 ContentImplHelper::acquire(); 181 } 182 183 //========================================================================= 184 // virtual 185 void SAL_CALL HierarchyContent::release() 186 throw( ) 187 { 188 ContentImplHelper::release(); 189 } 190 191 //========================================================================= 192 // virtual 193 uno::Any SAL_CALL HierarchyContent::queryInterface( const uno::Type & rType ) 194 { 195 uno::Any aRet = ContentImplHelper::queryInterface( rType ); 196 197 if ( !aRet.hasValue() ) 198 { 199 // Note: isReadOnly may be relative expensive. So avoid calling it 200 // unless it is really necessary. 201 aRet = cppu::queryInterface( 202 rType, static_cast< ucb::XContentCreator * >( this ) ); 203 if ( aRet.hasValue() ) 204 { 205 if ( !isFolder() || isReadOnly() ) 206 return uno::Any(); 207 } 208 } 209 210 return aRet; 211 } 212 213 //========================================================================= 214 // 215 // XTypeProvider methods. 216 // 217 //========================================================================= 218 219 XTYPEPROVIDER_COMMON_IMPL( HierarchyContent ); 220 221 //========================================================================= 222 // virtual 223 uno::Sequence< uno::Type > SAL_CALL HierarchyContent::getTypes() 224 { 225 cppu::OTypeCollection * pCollection = 0; 226 227 if ( isFolder() && !isReadOnly() ) 228 { 229 static cppu::OTypeCollection* pFolderTypes = 0; 230 231 pCollection = pFolderTypes; 232 if ( !pCollection ) 233 { 234 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 235 236 pCollection = pFolderTypes; 237 if ( !pCollection ) 238 { 239 static cppu::OTypeCollection aCollection( 240 CPPU_TYPE_REF( lang::XTypeProvider ), 241 CPPU_TYPE_REF( lang::XServiceInfo ), 242 CPPU_TYPE_REF( lang::XComponent ), 243 CPPU_TYPE_REF( ucb::XContent ), 244 CPPU_TYPE_REF( ucb::XCommandProcessor ), 245 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 246 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 247 CPPU_TYPE_REF( beans::XPropertyContainer ), 248 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 249 CPPU_TYPE_REF( container::XChild ), 250 CPPU_TYPE_REF( ucb::XContentCreator ) ); // !! 251 pCollection = &aCollection; 252 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 253 pFolderTypes = pCollection; 254 } 255 } 256 else { 257 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 258 } 259 } 260 else 261 { 262 static cppu::OTypeCollection* pDocumentTypes = 0; 263 264 pCollection = pDocumentTypes; 265 if ( !pCollection ) 266 { 267 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 268 269 pCollection = pDocumentTypes; 270 if ( !pCollection ) 271 { 272 static cppu::OTypeCollection aCollection( 273 CPPU_TYPE_REF( lang::XTypeProvider ), 274 CPPU_TYPE_REF( lang::XServiceInfo ), 275 CPPU_TYPE_REF( lang::XComponent ), 276 CPPU_TYPE_REF( ucb::XContent ), 277 CPPU_TYPE_REF( ucb::XCommandProcessor ), 278 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 279 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 280 CPPU_TYPE_REF( beans::XPropertyContainer ), 281 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 282 CPPU_TYPE_REF( container::XChild ) ); 283 pCollection = &aCollection; 284 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 285 pDocumentTypes = pCollection; 286 } 287 } 288 else { 289 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 290 } 291 } 292 293 return (*pCollection).getTypes(); 294 } 295 296 //========================================================================= 297 // 298 // XServiceInfo methods. 299 // 300 //========================================================================= 301 302 // virtual 303 rtl::OUString SAL_CALL HierarchyContent::getImplementationName() 304 { 305 return rtl::OUString::createFromAscii( 306 "com.sun.star.comp.ucb.HierarchyContent" ); 307 } 308 309 //========================================================================= 310 // virtual 311 uno::Sequence< rtl::OUString > SAL_CALL 312 HierarchyContent::getSupportedServiceNames() 313 { 314 uno::Sequence< rtl::OUString > aSNS( 1 ); 315 316 if ( m_eKind == LINK ) 317 aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( 318 HIERARCHY_LINK_CONTENT_SERVICE_NAME ); 319 else if ( m_eKind == FOLDER ) 320 aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( 321 HIERARCHY_FOLDER_CONTENT_SERVICE_NAME ); 322 else 323 aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( 324 HIERARCHY_ROOT_FOLDER_CONTENT_SERVICE_NAME ); 325 326 return aSNS; 327 } 328 329 //========================================================================= 330 // 331 // XContent methods. 332 // 333 //========================================================================= 334 335 // virtual 336 rtl::OUString SAL_CALL HierarchyContent::getContentType() 337 { 338 return m_aProps.getContentType(); 339 } 340 341 //========================================================================= 342 // virtual 343 uno::Reference< ucb::XContentIdentifier > SAL_CALL 344 HierarchyContent::getIdentifier() 345 { 346 // Transient? 347 if ( m_eState == TRANSIENT ) 348 { 349 // Transient contents have no identifier. 350 return uno::Reference< ucb::XContentIdentifier >(); 351 } 352 353 return ContentImplHelper::getIdentifier(); 354 } 355 356 //========================================================================= 357 // 358 // XCommandProcessor methods. 359 // 360 //========================================================================= 361 362 // virtual 363 uno::Any SAL_CALL HierarchyContent::execute( 364 const ucb::Command& aCommand, 365 sal_Int32 /*CommandId*/, 366 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 367 { 368 uno::Any aRet; 369 370 if ( aCommand.Name.equalsAsciiL( 371 RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) ) 372 { 373 ////////////////////////////////////////////////////////////////// 374 // getPropertyValues 375 ////////////////////////////////////////////////////////////////// 376 377 uno::Sequence< beans::Property > Properties; 378 if ( !( aCommand.Argument >>= Properties ) ) 379 { 380 ucbhelper::cancelCommandExecution( 381 uno::makeAny( lang::IllegalArgumentException( 382 rtl::OUString::createFromAscii( 383 "Wrong argument type!" ), 384 static_cast< cppu::OWeakObject * >( this ), 385 -1 ) ), 386 Environment ); 387 // Unreachable 388 } 389 390 aRet <<= getPropertyValues( Properties ); 391 } 392 else if ( aCommand.Name.equalsAsciiL( 393 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) ) 394 { 395 ////////////////////////////////////////////////////////////////// 396 // setPropertyValues 397 ////////////////////////////////////////////////////////////////// 398 399 uno::Sequence< beans::PropertyValue > aProperties; 400 if ( !( aCommand.Argument >>= aProperties ) ) 401 { 402 ucbhelper::cancelCommandExecution( 403 uno::makeAny( lang::IllegalArgumentException( 404 rtl::OUString::createFromAscii( 405 "Wrong argument type!" ), 406 static_cast< cppu::OWeakObject * >( this ), 407 -1 ) ), 408 Environment ); 409 // Unreachable 410 } 411 412 if ( !aProperties.getLength() ) 413 { 414 ucbhelper::cancelCommandExecution( 415 uno::makeAny( lang::IllegalArgumentException( 416 rtl::OUString::createFromAscii( 417 "No properties!" ), 418 static_cast< cppu::OWeakObject * >( this ), 419 -1 ) ), 420 Environment ); 421 // Unreachable 422 } 423 424 aRet <<= setPropertyValues( aProperties, Environment ); 425 } 426 else if ( aCommand.Name.equalsAsciiL( 427 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) ) 428 { 429 ////////////////////////////////////////////////////////////////// 430 // getPropertySetInfo 431 ////////////////////////////////////////////////////////////////// 432 433 aRet <<= getPropertySetInfo( Environment ); 434 } 435 else if ( aCommand.Name.equalsAsciiL( 436 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) ) 437 { 438 ////////////////////////////////////////////////////////////////// 439 // getCommandInfo 440 ////////////////////////////////////////////////////////////////// 441 442 aRet <<= getCommandInfo( Environment ); 443 } 444 else if ( aCommand.Name.equalsAsciiL( 445 RTL_CONSTASCII_STRINGPARAM( "open" ) ) && isFolder() ) 446 { 447 ////////////////////////////////////////////////////////////////// 448 // open command for a folder content 449 ////////////////////////////////////////////////////////////////// 450 451 ucb::OpenCommandArgument2 aOpenCommand; 452 if ( !( aCommand.Argument >>= aOpenCommand ) ) 453 { 454 ucbhelper::cancelCommandExecution( 455 uno::makeAny( lang::IllegalArgumentException( 456 rtl::OUString::createFromAscii( 457 "Wrong argument type!" ), 458 static_cast< cppu::OWeakObject * >( this ), 459 -1 ) ), 460 Environment ); 461 // Unreachable 462 } 463 464 uno::Reference< ucb::XDynamicResultSet > xSet 465 = new DynamicResultSet( m_xSMgr, this, aOpenCommand ); 466 aRet <<= xSet; 467 } 468 else if ( aCommand.Name.equalsAsciiL( 469 RTL_CONSTASCII_STRINGPARAM( "insert" ) ) && 470 ( m_eKind != ROOT ) && !isReadOnly() ) 471 { 472 ////////////////////////////////////////////////////////////////// 473 // insert 474 // ( Not available at root folder ) 475 ////////////////////////////////////////////////////////////////// 476 477 ucb::InsertCommandArgument aArg; 478 if ( !( aCommand.Argument >>= aArg ) ) 479 { 480 ucbhelper::cancelCommandExecution( 481 uno::makeAny( lang::IllegalArgumentException( 482 rtl::OUString::createFromAscii( 483 "Wrong argument type!" ), 484 static_cast< cppu::OWeakObject * >( this ), 485 -1 ) ), 486 Environment ); 487 // Unreachable 488 } 489 490 sal_Int32 nNameClash = aArg.ReplaceExisting 491 ? ucb::NameClash::OVERWRITE 492 : ucb::NameClash::ERROR; 493 insert( nNameClash, Environment ); 494 } 495 else if ( aCommand.Name.equalsAsciiL( 496 RTL_CONSTASCII_STRINGPARAM( "delete" ) ) && 497 ( m_eKind != ROOT ) && !isReadOnly() ) 498 { 499 ////////////////////////////////////////////////////////////////// 500 // delete 501 // ( Not available at root folder ) 502 ////////////////////////////////////////////////////////////////// 503 504 sal_Bool bDeletePhysical = sal_False; 505 aCommand.Argument >>= bDeletePhysical; 506 destroy( bDeletePhysical, Environment ); 507 508 // Remove own and all children's persistent data. 509 if ( !removeData() ) 510 { 511 uno::Any aProps 512 = uno::makeAny( 513 beans::PropertyValue( 514 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 515 "Uri")), 516 -1, 517 uno::makeAny(m_xIdentifier-> 518 getContentIdentifier()), 519 beans::PropertyState_DIRECT_VALUE)); 520 ucbhelper::cancelCommandExecution( 521 ucb::IOErrorCode_CANT_WRITE, 522 uno::Sequence< uno::Any >(&aProps, 1), 523 Environment, 524 rtl::OUString::createFromAscii( 525 "Cannot remove persistent data!" ), 526 this ); 527 // Unreachable 528 } 529 530 // Remove own and all children's Additional Core Properties. 531 removeAdditionalPropertySet( sal_True ); 532 } 533 else if ( aCommand.Name.equalsAsciiL( 534 RTL_CONSTASCII_STRINGPARAM( "transfer" ) ) && 535 isFolder() && !isReadOnly() ) 536 { 537 ////////////////////////////////////////////////////////////////// 538 // transfer 539 // ( Not available at link objects ) 540 ////////////////////////////////////////////////////////////////// 541 542 ucb::TransferInfo aInfo; 543 if ( !( aCommand.Argument >>= aInfo ) ) 544 { 545 OSL_ENSURE( sal_False, "Wrong argument type!" ); 546 ucbhelper::cancelCommandExecution( 547 uno::makeAny( lang::IllegalArgumentException( 548 rtl::OUString::createFromAscii( 549 "Wrong argument type!" ), 550 static_cast< cppu::OWeakObject * >( this ), 551 -1 ) ), 552 Environment ); 553 // Unreachable 554 } 555 556 transfer( aInfo, Environment ); 557 } 558 else if ( aCommand.Name.equalsAsciiL( 559 RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) && 560 isFolder() && !isReadOnly() ) 561 { 562 ////////////////////////////////////////////////////////////////// 563 // createNewContent 564 // ( Not available at link objects ) 565 ////////////////////////////////////////////////////////////////// 566 567 ucb::ContentInfo aInfo; 568 if ( !( aCommand.Argument >>= aInfo ) ) 569 { 570 OSL_ENSURE( sal_False, "Wrong argument type!" ); 571 ucbhelper::cancelCommandExecution( 572 uno::makeAny( lang::IllegalArgumentException( 573 rtl::OUString::createFromAscii( 574 "Wrong argument type!" ), 575 static_cast< cppu::OWeakObject * >( this ), 576 -1 ) ), 577 Environment ); 578 // Unreachable 579 } 580 581 aRet <<= createNewContent( aInfo ); 582 } 583 else 584 { 585 ////////////////////////////////////////////////////////////////// 586 // Unsupported command 587 ////////////////////////////////////////////////////////////////// 588 589 ucbhelper::cancelCommandExecution( 590 uno::makeAny( ucb::UnsupportedCommandException( 591 rtl::OUString(), 592 static_cast< cppu::OWeakObject * >( this ) ) ), 593 Environment ); 594 // Unreachable 595 } 596 597 return aRet; 598 } 599 600 //========================================================================= 601 // virtual 602 void SAL_CALL HierarchyContent::abort( sal_Int32 /*CommandId*/ ) 603 { 604 // @@@ Generally, no action takes much time... 605 } 606 607 //========================================================================= 608 // 609 // XContentCreator methods. 610 // 611 //========================================================================= 612 613 // virtual 614 uno::Sequence< ucb::ContentInfo > SAL_CALL 615 HierarchyContent::queryCreatableContentsInfo() 616 { 617 return m_aProps.getCreatableContentsInfo(); 618 } 619 620 //========================================================================= 621 // virtual 622 uno::Reference< ucb::XContent > SAL_CALL 623 HierarchyContent::createNewContent( const ucb::ContentInfo& Info ) 624 { 625 if ( isFolder() ) 626 { 627 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 628 629 if ( !Info.Type.getLength() ) 630 return uno::Reference< ucb::XContent >(); 631 632 sal_Bool bCreateFolder = 633 Info.Type.equalsAsciiL( 634 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_FOLDER_CONTENT_TYPE ) ); 635 636 if ( !bCreateFolder && 637 !Info.Type.equalsAsciiL( 638 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_LINK_CONTENT_TYPE ) ) ) 639 return uno::Reference< ucb::XContent >(); 640 641 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 642 643 OSL_ENSURE( aURL.getLength() > 0, 644 "HierarchyContent::createNewContent - empty identifier!" ); 645 646 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) 647 aURL += rtl::OUString::createFromAscii( "/" ); 648 649 if ( bCreateFolder ) 650 aURL += rtl::OUString::createFromAscii( "New_Folder" ); 651 else 652 aURL += rtl::OUString::createFromAscii( "New_Link" ); 653 654 uno::Reference< ucb::XContentIdentifier > xId 655 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ); 656 657 return create( m_xSMgr, m_pProvider, xId, Info ); 658 } 659 else 660 { 661 OSL_ENSURE( sal_False, 662 "createNewContent called on non-folder object!" ); 663 return uno::Reference< ucb::XContent >(); 664 } 665 } 666 667 //========================================================================= 668 // virtual 669 rtl::OUString HierarchyContent::getParentURL() 670 { 671 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() ); 672 return aUri.getParentUri(); 673 } 674 675 //========================================================================= 676 //static 677 sal_Bool HierarchyContent::hasData( 678 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 679 HierarchyContentProvider* pProvider, 680 const uno::Reference< ucb::XContentIdentifier >& Identifier ) 681 { 682 rtl::OUString aURL = Identifier->getContentIdentifier(); 683 684 // Am I a root folder? 685 HierarchyUri aUri( aURL ); 686 if ( aUri.isRootFolder() ) 687 { 688 // hasData must always return 'true' for root folder 689 // even if no persistent data exist!!! 690 return sal_True; 691 } 692 693 return HierarchyEntry( rxSMgr, pProvider, aURL ).hasData(); 694 } 695 696 //========================================================================= 697 //static 698 sal_Bool HierarchyContent::loadData( 699 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 700 HierarchyContentProvider* pProvider, 701 const uno::Reference< ucb::XContentIdentifier >& Identifier, 702 HierarchyContentProperties& rProps ) 703 { 704 rtl::OUString aURL = Identifier->getContentIdentifier(); 705 706 // Am I a root folder? 707 HierarchyUri aUri( aURL ); 708 if ( aUri.isRootFolder() ) 709 { 710 rProps = HierarchyContentProperties( HierarchyEntryData::FOLDER ); 711 } 712 else 713 { 714 HierarchyEntry aEntry( rxSMgr, pProvider, aURL ); 715 HierarchyEntryData aData; 716 if ( !aEntry.getData( aData ) ) 717 return sal_False; 718 719 rProps = HierarchyContentProperties( aData ); 720 } 721 return sal_True; 722 } 723 724 //========================================================================= 725 sal_Bool HierarchyContent::storeData() 726 { 727 HierarchyEntry aEntry( 728 m_xSMgr, m_pProvider, m_xIdentifier->getContentIdentifier() ); 729 return aEntry.setData( m_aProps.getHierarchyEntryData(), sal_True ); 730 } 731 732 //========================================================================= 733 sal_Bool HierarchyContent::renameData( 734 const uno::Reference< ucb::XContentIdentifier >& xOldId, 735 const uno::Reference< ucb::XContentIdentifier >& xNewId ) 736 { 737 HierarchyEntry aEntry( 738 m_xSMgr, m_pProvider, xOldId->getContentIdentifier() ); 739 return aEntry.move( xNewId->getContentIdentifier(), 740 m_aProps.getHierarchyEntryData() ); 741 } 742 743 //========================================================================= 744 sal_Bool HierarchyContent::removeData() 745 { 746 HierarchyEntry aEntry( 747 m_xSMgr, m_pProvider, m_xIdentifier->getContentIdentifier() ); 748 return aEntry.remove(); 749 } 750 751 //========================================================================= 752 void HierarchyContent::setKind( 753 const uno::Reference< ucb::XContentIdentifier >& Identifier ) 754 { 755 if ( m_aProps.getIsFolder() ) 756 { 757 // Am I a root folder? 758 HierarchyUri aUri( Identifier->getContentIdentifier() ); 759 if ( aUri.isRootFolder() ) 760 m_eKind = ROOT; 761 else 762 m_eKind = FOLDER; 763 } 764 else 765 m_eKind = LINK; 766 } 767 768 //========================================================================= 769 bool HierarchyContent::isReadOnly() 770 { 771 if ( !m_bCheckedReadOnly ) 772 { 773 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 774 if ( !m_bCheckedReadOnly ) 775 { 776 m_bCheckedReadOnly = true; 777 m_bIsReadOnly = true; 778 779 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() ); 780 uno::Reference< lang::XMultiServiceFactory > xConfigProv 781 = m_pProvider->getConfigProvider( aUri.getService() ); 782 if ( xConfigProv.is() ) 783 { 784 uno::Sequence< rtl::OUString > aNames 785 = xConfigProv->getAvailableServiceNames(); 786 sal_Int32 nCount = aNames.getLength(); 787 for ( sal_Int32 n = 0; n < nCount; ++n ) 788 { 789 if ( aNames[ n ].equalsAsciiL( 790 RTL_CONSTASCII_STRINGPARAM( 791 "com.sun.star.ucb.HierarchyDataReadWriteAccess" 792 ) ) ) 793 { 794 m_bIsReadOnly = false; 795 break; 796 } 797 } 798 } 799 } 800 } 801 802 return m_bIsReadOnly; 803 } 804 805 //========================================================================= 806 uno::Reference< ucb::XContentIdentifier > 807 HierarchyContent::makeNewIdentifier( const rtl::OUString& rTitle ) 808 { 809 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 810 811 // Assemble new content identifier... 812 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() ); 813 rtl::OUString aNewURL = aUri.getParentUri(); 814 aNewURL += rtl::OUString::createFromAscii( "/" ); 815 aNewURL += ::ucb_impl::urihelper::encodeSegment( rTitle ); 816 817 return uno::Reference< ucb::XContentIdentifier >( 818 new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewURL ) ); 819 } 820 821 //========================================================================= 822 void HierarchyContent::queryChildren( HierarchyContentRefList& rChildren ) 823 { 824 if ( ( m_eKind != FOLDER ) && ( m_eKind != ROOT ) ) 825 return; 826 827 // Obtain a list with a snapshot of all currently instantiated contents 828 // from provider and extract the contents which are direct children 829 // of this content. 830 831 ::ucbhelper::ContentRefList aAllContents; 832 m_xProvider->queryExistingContents( aAllContents ); 833 834 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 835 sal_Int32 nURLPos = aURL.lastIndexOf( '/' ); 836 837 if ( nURLPos != ( aURL.getLength() - 1 ) ) 838 { 839 // No trailing slash found. Append. 840 aURL += rtl::OUString::createFromAscii( "/" ); 841 } 842 843 sal_Int32 nLen = aURL.getLength(); 844 845 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); 846 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); 847 848 while ( it != end ) 849 { 850 ::ucbhelper::ContentImplHelperRef xChild = (*it); 851 rtl::OUString aChildURL 852 = xChild->getIdentifier()->getContentIdentifier(); 853 854 // Is aURL a prefix of aChildURL? 855 if ( ( aChildURL.getLength() > nLen ) && 856 ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) 857 { 858 sal_Int32 nPos = nLen; 859 nPos = aChildURL.indexOf( '/', nPos ); 860 861 if ( ( nPos == -1 ) || 862 ( nPos == ( aChildURL.getLength() - 1 ) ) ) 863 { 864 // No further slashes/ only a final slash. It's a child! 865 rChildren.push_back( 866 HierarchyContentRef( 867 static_cast< HierarchyContent * >( xChild.get() ) ) ); 868 } 869 } 870 ++it; 871 } 872 } 873 874 //========================================================================= 875 sal_Bool HierarchyContent::exchangeIdentity( 876 const uno::Reference< ucb::XContentIdentifier >& xNewId ) 877 { 878 if ( !xNewId.is() ) 879 return sal_False; 880 881 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 882 883 uno::Reference< ucb::XContent > xThis = this; 884 885 // Already persistent? 886 if ( m_eState != PERSISTENT ) 887 { 888 OSL_ENSURE( sal_False, 889 "HierarchyContent::exchangeIdentity - Not persistent!" ); 890 return sal_False; 891 } 892 893 // Am I the root folder? 894 if ( m_eKind == ROOT ) 895 { 896 OSL_ENSURE( sal_False, "HierarchyContent::exchangeIdentity - " 897 "Not supported by root folder!" ); 898 return sal_False; 899 } 900 901 // Exchange own identitity. 902 903 // Fail, if a content with given id already exists. 904 if ( !hasData( xNewId ) ) 905 { 906 rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier(); 907 908 aGuard.clear(); 909 if ( exchange( xNewId ) ) 910 { 911 if ( m_eKind == FOLDER ) 912 { 913 // Process instantiated children... 914 915 HierarchyContentRefList aChildren; 916 queryChildren( aChildren ); 917 918 HierarchyContentRefList::const_iterator it = aChildren.begin(); 919 HierarchyContentRefList::const_iterator end = aChildren.end(); 920 921 while ( it != end ) 922 { 923 HierarchyContentRef xChild = (*it); 924 925 // Create new content identifier for the child... 926 uno::Reference< ucb::XContentIdentifier > xOldChildId 927 = xChild->getIdentifier(); 928 rtl::OUString aOldChildURL 929 = xOldChildId->getContentIdentifier(); 930 rtl::OUString aNewChildURL 931 = aOldChildURL.replaceAt( 932 0, 933 aOldURL.getLength(), 934 xNewId->getContentIdentifier() ); 935 uno::Reference< ucb::XContentIdentifier > xNewChildId 936 = new ::ucbhelper::ContentIdentifier( 937 m_xSMgr, aNewChildURL ); 938 939 if ( !xChild->exchangeIdentity( xNewChildId ) ) 940 return sal_False; 941 942 ++it; 943 } 944 } 945 return sal_True; 946 } 947 } 948 949 OSL_ENSURE( sal_False, 950 "HierarchyContent::exchangeIdentity - " 951 "Panic! Cannot exchange identity!" ); 952 return sal_False; 953 } 954 955 //========================================================================= 956 // static 957 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues( 958 const uno::Reference< lang::XMultiServiceFactory >& rSMgr, 959 const uno::Sequence< beans::Property >& rProperties, 960 const HierarchyContentProperties& rData, 961 HierarchyContentProvider* pProvider, 962 const rtl::OUString& rContentId ) 963 { 964 // Note: Empty sequence means "get values of all supported properties". 965 966 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow 967 = new ::ucbhelper::PropertyValueSet( rSMgr ); 968 969 sal_Int32 nCount = rProperties.getLength(); 970 if ( nCount ) 971 { 972 uno::Reference< beans::XPropertySet > xAdditionalPropSet; 973 sal_Bool bTriedToGetAdditonalPropSet = sal_False; 974 975 const beans::Property* pProps = rProperties.getConstArray(); 976 for ( sal_Int32 n = 0; n < nCount; ++n ) 977 { 978 const beans::Property& rProp = pProps[ n ]; 979 980 // Process Core properties. 981 982 if ( rProp.Name.equalsAsciiL( 983 RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) 984 { 985 xRow->appendString ( rProp, rData.getContentType() ); 986 } 987 else if ( rProp.Name.equalsAsciiL( 988 RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) 989 { 990 xRow->appendString ( rProp, rData.getTitle() ); 991 } 992 else if ( rProp.Name.equalsAsciiL( 993 RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) 994 { 995 xRow->appendBoolean( rProp, rData.getIsDocument() ); 996 } 997 else if ( rProp.Name.equalsAsciiL( 998 RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) 999 { 1000 xRow->appendBoolean( rProp, rData.getIsFolder() ); 1001 } 1002 else if ( rProp.Name.equalsAsciiL( 1003 RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) 1004 { 1005 xRow->appendObject( 1006 rProp, uno::makeAny( rData.getCreatableContentsInfo() ) ); 1007 } 1008 else if ( rProp.Name.equalsAsciiL( 1009 RTL_CONSTASCII_STRINGPARAM( "TargetURL" ) ) ) 1010 { 1011 // TargetURL is only supported by links. 1012 1013 if ( rData.getIsDocument() ) 1014 xRow->appendString( rProp, rData.getTargetURL() ); 1015 else 1016 xRow->appendVoid( rProp ); 1017 } 1018 else 1019 { 1020 // Not a Core Property! Maybe it's an Additional Core Property?! 1021 1022 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) 1023 { 1024 xAdditionalPropSet 1025 = uno::Reference< beans::XPropertySet >( 1026 pProvider->getAdditionalPropertySet( rContentId, 1027 sal_False ), 1028 uno::UNO_QUERY ); 1029 bTriedToGetAdditonalPropSet = sal_True; 1030 } 1031 1032 if ( xAdditionalPropSet.is() ) 1033 { 1034 if ( !xRow->appendPropertySetValue( 1035 xAdditionalPropSet, 1036 rProp ) ) 1037 { 1038 // Append empty entry. 1039 xRow->appendVoid( rProp ); 1040 } 1041 } 1042 else 1043 { 1044 // Append empty entry. 1045 xRow->appendVoid( rProp ); 1046 } 1047 } 1048 } 1049 } 1050 else 1051 { 1052 // Append all Core Properties. 1053 xRow->appendString ( 1054 beans::Property( rtl::OUString::createFromAscii( "ContentType" ), 1055 -1, 1056 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1057 beans::PropertyAttribute::BOUND 1058 | beans::PropertyAttribute::READONLY ), 1059 rData.getContentType() ); 1060 xRow->appendString ( 1061 beans::Property( rtl::OUString::createFromAscii( "Title" ), 1062 -1, 1063 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1064 // @@@ Might actually be read-only! 1065 beans::PropertyAttribute::BOUND ), 1066 rData.getTitle() ); 1067 xRow->appendBoolean( 1068 beans::Property( rtl::OUString::createFromAscii( "IsDocument" ), 1069 -1, 1070 getCppuBooleanType(), 1071 beans::PropertyAttribute::BOUND 1072 | beans::PropertyAttribute::READONLY ), 1073 rData.getIsDocument() ); 1074 xRow->appendBoolean( 1075 beans::Property( rtl::OUString::createFromAscii( "IsFolder" ), 1076 -1, 1077 getCppuBooleanType(), 1078 beans::PropertyAttribute::BOUND 1079 | beans::PropertyAttribute::READONLY ), 1080 rData.getIsFolder() ); 1081 1082 if ( rData.getIsDocument() ) 1083 xRow->appendString( 1084 beans::Property( rtl::OUString::createFromAscii( "TargetURL" ), 1085 -1, 1086 getCppuType( 1087 static_cast< const rtl::OUString * >( 0 ) ), 1088 // @@@ Might actually be read-only! 1089 beans::PropertyAttribute::BOUND ), 1090 rData.getTargetURL() ); 1091 xRow->appendObject( 1092 beans::Property( 1093 rtl::OUString::createFromAscii( "CreatableContentsInfo" ), 1094 -1, 1095 getCppuType( static_cast< 1096 const uno::Sequence< ucb::ContentInfo > * >( 0 ) ), 1097 beans::PropertyAttribute::BOUND 1098 | beans::PropertyAttribute::READONLY ), 1099 uno::makeAny( rData.getCreatableContentsInfo() ) ); 1100 1101 // Append all Additional Core Properties. 1102 1103 uno::Reference< beans::XPropertySet > xSet( 1104 pProvider->getAdditionalPropertySet( rContentId, sal_False ), 1105 uno::UNO_QUERY ); 1106 xRow->appendPropertySet( xSet ); 1107 } 1108 1109 return uno::Reference< sdbc::XRow >( xRow.get() ); 1110 } 1111 1112 //========================================================================= 1113 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues( 1114 const uno::Sequence< beans::Property >& rProperties ) 1115 { 1116 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1117 return getPropertyValues( m_xSMgr, 1118 rProperties, 1119 m_aProps, 1120 m_pProvider, 1121 m_xIdentifier->getContentIdentifier() ); 1122 } 1123 1124 //========================================================================= 1125 uno::Sequence< uno::Any > HierarchyContent::setPropertyValues( 1126 const uno::Sequence< beans::PropertyValue >& rValues, 1127 const uno::Reference< ucb::XCommandEnvironment > & xEnv ) 1128 { 1129 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 1130 1131 uno::Sequence< uno::Any > aRet( rValues.getLength() ); 1132 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() ); 1133 sal_Int32 nChanged = 0; 1134 1135 beans::PropertyChangeEvent aEvent; 1136 aEvent.Source = static_cast< cppu::OWeakObject * >( this ); 1137 aEvent.Further = sal_False; 1138 // aEvent.PropertyName = 1139 aEvent.PropertyHandle = -1; 1140 // aEvent.OldValue = 1141 // aEvent.NewValue = 1142 1143 const beans::PropertyValue* pValues = rValues.getConstArray(); 1144 sal_Int32 nCount = rValues.getLength(); 1145 1146 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet; 1147 sal_Bool bTriedToGetAdditonalPropSet = sal_False; 1148 1149 sal_Bool bExchange = sal_False; 1150 rtl::OUString aOldTitle; 1151 rtl::OUString aOldName; 1152 sal_Int32 nTitlePos = -1; 1153 1154 for ( sal_Int32 n = 0; n < nCount; ++n ) 1155 { 1156 const beans::PropertyValue& rValue = pValues[ n ]; 1157 1158 if ( rValue.Name.equalsAsciiL( 1159 RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) 1160 { 1161 // Read-only property! 1162 aRet[ n ] <<= lang::IllegalAccessException( 1163 rtl::OUString::createFromAscii( 1164 "Property is read-only!" ), 1165 static_cast< cppu::OWeakObject * >( this ) ); 1166 } 1167 else if ( rValue.Name.equalsAsciiL( 1168 RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) 1169 { 1170 // Read-only property! 1171 aRet[ n ] <<= lang::IllegalAccessException( 1172 rtl::OUString::createFromAscii( 1173 "Property is read-only!" ), 1174 static_cast< cppu::OWeakObject * >( this ) ); 1175 } 1176 else if ( rValue.Name.equalsAsciiL( 1177 RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) 1178 { 1179 // Read-only property! 1180 aRet[ n ] <<= lang::IllegalAccessException( 1181 rtl::OUString::createFromAscii( 1182 "Property is read-only!" ), 1183 static_cast< cppu::OWeakObject * >( this ) ); 1184 } 1185 else if ( rValue.Name.equalsAsciiL( 1186 RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) 1187 { 1188 // Read-only property! 1189 aRet[ n ] <<= lang::IllegalAccessException( 1190 rtl::OUString::createFromAscii( 1191 "Property is read-only!" ), 1192 static_cast< cppu::OWeakObject * >( this ) ); 1193 } 1194 else if ( rValue.Name.equalsAsciiL( 1195 RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) 1196 { 1197 if ( isReadOnly() ) 1198 { 1199 aRet[ n ] <<= lang::IllegalAccessException( 1200 rtl::OUString::createFromAscii( 1201 "Property is read-only!" ), 1202 static_cast< cppu::OWeakObject * >( this ) ); 1203 } 1204 else 1205 { 1206 rtl::OUString aNewValue; 1207 if ( rValue.Value >>= aNewValue ) 1208 { 1209 // No empty titles! 1210 if ( aNewValue.getLength() > 0 ) 1211 { 1212 if ( aNewValue != m_aProps.getTitle() ) 1213 { 1214 // modified title -> modified URL -> exchange ! 1215 if ( m_eState == PERSISTENT ) 1216 bExchange = sal_True; 1217 1218 aOldTitle = m_aProps.getTitle(); 1219 aOldName = m_aProps.getName(); 1220 1221 m_aProps.setTitle( aNewValue ); 1222 m_aProps.setName( 1223 ::ucb_impl::urihelper::encodeSegment( 1224 aNewValue ) ); 1225 1226 // property change event will be set later... 1227 1228 // remember position within sequence of values 1229 // (for error handling). 1230 nTitlePos = n; 1231 } 1232 } 1233 else 1234 { 1235 aRet[ n ] <<= lang::IllegalArgumentException( 1236 rtl::OUString::createFromAscii( 1237 "Empty title not allowed!" ), 1238 static_cast< cppu::OWeakObject * >( this ), 1239 -1 ); 1240 } 1241 } 1242 else 1243 { 1244 aRet[ n ] <<= beans::IllegalTypeException( 1245 rtl::OUString::createFromAscii( 1246 "Property value has wrong type!" ), 1247 static_cast< cppu::OWeakObject * >( this ) ); 1248 } 1249 } 1250 } 1251 else if ( rValue.Name.equalsAsciiL( 1252 RTL_CONSTASCII_STRINGPARAM( "TargetURL" ) ) ) 1253 { 1254 if ( isReadOnly() ) 1255 { 1256 aRet[ n ] <<= lang::IllegalAccessException( 1257 rtl::OUString::createFromAscii( 1258 "Property is read-only!" ), 1259 static_cast< cppu::OWeakObject * >( this ) ); 1260 } 1261 else 1262 { 1263 // TargetURL is only supported by links. 1264 1265 if ( m_eKind == LINK ) 1266 { 1267 rtl::OUString aNewValue; 1268 if ( rValue.Value >>= aNewValue ) 1269 { 1270 // No empty target URL's! 1271 if ( aNewValue.getLength() > 0 ) 1272 { 1273 if ( aNewValue != m_aProps.getTargetURL() ) 1274 { 1275 aEvent.PropertyName = rValue.Name; 1276 aEvent.OldValue 1277 = uno::makeAny( m_aProps.getTargetURL() ); 1278 aEvent.NewValue 1279 = uno::makeAny( aNewValue ); 1280 1281 aChanges.getArray()[ nChanged ] = aEvent; 1282 1283 m_aProps.setTargetURL( aNewValue ); 1284 nChanged++; 1285 } 1286 } 1287 else 1288 { 1289 aRet[ n ] <<= lang::IllegalArgumentException( 1290 rtl::OUString::createFromAscii( 1291 "Empty target URL not allowed!" ), 1292 static_cast< cppu::OWeakObject * >( this ), 1293 -1 ); 1294 } 1295 } 1296 else 1297 { 1298 aRet[ n ] <<= beans::IllegalTypeException( 1299 rtl::OUString::createFromAscii( 1300 "Property value has wrong type!" ), 1301 static_cast< cppu::OWeakObject * >( this ) ); 1302 } 1303 } 1304 else 1305 { 1306 aRet[ n ] <<= beans::UnknownPropertyException( 1307 rtl::OUString::createFromAscii( 1308 "TargetURL only supported by links!" ), 1309 static_cast< cppu::OWeakObject * >( this ) ); 1310 } 1311 } 1312 } 1313 else 1314 { 1315 // Not a Core Property! Maybe it's an Additional Core Property?! 1316 1317 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) 1318 { 1319 xAdditionalPropSet = getAdditionalPropertySet( sal_False ); 1320 bTriedToGetAdditonalPropSet = sal_True; 1321 } 1322 1323 if ( xAdditionalPropSet.is() ) 1324 { 1325 try 1326 { 1327 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue( 1328 rValue.Name ); 1329 if ( aOldValue != rValue.Value ) 1330 { 1331 xAdditionalPropSet->setPropertyValue( 1332 rValue.Name, rValue.Value ); 1333 1334 aEvent.PropertyName = rValue.Name; 1335 aEvent.OldValue = aOldValue; 1336 aEvent.NewValue = rValue.Value; 1337 1338 aChanges.getArray()[ nChanged ] = aEvent; 1339 nChanged++; 1340 } 1341 } 1342 catch ( beans::UnknownPropertyException const & e ) 1343 { 1344 aRet[ n ] <<= e; 1345 } 1346 catch ( lang::WrappedTargetException const & e ) 1347 { 1348 aRet[ n ] <<= e; 1349 } 1350 catch ( beans::PropertyVetoException const & e ) 1351 { 1352 aRet[ n ] <<= e; 1353 } 1354 catch ( lang::IllegalArgumentException const & e ) 1355 { 1356 aRet[ n ] <<= e; 1357 } 1358 } 1359 else 1360 { 1361 aRet[ n ] <<= uno::Exception( 1362 rtl::OUString::createFromAscii( 1363 "No property set for storing the value!" ), 1364 static_cast< cppu::OWeakObject * >( this ) ); 1365 } 1366 } 1367 } 1368 1369 if ( bExchange ) 1370 { 1371 uno::Reference< ucb::XContentIdentifier > xOldId 1372 = m_xIdentifier; 1373 uno::Reference< ucb::XContentIdentifier > xNewId 1374 = makeNewIdentifier( m_aProps.getTitle() ); 1375 1376 aGuard.clear(); 1377 if ( exchangeIdentity( xNewId ) ) 1378 { 1379 // Adapt persistent data. 1380 renameData( xOldId, xNewId ); 1381 1382 // Adapt Additional Core Properties. 1383 renameAdditionalPropertySet( xOldId->getContentIdentifier(), 1384 xNewId->getContentIdentifier(), 1385 sal_True ); 1386 } 1387 else 1388 { 1389 // Roll-back. 1390 m_aProps.setTitle( aOldTitle ); 1391 m_aProps.setName ( aOldName ); 1392 1393 aOldTitle = aOldName = rtl::OUString(); 1394 1395 // Set error . 1396 aRet[ nTitlePos ] <<= uno::Exception( 1397 rtl::OUString::createFromAscii( "Exchange failed!" ), 1398 static_cast< cppu::OWeakObject * >( this ) ); 1399 } 1400 } 1401 1402 if ( aOldTitle.getLength() ) 1403 { 1404 aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" ); 1405 aEvent.OldValue = uno::makeAny( aOldTitle ); 1406 aEvent.NewValue = uno::makeAny( m_aProps.getTitle() ); 1407 1408 aChanges.getArray()[ nChanged ] = aEvent; 1409 nChanged++; 1410 } 1411 1412 if ( nChanged > 0 ) 1413 { 1414 // Save changes, if content was already made persistent. 1415 if ( !bExchange && ( m_eState == PERSISTENT ) ) 1416 { 1417 if ( !storeData() ) 1418 { 1419 uno::Any aProps 1420 = uno::makeAny( 1421 beans::PropertyValue( 1422 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1423 "Uri")), 1424 -1, 1425 uno::makeAny(m_xIdentifier-> 1426 getContentIdentifier()), 1427 beans::PropertyState_DIRECT_VALUE)); 1428 ucbhelper::cancelCommandExecution( 1429 ucb::IOErrorCode_CANT_WRITE, 1430 uno::Sequence< uno::Any >(&aProps, 1), 1431 xEnv, 1432 rtl::OUString::createFromAscii( 1433 "Cannot store persistent data!" ), 1434 this ); 1435 // Unreachable 1436 } 1437 } 1438 1439 aChanges.realloc( nChanged ); 1440 1441 aGuard.clear(); 1442 notifyPropertiesChange( aChanges ); 1443 } 1444 1445 return aRet; 1446 } 1447 1448 //========================================================================= 1449 void HierarchyContent::insert( sal_Int32 nNameClashResolve, 1450 const uno::Reference< 1451 ucb::XCommandEnvironment > & xEnv ) 1452 { 1453 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 1454 1455 // Am I the root folder? 1456 if ( m_eKind == ROOT ) 1457 { 1458 ucbhelper::cancelCommandExecution( 1459 uno::makeAny( ucb::UnsupportedCommandException( 1460 rtl::OUString::createFromAscii( 1461 "Not supported by root folder!" ), 1462 static_cast< cppu::OWeakObject * >( this ) ) ), 1463 xEnv ); 1464 // Unreachable 1465 } 1466 1467 // Check, if all required properties were set. 1468 if ( m_aProps.getTitle().getLength() == 0 ) 1469 { 1470 uno::Sequence< rtl::OUString > aProps( 1 ); 1471 aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" ); 1472 ucbhelper::cancelCommandExecution( 1473 uno::makeAny( ucb::MissingPropertiesException( 1474 rtl::OUString(), 1475 static_cast< cppu::OWeakObject * >( this ), 1476 aProps ) ), 1477 xEnv ); 1478 // Unreachable 1479 } 1480 1481 // Assemble new content identifier... 1482 1483 uno::Reference< ucb::XContentIdentifier > xId 1484 = makeNewIdentifier( m_aProps.getTitle() ); 1485 1486 // Handle possible name clash... 1487 1488 switch ( nNameClashResolve ) 1489 { 1490 // fail. 1491 case ucb::NameClash::ERROR: 1492 if ( hasData( xId ) ) 1493 { 1494 ucbhelper::cancelCommandExecution( 1495 uno::makeAny( 1496 ucb::NameClashException( 1497 rtl::OUString(), 1498 static_cast< cppu::OWeakObject * >( this ), 1499 task::InteractionClassification_ERROR, 1500 m_aProps.getTitle() ) ), 1501 xEnv ); 1502 // Unreachable 1503 } 1504 break; 1505 1506 // replace existing object. 1507 case ucb::NameClash::OVERWRITE: 1508 break; 1509 1510 // "invent" a new valid title. 1511 case ucb::NameClash::RENAME: 1512 if ( hasData( xId ) ) 1513 { 1514 sal_Int32 nTry = 0; 1515 1516 do 1517 { 1518 rtl::OUString aNewId = xId->getContentIdentifier(); 1519 aNewId += rtl::OUString::createFromAscii( "_" ); 1520 aNewId += rtl::OUString::valueOf( ++nTry ); 1521 xId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewId ); 1522 } 1523 while ( hasData( xId ) && ( nTry < 1000 ) ); 1524 1525 if ( nTry == 1000 ) 1526 { 1527 ucbhelper::cancelCommandExecution( 1528 uno::makeAny( 1529 ucb::UnsupportedNameClashException( 1530 rtl::OUString::createFromAscii( 1531 "Unable to resolve name clash!" ), 1532 static_cast< cppu::OWeakObject * >( this ), 1533 nNameClashResolve ) ), 1534 xEnv ); 1535 // Unreachable 1536 } 1537 else 1538 { 1539 rtl::OUString aNewTitle( m_aProps.getTitle() ); 1540 aNewTitle += rtl::OUString::createFromAscii( "_" ); 1541 aNewTitle += rtl::OUString::valueOf( nTry ); 1542 m_aProps.setTitle( aNewTitle ); 1543 } 1544 } 1545 break; 1546 1547 case ucb::NameClash::KEEP: // deprecated 1548 case ucb::NameClash::ASK: 1549 default: 1550 if ( hasData( xId ) ) 1551 { 1552 ucbhelper::cancelCommandExecution( 1553 uno::makeAny( 1554 ucb::UnsupportedNameClashException( 1555 rtl::OUString(), 1556 static_cast< cppu::OWeakObject * >( this ), 1557 nNameClashResolve ) ), 1558 xEnv ); 1559 // Unreachable 1560 } 1561 break; 1562 } 1563 1564 // Identifier changed? 1565 sal_Bool bNewId = ( xId->getContentIdentifier() 1566 != m_xIdentifier->getContentIdentifier() ); 1567 m_xIdentifier = xId; 1568 1569 if ( !storeData() ) 1570 { 1571 uno::Any aProps 1572 = uno::makeAny(beans::PropertyValue( 1573 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1574 "Uri")), 1575 -1, 1576 uno::makeAny(m_xIdentifier-> 1577 getContentIdentifier()), 1578 beans::PropertyState_DIRECT_VALUE)); 1579 ucbhelper::cancelCommandExecution( 1580 ucb::IOErrorCode_CANT_WRITE, 1581 uno::Sequence< uno::Any >(&aProps, 1), 1582 xEnv, 1583 rtl::OUString::createFromAscii( "Cannot store persistent data!" ), 1584 this ); 1585 // Unreachable 1586 } 1587 1588 m_eState = PERSISTENT; 1589 1590 if ( bNewId ) 1591 { 1592 aGuard.clear(); 1593 inserted(); 1594 } 1595 } 1596 1597 //========================================================================= 1598 void HierarchyContent::destroy( sal_Bool bDeletePhysical, 1599 const uno::Reference< 1600 ucb::XCommandEnvironment > & xEnv ) 1601 { 1602 // @@@ take care about bDeletePhysical -> trashcan support 1603 1604 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 1605 1606 uno::Reference< ucb::XContent > xThis = this; 1607 1608 // Persistent? 1609 if ( m_eState != PERSISTENT ) 1610 { 1611 ucbhelper::cancelCommandExecution( 1612 uno::makeAny( ucb::UnsupportedCommandException( 1613 rtl::OUString::createFromAscii( 1614 "Not persistent!" ), 1615 static_cast< cppu::OWeakObject * >( this ) ) ), 1616 xEnv ); 1617 // Unreachable 1618 } 1619 1620 // Am I the root folder? 1621 if ( m_eKind == ROOT ) 1622 { 1623 ucbhelper::cancelCommandExecution( 1624 uno::makeAny( ucb::UnsupportedCommandException( 1625 rtl::OUString::createFromAscii( 1626 "Not supported by root folder!" ), 1627 static_cast< cppu::OWeakObject * >( this ) ) ), 1628 xEnv ); 1629 // Unreachable 1630 } 1631 1632 m_eState = DEAD; 1633 1634 aGuard.clear(); 1635 deleted(); 1636 1637 if ( m_eKind == FOLDER ) 1638 { 1639 // Process instantiated children... 1640 1641 HierarchyContentRefList aChildren; 1642 queryChildren( aChildren ); 1643 1644 HierarchyContentRefList::const_iterator it = aChildren.begin(); 1645 HierarchyContentRefList::const_iterator end = aChildren.end(); 1646 1647 while ( it != end ) 1648 { 1649 (*it)->destroy( bDeletePhysical, xEnv ); 1650 ++it; 1651 } 1652 } 1653 } 1654 1655 //========================================================================= 1656 void HierarchyContent::transfer( 1657 const ucb::TransferInfo& rInfo, 1658 const uno::Reference< ucb::XCommandEnvironment > & xEnv ) 1659 { 1660 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 1661 1662 // Persistent? 1663 if ( m_eState != PERSISTENT ) 1664 { 1665 ucbhelper::cancelCommandExecution( 1666 uno::makeAny( ucb::UnsupportedCommandException( 1667 rtl::OUString::createFromAscii( 1668 "Not persistent!" ), 1669 static_cast< cppu::OWeakObject * >( this ) ) ), 1670 xEnv ); 1671 // Unreachable 1672 } 1673 1674 // Is source a hierarchy content? 1675 if ( ( rInfo.SourceURL.getLength() < HIERARCHY_URL_SCHEME_LENGTH + 2 ) || 1676 ( rInfo.SourceURL.compareToAscii( HIERARCHY_URL_SCHEME ":/", 1677 HIERARCHY_URL_SCHEME_LENGTH + 2 ) 1678 != 0 ) ) 1679 { 1680 ucbhelper::cancelCommandExecution( 1681 uno::makeAny( ucb::InteractiveBadTransferURLException( 1682 rtl::OUString(), 1683 static_cast< cppu::OWeakObject * >( this ) ) ), 1684 xEnv ); 1685 // Unreachable 1686 } 1687 1688 // Is source not a parent of me / not me? 1689 rtl::OUString aId = m_xIdentifier->getContentIdentifier(); 1690 sal_Int32 nPos = aId.lastIndexOf( '/' ); 1691 if ( nPos != ( aId.getLength() - 1 ) ) 1692 { 1693 // No trailing slash found. Append. 1694 aId += rtl::OUString::createFromAscii( "/" ); 1695 } 1696 1697 if ( rInfo.SourceURL.getLength() <= aId.getLength() ) 1698 { 1699 if ( aId.compareTo( 1700 rInfo.SourceURL, rInfo.SourceURL.getLength() ) == 0 ) 1701 { 1702 uno::Any aProps 1703 = uno::makeAny(beans::PropertyValue( 1704 rtl::OUString( 1705 RTL_CONSTASCII_USTRINGPARAM("Uri")), 1706 -1, 1707 uno::makeAny(rInfo.SourceURL), 1708 beans::PropertyState_DIRECT_VALUE)); 1709 ucbhelper::cancelCommandExecution( 1710 ucb::IOErrorCode_RECURSIVE, 1711 uno::Sequence< uno::Any >(&aProps, 1), 1712 xEnv, 1713 rtl::OUString::createFromAscii( 1714 "Target is equal to or is a child of source!" ), 1715 this ); 1716 // Unreachable 1717 } 1718 } 1719 1720 ////////////////////////////////////////////////////////////////////// 1721 // 0) Obtain content object for source. 1722 ////////////////////////////////////////////////////////////////////// 1723 1724 uno::Reference< ucb::XContentIdentifier > xId 1725 = new ::ucbhelper::ContentIdentifier( m_xSMgr, rInfo.SourceURL ); 1726 1727 // Note: The static cast is okay here, because its sure that 1728 // m_xProvider is always the HierarchyContentProvider. 1729 rtl::Reference< HierarchyContent > xSource; 1730 1731 try 1732 { 1733 xSource = static_cast< HierarchyContent * >( 1734 m_xProvider->queryContent( xId ).get() ); 1735 } 1736 catch ( ucb::IllegalIdentifierException const & ) 1737 { 1738 // queryContent 1739 } 1740 1741 if ( !xSource.is() ) 1742 { 1743 uno::Any aProps 1744 = uno::makeAny(beans::PropertyValue( 1745 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1746 "Uri")), 1747 -1, 1748 uno::makeAny(xId->getContentIdentifier()), 1749 beans::PropertyState_DIRECT_VALUE)); 1750 ucbhelper::cancelCommandExecution( 1751 ucb::IOErrorCode_CANT_READ, 1752 uno::Sequence< uno::Any >(&aProps, 1), 1753 xEnv, 1754 rtl::OUString::createFromAscii( 1755 "Cannot instantiate source object!" ), 1756 this ); 1757 // Unreachable 1758 } 1759 1760 ////////////////////////////////////////////////////////////////////// 1761 // 1) Create new child content. 1762 ////////////////////////////////////////////////////////////////////// 1763 1764 rtl::OUString aType = xSource->isFolder() 1765 ? rtl::OUString::createFromAscii( HIERARCHY_FOLDER_CONTENT_TYPE ) 1766 : rtl::OUString::createFromAscii( HIERARCHY_LINK_CONTENT_TYPE ); 1767 ucb::ContentInfo aContentInfo; 1768 aContentInfo.Type = aType; 1769 aContentInfo.Attributes = 0; 1770 1771 // Note: The static cast is okay here, because its sure that 1772 // createNewContent always creates a HierarchyContent. 1773 rtl::Reference< HierarchyContent > xTarget 1774 = static_cast< HierarchyContent * >( 1775 createNewContent( aContentInfo ).get() ); 1776 if ( !xTarget.is() ) 1777 { 1778 uno::Any aProps 1779 = uno::makeAny(beans::PropertyValue( 1780 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1781 "Folder")), 1782 -1, 1783 uno::makeAny(aId), 1784 beans::PropertyState_DIRECT_VALUE)); 1785 ucbhelper::cancelCommandExecution( 1786 ucb::IOErrorCode_CANT_CREATE, 1787 uno::Sequence< uno::Any >(&aProps, 1), 1788 xEnv, 1789 rtl::OUString::createFromAscii( 1790 "XContentCreator::createNewContent failed!" ), 1791 this ); 1792 // Unreachable 1793 } 1794 1795 ////////////////////////////////////////////////////////////////////// 1796 // 2) Copy data from source content to child content. 1797 ////////////////////////////////////////////////////////////////////// 1798 1799 uno::Sequence< beans::Property > aSourceProps 1800 = xSource->getPropertySetInfo( xEnv )->getProperties(); 1801 sal_Int32 nCount = aSourceProps.getLength(); 1802 1803 if ( nCount ) 1804 { 1805 sal_Bool bHadTitle = ( rInfo.NewTitle.getLength() == 0 ); 1806 1807 // Get all source values. 1808 uno::Reference< sdbc::XRow > xRow 1809 = xSource->getPropertyValues( aSourceProps ); 1810 1811 uno::Sequence< beans::PropertyValue > aValues( nCount ); 1812 beans::PropertyValue* pValues = aValues.getArray(); 1813 1814 const beans::Property* pProps = aSourceProps.getConstArray(); 1815 for ( sal_Int32 n = 0; n < nCount; ++n ) 1816 { 1817 const beans::Property& rProp = pProps[ n ]; 1818 beans::PropertyValue& rValue = pValues[ n ]; 1819 1820 rValue.Name = rProp.Name; 1821 rValue.Handle = rProp.Handle; 1822 1823 if ( !bHadTitle && rProp.Name.equalsAsciiL( 1824 RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) 1825 { 1826 // Set new title instead of original. 1827 bHadTitle = sal_True; 1828 rValue.Value <<= rInfo.NewTitle; 1829 } 1830 else 1831 rValue.Value = xRow->getObject( 1832 n + 1, 1833 uno::Reference< container::XNameAccess >() ); 1834 1835 rValue.State = beans::PropertyState_DIRECT_VALUE; 1836 1837 if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE ) 1838 { 1839 // Add Additional Core Property. 1840 try 1841 { 1842 xTarget->addProperty( rProp.Name, 1843 rProp.Attributes, 1844 rValue.Value ); 1845 } 1846 catch ( beans::PropertyExistException const & ) 1847 { 1848 } 1849 catch ( beans::IllegalTypeException const & ) 1850 { 1851 } 1852 catch ( lang::IllegalArgumentException const & ) 1853 { 1854 } 1855 } 1856 } 1857 1858 // Set target values. 1859 xTarget->setPropertyValues( aValues, xEnv ); 1860 } 1861 1862 ////////////////////////////////////////////////////////////////////// 1863 // 3) Commit (insert) child. 1864 ////////////////////////////////////////////////////////////////////// 1865 1866 xTarget->insert( rInfo.NameClash, xEnv ); 1867 1868 ////////////////////////////////////////////////////////////////////// 1869 // 4) Transfer (copy) children of source. 1870 ////////////////////////////////////////////////////////////////////// 1871 1872 if ( xSource->isFolder() ) 1873 { 1874 HierarchyEntry aFolder( 1875 m_xSMgr, m_pProvider, xId->getContentIdentifier() ); 1876 HierarchyEntry::iterator it; 1877 1878 while ( aFolder.next( it ) ) 1879 { 1880 const HierarchyEntryData& rResult = *it; 1881 1882 rtl::OUString aChildId = xId->getContentIdentifier(); 1883 if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() ) 1884 aChildId += rtl::OUString::createFromAscii( "/" ); 1885 1886 aChildId += rResult.getName(); 1887 1888 ucb::TransferInfo aInfo; 1889 aInfo.MoveData = sal_False; 1890 aInfo.NewTitle = rtl::OUString(); 1891 aInfo.SourceURL = aChildId; 1892 aInfo.NameClash = rInfo.NameClash; 1893 1894 // Transfer child to target. 1895 xTarget->transfer( aInfo, xEnv ); 1896 } 1897 } 1898 1899 ////////////////////////////////////////////////////////////////////// 1900 // 5) Destroy source ( when moving only ) . 1901 ////////////////////////////////////////////////////////////////////// 1902 1903 if ( rInfo.MoveData ) 1904 { 1905 xSource->destroy( sal_True, xEnv ); 1906 1907 // Remove all persistent data of source and its children. 1908 if ( !xSource->removeData() ) 1909 { 1910 uno::Any aProps 1911 = uno::makeAny( 1912 beans::PropertyValue( 1913 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 1914 "Uri")), 1915 -1, 1916 uno::makeAny( 1917 xSource->m_xIdentifier-> 1918 getContentIdentifier()), 1919 beans::PropertyState_DIRECT_VALUE)); 1920 ucbhelper::cancelCommandExecution( 1921 ucb::IOErrorCode_CANT_WRITE, 1922 uno::Sequence< uno::Any >(&aProps, 1), 1923 xEnv, 1924 rtl::OUString::createFromAscii( 1925 "Cannot remove persistent data of source object!" ), 1926 this ); 1927 // Unreachable 1928 } 1929 1930 // Remove own and all children's Additional Core Properties. 1931 xSource->removeAdditionalPropertySet( sal_True ); 1932 } 1933 } 1934 1935 //========================================================================= 1936 //========================================================================= 1937 // 1938 // HierarchyContentProperties Implementation. 1939 // 1940 //========================================================================= 1941 //========================================================================= 1942 1943 uno::Sequence< ucb::ContentInfo > 1944 HierarchyContentProperties::getCreatableContentsInfo() const 1945 { 1946 if ( getIsFolder() ) 1947 { 1948 uno::Sequence< ucb::ContentInfo > aSeq( 2 ); 1949 1950 // Folder. 1951 aSeq.getArray()[ 0 ].Type 1952 = rtl::OUString::createFromAscii( HIERARCHY_FOLDER_CONTENT_TYPE ); 1953 aSeq.getArray()[ 0 ].Attributes 1954 = ucb::ContentInfoAttribute::KIND_FOLDER; 1955 1956 uno::Sequence< beans::Property > aFolderProps( 1 ); 1957 aFolderProps.getArray()[ 0 ] = beans::Property( 1958 rtl::OUString::createFromAscii( "Title" ), 1959 -1, 1960 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1961 beans::PropertyAttribute::BOUND ); 1962 aSeq.getArray()[ 0 ].Properties = aFolderProps; 1963 1964 // Link. 1965 aSeq.getArray()[ 1 ].Type 1966 = rtl::OUString::createFromAscii( HIERARCHY_LINK_CONTENT_TYPE ); 1967 aSeq.getArray()[ 1 ].Attributes 1968 = ucb::ContentInfoAttribute::KIND_LINK; 1969 1970 uno::Sequence< beans::Property > aLinkProps( 2 ); 1971 aLinkProps.getArray()[ 0 ] = beans::Property( 1972 rtl::OUString::createFromAscii( "Title" ), 1973 -1, 1974 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1975 beans::PropertyAttribute::BOUND ); 1976 aLinkProps.getArray()[ 1 ] = beans::Property( 1977 rtl::OUString::createFromAscii( "TargetURL" ), 1978 -1, 1979 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1980 beans::PropertyAttribute::BOUND ); 1981 aSeq.getArray()[ 1 ].Properties = aLinkProps; 1982 1983 return aSeq; 1984 } 1985 else 1986 { 1987 return uno::Sequence< ucb::ContentInfo >( 0 ); 1988 } 1989 } 1990