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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_ucb.hxx" 30 31 /************************************************************************** 32 TODO 33 ************************************************************************** 34 35 *************************************************************************/ 36 #include <osl/diagnose.h> 37 #include "odma_contentprops.hxx" 38 #include <com/sun/star/ucb/XDynamicResultSet.hpp> 39 #include <com/sun/star/beans/PropertyAttribute.hpp> 40 #include <com/sun/star/beans/XPropertyAccess.hpp> 41 #include <com/sun/star/lang/IllegalAccessException.hpp> 42 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> 43 #include <com/sun/star/sdbc/XRow.hpp> 44 #include <com/sun/star/io/XOutputStream.hpp> 45 #include <com/sun/star/io/XActiveDataSink.hpp> 46 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 47 #include <com/sun/star/ucb/OpenMode.hpp> 48 #include <com/sun/star/ucb/XCommandInfo.hpp> 49 #include <com/sun/star/ucb/XPersistentPropertySet.hpp> 50 #include <ucbhelper/contentidentifier.hxx> 51 #include <ucbhelper/propertyvalueset.hxx> 52 #include <ucbhelper/cancelcommandexecution.hxx> 53 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> 54 #include <com/sun/star/ucb/MissingInputStreamException.hpp> 55 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 56 #include <com/sun/star/ucb/MissingPropertiesException.hpp> 57 #include <com/sun/star/io/XActiveDataStreamer.hpp> 58 #include <com/sun/star/ucb/TransferInfo.hpp> 59 #include <com/sun/star/ucb/NameClash.hpp> 60 #include "odma_content.hxx" 61 #include "odma_provider.hxx" 62 #include "odma_resultset.hxx" 63 #include "odma_inputstream.hxx" 64 #include <ucbhelper/content.hxx> 65 #include <com/sun/star/uno/Exception.hpp> 66 #include <rtl/ref.hxx> 67 #include <osl/file.hxx> 68 69 using namespace com::sun::star; 70 using namespace odma; 71 72 //========================================================================= 73 //========================================================================= 74 // 75 // Content Implementation. 76 // 77 //========================================================================= 78 //========================================================================= 79 80 Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 81 ContentProvider* pProvider, 82 const uno::Reference< ucb::XContentIdentifier >& Identifier, 83 const ::rtl::Reference<ContentProperties>& _rProps) 84 : ContentImplHelper( rxSMgr, pProvider, Identifier ) 85 ,m_aProps(_rProps) 86 ,m_pProvider(pProvider) 87 ,m_pContent(NULL) 88 { 89 OSL_ENSURE(m_aProps.is(),"No valid ContentPropeties!"); 90 } 91 92 //========================================================================= 93 // virtual 94 Content::~Content() 95 { 96 delete m_pContent; 97 } 98 99 //========================================================================= 100 // 101 // XInterface methods. 102 // 103 //========================================================================= 104 105 // virtual 106 void SAL_CALL Content::acquire() throw() 107 { 108 ContentImplHelper::acquire(); 109 } 110 111 //========================================================================= 112 // virtual 113 void SAL_CALL Content::release() throw() 114 { 115 ContentImplHelper::release(); 116 } 117 118 //========================================================================= 119 // virtual 120 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) 121 throw ( uno::RuntimeException ) 122 { 123 uno::Any aRet; 124 125 // @@@ Add support for additional interfaces. 126 #if 0 127 aRet = cppu::queryInterface( rType, 128 static_cast< yyy::Xxxxxxxxx * >( this ) ); 129 #endif 130 131 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType ); 132 } 133 134 //========================================================================= 135 // 136 // XTypeProvider methods. 137 // 138 //========================================================================= 139 140 XTYPEPROVIDER_COMMON_IMPL( Content ); 141 142 //========================================================================= 143 // virtual 144 uno::Sequence< uno::Type > SAL_CALL Content::getTypes() 145 throw( uno::RuntimeException ) 146 { 147 // @@@ Add own interfaces. 148 149 static cppu::OTypeCollection* pCollection = 0; 150 151 if ( !pCollection ) 152 { 153 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 154 if ( !pCollection ) 155 { 156 static cppu::OTypeCollection aCollection( 157 CPPU_TYPE_REF( lang::XTypeProvider ), 158 CPPU_TYPE_REF( lang::XServiceInfo ), 159 CPPU_TYPE_REF( lang::XComponent ), 160 CPPU_TYPE_REF( ucb::XContent ), 161 CPPU_TYPE_REF( ucb::XCommandProcessor ), 162 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 163 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 164 CPPU_TYPE_REF( beans::XPropertyContainer ), 165 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 166 CPPU_TYPE_REF( container::XChild ) ); 167 pCollection = &aCollection; 168 } 169 } 170 171 return (*pCollection).getTypes(); 172 } 173 174 //========================================================================= 175 // 176 // XServiceInfo methods. 177 // 178 //========================================================================= 179 180 // virtual 181 rtl::OUString SAL_CALL Content::getImplementationName() 182 throw( uno::RuntimeException ) 183 { 184 // @@@ Adjust implementation name. Keep the prefix "com.sun.star.comp."! 185 return rtl::OUString::createFromAscii( "com.sun.star.comp.odma.Content" ); 186 } 187 188 //========================================================================= 189 // virtual 190 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames() 191 throw( uno::RuntimeException ) 192 { 193 // @@@ Adjust macro name. 194 uno::Sequence< rtl::OUString > aSNS( 1 ); 195 aSNS.getArray()[ 0 ] 196 = rtl::OUString::createFromAscii( ODMA_CONTENT_SERVICE_NAME ); 197 return aSNS; 198 } 199 200 //========================================================================= 201 // 202 // XContent methods. 203 // 204 //========================================================================= 205 206 // virtual 207 rtl::OUString SAL_CALL Content::getContentType() 208 throw( uno::RuntimeException ) 209 { 210 // @@@ Adjust macro name ( def in odma_provider.hxx ). 211 return rtl::OUString::createFromAscii( ODMA_CONTENT_TYPE ); 212 } 213 214 //========================================================================= 215 // 216 // XCommandProcessor methods. 217 // 218 //========================================================================= 219 220 // virtual 221 uno::Any SAL_CALL Content::execute( 222 const ucb::Command& aCommand, 223 sal_Int32 /*CommandId*/, 224 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 225 throw( uno::Exception, 226 ucb::CommandAbortedException, 227 uno::RuntimeException ) 228 { 229 uno::Any aRet; 230 231 if ( aCommand.Name.equalsAsciiL( 232 RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) ) 233 { 234 ////////////////////////////////////////////////////////////////// 235 // getPropertyValues 236 ////////////////////////////////////////////////////////////////// 237 238 uno::Sequence< beans::Property > Properties; 239 if ( !( aCommand.Argument >>= Properties ) ) 240 { 241 OSL_ENSURE( sal_False, "Wrong argument type!" ); 242 ucbhelper::cancelCommandExecution( 243 uno::makeAny( lang::IllegalArgumentException( 244 rtl::OUString(), 245 static_cast< cppu::OWeakObject * >( this ), 246 -1 ) ), 247 Environment ); 248 // Unreachable 249 } 250 251 aRet <<= getPropertyValues( Properties, Environment ); 252 } 253 else if ( aCommand.Name.equalsAsciiL( 254 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) ) 255 { 256 ////////////////////////////////////////////////////////////////// 257 // setPropertyValues 258 ////////////////////////////////////////////////////////////////// 259 260 uno::Sequence< beans::PropertyValue > aProperties; 261 if ( !( aCommand.Argument >>= aProperties ) ) 262 { 263 OSL_ENSURE( sal_False, "Wrong argument type!" ); 264 ucbhelper::cancelCommandExecution( 265 uno::makeAny( lang::IllegalArgumentException( 266 rtl::OUString(), 267 static_cast< cppu::OWeakObject * >( this ), 268 -1 ) ), 269 Environment ); 270 // Unreachable 271 } 272 273 if ( !aProperties.getLength() ) 274 { 275 OSL_ENSURE( sal_False, "No properties!" ); 276 ucbhelper::cancelCommandExecution( 277 uno::makeAny( lang::IllegalArgumentException( 278 rtl::OUString(), 279 static_cast< cppu::OWeakObject * >( this ), 280 -1 ) ), 281 Environment ); 282 // Unreachable 283 } 284 285 aRet <<= setPropertyValues( aProperties, Environment ); 286 } 287 else if ( aCommand.Name.equalsAsciiL( 288 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) ) 289 { 290 ////////////////////////////////////////////////////////////////// 291 // getPropertySetInfo 292 ////////////////////////////////////////////////////////////////// 293 294 // Note: Implemented by base class. 295 aRet <<= getPropertySetInfo( Environment ); 296 } 297 else if ( aCommand.Name.equalsAsciiL( 298 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) ) 299 { 300 ////////////////////////////////////////////////////////////////// 301 // getCommandInfo 302 ////////////////////////////////////////////////////////////////// 303 304 // Note: Implemented by base class. 305 aRet <<= getCommandInfo( Environment ); 306 } 307 else if ( aCommand.Name.equalsAsciiL( 308 RTL_CONSTASCII_STRINGPARAM( "open" ) ) ) 309 { 310 ucb::OpenCommandArgument2 aOpenCommand; 311 if ( !( aCommand.Argument >>= aOpenCommand ) ) 312 { 313 OSL_ENSURE( sal_False, "Wrong argument type!" ); 314 ucbhelper::cancelCommandExecution( 315 uno::makeAny( lang::IllegalArgumentException( 316 rtl::OUString(), 317 static_cast< cppu::OWeakObject * >( this ), 318 -1 ) ), 319 Environment ); 320 // Unreachable 321 } 322 323 sal_Bool bOpenFolder = 324 ( ( aOpenCommand.Mode == ucb::OpenMode::ALL ) || 325 ( aOpenCommand.Mode == ucb::OpenMode::FOLDERS ) || 326 ( aOpenCommand.Mode == ucb::OpenMode::DOCUMENTS ) ); 327 328 if ( bOpenFolder) 329 { 330 // open as folder - return result set 331 332 uno::Reference< ucb::XDynamicResultSet > xSet 333 = new DynamicResultSet( m_xSMgr, 334 this, 335 aOpenCommand, 336 Environment ); 337 aRet <<= xSet; 338 } 339 340 if ( aOpenCommand.Sink.is() ) 341 { 342 // Open document - supply document data stream. 343 344 // Check open mode 345 if ( ( aOpenCommand.Mode 346 == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) || 347 ( aOpenCommand.Mode 348 == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) ) 349 { 350 // Unsupported. 351 ucbhelper::cancelCommandExecution( 352 uno::makeAny( ucb::UnsupportedOpenModeException( 353 rtl::OUString(), 354 static_cast< cppu::OWeakObject * >( this ), 355 sal_Int16( aOpenCommand.Mode ) ) ), 356 Environment ); 357 // Unreachable 358 } 359 360 361 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 362 rtl::OUString sFileURL = openDoc(); 363 delete m_pContent; 364 m_pContent = new ::ucbhelper::Content(sFileURL,NULL); 365 if(!m_pContent->isDocument()) 366 { 367 rtl::OUString sErrorMsg(RTL_CONSTASCII_USTRINGPARAM("File: ")); 368 sErrorMsg += sFileURL; 369 sErrorMsg += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" could not be found.")); 370 ucbhelper::cancelCommandExecution( 371 uno::makeAny( io::IOException( 372 sErrorMsg, 373 static_cast< cppu::OWeakObject * >( this )) ), 374 Environment ); 375 } 376 377 uno::Reference< io::XOutputStream > xOut 378 = uno::Reference< io::XOutputStream >( 379 aOpenCommand.Sink, uno::UNO_QUERY ); 380 if ( xOut.is() ) 381 { 382 // @@@ PUSH: write data into xOut 383 m_pContent->openStream(xOut); 384 } 385 else 386 { 387 uno::Reference< io::XActiveDataSink > xDataSink 388 = uno::Reference< io::XActiveDataSink >( 389 aOpenCommand.Sink, uno::UNO_QUERY ); 390 if ( xDataSink.is() ) 391 { 392 // @@@ PULL: wait for client read 393 uno::Reference< io::XInputStream > xIn; 394 try 395 { 396 xIn = m_pContent->openStream(); 397 } 398 catch(uno::Exception&) 399 { 400 OSL_ENSURE(0,"Exception occured while creating the file content!"); 401 } 402 xDataSink->setInputStream( xIn ); 403 } 404 else 405 { 406 uno::Reference< io::XActiveDataStreamer > activeDataStreamer( aOpenCommand.Sink,uno::UNO_QUERY ); 407 if(activeDataStreamer.is()) 408 { 409 activeDataStreamer->setStream(new OOdmaStream(m_pContent,getContentProvider(),m_aProps)); 410 m_pContent = NULL; // don't delete here because the stream is now the owner 411 } 412 else 413 { 414 // Note: aOpenCommand.Sink may contain an XStream 415 // implementation. Support for this type of 416 // sink is optional... 417 ucbhelper::cancelCommandExecution( 418 uno::makeAny( ucb::UnsupportedDataSinkException( 419 rtl::OUString(), 420 static_cast< cppu::OWeakObject * >( this ), 421 aOpenCommand.Sink ) ), 422 Environment ); 423 // Unreachable 424 } 425 } 426 } 427 } 428 } 429 else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "close" ) ) ) 430 { 431 getContentProvider()->closeDocument(m_aProps->m_sDocumentId); 432 } 433 else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "delete" ) ) ) 434 { 435 ////////////////////////////////////////////////////////////////// 436 // delete 437 ////////////////////////////////////////////////////////////////// 438 439 // Remove own and all children's Additional Core Properties. 440 removeAdditionalPropertySet( sal_True ); 441 // Remove own and all childrens(!) persistent data. 442 if(!getContentProvider()->deleteDocument(m_aProps)) 443 ucbhelper::cancelCommandExecution( 444 uno::makeAny( lang::IllegalArgumentException( 445 rtl::OUString(), 446 static_cast< cppu::OWeakObject * >( this ), 447 -1 ) ), 448 Environment ); 449 } 450 else if ( aCommand.Name.equalsAsciiL( 451 RTL_CONSTASCII_STRINGPARAM( "insert" ) ) ) 452 { 453 ////////////////////////////////////////////////////////////////// 454 // insert 455 ////////////////////////////////////////////////////////////////// 456 457 ucb::InsertCommandArgument arg; 458 if ( !( aCommand.Argument >>= arg ) ) 459 { 460 OSL_ENSURE( sal_False, "Wrong argument type!" ); 461 ucbhelper::cancelCommandExecution( 462 uno::makeAny( lang::IllegalArgumentException( 463 rtl::OUString(), 464 static_cast< cppu::OWeakObject * >( this ), 465 -1 ) ), 466 Environment ); 467 // Unreachable 468 } 469 470 insert( arg.Data, arg.ReplaceExisting, Environment ); 471 } 472 else if( ! aCommand.Name.compareToAscii( "transfer" ) ) 473 { 474 ucb::TransferInfo aTransferInfo; 475 if( ! ( aCommand.Argument >>= aTransferInfo ) ) 476 { 477 OSL_ENSURE( sal_False, "Wrong argument type!" ); 478 ucbhelper::cancelCommandExecution( 479 uno::makeAny( lang::IllegalArgumentException( 480 rtl::OUString(), 481 static_cast< cppu::OWeakObject * >( this ), 482 -1 ) ), 483 Environment ); 484 // Unreachable 485 } 486 ::rtl::Reference<ContentProperties> aProp = m_aProps; 487 if(aProp->m_bIsFolder) 488 { 489 aProp = getContentProvider()->getContentPropertyWithTitle(aTransferInfo.NewTitle); 490 if(!aProp.is()) 491 aProp = getContentProvider()->getContentPropertyWithSavedAsName(aTransferInfo.NewTitle); 492 sal_Bool bError = !aProp.is(); 493 if(bError) 494 { 495 sal_Char* pExtension = NULL; 496 ::rtl::OString sExt; 497 sal_Int32 nPos = aTransferInfo.NewTitle.lastIndexOf('.'); 498 if(nPos != -1) 499 { 500 sExt = ::rtl::OUStringToOString(aTransferInfo.NewTitle.copy(nPos+1),RTL_TEXTENCODING_ASCII_US); 501 if(sExt.equalsIgnoreAsciiCase("txt")) 502 pExtension = ODM_FORMAT_TEXT; 503 else if(sExt.equalsIgnoreAsciiCase("rtf")) 504 pExtension = ODM_FORMAT_RTF; 505 else if(sExt.equalsIgnoreAsciiCase("ps")) 506 pExtension = ODM_FORMAT_PS; 507 else 508 pExtension = const_cast<sal_Char*>(sExt.getStr()); 509 } 510 else 511 pExtension = ODM_FORMAT_TEXT; 512 513 sal_Char* lpszNewDocId = new sal_Char[ODM_DOCID_MAX]; 514 void *pData = NULL; 515 DWORD dwFlags = ODM_SILENT; 516 ODMSTATUS odm = NODMSaveAsEx(ContentProvider::getHandle(), 517 NULL, // means it is saved the first time 518 lpszNewDocId, 519 pExtension, 520 NULL, // no callback function here 521 pData, 522 &dwFlags); 523 524 // check if we have to call the DMS dialog 525 if(odm == ODM_E_USERINT) 526 { 527 dwFlags = 0; 528 odm = NODMSaveAsEx(ContentProvider::getHandle(), 529 NULL, // means it is saved the first time 530 lpszNewDocId, 531 pExtension, 532 NULL, // no callback function here 533 pData, 534 &dwFlags); 535 } 536 bError = odm != ODM_SUCCESS; 537 if(!bError) 538 { 539 aProp = new ContentProperties(); 540 aProp->m_sDocumentId = ::rtl::OString(lpszNewDocId); 541 aProp->m_sContentType = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE)); 542 aProp->m_sSavedAsName = aTransferInfo.NewTitle; 543 getContentProvider()->append(aProp); 544 545 // now set the title 546 WORD nDocInfo = ODM_NAME; 547 ::rtl::OUString sFileName = aTransferInfo.NewTitle; 548 sal_Int32 nIndex = aTransferInfo.NewTitle.lastIndexOf( sal_Unicode('.') ); 549 if(nIndex != -1) 550 sFileName = aTransferInfo.NewTitle.copy(0,nIndex); 551 552 ::rtl::OString sDocInfoValue = ::rtl::OUStringToOString(sFileName,RTL_TEXTENCODING_ASCII_US); 553 odm = NODMSetDocInfo( ContentProvider::getHandle(), 554 lpszNewDocId, 555 nDocInfo, 556 const_cast<sal_Char*>(sDocInfoValue.getStr()) 557 ); 558 559 } 560 else if ( odm == ODM_E_CANCEL) 561 NODMActivate(ContentProvider::getHandle(), 562 ODM_DELETE, 563 lpszNewDocId); 564 565 delete [] lpszNewDocId; 566 } 567 if(bError) 568 ucbhelper::cancelCommandExecution( 569 uno::makeAny( lang::IllegalArgumentException( 570 rtl::OUString(), 571 static_cast< cppu::OWeakObject * >( this ), 572 -1 ) ), 573 Environment ); 574 } 575 rtl::OUString sFileURL = ContentProvider::openDoc(aProp); 576 577 sal_Int32 nLastIndex = sFileURL.lastIndexOf( sal_Unicode('/') ); 578 ::ucbhelper::Content aContent(sFileURL.copy(0,nLastIndex),NULL); 579 // aTransferInfo.NameClash = ucb::NameClash::OVERWRITE; 580 aTransferInfo.NewTitle = sFileURL.copy( 1 + nLastIndex ); 581 aContent.executeCommand(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("transfer")),uno::makeAny(aTransferInfo)); 582 getContentProvider()->saveDocument(aProp->m_sDocumentId); 583 } 584 else 585 { 586 ////////////////////////////////////////////////////////////////// 587 // Unsupported command 588 ////////////////////////////////////////////////////////////////// 589 590 OSL_ENSURE( sal_False, "Content::execute - unsupported command!" ); 591 592 ucbhelper::cancelCommandExecution( 593 uno::makeAny( ucb::UnsupportedCommandException( 594 rtl::OUString(), 595 static_cast< cppu::OWeakObject * >( this ) ) ), 596 Environment ); 597 // Unreachable 598 } 599 600 return aRet; 601 } 602 603 //========================================================================= 604 // virtual 605 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) 606 throw( uno::RuntimeException ) 607 { 608 // @@@ Implement logic to abort running commands, if this makes 609 // sense for your content. 610 } 611 612 //========================================================================= 613 // 614 // Non-interface methods. 615 // 616 //========================================================================= 617 618 // virtual 619 ::rtl::OUString Content::getParentURL() 620 { 621 ::rtl::OUString sURL = m_xIdentifier->getContentIdentifier(); 622 623 // @@@ Extract URL of parent from aURL and return it... 624 static ::rtl::OUString sScheme1(RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT "/")); 625 static ::rtl::OUString sScheme2(RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT)); 626 if(sURL == sScheme1 || sURL == sScheme2) 627 sURL = ::rtl::OUString(); 628 else 629 sURL = sScheme1; 630 631 return sURL; 632 } 633 634 //========================================================================= 635 // static 636 uno::Reference< sdbc::XRow > Content::getPropertyValues( 637 const uno::Reference< lang::XMultiServiceFactory >& rSMgr, 638 const uno::Sequence< beans::Property >& rProperties, 639 const rtl::Reference<ContentProperties>& rData, 640 const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider, 641 const rtl::OUString& rContentId ) 642 { 643 // Note: Empty sequence means "get values of all supported properties". 644 645 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow 646 = new ::ucbhelper::PropertyValueSet( rSMgr ); 647 648 sal_Int32 nCount = rProperties.getLength(); 649 if ( nCount ) 650 { 651 uno::Reference< beans::XPropertySet > xAdditionalPropSet; 652 sal_Bool bTriedToGetAdditonalPropSet = sal_False; 653 654 const beans::Property* pProps = rProperties.getConstArray(); 655 for ( sal_Int32 n = 0; n < nCount; ++n ) 656 { 657 const beans::Property& rProp = pProps[ n ]; 658 659 // Process Core properties. 660 661 if ( rProp.Name.equalsAsciiL( 662 RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) 663 { 664 xRow->appendString ( rProp, rData->m_sContentType ); 665 } 666 else if ( rProp.Name.equalsAsciiL( 667 RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) 668 { 669 xRow->appendString ( rProp, rData->m_sTitle ); 670 } 671 else if ( rProp.Name.equalsAsciiL( 672 RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) 673 { 674 xRow->appendBoolean( rProp, rData->m_bIsDocument ); 675 } 676 else if ( rProp.Name.equalsAsciiL( 677 RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) 678 { 679 xRow->appendBoolean( rProp, rData->m_bIsFolder ); 680 } 681 else if ( rProp.Name.equalsAsciiL( 682 RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ) 683 { 684 xRow->appendTimestamp( rProp, rData->m_aDateCreated ); 685 } 686 else if ( rProp.Name.equalsAsciiL( 687 RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) 688 { 689 xRow->appendTimestamp( rProp, rData->m_aDateModified ); 690 } 691 else if ( rProp.Name.equalsAsciiL( 692 RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) ) 693 { 694 xRow->appendBoolean( rProp, rData->m_bIsReadOnly ); 695 } 696 else if ( rProp.Name.equalsAsciiL( 697 RTL_CONSTASCII_STRINGPARAM( "Author" ) ) ) 698 { 699 xRow->appendString ( rProp, rData->m_sAuthor ); 700 } 701 else if ( rProp.Name.equalsAsciiL( 702 RTL_CONSTASCII_STRINGPARAM( "Subject" ) ) ) 703 { 704 xRow->appendString ( rProp, rData->m_sSubject ); 705 } 706 else if ( rProp.Name.equalsAsciiL( 707 RTL_CONSTASCII_STRINGPARAM( "Keywords" ) ) ) 708 { 709 xRow->appendString ( rProp, rData->m_sKeywords ); 710 } 711 else 712 { 713 // @@@ Note: If your data source supports adding/removing 714 // properties, you should implement the interface 715 // XPropertyContainer by yourself and supply your own 716 // logic here. The base class uses the service 717 // "com.sun.star.ucb.Store" to maintain Additional Core 718 // properties. But using server functionality is preferred! 719 720 // Not a Core Property! Maybe it's an Additional Core Property?! 721 722 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) 723 { 724 xAdditionalPropSet 725 = uno::Reference< beans::XPropertySet >( 726 rProvider->getAdditionalPropertySet( rContentId, 727 sal_False ), 728 uno::UNO_QUERY ); 729 bTriedToGetAdditonalPropSet = sal_True; 730 } 731 732 if ( xAdditionalPropSet.is() ) 733 { 734 if ( !xRow->appendPropertySetValue( 735 xAdditionalPropSet, 736 rProp ) ) 737 { 738 // Append empty entry. 739 xRow->appendVoid( rProp ); 740 } 741 } 742 else 743 { 744 // Append empty entry. 745 xRow->appendVoid( rProp ); 746 } 747 } 748 } 749 } 750 else 751 { 752 // Append all Core Properties. 753 xRow->appendString ( 754 beans::Property( rtl::OUString::createFromAscii( "ContentType" ), 755 -1, 756 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 757 beans::PropertyAttribute::BOUND 758 | beans::PropertyAttribute::READONLY ), 759 rData->m_sContentType ); 760 xRow->appendString ( 761 beans::Property( rtl::OUString::createFromAscii( "Title" ), 762 -1, 763 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 764 beans::PropertyAttribute::BOUND ), 765 rData->m_sTitle ); 766 xRow->appendBoolean( 767 beans::Property( rtl::OUString::createFromAscii( "IsDocument" ), 768 -1, 769 getCppuBooleanType(), 770 beans::PropertyAttribute::BOUND 771 | beans::PropertyAttribute::READONLY ), 772 rData->m_bIsDocument ); 773 xRow->appendBoolean( 774 beans::Property( rtl::OUString::createFromAscii( "IsFolder" ), 775 -1, 776 getCppuBooleanType(), 777 beans::PropertyAttribute::BOUND 778 | beans::PropertyAttribute::READONLY ), 779 rData->m_bIsFolder ); 780 781 // @@@ Append other properties supported directly. 782 xRow->appendTimestamp( 783 beans::Property( rtl::OUString::createFromAscii( "DateCreated" ), 784 -1, 785 getCppuType(static_cast< const util::DateTime * >( 0 ) ), 786 beans::PropertyAttribute::BOUND 787 | beans::PropertyAttribute::READONLY ), 788 rData->m_aDateCreated ); 789 xRow->appendTimestamp( 790 beans::Property( rtl::OUString::createFromAscii( "DateModified" ), 791 -1, 792 getCppuType(static_cast< const util::DateTime * >( 0 ) ), 793 beans::PropertyAttribute::BOUND 794 | beans::PropertyAttribute::READONLY ), 795 rData->m_aDateModified ); 796 xRow->appendBoolean( 797 beans::Property( rtl::OUString::createFromAscii( "IsReadOnly" ), 798 -1, 799 getCppuBooleanType(), 800 beans::PropertyAttribute::BOUND 801 | beans::PropertyAttribute::READONLY ), 802 rData->m_bIsReadOnly ); 803 xRow->appendString ( 804 beans::Property( rtl::OUString::createFromAscii( "Author" ), 805 -1, 806 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 807 beans::PropertyAttribute::BOUND ), 808 rData->m_sAuthor ); 809 xRow->appendString ( 810 beans::Property( rtl::OUString::createFromAscii( "Subject" ), 811 -1, 812 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 813 beans::PropertyAttribute::BOUND ), 814 rData->m_sSubject ); 815 xRow->appendString ( 816 beans::Property( rtl::OUString::createFromAscii( "Keywords" ), 817 -1, 818 getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 819 beans::PropertyAttribute::BOUND ), 820 rData->m_sKeywords ); 821 822 // @@@ Note: If your data source supports adding/removing 823 // properties, you should implement the interface 824 // XPropertyContainer by yourself and supply your own 825 // logic here. The base class uses the service 826 // "com.sun.star.ucb.Store" to maintain Additional Core 827 // properties. But using server functionality is preferred! 828 829 // Append all Additional Core Properties. 830 831 uno::Reference< beans::XPropertySet > xSet( 832 rProvider->getAdditionalPropertySet( rContentId, sal_False ), 833 uno::UNO_QUERY ); 834 xRow->appendPropertySet( xSet ); 835 } 836 837 return uno::Reference< sdbc::XRow >( xRow.get() ); 838 } 839 840 //========================================================================= 841 uno::Reference< sdbc::XRow > Content::getPropertyValues( 842 const uno::Sequence< beans::Property >& rProperties, 843 const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ ) 844 { 845 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 846 return getPropertyValues( m_xSMgr, 847 rProperties, 848 m_aProps, 849 rtl::Reference< 850 ::ucbhelper::ContentProviderImplHelper >( 851 m_xProvider.get() ), 852 m_xIdentifier->getContentIdentifier() ); 853 } 854 855 //========================================================================= 856 uno::Sequence< uno::Any > Content::setPropertyValues( 857 const uno::Sequence< beans::PropertyValue >& rValues, 858 const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ ) 859 { 860 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 861 862 uno::Sequence< uno::Any > aRet( rValues.getLength() ); 863 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() ); 864 sal_Int32 nChanged = 0; 865 866 beans::PropertyChangeEvent aEvent; 867 aEvent.Source = static_cast< cppu::OWeakObject * >( this ); 868 aEvent.Further = sal_False; 869 // aEvent.PropertyName = 870 aEvent.PropertyHandle = -1; 871 // aEvent.OldValue = 872 // aEvent.NewValue = 873 874 const beans::PropertyValue* pValues = rValues.getConstArray(); 875 sal_Int32 nCount = rValues.getLength(); 876 877 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet; 878 sal_Bool bTriedToGetAdditonalPropSet = sal_False; 879 880 for ( sal_Int32 n = 0; n < nCount; ++n ) 881 { 882 const beans::PropertyValue& rValue = pValues[ n ]; 883 884 if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) 885 { 886 changePropertyValue(rValue,n,m_aProps->m_sTitle,nChanged,aRet,aChanges); 887 } 888 else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Author") ) ) 889 { 890 changePropertyValue(rValue,n,m_aProps->m_sAuthor,nChanged,aRet,aChanges); 891 } 892 else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Keywords") ) ) 893 { 894 changePropertyValue(rValue,n,m_aProps->m_sKeywords,nChanged,aRet,aChanges); 895 } 896 else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Subject") ) ) 897 { 898 changePropertyValue(rValue,n,m_aProps->m_sSubject,nChanged,aRet,aChanges); 899 } 900 else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) || 901 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) || 902 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) || 903 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) || 904 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) || 905 rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) ) 906 { 907 // Read-only property! 908 aRet[ n ] <<= lang::IllegalAccessException( 909 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 910 "Property is read-only!") ), 911 static_cast< cppu::OWeakObject * >( this ) ); 912 } 913 else 914 { 915 // @@@ Note: If your data source supports adding/removing 916 // properties, you should implement the interface 917 // XPropertyContainer by yourself and supply your own 918 // logic here. The base class uses the service 919 // "com.sun.star.ucb.Store" to maintain Additional Core 920 // properties. But using server functionality is preferred! 921 922 // Not a Core Property! Maybe it's an Additional Core Property?! 923 924 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) 925 { 926 xAdditionalPropSet = getAdditionalPropertySet( sal_False ); 927 bTriedToGetAdditonalPropSet = sal_True; 928 } 929 930 if ( xAdditionalPropSet.is() ) 931 { 932 try 933 { 934 uno::Any aOldValue 935 = xAdditionalPropSet->getPropertyValue( rValue.Name ); 936 if ( aOldValue != rValue.Value ) 937 { 938 xAdditionalPropSet->setPropertyValue( 939 rValue.Name, rValue.Value ); 940 941 aEvent.PropertyName = rValue.Name; 942 aEvent.OldValue = aOldValue; 943 aEvent.NewValue = rValue.Value; 944 945 aChanges.getArray()[ nChanged ] = aEvent; 946 nChanged++; 947 } 948 else 949 { 950 // Old value equals new value. No error! 951 } 952 } 953 catch ( beans::UnknownPropertyException const & e ) 954 { 955 aRet[ n ] <<= e; 956 } 957 catch ( lang::WrappedTargetException const & e ) 958 { 959 aRet[ n ] <<= e; 960 } 961 catch ( beans::PropertyVetoException const & e ) 962 { 963 aRet[ n ] <<= e; 964 } 965 catch ( lang::IllegalArgumentException const & e ) 966 { 967 aRet[ n ] <<= e; 968 } 969 } 970 else 971 { 972 aRet[ n ] <<= uno::Exception( 973 rtl::OUString::createFromAscii( 974 "No property set for storing the value!" ), 975 static_cast< cppu::OWeakObject * >( this ) ); 976 } 977 } 978 } 979 980 if ( nChanged > 0 ) 981 { 982 // @@@ Save changes. 983 // storeData(); 984 985 aGuard.clear(); 986 aChanges.realloc( nChanged ); 987 notifyPropertiesChange( aChanges ); 988 } 989 990 return aRet; 991 } 992 993 #if 0 994 //========================================================================= 995 void Content::queryChildren( ContentRefList& rChildren ) 996 { 997 // @@@ Adapt method to your URL scheme... 998 999 // Obtain a list with a snapshot of all currently instanciated contents 1000 // from provider and extract the contents which are direct children 1001 // of this content. 1002 1003 ::ucbhelper::ContentRefList aAllContents; 1004 m_xProvider->queryExistingContents( aAllContents ); 1005 1006 OUString aURL = m_xIdentifier->getContentIdentifier(); 1007 sal_Int32 nPos = aURL.lastIndexOf( '/' ); 1008 1009 if ( nPos != ( aURL.getLength() - 1 ) ) 1010 { 1011 // No trailing slash found. Append. 1012 aURL += OUString::createFromAscii( "/" ); 1013 } 1014 1015 sal_Int32 nLen = aURL.getLength(); 1016 1017 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); 1018 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); 1019 1020 while ( it != end ) 1021 { 1022 ::ucbhelper::ContentImplHelperRef xChild = (*it); 1023 OUString aChildURL = xChild->getIdentifier()->getContentIdentifier(); 1024 1025 // Is aURL a prefix of aChildURL? 1026 if ( ( aChildURL.getLength() > nLen ) && 1027 ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) 1028 { 1029 sal_Int32 nPos = nLen; 1030 nPos = aChildURL.indexOf( '/', nPos ); 1031 1032 if ( ( nPos == -1 ) || 1033 ( nPos == ( aChildURL.getLength() - 1 ) ) ) 1034 { 1035 // No further slashes / only a final slash. It's a child! 1036 rChildren.push_back( 1037 ContentRef( 1038 static_cast< Content * >( xChild.get() ) ) ); 1039 } 1040 } 1041 ++it; 1042 } 1043 } 1044 #endif 1045 //========================================================================= 1046 void Content::insert( 1047 const uno::Reference< io::XInputStream > & xInputStream, 1048 sal_Bool bReplaceExisting, 1049 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 1050 throw( uno::Exception ) 1051 { 1052 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 1053 1054 // Check, if all required properties were set. 1055 if ( !m_aProps->m_sTitle.getLength()) 1056 { 1057 OSL_ENSURE( sal_False, "Content::insert - property value missing!" ); 1058 1059 uno::Sequence< rtl::OUString > aProps( 1 ); 1060 aProps[ 0 ] = rtl::OUString::createFromAscii( "zzzz" ); 1061 ucbhelper::cancelCommandExecution( 1062 uno::makeAny( ucb::MissingPropertiesException( 1063 rtl::OUString(), 1064 static_cast< cppu::OWeakObject * >( this ), 1065 aProps ) ), 1066 Environment ); 1067 // Unreachable 1068 } 1069 1070 if ( !xInputStream.is() ) 1071 { 1072 OSL_ENSURE( sal_False, "Content::insert - No data stream!" ); 1073 1074 ucbhelper::cancelCommandExecution( 1075 uno::makeAny( ucb::MissingInputStreamException( 1076 rtl::OUString(), 1077 static_cast< cppu::OWeakObject * >( this ) ) ), 1078 Environment ); 1079 // Unreachable 1080 } 1081 1082 // Assemble new content identifier... 1083 1084 // uno::Reference< ucb::XContentIdentifier > xId = ...; 1085 1086 // Fail, if a resource with given id already exists. 1087 if ( !bReplaceExisting ) // && hasData( m_xIdentifier ) ) 1088 { 1089 ucbhelper::cancelCommandExecution( 1090 uno::makeAny( ucb::UnsupportedCommandException( 1091 rtl::OUString(), 1092 static_cast< cppu::OWeakObject * >( this ) ) ), 1093 Environment ); 1094 // ucbhelper::cancelCommandExecution( 1095 // ucb::IOErrorCode_ALREADY_EXISTING, 1096 // Environment, 1097 // uno::makeAny(static_cast< cppu::OWeakObject * >( this )) 1098 // ); 1099 // Unreachable 1100 } 1101 1102 // m_xIdentifier = xId; 1103 1104 // @@@ 1105 // storeData(); 1106 1107 aGuard.clear(); 1108 inserted(); 1109 } 1110 #if 0 1111 //========================================================================= 1112 void Content::destroy( sal_Bool bDeletePhysical ) 1113 throw( uno::Exception ) 1114 { 1115 // @@@ take care about bDeletePhysical -> trashcan support 1116 1117 uno::Reference< ucb::XContent > xThis = this; 1118 1119 deleted(); 1120 1121 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1122 1123 // Process instanciated children... 1124 1125 ContentRefList aChildren; 1126 queryChildren( aChildren ); 1127 1128 ContentRefList::const_iterator it = aChildren.begin(); 1129 ContentRefList::const_iterator end = aChildren.end(); 1130 1131 while ( it != end ) 1132 { 1133 (*it)->destroy( bDeletePhysical ); 1134 ++it; 1135 } 1136 } 1137 #endif 1138 1139 // ----------------------------------------------------------------------------- 1140 ::rtl::OUString Content::openDoc() 1141 { 1142 OSL_ENSURE(m_aProps.is(),"No valid content properties!"); 1143 return ContentProvider::openDoc(m_aProps); 1144 } 1145 // ----------------------------------------------------------------------------- 1146 void Content::changePropertyValue(const beans::PropertyValue& _rValue, 1147 sal_Int32 _rnCurrentPos, 1148 ::rtl::OUString& _rsMemberValue, 1149 sal_Int32& _rnChanged, 1150 uno::Sequence< uno::Any >& _rRet, 1151 uno::Sequence< beans::PropertyChangeEvent >& _rChanges) throw (beans::IllegalTypeException) 1152 { 1153 rtl::OUString sNewValue; 1154 sal_Bool bError = sal_False; 1155 if ( _rValue.Value >>= sNewValue ) 1156 { 1157 if ( sNewValue != _rsMemberValue ) 1158 { 1159 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1160 // first we have to check if we could change the property inside the DMS 1161 ::rtl::OString sDocInfoValue = ::rtl::OUStringToOString(sNewValue,RTL_TEXTENCODING_ASCII_US); 1162 WORD nDocInfo = 0; 1163 if(&_rsMemberValue == &m_aProps->m_sTitle) 1164 nDocInfo = ODM_TITLETEXT; 1165 else if(&_rsMemberValue == &m_aProps->m_sAuthor) 1166 nDocInfo = ODM_AUTHOR; 1167 else if(&_rsMemberValue == &m_aProps->m_sSubject) 1168 nDocInfo = ODM_SUBJECT; 1169 else if(&_rsMemberValue == &m_aProps->m_sKeywords) 1170 nDocInfo = ODM_KEYWORDS; 1171 else 1172 bError = sal_True; 1173 1174 if(!bError) 1175 { 1176 ODMSTATUS odm = NODMSetDocInfo( ContentProvider::getHandle(), 1177 const_cast<sal_Char*>(m_aProps->m_sDocumentId.getStr()), 1178 nDocInfo, 1179 const_cast<sal_Char*>(sDocInfoValue.getStr()) 1180 ); 1181 if(odm == ODM_SUCCESS) 1182 { 1183 beans::PropertyChangeEvent aEvent; 1184 aEvent.Source = static_cast< cppu::OWeakObject * >( this ); 1185 aEvent.Further = sal_False; 1186 aEvent.PropertyHandle = -1; 1187 aEvent.PropertyName = _rValue.Name; 1188 aEvent.OldValue = uno::makeAny( _rsMemberValue ); 1189 aEvent.NewValue = uno::makeAny( sNewValue ); 1190 1191 _rChanges.getArray()[ _rnChanged ] = aEvent; 1192 1193 _rsMemberValue = sNewValue; 1194 ++_rnChanged; 1195 } 1196 } 1197 } 1198 else 1199 { 1200 // Old value equals new value. No error! 1201 } 1202 } 1203 else 1204 bError = sal_True; 1205 1206 if(bError) 1207 { 1208 _rRet[ _rnCurrentPos ] <<= beans::IllegalTypeException( 1209 rtl::OUString::createFromAscii( 1210 "Property value has wrong type!" ), 1211 static_cast< cppu::OWeakObject * >( this ) ); 1212 } 1213 } 1214 // ----------------------------------------------------------------------------- 1215 1216