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_sw.hxx" 26 27 28 #include <vcl/svapp.hxx> 29 #include <vos/mutex.hxx> 30 #include <osl/mutex.hxx> 31 #include <svl/itemprop.hxx> 32 #include <svl/urihelper.hxx> 33 #include <svx/dataaccessdescriptor.hxx> 34 #include <tools/shl.hxx> // GetAppData 35 #include <tools/tempfile.hxx> 36 #include <sfx2/app.hxx> 37 #include <sfx2/docfile.hxx> 38 #include <sfx2/docfilt.hxx> 39 #include <comphelper/processfactory.hxx> 40 #include <vcl/timer.hxx> 41 #include <com/sun/star/sdb/CommandType.hpp> 42 #include <com/sun/star/text/MailMergeType.hpp> 43 #include <com/sun/star/text/MailMergeEvent.hpp> 44 #include <com/sun/star/text/XMailMergeListener.hpp> 45 #include <com/sun/star/text/XMailMergeBroadcaster.hpp> 46 #include <com/sun/star/beans/PropertyAttribute.hpp> 47 #include <com/sun/star/lang/XUnoTunnel.hpp> 48 #include <com/sun/star/sdbc/XResultSet.hpp> 49 #include <com/sun/star/sdbc/XConnection.hpp> 50 #include <com/sun/star/sdbc/XRowSet.hpp> 51 #include <com/sun/star/frame/XComponentLoader.hpp> 52 #include <com/sun/star/util/XCloseable.hpp> 53 #ifndef _COM_SUN_STAR_UTIL_CloseVetoException_HPP_ 54 #include <com/sun/star/util/CloseVetoException.hpp> 55 #endif 56 #include <com/sun/star/sdbcx/XRowLocate.hpp> 57 #include <com/sun/star/frame/XStorable.hpp> 58 #include "com/sun/star/mail/XSmtpService.hpp" 59 #include <sfx2/viewfrm.hxx> 60 #include <sfx2/event.hxx> 61 #include <swevent.hxx> 62 #include <unomailmerge.hxx> 63 #include <swdll.hxx> 64 #include <swmodule.hxx> 65 #include <unoprnms.hxx> 66 #include <unomap.hxx> 67 #include <swunohelper.hxx> 68 #include <docsh.hxx> 69 #ifndef IDOCUMENTDEVICEACCESS_HXX_INCLUDED 70 #include <IDocumentDeviceAccess.hxx> 71 #endif 72 #include <view.hxx> 73 #include <dbmgr.hxx> 74 #include <unotxdoc.hxx> 75 #include <prtopt.hxx> 76 #include <wrtsh.hxx> 77 #include <shellio.hxx> 78 #include <mmconfigitem.hxx> 79 #include <mailmergehelper.hxx> 80 #include <memory> 81 82 #include <unomid.h> 83 84 85 #define SN_MAIL_MERGE "com.sun.star.text.MailMerge" 86 #define SN_DATA_ACCESS_DESCRIPTOR "com.sun.star.sdb.DataAccessDescriptor" 87 88 using namespace ::com::sun::star; 89 using namespace ::com::sun::star::frame; 90 using namespace ::com::sun::star::uno; 91 using namespace ::com::sun::star::lang; 92 using namespace ::com::sun::star::beans; 93 using namespace ::com::sun::star::text; 94 using ::rtl::OUString; 95 using namespace SWUnoHelper; 96 97 //////////////////////////////////////////////////////////// 98 99 typedef ::utl::SharedUNOComponent< XInterface > SharedComponent; 100 101 //////////////////////////////////////////////////////////// 102 103 osl::Mutex & GetMailMergeMutex() 104 { 105 static osl::Mutex aMutex; 106 return aMutex; 107 } 108 109 //////////////////////////////////////////////////////////// 110 111 enum CloseResult 112 { 113 eSuccess, // successfully closed 114 eVetoed, // vetoed, ownership transferred to the vetoing instance 115 eFailed // failed for some unknown reason 116 }; 117 static CloseResult CloseModelAndDocSh( 118 Reference< frame::XModel > &rxModel, 119 SfxObjectShellRef &rxDocSh ) 120 { 121 CloseResult eResult = eSuccess; 122 123 rxDocSh = 0; 124 125 //! models/documents should never be disposed (they may still be 126 //! used for printing which is called asynchronously for example) 127 //! instead call close 128 Reference< util::XCloseable > xClose( rxModel, UNO_QUERY ); 129 if (xClose.is()) 130 { 131 try 132 { 133 //! 'sal_True' -> transfer ownership to vetoing object if vetoed! 134 //! I.e. now that object is responsible for closing the model and doc shell. 135 xClose->close( sal_True ); 136 } 137 catch (util::CloseVetoException &) 138 { 139 //! here we have the problem that the temporary file that is 140 //! currently being printed will never be deleted. :-( 141 eResult = eVetoed; 142 } 143 catch ( const uno::RuntimeException& ) 144 { 145 eResult = eFailed; 146 } 147 } 148 return eResult; 149 } 150 151 //////////////////////////////////////////////////////////// 152 153 static sal_Bool LoadFromURL_impl( 154 Reference< frame::XModel > &rxModel, 155 SfxObjectShellRef &rxDocSh, 156 const String &rURL, 157 sal_Bool bClose ) 158 { 159 // try to open the document readonly and hidden 160 Reference< frame::XModel > xTmpModel; 161 Sequence < PropertyValue > aArgs( 1 ); 162 aArgs[0].Name = C2U("Hidden"); 163 sal_Bool bVal = sal_True; 164 aArgs[0].Value <<= bVal; 165 try 166 { 167 Reference < XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()-> 168 createInstance( C2U("com.sun.star.frame.Desktop") ), UNO_QUERY ); 169 xTmpModel = Reference < XModel >( xDesktop->loadComponentFromURL( 170 rURL, C2U("_blank"), 0, aArgs ), UNO_QUERY ); 171 } 172 catch( Exception & ) 173 { 174 return sal_False; 175 } 176 177 // try to get the DocShell 178 SwDocShell *pTmpDocShell = 0; 179 Reference < XUnoTunnel > xTunnel( xTmpModel, UNO_QUERY ); 180 if (xTunnel.is()) 181 { 182 SwXTextDocument* pTextDoc = reinterpret_cast<SwXTextDocument *>( 183 xTunnel->getSomething( SwXTextDocument::getUnoTunnelId() )); 184 pTmpDocShell = pTextDoc ? pTextDoc->GetDocShell() : 0; 185 } 186 187 sal_Bool bRes = sal_False; 188 if (xTmpModel.is() && pTmpDocShell) // everything available? 189 { 190 if (bClose) 191 CloseModelAndDocSh( rxModel, rxDocSh ); 192 // set new stuff 193 rxModel = xTmpModel; 194 rxDocSh = pTmpDocShell; 195 bRes = sal_True; 196 } 197 else 198 { 199 // SfxObjectShellRef is ok here, since the document will be explicitly closed 200 SfxObjectShellRef xTmpDocSh = pTmpDocShell; 201 CloseModelAndDocSh( xTmpModel, xTmpDocSh ); 202 } 203 204 return bRes; 205 } 206 207 //========================================================== 208 namespace 209 { 210 class DelayedFileDeletion : public ::cppu::WeakImplHelper1< util::XCloseListener > 211 { 212 protected: 213 ::osl::Mutex m_aMutex; 214 Reference< util::XCloseable > m_xDocument; 215 Timer m_aDeleteTimer; 216 String m_sTemporaryFile; 217 sal_Int32 m_nPendingDeleteAttempts; 218 219 public: 220 DelayedFileDeletion( const Reference< XModel >& _rxModel, 221 const String& _rTemporaryFile ); 222 223 protected: 224 ~DelayedFileDeletion( ); 225 226 // XCloseListener 227 virtual void SAL_CALL queryClosing( const EventObject& _rSource, sal_Bool _bGetsOwnership ); 228 virtual void SAL_CALL notifyClosing( const EventObject& _rSource ); 229 230 // XEventListener 231 virtual void SAL_CALL disposing( const EventObject& Source ); 232 233 private: 234 void implTakeOwnership( ); 235 DECL_LINK( OnTryDeleteFile, void* ); 236 237 private: 238 DelayedFileDeletion( const DelayedFileDeletion& ); // never implemented 239 DelayedFileDeletion& operator=( const DelayedFileDeletion& ); // never implemented 240 }; 241 242 DBG_NAME( DelayedFileDeletion ) 243 //------------------------------------------------------ 244 DelayedFileDeletion::DelayedFileDeletion( const Reference< XModel >& _rxModel, const String& _rTemporaryFile ) 245 : 246 m_xDocument( _rxModel, UNO_QUERY ) 247 ,m_sTemporaryFile( _rTemporaryFile ) 248 ,m_nPendingDeleteAttempts( 0 ) 249 { 250 DBG_CTOR( DelayedFileDeletion, NULL ); 251 252 osl_incrementInterlockedCount( &m_refCount ); 253 try 254 { 255 if ( m_xDocument.is() ) 256 { 257 m_xDocument->addCloseListener( this ); 258 // successfully added -> keep ourself alive 259 acquire(); 260 } 261 else { 262 DBG_ERROR( "DelayedFileDeletion::DelayedFileDeletion: model is no component!" ); 263 } 264 } 265 catch( const Exception& ) 266 { 267 DBG_ERROR( "DelayedFileDeletion::DelayedFileDeletion: could not register as event listener at the model!" ); 268 } 269 osl_decrementInterlockedCount( &m_refCount ); 270 } 271 272 //-------------------------------------------------------------------- 273 IMPL_LINK( DelayedFileDeletion, OnTryDeleteFile, void*, EMPTYARG ) 274 { 275 ::osl::ClearableMutexGuard aGuard( m_aMutex ); 276 277 sal_Bool bSuccess = sal_False; 278 try 279 { 280 sal_Bool bDeliverOwnership = ( 0 == m_nPendingDeleteAttempts ); 281 // if this is our last attempt, then anybody which vetoes this has to take the consequences 282 // (means take the ownership) 283 m_xDocument->close( bDeliverOwnership ); 284 bSuccess = sal_True; 285 } 286 catch( const util::CloseVetoException& ) 287 { 288 // somebody vetoed -> next try 289 if ( m_nPendingDeleteAttempts ) 290 { 291 // next attempt 292 --m_nPendingDeleteAttempts; 293 m_aDeleteTimer.Start(); 294 } 295 else 296 bSuccess = sal_True; // can't do anything here ... 297 } 298 catch( const Exception& ) 299 { 300 DBG_ERROR( "DelayedFileDeletion::OnTryDeleteFile: caught a strange exception!" ); 301 bSuccess = sal_True; 302 // can't do anything here ... 303 } 304 305 if ( bSuccess ) 306 { 307 SWUnoHelper::UCB_DeleteFile( m_sTemporaryFile ); 308 aGuard.clear(); 309 release(); // this should be our last reference, we should be dead after this 310 } 311 return 0L; 312 } 313 314 //-------------------------------------------------------------------- 315 void DelayedFileDeletion::implTakeOwnership( ) 316 { 317 // revoke ourself as listener 318 try 319 { 320 m_xDocument->removeCloseListener( this ); 321 } 322 catch( const Exception & ) 323 { 324 DBG_ERROR( "DelayedFileDeletion::implTakeOwnership: could not revoke the listener!" ); 325 } 326 327 m_aDeleteTimer.SetTimeout( 3000 ); // 3 seconds 328 m_aDeleteTimer.SetTimeoutHdl( LINK( this, DelayedFileDeletion, OnTryDeleteFile ) ); 329 m_nPendingDeleteAttempts = 3; // try 3 times at most 330 m_aDeleteTimer.Start( ); 331 } 332 333 //-------------------------------------------------------------------- 334 void SAL_CALL DelayedFileDeletion::queryClosing( const EventObject& , sal_Bool _bGetsOwnership ) 335 { 336 ::osl::MutexGuard aGuard( m_aMutex ); 337 if ( _bGetsOwnership ) 338 implTakeOwnership( ); 339 340 // always veto: We want to take the ownership ourself, as this is the only chance to delete 341 // the temporary file which the model is based on 342 throw util::CloseVetoException( ); 343 } 344 345 //-------------------------------------------------------------------- 346 void SAL_CALL DelayedFileDeletion::notifyClosing( const EventObject& ) 347 { 348 DBG_ERROR( "DelayedFileDeletion::notifyClosing: how this?" ); 349 // this should not happen: 350 // Either, a foreign instance closes the document, then we should veto this, and take the ownership 351 // Or, we ourself close the document, then we should not be a listener anymore 352 } 353 354 //------------------------------------------------------ 355 void SAL_CALL DelayedFileDeletion::disposing( const EventObject& ) 356 { 357 DBG_ERROR( "DelayedFileDeletion::disposing: how this?" ); 358 // this should not happen: 359 // Either, a foreign instance closes the document, then we should veto this, and take the ownership 360 // Or, we ourself close the document, then we should not be a listener anymore 361 } 362 363 //------------------------------------------------------ 364 DelayedFileDeletion::~DelayedFileDeletion( ) 365 { 366 DBG_DTOR( DelayedFileDeletion, NULL ); 367 } 368 } 369 370 //////////////////////////////////////////////////////////// 371 372 static sal_Bool DeleteTmpFile_Impl( 373 Reference< frame::XModel > &rxModel, 374 SfxObjectShellRef &rxDocSh, 375 const String &rTmpFileURL ) 376 { 377 sal_Bool bRes = sal_False; 378 if (rTmpFileURL.Len()) 379 { 380 sal_Bool bDelete = sal_True; 381 if ( eVetoed == CloseModelAndDocSh( rxModel, rxDocSh ) ) 382 { 383 // somebody vetoed the closing, and took the ownership of the document 384 // -> ensure that the temporary file is deleted later on 385 Reference< XEventListener > xEnsureDelete( new DelayedFileDeletion( rxModel, rTmpFileURL ) ); 386 // note: as soon as #106931# is fixed, the whole DelayedFileDeletion is to be superseeded by 387 // a better solution 388 bDelete = sal_False; 389 } 390 391 rxModel = 0; 392 rxDocSh = 0; // destroy doc shell 393 394 if ( bDelete ) 395 { 396 if ( !SWUnoHelper::UCB_DeleteFile( rTmpFileURL ) ) 397 { 398 Reference< XEventListener > xEnsureDelete( new DelayedFileDeletion( rxModel, rTmpFileURL ) ); 399 // same not as above: as soon as #106931#, ... 400 } 401 } 402 else 403 bRes = sal_True; // file will be deleted delayed 404 } 405 return bRes; 406 } 407 408 //////////////////////////////////////////////////////////// 409 410 SwXMailMerge::SwXMailMerge() : 411 aEvtListeners ( GetMailMergeMutex() ), 412 aMergeListeners ( GetMailMergeMutex() ), 413 aPropListeners ( GetMailMergeMutex() ), 414 pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_MAILMERGE ) ), 415 bSendAsHTML(sal_False), 416 bSendAsAttachment(sal_False), 417 bSaveAsSingleFile(sal_False) 418 419 { 420 // create empty document 421 // like in: SwModule::InsertEnv (appenv.cxx) 422 SwDocShell *pDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD ); 423 xDocSh = pDocShell; 424 xDocSh->DoInitNew( 0 ); 425 SfxViewFrame *pFrame = SfxViewFrame::LoadHiddenDocument( *xDocSh, 0 ); 426 SwView *pView = (SwView*) pFrame->GetViewShell(); 427 pView->AttrChangedNotify( &pView->GetWrtShell() );//Damit SelectShell gerufen wird. 428 429 xModel = pDocShell->GetModel(); 430 431 nDataCommandType = sdb::CommandType::TABLE; 432 nOutputType = MailMergeType::PRINTER; 433 bEscapeProcessing = sal_True; //!! allow to process properties like "Filter", "Order", ... 434 bSinglePrintJobs = sal_False; 435 bFileNameFromColumn = sal_False; 436 437 bDisposing = sal_False; 438 } 439 440 SwXMailMerge::~SwXMailMerge() 441 { 442 if (aTmpFileName.Len()) 443 DeleteTmpFile_Impl( xModel, xDocSh, aTmpFileName ); 444 else // there was no temporary file in use 445 { 446 //! we still need to close the model and doc shell manually 447 //! because there is no automatism that will do that later. 448 //! #120086# 449 if ( eVetoed == CloseModelAndDocSh( xModel, xDocSh ) ) 450 DBG_WARNING( "owner ship transferred to vetoing object!" ); 451 452 xModel = 0; 453 xDocSh = 0; // destroy doc shell 454 } 455 } 456 457 uno::Any SAL_CALL SwXMailMerge::execute( 458 const uno::Sequence< beans::NamedValue >& rArguments ) 459 { 460 vos::OGuard aGuard( Application::GetSolarMutex() ); 461 462 // 463 // get property values to be used 464 // (use values from the service as default and override them with 465 // the values that are provided as arguments) 466 // 467 uno::Sequence< uno::Any > aCurSelection = aSelection; 468 uno::Reference< sdbc::XResultSet > xCurResultSet = xResultSet; 469 uno::Reference< sdbc::XConnection > xCurConnection = xConnection; 470 uno::Reference< frame::XModel > xCurModel = xModel; 471 OUString aCurDataSourceName = aDataSourceName; 472 OUString aCurDataCommand = aDataCommand; 473 OUString aCurFilter = aFilter; 474 OUString aCurDocumentURL = aDocumentURL; 475 OUString aCurOutputURL = aOutputURL; 476 OUString aCurFileNamePrefix = aFileNamePrefix; 477 sal_Int32 nCurDataCommandType = nDataCommandType; 478 sal_Int16 nCurOutputType = nOutputType; 479 sal_Bool bCurEscapeProcessing = bEscapeProcessing; 480 sal_Bool bCurSinglePrintJobs = bSinglePrintJobs; 481 sal_Bool bCurFileNameFromColumn = bFileNameFromColumn; 482 // 483 SfxObjectShellRef xCurDocSh = xDocSh; // the document 484 // 485 const beans::NamedValue *pArguments = rArguments.getConstArray(); 486 sal_Int32 nArgs = rArguments.getLength(); 487 for (sal_Int32 i = 0; i < nArgs; ++i) 488 { 489 const OUString &rName = pArguments[i].Name; 490 const Any &rValue = pArguments[i].Value; 491 492 sal_Bool bOK = sal_True; 493 if (rName.equalsAscii( GetPropName( UNO_NAME_SELECTION ) )) 494 bOK = rValue >>= aCurSelection; 495 else if (rName.equalsAscii( GetPropName( UNO_NAME_RESULT_SET ) )) 496 bOK = rValue >>= xCurResultSet; 497 else if (rName.equalsAscii( GetPropName( UNO_NAME_CONNECTION ) )) 498 bOK = rValue >>= xCurConnection; 499 else if (rName.equalsAscii( GetPropName( UNO_NAME_MODEL ) )) 500 throw PropertyVetoException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property is read-only: " ) ) + rName, static_cast < cppu::OWeakObject * > ( this ) ); 501 else if (rName.equalsAscii( GetPropName( UNO_NAME_DATA_SOURCE_NAME ) )) 502 bOK = rValue >>= aCurDataSourceName; 503 else if (rName.equalsAscii( GetPropName( UNO_NAME_DAD_COMMAND ) )) 504 bOK = rValue >>= aCurDataCommand; 505 else if (rName.equalsAscii( GetPropName( UNO_NAME_FILTER ) )) 506 bOK = rValue >>= aCurFilter; 507 else if (rName.equalsAscii( GetPropName( UNO_NAME_DOCUMENT_URL ) )) 508 { 509 bOK = rValue >>= aCurDocumentURL; 510 if (aCurDocumentURL.getLength() 511 && !LoadFromURL_impl( xCurModel, xCurDocSh, aCurDocumentURL, sal_False )) 512 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to create document from URL: " ) ) + aCurDocumentURL, static_cast < cppu::OWeakObject * > ( this ) ); 513 } 514 else if (rName.equalsAscii( GetPropName( UNO_NAME_OUTPUT_URL ) )) 515 { 516 bOK = rValue >>= aCurOutputURL; 517 if (aCurOutputURL.getLength()) 518 { 519 if (!UCB_IsDirectory(aCurOutputURL)) 520 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL does not point to a directory: " ) ) + aCurOutputURL, static_cast < cppu::OWeakObject * > ( this ), 0 ); 521 if (UCB_IsReadOnlyFileName(aCurOutputURL)) 522 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL is read-only: " ) ) + aCurOutputURL, static_cast < cppu::OWeakObject * > ( this ), 0 ); 523 } 524 } 525 else if (rName.equalsAscii( GetPropName( UNO_NAME_FILE_NAME_PREFIX ) )) 526 bOK = rValue >>= aCurFileNamePrefix; 527 else if (rName.equalsAscii( GetPropName( UNO_NAME_DAD_COMMAND_TYPE ) )) 528 bOK = rValue >>= nCurDataCommandType; 529 else if (rName.equalsAscii( GetPropName( UNO_NAME_OUTPUT_TYPE ) )) 530 bOK = rValue >>= nCurOutputType; 531 else if (rName.equalsAscii( GetPropName( UNO_NAME_ESCAPE_PROCESSING ) )) 532 bOK = rValue >>= bCurEscapeProcessing; 533 else if (rName.equalsAscii( GetPropName( UNO_NAME_SINGLE_PRINT_JOBS ) )) 534 bOK = rValue >>= bCurSinglePrintJobs; 535 else if (rName.equalsAscii( GetPropName( UNO_NAME_FILE_NAME_FROM_COLUMN ) )) 536 bOK = rValue >>= bCurFileNameFromColumn; 537 else if (rName.equalsAscii( GetPropName( UNO_NAME_SUBJECT ) )) 538 bOK = rValue >>= sSubject; 539 else if (rName.equalsAscii( GetPropName( UNO_NAME_ADDRESS_FROM_COLUMN ) )) 540 bOK = rValue >>= sAddressFromColumn; 541 else if (rName.equalsAscii( GetPropName( UNO_NAME_SEND_AS_HTML ) )) 542 bOK = rValue >>= bSendAsHTML; 543 else if (rName.equalsAscii( GetPropName( UNO_NAME_MAIL_BODY ) )) 544 bOK = rValue >>= sMailBody; 545 else if (rName.equalsAscii( GetPropName( UNO_NAME_ATTACHMENT_NAME ) )) 546 bOK = rValue >>= sAttachmentName; 547 else if (rName.equalsAscii( GetPropName( UNO_NAME_ATTACHMENT_FILTER ) )) 548 bOK = rValue >>= sAttachmentFilter; 549 else if (rName.equalsAscii( GetPropName( UNO_NAME_COPIES_TO ) )) 550 bOK = rValue >>= aCopiesTo; 551 else if (rName.equalsAscii( GetPropName( UNO_NAME_BLIND_COPIES_TO ) )) 552 bOK = rValue >>= aBlindCopiesTo; 553 else if (rName.equalsAscii( GetPropName( UNO_NAME_SEND_AS_ATTACHMENT ) )) 554 bOK = rValue >>= bSendAsAttachment; 555 else if (rName.equalsAscii( GetPropName( UNO_NAME_PRINT_OPTIONS ) )) 556 bOK = rValue >>= aPrintSettings; 557 else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_AS_SINGLE_FILE ) )) 558 bOK = rValue >>= bSaveAsSingleFile; 559 else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_FILTER ) )) 560 bOK = rValue >>= sSaveFilter; 561 else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_FILTER_OPTIONS ) )) 562 bOK = rValue >>= sSaveFilterOptions; 563 else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_FILTER_DATA ) )) 564 bOK = rValue >>= aSaveFilterData; 565 else if (rName.equalsAscii( GetPropName( UNO_NAME_IN_SERVER_PASSWORD ) )) 566 bOK = rValue >>= sInServerPassword; 567 else if (rName.equalsAscii( GetPropName( UNO_NAME_OUT_SERVER_PASSWORD ) )) 568 bOK = rValue >>= sOutServerPassword; 569 else 570 throw UnknownPropertyException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property is unknown: " ) ) + rName, static_cast < cppu::OWeakObject * > ( this ) ); 571 572 if (!bOK) 573 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property type mismatch or property not set: " ) ) + rName, static_cast < cppu::OWeakObject * > ( this ), 0 ); 574 } 575 576 // need to translate the selection: the API here requires a sequence of bookmarks, but the MergeNew 577 // method we will call below requires a sequence of indicies. 578 if ( aCurSelection.getLength() ) 579 { 580 Sequence< Any > aTranslated( aCurSelection.getLength() ); 581 582 sal_Bool bValid = sal_False; 583 Reference< sdbcx::XRowLocate > xRowLocate( xCurResultSet, UNO_QUERY ); 584 if ( xRowLocate.is() ) 585 { 586 587 const Any* pBookmarks = aCurSelection.getConstArray(); 588 const Any* pBookmarksEnd = pBookmarks + aCurSelection.getLength(); 589 Any* pTranslated = aTranslated.getArray(); 590 591 try 592 { 593 sal_Bool bEverythingsFine = sal_True; 594 for ( ; ( pBookmarks != pBookmarksEnd ) && bEverythingsFine; ++pBookmarks ) 595 { 596 if ( xRowLocate->moveToBookmark( *pBookmarks ) ) 597 *pTranslated <<= xCurResultSet->getRow(); 598 else 599 bEverythingsFine = sal_False; 600 } 601 if ( bEverythingsFine ) 602 bValid = sal_True; 603 } 604 catch( const Exception& ) 605 { 606 bValid = sal_False; 607 } 608 } 609 610 if ( !bValid ) 611 { 612 throw IllegalArgumentException( 613 OUString ( RTL_CONSTASCII_USTRINGPARAM ( "The current 'Selection' does not describe a valid array of bookmarks, relative to the current 'ResultSet'." ) ), 614 static_cast < cppu::OWeakObject * > ( this ), 615 0 616 ); 617 } 618 619 aCurSelection = aTranslated; 620 } 621 622 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( xCurDocSh, sal_False); 623 SwView *pView = PTR_CAST( SwView, pFrame->GetViewShell() ); 624 if (!pView) 625 throw RuntimeException(); 626 SwWrtShell &rSh = *pView->GetWrtShellPtr(); 627 628 // avoid assertion in 'Update' from Sfx by supplying a shell 629 // and thus avoiding the SelectShell call in Writers GetState function 630 // while still in Update of Sfx. 631 // (GetSelection in Update is not allowed) 632 if (pView && aCurDocumentURL.getLength()) 633 pView->AttrChangedNotify( &pView->GetWrtShell() );//Damit SelectShell gerufen wird. 634 635 SharedComponent aRowSetDisposeHelper; 636 if (!xCurResultSet.is()) 637 { 638 if (!aCurDataSourceName.getLength() || !aCurDataCommand.getLength() ) 639 { 640 DBG_ERROR("PropertyValues missing or unset"); 641 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Either the ResultSet or DataSourceName and DataCommand must be set." ) ), static_cast < cppu::OWeakObject * > ( this ), 0 ); 642 } 643 644 // 645 // build ResultSet from DataSourceName, DataCommand and DataCommandType 646 // 647 Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); 648 if (xMgr.is()) 649 { 650 Reference< XInterface > xInstance = xMgr->createInstance( 651 C2U( "com.sun.star.sdb.RowSet" )); 652 aRowSetDisposeHelper.reset( xInstance, SharedComponent::TakeOwnership ); 653 Reference< XPropertySet > xRowSetPropSet( xInstance, UNO_QUERY ); 654 DBG_ASSERT( xRowSetPropSet.is(), "failed to get XPropertySet interface from RowSet" ); 655 if (xRowSetPropSet.is()) 656 { 657 if (xCurConnection.is()) 658 xRowSetPropSet->setPropertyValue( C2U("ActiveConnection"), makeAny( xCurConnection ) ); 659 xRowSetPropSet->setPropertyValue( C2U("DataSourceName"), makeAny( aCurDataSourceName ) ); 660 xRowSetPropSet->setPropertyValue( C2U("Command"), makeAny( aCurDataCommand ) ); 661 xRowSetPropSet->setPropertyValue( C2U("CommandType"), makeAny( nCurDataCommandType ) ); 662 xRowSetPropSet->setPropertyValue( C2U("EscapeProcessing"), makeAny( bCurEscapeProcessing ) ); 663 xRowSetPropSet->setPropertyValue( C2U("ApplyFilter"), makeAny( sal_True ) ); 664 xRowSetPropSet->setPropertyValue( C2U("Filter"), makeAny( aCurFilter ) ); 665 666 Reference< sdbc::XRowSet > xRowSet( xInstance, UNO_QUERY ); 667 if (xRowSet.is()) 668 xRowSet->execute(); // build ResultSet from properties 669 if( !xCurConnection.is() ) 670 xCurConnection.set( xRowSetPropSet->getPropertyValue( C2U( "ActiveConnection" )), UNO_QUERY ); 671 xCurResultSet = Reference< sdbc::XResultSet >( xRowSet, UNO_QUERY ); 672 DBG_ASSERT( xCurResultSet.is(), "failed to build ResultSet" ); 673 } 674 } 675 } 676 677 svx::ODataAccessDescriptor aDescriptor; 678 aDescriptor.setDataSource(aCurDataSourceName); 679 aDescriptor[ svx::daConnection ] <<= xCurConnection; 680 aDescriptor[ svx::daCommand ] <<= aCurDataCommand; 681 aDescriptor[ svx::daCommandType ] <<= nCurDataCommandType; 682 aDescriptor[ svx::daEscapeProcessing ] <<= bCurEscapeProcessing; 683 aDescriptor[ svx::daCursor ] <<= xCurResultSet; 684 // aDescriptor[ svx::daColumnName ] not used 685 // aDescriptor[ svx::daColumnObject ] not used 686 aDescriptor[ svx::daSelection ] <<= aCurSelection; 687 688 sal_uInt16 nMergeType; 689 switch (nCurOutputType) 690 { 691 case MailMergeType::PRINTER : nMergeType = DBMGR_MERGE_MAILMERGE; break; 692 case MailMergeType::FILE : nMergeType = DBMGR_MERGE_MAILFILES; break; 693 case MailMergeType::MAIL : nMergeType = DBMGR_MERGE_MAILING; break; 694 default: 695 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Invalid value of property:" ) ) + C2U("OutputType"), static_cast < cppu::OWeakObject * > ( this ), 0 ); 696 } 697 698 SwNewDBMgr* pMgr = rSh.GetNewDBMgr(); 699 //force layout creation 700 rSh.CalcLayout(); 701 DBG_ASSERT( pMgr, "database manager missing" ); 702 703 SwMergeDescriptor aMergeDesc( nMergeType, rSh, aDescriptor ); 704 705 std::auto_ptr< SwMailMergeConfigItem > pMMConfigItem; 706 uno::Reference< mail::XMailService > xInService; 707 if (MailMergeType::PRINTER == nCurOutputType) 708 { 709 IDocumentDeviceAccess* pIDDA = rSh.getIDocumentDeviceAccess(); 710 SwPrintData aPrtData( pIDDA->getPrintData() ); 711 aPrtData.SetPrintSingleJobs( bCurSinglePrintJobs ); 712 pIDDA->setPrintData( aPrtData ); 713 // #i25686# printing should not be done asynchronously to prevent dangling offices 714 // when mail merge is called as command line macro 715 aMergeDesc.bPrintAsync = sal_False; 716 aMergeDesc.aPrintOptions = aPrintSettings; 717 aMergeDesc.bCreateSingleFile = true; 718 } 719 else /* FILE and MAIL*/ 720 { 721 INetURLObject aURLObj; 722 aURLObj.SetSmartProtocol( INET_PROT_FILE ); 723 724 if (aCurDocumentURL.getLength()) 725 { 726 // if OutputURL or FileNamePrefix are missing get 727 // them from DocumentURL 728 aURLObj.SetSmartURL( aCurDocumentURL ); 729 if (!aCurFileNamePrefix.getLength()) 730 aCurFileNamePrefix = aURLObj.GetBase(); // filename without extension 731 if (!aCurOutputURL.getLength()) 732 { 733 //aCurOutputURL = aURLObj.GetURLPath(); 734 aURLObj.removeSegment(); 735 aCurOutputURL = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); 736 } 737 } 738 else // default empty document without URL 739 { 740 if (!aCurOutputURL.getLength()) 741 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "OutputURL is not set and can not be obtained." ) ), static_cast < cppu::OWeakObject * > ( this ) ); 742 } 743 744 aURLObj.SetSmartURL( aCurOutputURL ); 745 String aPath = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); 746 747 String aDelim( INET_PATH_TOKEN ); 748 if (aPath.Len() >= aDelim.Len() && 749 aPath.Copy( aPath.Len()-aDelim.Len() ).CompareTo( aDelim ) != COMPARE_EQUAL) 750 aPath += aDelim; 751 if (bCurFileNameFromColumn) 752 pMgr->SetEMailColumn( aCurFileNamePrefix ); 753 else 754 { 755 aPath += String( aCurFileNamePrefix ); 756 pMgr->SetEMailColumn( String() ); 757 } 758 pMgr->SetSubject( aPath ); 759 if(MailMergeType::FILE == nCurOutputType) 760 { 761 aMergeDesc.sSaveToFilter = sSaveFilter; 762 aMergeDesc.sSaveToFilterOptions = sSaveFilterOptions; 763 aMergeDesc.aSaveToFilterData = aSaveFilterData; 764 aMergeDesc.bCreateSingleFile = bSaveAsSingleFile; 765 } 766 else /*if(MailMergeType::MAIL == nCurOutputType)*/ 767 { 768 pMgr->SetEMailColumn( sAddressFromColumn ); 769 if(!sAddressFromColumn.getLength()) 770 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Mail address column not set." ) ), static_cast < cppu::OWeakObject * > ( this ) ); 771 aMergeDesc.sSaveToFilter = sAttachmentFilter; 772 aMergeDesc.sSubject = sSubject; 773 aMergeDesc.sMailBody = sMailBody; 774 aMergeDesc.sAttachmentName = sAttachmentName; 775 aMergeDesc.aCopiesTo = aCopiesTo; 776 aMergeDesc.aBlindCopiesTo = aBlindCopiesTo; 777 aMergeDesc.bSendAsHTML = bSendAsHTML; 778 aMergeDesc.bSendAsAttachment = bSendAsAttachment; 779 780 aMergeDesc.bCreateSingleFile = sal_False; 781 pMMConfigItem = std::auto_ptr< SwMailMergeConfigItem >(new SwMailMergeConfigItem); 782 aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get(); 783 aMergeDesc.xSmtpServer = SwMailMergeHelper::ConnectToSmtpServer( 784 *pMMConfigItem, 785 xInService, 786 sInServerPassword, sOutServerPassword ); 787 if( !aMergeDesc.xSmtpServer.is() || !aMergeDesc.xSmtpServer->isConnected()) 788 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to connect to mail server." ) ), static_cast < cppu::OWeakObject * > ( this ) ); 789 } 790 } 791 792 793 // save document with temporary filename 794 const SfxFilter *pSfxFlt = SwIoSystem::GetFilterOfFormat( 795 String::CreateFromAscii( FILTER_XML ), 796 SwDocShell::Factory().GetFilterContainer() ); 797 String aExtension( pSfxFlt->GetDefaultExtension() ); 798 aExtension.EraseLeadingChars( '*' ); 799 TempFile aTempFile( C2U("SwMM"), &aExtension ); 800 aTmpFileName = aTempFile.GetName(); 801 802 Reference< XStorable > xStorable( xCurModel, UNO_QUERY ); 803 sal_Bool bStoredAsTemporary = sal_False; 804 if ( xStorable.is() ) 805 { 806 try 807 { 808 xStorable->storeAsURL( aTmpFileName, Sequence< PropertyValue >() ); 809 bStoredAsTemporary = sal_True; 810 } 811 catch( const Exception& ) 812 { 813 } 814 } 815 if ( !bStoredAsTemporary ) 816 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to save temporary file." ) ), static_cast < cppu::OWeakObject * > ( this ) ); 817 818 pMgr->SetMergeSilent( sal_True ); // suppress dialogs, message boxes, etc. 819 const SwXMailMerge *pOldSrc = pMgr->GetMailMergeEvtSrc(); 820 DBG_ASSERT( !pOldSrc || pOldSrc == this, "Ooops... different event source already set." ); 821 pMgr->SetMailMergeEvtSrc( this ); // launch events for listeners 822 823 SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE), xCurDocSh)); 824 sal_Bool bSucc = pMgr->MergeNew( aMergeDesc ); 825 SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE_END, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END), xCurDocSh)); 826 827 pMgr->SetMailMergeEvtSrc( pOldSrc ); 828 829 if ( xCurModel.get() != xModel.get() ) 830 { // in case it was a temporary model -> close it, and delete the file 831 DeleteTmpFile_Impl( xCurModel, xCurDocSh, aTmpFileName ); 832 aTmpFileName.Erase(); 833 } 834 // (in case it wasn't a temporary model, it will be closed in the dtor, at the latest) 835 836 if (!bSucc) 837 throw Exception( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Mail merge failed. Sorry, no further information available." ) ), static_cast < cppu::OWeakObject * > ( this ) ); 838 839 //de-initialize services 840 if(xInService.is() && xInService->isConnected()) 841 xInService->disconnect(); 842 if(aMergeDesc.xSmtpServer.is() && aMergeDesc.xSmtpServer->isConnected()) 843 aMergeDesc.xSmtpServer->disconnect(); 844 845 return makeAny( sal_True ); 846 } 847 848 void SwXMailMerge::LaunchMailMergeEvent( const MailMergeEvent &rEvt ) const 849 { 850 cppu::OInterfaceIteratorHelper aIt( ((SwXMailMerge *) this)->aMergeListeners ); 851 while (aIt.hasMoreElements()) 852 { 853 Reference< XMailMergeListener > xRef( aIt.next(), UNO_QUERY ); 854 if (xRef.is()) 855 xRef->notifyMailMergeEvent( rEvt ); 856 } 857 } 858 859 void SwXMailMerge::launchEvent( const PropertyChangeEvent &rEvt ) const 860 { 861 cppu::OInterfaceContainerHelper *pContainer = 862 aPropListeners.getContainer( rEvt.PropertyHandle ); 863 if (pContainer) 864 { 865 cppu::OInterfaceIteratorHelper aIt( *pContainer ); 866 while (aIt.hasMoreElements()) 867 { 868 Reference< XPropertyChangeListener > xRef( aIt.next(), UNO_QUERY ); 869 if (xRef.is()) 870 xRef->propertyChange( rEvt ); 871 } 872 } 873 } 874 875 876 uno::Reference< beans::XPropertySetInfo > SAL_CALL SwXMailMerge::getPropertySetInfo( ) 877 { 878 vos::OGuard aGuard( Application::GetSolarMutex() ); 879 static Reference< XPropertySetInfo > aRef = pPropSet->getPropertySetInfo(); 880 return aRef; 881 } 882 883 void SAL_CALL SwXMailMerge::setPropertyValue( 884 const OUString& rPropertyName, const uno::Any& rValue ) 885 { 886 vos::OGuard aGuard( Application::GetSolarMutex() ); 887 888 const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName ); 889 if (!pCur) 890 throw UnknownPropertyException(); 891 else if (pCur->nFlags & PropertyAttribute::READONLY) 892 throw PropertyVetoException(); 893 else 894 { 895 void *pData = NULL; 896 const uno::Type* pType = pCur->pType; 897 switch (pCur->nWID) 898 { 899 case WID_SELECTION : pData = &aSelection; break; 900 case WID_RESULT_SET : pData = &xResultSet; break; 901 case WID_CONNECTION : pData = &xConnection; break; 902 case WID_MODEL : pData = &xModel; break; 903 case WID_DATA_SOURCE_NAME : pData = &aDataSourceName; break; 904 case WID_DATA_COMMAND : pData = &aDataCommand; break; 905 case WID_FILTER : pData = &aFilter; break; 906 case WID_DOCUMENT_URL : pData = &aDocumentURL; break; 907 case WID_OUTPUT_URL : pData = &aOutputURL; break; 908 case WID_DATA_COMMAND_TYPE : pData = &nDataCommandType; break; 909 case WID_OUTPUT_TYPE : pData = &nOutputType; break; 910 case WID_ESCAPE_PROCESSING : pData = &bEscapeProcessing; break; 911 case WID_SINGLE_PRINT_JOBS : pData = &bSinglePrintJobs; break; 912 case WID_FILE_NAME_FROM_COLUMN : pData = &bFileNameFromColumn; break; 913 case WID_FILE_NAME_PREFIX : pData = &aFileNamePrefix; break; 914 case WID_MAIL_SUBJECT: pData = &sSubject; break; 915 case WID_ADDRESS_FROM_COLUMN: pData = &sAddressFromColumn; break; 916 case WID_SEND_AS_HTML: pData = &bSendAsHTML; break; 917 case WID_SEND_AS_ATTACHMENT: pData = &bSendAsAttachment; break; 918 case WID_MAIL_BODY: pData = &sMailBody; break; 919 case WID_ATTACHMENT_NAME: pData = &sAttachmentName; break; 920 case WID_ATTACHMENT_FILTER: pData = &sAttachmentFilter;break; 921 case WID_PRINT_OPTIONS: pData = &aPrintSettings; break; 922 case WID_SAVE_AS_SINGLE_FILE: pData = &bSaveAsSingleFile; break; 923 case WID_SAVE_FILTER: pData = &sSaveFilter; break; 924 case WID_SAVE_FILTER_OPTIONS: pData = &sSaveFilterOptions; break; 925 case WID_SAVE_FILTER_DATA: pData = &aSaveFilterData; break; 926 case WID_COPIES_TO: pData = &aCopiesTo; break; 927 case WID_BLIND_COPIES_TO: pData = &aBlindCopiesTo;break; 928 case WID_IN_SERVER_PASSWORD: pData = &sInServerPassword; break; 929 case WID_OUT_SERVER_PASSWORD: pData = &sOutServerPassword; break; 930 default : 931 DBG_ERROR("unknown WID"); 932 } 933 Any aOld( pData, *pType ); 934 935 sal_Bool bChanged = sal_False; 936 sal_Bool bOK = sal_True; 937 if (aOld != rValue) 938 { 939 if (pData == &aSelection) 940 bOK = rValue >>= aSelection; 941 else if (pData == &xResultSet) 942 bOK = rValue >>= xResultSet; 943 else if (pData == &xConnection) 944 bOK = rValue >>= xConnection; 945 else if (pData == &xModel) 946 bOK = rValue >>= xModel; 947 else if (pData == &aDataSourceName) 948 bOK = rValue >>= aDataSourceName; 949 else if (pData == &aDataCommand) 950 bOK = rValue >>= aDataCommand; 951 else if (pData == &aFilter) 952 bOK = rValue >>= aFilter; 953 else if (pData == &aDocumentURL) 954 { 955 OUString aText; 956 bOK = rValue >>= aText; 957 if (aText.getLength() 958 && !LoadFromURL_impl( xModel, xDocSh, aText, sal_True )) 959 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to create document from URL: " ) ) + aText, static_cast < cppu::OWeakObject * > ( this ) ); 960 aDocumentURL = aText; 961 } 962 else if (pData == &aOutputURL) 963 { 964 OUString aText; 965 bOK = rValue >>= aText; 966 if (aText.getLength()) 967 { 968 if (!UCB_IsDirectory(aText)) 969 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL does not point to a directory: " ) ) + aText, static_cast < cppu::OWeakObject * > ( this ), 0 ); 970 if (UCB_IsReadOnlyFileName(aText)) 971 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL is read-only: " ) ) + aText, static_cast < cppu::OWeakObject * > ( this ), 0 ); 972 } 973 aOutputURL = aText; 974 } 975 else if (pData == &nDataCommandType) 976 bOK = rValue >>= nDataCommandType; 977 else if (pData == &nOutputType) 978 bOK = rValue >>= nOutputType; 979 else if (pData == &bEscapeProcessing) 980 bOK = rValue >>= bEscapeProcessing; 981 else if (pData == &bSinglePrintJobs) 982 bOK = rValue >>= bSinglePrintJobs; 983 else if (pData == &bFileNameFromColumn) 984 bOK = rValue >>= bFileNameFromColumn; 985 else if (pData == &aFileNamePrefix) 986 bOK = rValue >>= aFileNamePrefix; 987 else if (pData == &sSubject) 988 bOK = rValue >>= sSubject; 989 else if (pData == &sAddressFromColumn) 990 bOK = rValue >>= sAddressFromColumn; 991 else if (pData == &bSendAsHTML) 992 bOK = rValue >>= bSendAsHTML; 993 else if (pData == &bSendAsAttachment) 994 bOK = rValue >>= bSendAsAttachment; 995 else if (pData == &sMailBody) 996 bOK = rValue >>= sMailBody; 997 else if (pData == &sAttachmentName) 998 bOK = rValue >>= sAttachmentName; 999 else if (pData == &sAttachmentFilter) 1000 bOK = rValue >>= sAttachmentFilter; 1001 else if (pData == &aPrintSettings) 1002 bOK = rValue >>= aPrintSettings; 1003 else if (pData == &bSaveAsSingleFile) 1004 bOK = rValue >>= bSaveAsSingleFile; 1005 else if (pData == &sSaveFilter) 1006 bOK = rValue >>= sSaveFilter; 1007 else if (pData == &sSaveFilterOptions) 1008 bOK = rValue >>= sSaveFilterOptions; 1009 else if (pData == &aSaveFilterData) 1010 bOK = rValue >>= aSaveFilterData; 1011 else if (pData == &aCopiesTo) 1012 bOK = rValue >>= aCopiesTo; 1013 else if (pData == &aBlindCopiesTo) 1014 bOK = rValue >>= aBlindCopiesTo; 1015 else if(pData == &sInServerPassword) 1016 bOK = rValue >>= sInServerPassword; 1017 else if(pData == &sOutServerPassword) 1018 bOK = rValue >>= sInServerPassword; 1019 else { 1020 DBG_ERROR( "invalid pointer" ); 1021 } 1022 DBG_ASSERT( bOK, "set value failed" ); 1023 bChanged = sal_True; 1024 } 1025 if (!bOK) 1026 throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property type mismatch or property not set: " ) ) + rPropertyName, static_cast < cppu::OWeakObject * > ( this ), 0 ); 1027 1028 if (bChanged) 1029 { 1030 PropertyChangeEvent aChgEvt( (XPropertySet *) this, rPropertyName, 1031 sal_False, pCur->nWID, aOld, rValue ); 1032 launchEvent( aChgEvt ); 1033 } 1034 } 1035 } 1036 1037 uno::Any SAL_CALL SwXMailMerge::getPropertyValue( 1038 const OUString& rPropertyName ) 1039 { 1040 vos::OGuard aGuard( Application::GetSolarMutex() ); 1041 1042 Any aRet; 1043 1044 const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName ); 1045 if (!pCur) 1046 throw UnknownPropertyException(); 1047 else 1048 { 1049 switch (pCur->nWID) 1050 { 1051 case WID_SELECTION : aRet <<= aSelection; break; 1052 case WID_RESULT_SET : aRet <<= xResultSet; break; 1053 case WID_CONNECTION : aRet <<= xConnection; break; 1054 case WID_MODEL : aRet <<= xModel; break; 1055 case WID_DATA_SOURCE_NAME : aRet <<= aDataSourceName; break; 1056 case WID_DATA_COMMAND : aRet <<= aDataCommand; break; 1057 case WID_FILTER : aRet <<= aFilter; break; 1058 case WID_DOCUMENT_URL : aRet <<= aDocumentURL; break; 1059 case WID_OUTPUT_URL : aRet <<= aOutputURL; break; 1060 case WID_DATA_COMMAND_TYPE : aRet <<= nDataCommandType; break; 1061 case WID_OUTPUT_TYPE : aRet <<= nOutputType; break; 1062 case WID_ESCAPE_PROCESSING : aRet <<= bEscapeProcessing; break; 1063 case WID_SINGLE_PRINT_JOBS : aRet <<= bSinglePrintJobs; break; 1064 case WID_FILE_NAME_FROM_COLUMN : aRet <<= bFileNameFromColumn; break; 1065 case WID_FILE_NAME_PREFIX : aRet <<= aFileNamePrefix; break; 1066 case WID_MAIL_SUBJECT: aRet <<= sSubject; break; 1067 case WID_ADDRESS_FROM_COLUMN: aRet <<= sAddressFromColumn; break; 1068 case WID_SEND_AS_HTML: aRet <<= bSendAsHTML; break; 1069 case WID_SEND_AS_ATTACHMENT: aRet <<= bSendAsAttachment; break; 1070 case WID_MAIL_BODY: aRet <<= sMailBody; break; 1071 case WID_ATTACHMENT_NAME: aRet <<= sAttachmentName; break; 1072 case WID_ATTACHMENT_FILTER: aRet <<= sAttachmentFilter;break; 1073 case WID_PRINT_OPTIONS: aRet <<= aPrintSettings; break; 1074 case WID_SAVE_AS_SINGLE_FILE: aRet <<= bSaveAsSingleFile; break; 1075 case WID_SAVE_FILTER: aRet <<= sSaveFilter; break; 1076 case WID_SAVE_FILTER_OPTIONS: aRet <<= sSaveFilterOptions; break; 1077 case WID_SAVE_FILTER_DATA: aRet <<= aSaveFilterData; break; 1078 case WID_COPIES_TO: aRet <<= aCopiesTo; break; 1079 case WID_BLIND_COPIES_TO: aRet <<= aBlindCopiesTo;break; 1080 case WID_IN_SERVER_PASSWORD: aRet <<= sInServerPassword; break; 1081 case WID_OUT_SERVER_PASSWORD: aRet <<= sOutServerPassword; break; 1082 default : 1083 DBG_ERROR("unknown WID"); 1084 } 1085 } 1086 1087 return aRet; 1088 } 1089 1090 void SAL_CALL SwXMailMerge::addPropertyChangeListener( 1091 const OUString& rPropertyName, 1092 const uno::Reference< beans::XPropertyChangeListener >& rListener ) 1093 { 1094 vos::OGuard aGuard( Application::GetSolarMutex() ); 1095 if (!bDisposing && rListener.is()) 1096 { 1097 const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName ); 1098 if (pCur) 1099 aPropListeners.addInterface( pCur->nWID, rListener ); 1100 else 1101 throw UnknownPropertyException(); 1102 } 1103 } 1104 1105 void SAL_CALL SwXMailMerge::removePropertyChangeListener( 1106 const OUString& rPropertyName, 1107 const uno::Reference< beans::XPropertyChangeListener >& rListener ) 1108 { 1109 vos::OGuard aGuard( Application::GetSolarMutex() ); 1110 if (!bDisposing && rListener.is()) 1111 { 1112 const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName ); 1113 if (pCur) 1114 aPropListeners.removeInterface( pCur->nWID, rListener ); 1115 else 1116 throw UnknownPropertyException(); 1117 } 1118 } 1119 1120 void SAL_CALL SwXMailMerge::addVetoableChangeListener( 1121 const OUString& /*rPropertyName*/, 1122 const uno::Reference< beans::XVetoableChangeListener >& /*rListener*/ ) 1123 { 1124 // no vetoable property, thus no support for vetoable change listeners 1125 DBG_WARNING( "not implemented"); 1126 } 1127 1128 void SAL_CALL SwXMailMerge::removeVetoableChangeListener( 1129 const OUString& /*rPropertyName*/, 1130 const uno::Reference< beans::XVetoableChangeListener >& /*rListener*/ ) 1131 { 1132 // no vetoable property, thus no support for vetoable change listeners 1133 DBG_WARNING( "not implemented"); 1134 } 1135 1136 1137 void SAL_CALL SwXMailMerge::dispose() 1138 { 1139 vos::OGuard aGuard( Application::GetSolarMutex() ); 1140 1141 if (!bDisposing) 1142 { 1143 bDisposing = sal_True; 1144 1145 EventObject aEvtObj( (XPropertySet *) this ); 1146 aEvtListeners.disposeAndClear( aEvtObj ); 1147 aMergeListeners.disposeAndClear( aEvtObj ); 1148 aPropListeners.disposeAndClear( aEvtObj ); 1149 } 1150 } 1151 1152 void SAL_CALL SwXMailMerge::addEventListener( 1153 const Reference< XEventListener >& rxListener ) 1154 { 1155 vos::OGuard aGuard( Application::GetSolarMutex() ); 1156 if (!bDisposing && rxListener.is()) 1157 aEvtListeners.addInterface( rxListener ); 1158 } 1159 1160 void SAL_CALL SwXMailMerge::removeEventListener( 1161 const Reference< XEventListener >& rxListener ) 1162 { 1163 vos::OGuard aGuard( Application::GetSolarMutex() ); 1164 if (!bDisposing && rxListener.is()) 1165 aEvtListeners.removeInterface( rxListener ); 1166 } 1167 1168 void SAL_CALL SwXMailMerge::addMailMergeEventListener( 1169 const uno::Reference< XMailMergeListener >& rxListener ) 1170 { 1171 vos::OGuard aGuard( Application::GetSolarMutex() ); 1172 if (!bDisposing && rxListener.is()) 1173 aMergeListeners.addInterface( rxListener ); 1174 } 1175 1176 void SAL_CALL SwXMailMerge::removeMailMergeEventListener( 1177 const uno::Reference< XMailMergeListener >& rxListener ) 1178 { 1179 vos::OGuard aGuard( Application::GetSolarMutex() ); 1180 if (!bDisposing && rxListener.is()) 1181 aMergeListeners.removeInterface( rxListener ); 1182 } 1183 1184 OUString SAL_CALL SwXMailMerge::getImplementationName() 1185 { 1186 vos::OGuard aGuard( Application::GetSolarMutex() ); 1187 return SwXMailMerge_getImplementationName(); 1188 } 1189 1190 sal_Bool SAL_CALL SwXMailMerge::supportsService( const OUString& rServiceName ) 1191 { 1192 vos::OGuard aGuard( Application::GetSolarMutex() ); 1193 return C2U( SN_MAIL_MERGE ) == rServiceName || 1194 C2U( SN_DATA_ACCESS_DESCRIPTOR ) == rServiceName; 1195 } 1196 1197 uno::Sequence< OUString > SAL_CALL SwXMailMerge::getSupportedServiceNames() 1198 { 1199 vos::OGuard aGuard( Application::GetSolarMutex() ); 1200 return SwXMailMerge_getSupportedServiceNames(); 1201 } 1202 1203 //////////////////////////////////////////////////////////// 1204 1205 uno::Sequence< OUString > SAL_CALL SwXMailMerge_getSupportedServiceNames() 1206 throw() 1207 { 1208 uno::Sequence< OUString > aNames(2); 1209 OUString *pName = aNames.getArray(); 1210 pName[0] = C2U( SN_MAIL_MERGE ); 1211 pName[1] = C2U( SN_DATA_ACCESS_DESCRIPTOR ); 1212 return aNames; 1213 } 1214 1215 OUString SAL_CALL SwXMailMerge_getImplementationName() 1216 throw() 1217 { 1218 return OUString( C2U( "SwXMailMerge" ) ); 1219 } 1220 1221 uno::Reference< uno::XInterface > SAL_CALL SwXMailMerge_createInstance( 1222 const uno::Reference< XMultiServiceFactory > & /*rSMgr*/) 1223 { 1224 vos::OGuard aGuard( Application::GetSolarMutex() ); 1225 1226 //the module may not be loaded 1227 SwDLL::Init(); 1228 uno::Reference< uno::XInterface > xRef = (cppu::OWeakObject *) new SwXMailMerge(); 1229 return xRef; 1230 } 1231