1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/servicehelper.hxx>
22 #include <vcl/svapp.hxx>
23 #include <osl/mutex.hxx>
24 #include <svl/itemprop.hxx>
25 #include <svx/dataaccessdescriptor.hxx>
26 #include <unotools/tempfile.hxx>
27 #include <sfx2/app.hxx>
28 #include <sfx2/docfilt.hxx>
29 #include <tools/urlobj.hxx>
30 #include <comphelper/diagnose_ex.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/propertyvalue.hxx>
33 #include <comphelper/string.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <vcl/timer.hxx>
36 #include <com/sun/star/sdb/CommandType.hpp>
37 #include <com/sun/star/text/MailMergeType.hpp>
38 #include <com/sun/star/text/MailMergeEvent.hpp>
39 #include <com/sun/star/text/XMailMergeListener.hpp>
40 #include <com/sun/star/beans/PropertyAttribute.hpp>
41 #include <com/sun/star/sdbc/XResultSet.hpp>
42 #include <com/sun/star/sdbc/XConnection.hpp>
43 #include <com/sun/star/sdbc/XRowSet.hpp>
44 #include <com/sun/star/frame/Desktop.hpp>
45 #include <com/sun/star/util/XCloseable.hpp>
46 #include <com/sun/star/util/CloseVetoException.hpp>
47 #include <com/sun/star/sdbcx/XRowLocate.hpp>
48 #include <com/sun/star/frame/XStorable.hpp>
49 #include <com/sun/star/mail/XSmtpService.hpp>
50 #include <sfx2/viewfrm.hxx>
51 #include <sfx2/event.hxx>
52 #include <cppuhelper/implbase.hxx>
53 #include <printdata.hxx>
54 #include <swevent.hxx>
55 #include <unomailmerge.hxx>
56 #include <unoprnms.hxx>
58 #include <swunohelper.hxx>
60 #include <IDocumentDeviceAccess.hxx>
63 #include <unotxdoc.hxx>
65 #include <mmconfigitem.hxx>
66 #include <mailmergehelper.hxx>
68 #include <iodetect.hxx>
72 using namespace ::com::sun::star
;
73 using namespace ::com::sun::star::frame
;
74 using namespace ::com::sun::star::uno
;
75 using namespace ::com::sun::star::lang
;
76 using namespace ::com::sun::star::beans
;
77 using namespace ::com::sun::star::text
;
78 using namespace SWUnoHelper
;
80 typedef ::utl::SharedUNOComponent
< XInterface
> SharedComponent
;
82 static osl::Mutex
& GetMailMergeMutex()
84 static osl::Mutex aMutex
;
92 eSuccess
, // successfully closed
93 eVetoed
, // vetoed, ownership transferred to the vetoing instance
94 eFailed
// failed for some unknown reason
99 static CloseResult
CloseModelAndDocSh(
100 Reference
< frame::XModel
> const &rxModel
,
101 SfxObjectShellRef
&rxDocSh
)
103 CloseResult eResult
= eSuccess
;
107 //! models/documents should never be disposed (they may still be
108 //! used for printing which is called asynchronously for example)
109 //! instead call close
110 Reference
< util::XCloseable
> xClose( rxModel
, UNO_QUERY
);
115 //! 'sal_True' -> transfer ownership to vetoing object if vetoed!
116 //! I.e. now that object is responsible for closing the model and doc shell.
117 xClose
->close( true );
119 catch (const util::CloseVetoException
&)
121 //! here we have the problem that the temporary file that is
122 //! currently being printed will never be deleted. :-(
125 catch (const uno::RuntimeException
&)
133 /// @throws RuntimeException
134 static bool LoadFromURL_impl(
135 Reference
< frame::XModel
> &rxModel
,
136 SfxObjectShellRef
&rxDocSh
,
137 const OUString
&rURL
,
140 // try to open the document readonly and hidden
141 Reference
< frame::XModel
> xTmpModel
;
142 Sequence
< PropertyValue
> aArgs
{ comphelper::makePropertyValue("Hidden", true) };
145 Reference
< XDesktop2
> xDesktop
= Desktop::create( ::comphelper::getProcessComponentContext() );
146 xTmpModel
.set( xDesktop
->loadComponentFromURL( rURL
, "_blank", 0, aArgs
), UNO_QUERY
);
148 catch (const Exception
&)
153 // try to get the DocShell
154 SwDocShell
*pTmpDocShell
= nullptr;
155 if (auto pTextDoc
= comphelper::getFromUnoTunnel
<SwXTextDocument
>(xTmpModel
); pTextDoc
)
156 pTmpDocShell
= pTextDoc
->GetDocShell();
159 if (xTmpModel
.is() && pTmpDocShell
) // everything available?
162 CloseModelAndDocSh( rxModel
, rxDocSh
);
165 rxDocSh
= pTmpDocShell
;
170 // SfxObjectShellRef is ok here, since the document will be explicitly closed
171 SfxObjectShellRef xTmpDocSh
= pTmpDocShell
;
172 CloseModelAndDocSh( xTmpModel
, xTmpDocSh
);
180 class DelayedFileDeletion
: public ::cppu::WeakImplHelper
<util::XCloseListener
>
183 ::osl::Mutex m_aMutex
;
184 Reference
< util::XCloseable
> m_xDocument
;
185 Timer m_aDeleteTimer
;
186 OUString m_sTemporaryFile
;
187 sal_Int32 m_nPendingDeleteAttempts
;
189 DelayedFileDeletion(DelayedFileDeletion
const&) = delete;
190 DelayedFileDeletion
& operator=(DelayedFileDeletion
const&) = delete;
193 DelayedFileDeletion( const Reference
< XModel
>& _rxModel
,
194 OUString _aTemporaryFile
);
197 virtual ~DelayedFileDeletion( ) override
;
200 virtual void SAL_CALL
queryClosing( const EventObject
& _rSource
, sal_Bool _bGetsOwnership
) override
;
201 virtual void SAL_CALL
notifyClosing( const EventObject
& _rSource
) override
;
204 virtual void SAL_CALL
disposing( const EventObject
& Source
) override
;
207 void implTakeOwnership( );
208 DECL_LINK( OnTryDeleteFile
, Timer
*, void );
211 DelayedFileDeletion::DelayedFileDeletion( const Reference
< XModel
>& _rxModel
, OUString _aTemporaryFile
)
213 m_xDocument( _rxModel
, UNO_QUERY
)
214 ,m_aDeleteTimer("sw DelayedFileDeletion m_aDeleteTimer")
215 ,m_sTemporaryFile(std::move( _aTemporaryFile
))
216 ,m_nPendingDeleteAttempts( 0 )
218 osl_atomic_increment( &m_refCount
);
221 if ( m_xDocument
.is() )
223 m_xDocument
->addCloseListener( this );
224 // successfully added -> keep ourself alive
228 OSL_FAIL("DelayedFileDeletion::DelayedFileDeletion: model is no component!" );
231 catch (const Exception
&)
233 OSL_FAIL("DelayedFileDeletion::DelayedFileDeletion: could not register as event listener at the model!" );
235 osl_atomic_decrement( &m_refCount
);
238 IMPL_LINK_NOARG(DelayedFileDeletion
, OnTryDeleteFile
, Timer
*, void)
240 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
242 bool bSuccess
= false;
245 bool bDeliverOwnership
= ( 0 == m_nPendingDeleteAttempts
);
246 // if this is our last attempt, then anybody which vetoes this has to take the consequences
247 // (means take the ownership)
248 m_xDocument
->close( bDeliverOwnership
);
251 catch (const util::CloseVetoException
&)
253 // somebody vetoed -> next try
254 if ( m_nPendingDeleteAttempts
)
257 --m_nPendingDeleteAttempts
;
258 m_aDeleteTimer
.Start();
261 bSuccess
= true; // can't do anything here ...
263 catch (const Exception
&)
265 TOOLS_WARN_EXCEPTION( "sw", "DelayedFileDeletion::OnTryDeleteFile: caught a strange exception!" );
267 // can't do anything here ...
272 SWUnoHelper::UCB_DeleteFile( m_sTemporaryFile
);
274 release(); // this should be our last reference, we should be dead after this
278 void DelayedFileDeletion::implTakeOwnership( )
280 // revoke ourself as listener
283 m_xDocument
->removeCloseListener( this );
285 catch (const Exception
&)
287 OSL_FAIL("DelayedFileDeletion::implTakeOwnership: could not revoke the listener!" );
290 m_aDeleteTimer
.SetTimeout( 3000 ); // 3 seconds
291 m_aDeleteTimer
.SetInvokeHandler( LINK( this, DelayedFileDeletion
, OnTryDeleteFile
) );
292 m_nPendingDeleteAttempts
= 3; // try 3 times at most
293 m_aDeleteTimer
.Start( );
296 void SAL_CALL
DelayedFileDeletion::queryClosing( const EventObject
& , sal_Bool _bGetsOwnership
)
298 ::osl::MutexGuard
aGuard( m_aMutex
);
299 if ( _bGetsOwnership
)
300 implTakeOwnership( );
302 // always veto: We want to take the ownership ourself, as this is the only chance to delete
303 // the temporary file which the model is based on
304 throw util::CloseVetoException( );
307 void SAL_CALL
DelayedFileDeletion::notifyClosing( const EventObject
& )
309 OSL_FAIL("DelayedFileDeletion::notifyClosing: how this?" );
310 // this should not happen:
311 // Either, a foreign instance closes the document, then we should veto this, and take the ownership
312 // Or, we ourself close the document, then we should not be a listener anymore
315 void SAL_CALL
DelayedFileDeletion::disposing( const EventObject
& )
317 OSL_FAIL("DelayedFileDeletion::disposing: how this?" );
318 // this should not happen:
319 // Either, a foreign instance closes the document, then we should veto this, and take the ownership
320 // Or, we ourself close the document, then we should not be a listener anymore
323 DelayedFileDeletion::~DelayedFileDeletion( )
328 static bool DeleteTmpFile_Impl(
329 Reference
< frame::XModel
> &rxModel
,
330 SfxObjectShellRef
&rxDocSh
,
331 const OUString
&rTmpFileURL
)
334 if (!rTmpFileURL
.isEmpty())
337 if ( eVetoed
== CloseModelAndDocSh( rxModel
, rxDocSh
) )
339 // somebody vetoed the closing, and took the ownership of the document
340 // -> ensure that the temporary file is deleted later on
341 new DelayedFileDeletion( rxModel
, rTmpFileURL
);
342 // note: as soon as #106931# is fixed, the whole DelayedFileDeletion is to be superseded by
348 rxDocSh
= nullptr; // destroy doc shell
352 if ( !SWUnoHelper::UCB_DeleteFile( rTmpFileURL
) )
354 new DelayedFileDeletion( rxModel
, rTmpFileURL
);
355 // same not as above: as soon as #106931#, ...
359 bRes
= true; // file will be deleted delayed
364 SwXMailMerge::SwXMailMerge() :
365 m_aEvtListeners ( GetMailMergeMutex() ),
366 m_aMergeListeners ( GetMailMergeMutex() ),
367 m_aPropListeners ( GetMailMergeMutex() ),
368 m_pPropSet( aSwMapProvider
.GetPropertySet( PROPERTY_MAP_MAILMERGE
) ),
369 m_nDataCommandType(sdb::CommandType::TABLE
),
370 m_nOutputType(MailMergeType::PRINTER
),
371 m_bEscapeProcessing(true), //!! allow to process properties like "Filter", "Order", ...
372 m_bSinglePrintJobs(false),
373 m_bFileNameFromColumn(false),
374 m_bSendAsHTML(false),
375 m_bSendAsAttachment(false),
376 m_bSaveAsSingleFile(false),
380 // create empty document
381 // like in: SwModule::InsertEnv (appenv.cxx)
382 m_xDocSh
= new SwDocShell( SfxObjectCreateMode::STANDARD
);
383 m_xDocSh
->DoInitNew();
384 SfxViewFrame
*pFrame
= SfxViewFrame::LoadHiddenDocument( *m_xDocSh
, SFX_INTERFACE_NONE
);
385 SwView
*pView
= static_cast<SwView
*>( pFrame
->GetViewShell() );
386 pView
->AttrChangedNotify(nullptr); //So that SelectShell is called.
387 m_xModel
= m_xDocSh
->GetModel();
390 SwXMailMerge::~SwXMailMerge()
392 if (!m_aTmpFileName
.isEmpty())
393 DeleteTmpFile_Impl( m_xModel
, m_xDocSh
, m_aTmpFileName
);
394 else // there was no temporary file in use
396 //! we still need to close the model and doc shell manually
397 //! because there is no automatism that will do that later.
399 if ( eVetoed
== CloseModelAndDocSh( m_xModel
, m_xDocSh
) )
400 OSL_FAIL("ownership transferred to vetoing object!" );
403 m_xDocSh
= nullptr; // destroy doc shell
407 // Guarantee object consistence in case of an exception
408 class MailMergeExecuteFinalizer
411 explicit MailMergeExecuteFinalizer(SwXMailMerge
*mailmerge
)
412 : m_pMailMerge(mailmerge
)
414 assert(m_pMailMerge
); //mailmerge object missing
416 ~MailMergeExecuteFinalizer()
418 osl::MutexGuard
aMgrGuard( GetMailMergeMutex() );
419 m_pMailMerge
->m_pMgr
= nullptr;
423 MailMergeExecuteFinalizer(MailMergeExecuteFinalizer
const&) = delete;
424 MailMergeExecuteFinalizer
& operator=(MailMergeExecuteFinalizer
const&) = delete;
426 SwXMailMerge
*m_pMailMerge
;
429 uno::Any SAL_CALL
SwXMailMerge::execute(
430 const uno::Sequence
< beans::NamedValue
>& rArguments
)
432 SolarMutexGuard aGuard
;
433 MailMergeExecuteFinalizer
aFinalizer(this);
435 // get property values to be used
436 // (use values from the service as default and override them with
437 // the values that are provided as arguments)
439 uno::Sequence
< uno::Any
> aCurSelection
= m_aSelection
;
440 uno::Reference
< sdbc::XResultSet
> xCurResultSet
= m_xResultSet
;
441 uno::Reference
< sdbc::XConnection
> xCurConnection
= m_xConnection
;
442 uno::Reference
< frame::XModel
> xCurModel
= m_xModel
;
443 OUString aCurDataSourceName
= m_aDataSourceName
;
444 OUString aCurDataCommand
= m_aDataCommand
;
445 OUString aCurFilter
= m_aFilter
;
446 OUString aCurDocumentURL
= m_aDocumentURL
;
447 OUString aCurOutputURL
= m_aOutputURL
;
448 OUString aCurFileNamePrefix
= m_aFileNamePrefix
;
449 sal_Int32 nCurDataCommandType
= m_nDataCommandType
;
450 sal_Int16 nCurOutputType
= m_nOutputType
;
451 bool bCurEscapeProcessing
= m_bEscapeProcessing
;
452 bool bCurSinglePrintJobs
= m_bSinglePrintJobs
;
453 bool bCurFileNameFromColumn
= m_bFileNameFromColumn
;
455 SfxObjectShellRef xCurDocSh
= m_xDocSh
; // the document
457 for (const beans::NamedValue
& rArgument
: rArguments
)
459 const OUString
&rName
= rArgument
.Name
;
460 const Any
&rValue
= rArgument
.Value
;
463 if (rName
== UNO_NAME_SELECTION
)
464 bOK
= rValue
>>= aCurSelection
;
465 else if (rName
== UNO_NAME_RESULT_SET
)
466 bOK
= rValue
>>= xCurResultSet
;
467 else if (rName
== UNO_NAME_CONNECTION
)
468 bOK
= rValue
>>= xCurConnection
;
469 else if (rName
== UNO_NAME_MODEL
)
470 throw PropertyVetoException("Property is read-only: " + rName
, static_cast < cppu::OWeakObject
* > ( this ) );
471 else if (rName
== UNO_NAME_DATA_SOURCE_NAME
)
472 bOK
= rValue
>>= aCurDataSourceName
;
473 else if (rName
== UNO_NAME_DAD_COMMAND
)
474 bOK
= rValue
>>= aCurDataCommand
;
475 else if (rName
== UNO_NAME_FILTER
)
476 bOK
= rValue
>>= aCurFilter
;
477 else if (rName
== UNO_NAME_DOCUMENT_URL
)
479 bOK
= rValue
>>= aCurDocumentURL
;
480 if (!aCurDocumentURL
.isEmpty()
481 && !LoadFromURL_impl( xCurModel
, xCurDocSh
, aCurDocumentURL
, false ))
482 throw RuntimeException("Failed to create document from URL: " + aCurDocumentURL
, static_cast < cppu::OWeakObject
* > ( this ) );
484 else if (rName
== UNO_NAME_OUTPUT_URL
)
486 bOK
= rValue
>>= aCurOutputURL
;
487 if (!aCurOutputURL
.isEmpty())
489 if (!UCB_IsDirectory(aCurOutputURL
))
490 throw IllegalArgumentException("URL does not point to a directory: " + aCurOutputURL
, static_cast < cppu::OWeakObject
* > ( this ), 0 );
491 if (UCB_IsReadOnlyFileName(aCurOutputURL
))
492 throw IllegalArgumentException("URL is read-only: " + aCurOutputURL
, static_cast < cppu::OWeakObject
* > ( this ), 0 );
495 else if (rName
== UNO_NAME_FILE_NAME_PREFIX
)
496 bOK
= rValue
>>= aCurFileNamePrefix
;
497 else if (rName
== UNO_NAME_DAD_COMMAND_TYPE
)
498 bOK
= rValue
>>= nCurDataCommandType
;
499 else if (rName
== UNO_NAME_OUTPUT_TYPE
)
500 bOK
= rValue
>>= nCurOutputType
;
501 else if (rName
== UNO_NAME_ESCAPE_PROCESSING
)
502 bOK
= rValue
>>= bCurEscapeProcessing
;
503 else if (rName
== UNO_NAME_SINGLE_PRINT_JOBS
)
504 bOK
= rValue
>>= bCurSinglePrintJobs
;
505 else if (rName
== UNO_NAME_FILE_NAME_FROM_COLUMN
)
506 bOK
= rValue
>>= bCurFileNameFromColumn
;
507 else if (rName
== UNO_NAME_SUBJECT
)
508 bOK
= rValue
>>= m_sSubject
;
509 else if (rName
== UNO_NAME_ADDRESS_FROM_COLUMN
)
510 bOK
= rValue
>>= m_sAddressFromColumn
;
511 else if (rName
== UNO_NAME_SEND_AS_HTML
)
512 bOK
= rValue
>>= m_bSendAsHTML
;
513 else if (rName
== UNO_NAME_MAIL_BODY
)
514 bOK
= rValue
>>= m_sMailBody
;
515 else if (rName
== UNO_NAME_ATTACHMENT_NAME
)
516 bOK
= rValue
>>= m_sAttachmentName
;
517 else if (rName
== UNO_NAME_ATTACHMENT_FILTER
)
518 bOK
= rValue
>>= m_sAttachmentFilter
;
519 else if (rName
== UNO_NAME_COPIES_TO
)
520 bOK
= rValue
>>= m_aCopiesTo
;
521 else if (rName
== UNO_NAME_BLIND_COPIES_TO
)
522 bOK
= rValue
>>= m_aBlindCopiesTo
;
523 else if (rName
== UNO_NAME_SEND_AS_ATTACHMENT
)
524 bOK
= rValue
>>= m_bSendAsAttachment
;
525 else if (rName
== UNO_NAME_PRINT_OPTIONS
)
526 bOK
= rValue
>>= m_aPrintSettings
;
527 else if (rName
== UNO_NAME_SAVE_AS_SINGLE_FILE
)
528 bOK
= rValue
>>= m_bSaveAsSingleFile
;
529 else if (rName
== UNO_NAME_SAVE_FILTER
)
530 bOK
= rValue
>>= m_sSaveFilter
;
531 else if (rName
== UNO_NAME_SAVE_FILTER_OPTIONS
)
532 bOK
= rValue
>>= m_sSaveFilterOptions
;
533 else if (rName
== UNO_NAME_SAVE_FILTER_DATA
)
534 bOK
= rValue
>>= m_aSaveFilterData
;
535 else if (rName
== UNO_NAME_IN_SERVER_PASSWORD
)
536 bOK
= rValue
>>= m_sInServerPassword
;
537 else if (rName
== UNO_NAME_OUT_SERVER_PASSWORD
)
538 bOK
= rValue
>>= m_sOutServerPassword
;
540 throw UnknownPropertyException( "Property is unknown: " + rName
, static_cast < cppu::OWeakObject
* > ( this ) );
543 throw IllegalArgumentException("Property type mismatch or property not set: " + rName
, static_cast < cppu::OWeakObject
* > ( this ), 0 );
546 // need to translate the selection: the API here requires a sequence of bookmarks, but the Merge
547 // method we will call below requires a sequence of indices.
548 if ( aCurSelection
.hasElements() )
550 Sequence
< Any
> aTranslated( aCurSelection
.getLength() );
553 Reference
< sdbcx::XRowLocate
> xRowLocate( xCurResultSet
, UNO_QUERY
);
554 if ( xRowLocate
.is() )
556 Any
* pTranslated
= aTranslated
.getArray();
560 bool bEverythingsFine
= true;
561 for ( const Any
& rBookmark
: std::as_const(aCurSelection
) )
563 bEverythingsFine
= xRowLocate
->moveToBookmark( rBookmark
);
564 if ( !bEverythingsFine
)
566 *pTranslated
<<= xCurResultSet
->getRow();
569 if ( bEverythingsFine
)
572 catch (const Exception
&)
580 throw IllegalArgumentException(
581 "The current 'Selection' does not describe a valid array of bookmarks, relative to the current 'ResultSet'.",
582 static_cast < cppu::OWeakObject
* > ( this ),
587 aCurSelection
= aTranslated
;
590 SfxViewFrame
* pFrame
= SfxViewFrame::GetFirst( xCurDocSh
.get(), false);
591 SwView
*pView
= pFrame
? dynamic_cast<SwView
*>( pFrame
->GetViewShell() ) : nullptr;
593 throw RuntimeException();
595 // avoid assertion in 'Update' from Sfx by supplying a shell
596 // and thus avoiding the SelectShell call in Writers GetState function
597 // while still in Update of Sfx.
598 // (GetSelection in Update is not allowed)
599 if (!aCurDocumentURL
.isEmpty())
600 pView
->AttrChangedNotify(nullptr);//So that SelectShell is called.
602 SharedComponent aRowSetDisposeHelper
;
603 if (!xCurResultSet
.is())
605 if (aCurDataSourceName
.isEmpty() || aCurDataCommand
.isEmpty() )
607 OSL_FAIL("PropertyValues missing or unset");
608 throw IllegalArgumentException("Either the ResultSet or DataSourceName and DataCommand must be set.", static_cast < cppu::OWeakObject
* > ( this ), 0 );
611 // build ResultSet from DataSourceName, DataCommand and DataCommandType
613 Reference
< XMultiServiceFactory
> xMgr( ::comphelper::getProcessServiceFactory() );
616 Reference
< XInterface
> xInstance
= xMgr
->createInstance( "com.sun.star.sdb.RowSet" );
617 aRowSetDisposeHelper
.reset( xInstance
, SharedComponent::TakeOwnership
);
618 Reference
< XPropertySet
> xRowSetPropSet( xInstance
, UNO_QUERY
);
619 OSL_ENSURE( xRowSetPropSet
.is(), "failed to get XPropertySet interface from RowSet" );
620 if (xRowSetPropSet
.is())
622 if (xCurConnection
.is())
623 xRowSetPropSet
->setPropertyValue( "ActiveConnection", Any( xCurConnection
) );
624 xRowSetPropSet
->setPropertyValue( "DataSourceName", Any( aCurDataSourceName
) );
625 xRowSetPropSet
->setPropertyValue( "Command", Any( aCurDataCommand
) );
626 xRowSetPropSet
->setPropertyValue( "CommandType", Any( nCurDataCommandType
) );
627 xRowSetPropSet
->setPropertyValue( "EscapeProcessing", Any( bCurEscapeProcessing
) );
628 xRowSetPropSet
->setPropertyValue( "ApplyFilter", Any( true ) );
629 xRowSetPropSet
->setPropertyValue( "Filter", Any( aCurFilter
) );
631 Reference
< sdbc::XRowSet
> xRowSet( xInstance
, UNO_QUERY
);
633 xRowSet
->execute(); // build ResultSet from properties
634 if( !xCurConnection
.is() )
635 xCurConnection
.set( xRowSetPropSet
->getPropertyValue( "ActiveConnection" ), UNO_QUERY
);
636 xCurResultSet
= xRowSet
;
637 OSL_ENSURE( xCurResultSet
.is(), "failed to build ResultSet" );
642 svx::ODataAccessDescriptor aDescriptor
;
643 aDescriptor
.setDataSource(aCurDataSourceName
);
644 aDescriptor
[ svx::DataAccessDescriptorProperty::Connection
] <<= xCurConnection
;
645 aDescriptor
[ svx::DataAccessDescriptorProperty::Command
] <<= aCurDataCommand
;
646 aDescriptor
[ svx::DataAccessDescriptorProperty::CommandType
] <<= nCurDataCommandType
;
647 aDescriptor
[ svx::DataAccessDescriptorProperty::EscapeProcessing
] <<= bCurEscapeProcessing
;
648 aDescriptor
[ svx::DataAccessDescriptorProperty::Cursor
] <<= xCurResultSet
;
649 // aDescriptor[ svx::DataAccessDescriptorProperty::ColumnName ] not used
650 // aDescriptor[ svx::DataAccessDescriptorProperty::ColumnObject ] not used
651 aDescriptor
[ svx::DataAccessDescriptorProperty::Selection
] <<= aCurSelection
;
653 DBManagerOptions nMergeType
;
654 switch (nCurOutputType
)
656 case MailMergeType::PRINTER
: nMergeType
= DBMGR_MERGE_PRINTER
; break;
657 case MailMergeType::FILE : nMergeType
= DBMGR_MERGE_FILE
; break;
658 case MailMergeType::MAIL
: nMergeType
= DBMGR_MERGE_EMAIL
; break;
659 case MailMergeType::SHELL
: nMergeType
= DBMGR_MERGE_SHELL
; break;
661 throw IllegalArgumentException("Invalid value of property: OutputType", static_cast < cppu::OWeakObject
* > ( this ), 0 );
664 SwWrtShell
&rSh
= pView
->GetWrtShell();
665 SwDBManager
* pMgr
= rSh
.GetDBManager();
666 //force layout creation
668 OSL_ENSURE( pMgr
, "database manager missing" );
671 SwMergeDescriptor
aMergeDesc( nMergeType
, rSh
, aDescriptor
);
673 std::unique_ptr
< SwMailMergeConfigItem
> pMMConfigItem
;
674 uno::Reference
< mail::XMailService
> xInService
;
675 switch (nCurOutputType
)
677 case MailMergeType::PRINTER
:
679 IDocumentDeviceAccess
& rIDDA
= rSh
.getIDocumentDeviceAccess();
680 SwPrintData
aPrtData( rIDDA
.getPrintData() );
681 aPrtData
.SetPrintSingleJobs( bCurSinglePrintJobs
);
682 rIDDA
.setPrintData( aPrtData
);
683 // #i25686# printing should not be done asynchronously to prevent dangling offices
684 // when mail merge is called as command line macro
685 aMergeDesc
.aPrintOptions
= m_aPrintSettings
;
686 aMergeDesc
.bCreateSingleFile
= true;
689 case MailMergeType::SHELL
:
690 aMergeDesc
.bCreateSingleFile
= true;
691 pMMConfigItem
.reset(new SwMailMergeConfigItem
);
692 aMergeDesc
.pMailMergeConfigItem
= pMMConfigItem
.get();
694 case MailMergeType::FILE:
696 INetURLObject aURLObj
;
697 aURLObj
.SetSmartProtocol( INetProtocol::File
);
699 if (!aCurDocumentURL
.isEmpty())
701 // if OutputURL or FileNamePrefix are missing get
702 // them from DocumentURL
703 aURLObj
.SetSmartURL( aCurDocumentURL
);
704 if (aCurFileNamePrefix
.isEmpty())
705 aCurFileNamePrefix
= aURLObj
.GetBase(); // filename without extension
706 if (aCurOutputURL
.isEmpty())
708 aURLObj
.removeSegment();
709 aCurOutputURL
= aURLObj
.GetMainURL( INetURLObject::DecodeMechanism::ToIUri
);
712 else // default empty document without URL
714 if (aCurOutputURL
.isEmpty())
715 throw RuntimeException("OutputURL is not set and can not be obtained.", static_cast < cppu::OWeakObject
* > ( this ) );
718 aURLObj
.SetSmartURL( aCurOutputURL
);
719 OUString aPath
= aURLObj
.GetMainURL( INetURLObject::DecodeMechanism::ToIUri
);
721 static const OUStringLiteral
aDelim( u
"/" );
722 if (!aPath
.isEmpty() && !aPath
.endsWith(aDelim
))
724 if (bCurFileNameFromColumn
)
725 aMergeDesc
.sDBcolumn
= aCurFileNamePrefix
;
728 aPath
+= aCurFileNamePrefix
;
731 aMergeDesc
.sPrefix
= aPath
;
732 aMergeDesc
.sSaveToFilter
= m_sSaveFilter
;
733 aMergeDesc
.sSaveToFilterOptions
= m_sSaveFilterOptions
;
734 aMergeDesc
.aSaveToFilterData
= m_aSaveFilterData
;
735 aMergeDesc
.bCreateSingleFile
= m_bSaveAsSingleFile
;
738 case MailMergeType::MAIL
:
740 aMergeDesc
.sDBcolumn
= m_sAddressFromColumn
;
741 if(m_sAddressFromColumn
.isEmpty())
742 throw RuntimeException("Mail address column not set.", static_cast < cppu::OWeakObject
* > ( this ) );
743 aMergeDesc
.sSaveToFilter
= m_sAttachmentFilter
;
744 aMergeDesc
.sSubject
= m_sSubject
;
745 aMergeDesc
.sMailBody
= m_sMailBody
;
746 aMergeDesc
.sAttachmentName
= m_sAttachmentName
;
747 aMergeDesc
.aCopiesTo
= m_aCopiesTo
;
748 aMergeDesc
.aBlindCopiesTo
= m_aBlindCopiesTo
;
749 aMergeDesc
.bSendAsHTML
= m_bSendAsHTML
;
750 aMergeDesc
.bSendAsAttachment
= m_bSendAsAttachment
;
752 aMergeDesc
.bCreateSingleFile
= false;
753 pMMConfigItem
.reset(new SwMailMergeConfigItem
);
754 aMergeDesc
.pMailMergeConfigItem
= pMMConfigItem
.get();
755 aMergeDesc
.xSmtpServer
= SwMailMergeHelper::ConnectToSmtpServer(
758 m_sInServerPassword
, m_sOutServerPassword
);
759 if( !aMergeDesc
.xSmtpServer
.is() || !aMergeDesc
.xSmtpServer
->isConnected())
760 throw RuntimeException("Failed to connect to mail server.", static_cast < cppu::OWeakObject
* > ( this ) );
765 // save document with temporary filename
766 std::shared_ptr
<const SfxFilter
> pSfxFlt
= SwIoSystem::GetFilterOfFormat(
768 SwDocShell::Factory().GetFilterContainer() );
769 OUString
aExtension(comphelper::string::stripStart(pSfxFlt
->GetDefaultExtension(), '*'));
770 m_aTmpFileName
= utl::CreateTempURL( u
"SwMM", true, aExtension
);
772 Reference
< XStorable
> xStorable( xCurModel
, UNO_QUERY
);
773 bool bStoredAsTemporary
= false;
774 if ( xStorable
.is() )
778 xStorable
->storeAsURL( m_aTmpFileName
, Sequence
< PropertyValue
>() );
779 bStoredAsTemporary
= true;
781 catch (const Exception
&)
785 if ( !bStoredAsTemporary
)
786 throw RuntimeException("Failed to save temporary file.", static_cast < cppu::OWeakObject
* > ( this ) );
788 pMgr
->SetMergeSilent( true ); // suppress dialogs, message boxes, etc.
789 const SwXMailMerge
*pOldSrc
= pMgr
->GetMailMergeEvtSrc();
790 OSL_ENSURE( !pOldSrc
|| pOldSrc
== this, "Ooops... different event source already set." );
791 pMgr
->SetMailMergeEvtSrc( this ); // launch events for listeners
793 SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwMailMerge
, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE
), xCurDocSh
.get()));
794 bool bSucc
= pMgr
->Merge( aMergeDesc
);
795 SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwMailMergeEnd
, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END
), xCurDocSh
.get()));
797 pMgr
->SetMailMergeEvtSrc( pOldSrc
);
799 if ( xCurModel
.get() != m_xModel
.get() )
800 { // in case it was a temporary model -> close it, and delete the file
801 DeleteTmpFile_Impl( xCurModel
, xCurDocSh
, m_aTmpFileName
);
802 m_aTmpFileName
.clear();
804 // (in case it wasn't a temporary model, it will be closed in the dtor, at the latest)
807 throw Exception("Mail merge failed. Sorry, no further information available.", static_cast < cppu::OWeakObject
* > ( this ) );
809 //de-initialize services
810 if(xInService
.is() && xInService
->isConnected())
811 xInService
->disconnect();
812 if(aMergeDesc
.xSmtpServer
.is() && aMergeDesc
.xSmtpServer
->isConnected())
813 aMergeDesc
.xSmtpServer
->disconnect();
815 if (DBMGR_MERGE_SHELL
== nMergeType
)
817 return Any( aMergeDesc
.pMailMergeConfigItem
->GetTargetView()->GetDocShell()->GetBaseModel() );
823 void SAL_CALL
SwXMailMerge::cancel()
825 // Cancel may be called from a second thread, so this protects from m_pMgr
826 /// cleanup in the execute function.
827 osl::MutexGuard
aMgrGuard( GetMailMergeMutex() );
829 m_pMgr
->MergeCancel();
832 void SwXMailMerge::LaunchMailMergeEvent( const MailMergeEvent
&rEvt
) const
834 comphelper::OInterfaceIteratorHelper2
aIt( const_cast<SwXMailMerge
*>(this)->m_aMergeListeners
);
835 while (aIt
.hasMoreElements())
837 static_cast< XMailMergeListener
* >( aIt
.next() )->notifyMailMergeEvent( rEvt
);
841 void SwXMailMerge::launchEvent( const PropertyChangeEvent
&rEvt
) const
843 comphelper::OInterfaceContainerHelper3
<XPropertyChangeListener
> *pContainer
=
844 m_aPropListeners
.getContainer( rEvt
.PropertyHandle
);
847 pContainer
->notifyEach( &XPropertyChangeListener::propertyChange
, rEvt
);
851 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
SwXMailMerge::getPropertySetInfo( )
853 SolarMutexGuard aGuard
;
854 static Reference
< XPropertySetInfo
> aRef
= m_pPropSet
->getPropertySetInfo();
858 void SAL_CALL
SwXMailMerge::setPropertyValue(
859 const OUString
& rPropertyName
, const uno::Any
& rValue
)
861 SolarMutexGuard aGuard
;
863 const SfxItemPropertyMapEntry
* pCur
= m_pPropSet
->getPropertyMap().getByName( rPropertyName
);
865 throw UnknownPropertyException(rPropertyName
);
866 else if (pCur
->nFlags
& PropertyAttribute::READONLY
)
867 throw PropertyVetoException();
870 void *pData
= nullptr;
873 case WID_SELECTION
: pData
= &m_aSelection
; break;
874 case WID_RESULT_SET
: pData
= &m_xResultSet
; break;
875 case WID_CONNECTION
: pData
= &m_xConnection
; break;
876 case WID_MODEL
: pData
= &m_xModel
; break;
877 case WID_DATA_SOURCE_NAME
: pData
= &m_aDataSourceName
; break;
878 case WID_DATA_COMMAND
: pData
= &m_aDataCommand
; break;
879 case WID_FILTER
: pData
= &m_aFilter
; break;
880 case WID_DOCUMENT_URL
: pData
= &m_aDocumentURL
; break;
881 case WID_OUTPUT_URL
: pData
= &m_aOutputURL
; break;
882 case WID_DATA_COMMAND_TYPE
: pData
= &m_nDataCommandType
; break;
883 case WID_OUTPUT_TYPE
: pData
= &m_nOutputType
; break;
884 case WID_ESCAPE_PROCESSING
: pData
= &m_bEscapeProcessing
; break;
885 case WID_SINGLE_PRINT_JOBS
: pData
= &m_bSinglePrintJobs
; break;
886 case WID_FILE_NAME_FROM_COLUMN
: pData
= &m_bFileNameFromColumn
; break;
887 case WID_FILE_NAME_PREFIX
: pData
= &m_aFileNamePrefix
; break;
888 case WID_MAIL_SUBJECT
: pData
= &m_sSubject
; break;
889 case WID_ADDRESS_FROM_COLUMN
: pData
= &m_sAddressFromColumn
; break;
890 case WID_SEND_AS_HTML
: pData
= &m_bSendAsHTML
; break;
891 case WID_SEND_AS_ATTACHMENT
: pData
= &m_bSendAsAttachment
; break;
892 case WID_MAIL_BODY
: pData
= &m_sMailBody
; break;
893 case WID_ATTACHMENT_NAME
: pData
= &m_sAttachmentName
; break;
894 case WID_ATTACHMENT_FILTER
: pData
= &m_sAttachmentFilter
;break;
895 case WID_PRINT_OPTIONS
: pData
= &m_aPrintSettings
; break;
896 case WID_SAVE_AS_SINGLE_FILE
: pData
= &m_bSaveAsSingleFile
; break;
897 case WID_SAVE_FILTER
: pData
= &m_sSaveFilter
; break;
898 case WID_SAVE_FILTER_OPTIONS
: pData
= &m_sSaveFilterOptions
; break;
899 case WID_SAVE_FILTER_DATA
: pData
= &m_aSaveFilterData
; break;
900 case WID_COPIES_TO
: pData
= &m_aCopiesTo
; break;
901 case WID_BLIND_COPIES_TO
: pData
= &m_aBlindCopiesTo
;break;
902 case WID_IN_SERVER_PASSWORD
: pData
= &m_sInServerPassword
; break;
903 case WID_OUT_SERVER_PASSWORD
: pData
= &m_sOutServerPassword
; break;
905 OSL_FAIL("unknown WID");
907 Any
aOld( pData
, pCur
->aType
);
909 bool bChanged
= false;
913 if (pData
== &m_aSelection
)
914 bOK
= rValue
>>= m_aSelection
;
915 else if (pData
== &m_xResultSet
)
916 bOK
= rValue
>>= m_xResultSet
;
917 else if (pData
== &m_xConnection
)
918 bOK
= rValue
>>= m_xConnection
;
919 else if (pData
== &m_xModel
)
920 bOK
= rValue
>>= m_xModel
;
921 else if (pData
== &m_aDataSourceName
)
922 bOK
= rValue
>>= m_aDataSourceName
;
923 else if (pData
== &m_aDataCommand
)
924 bOK
= rValue
>>= m_aDataCommand
;
925 else if (pData
== &m_aFilter
)
926 bOK
= rValue
>>= m_aFilter
;
927 else if (pData
== &m_aDocumentURL
)
930 bOK
= rValue
>>= aText
;
932 && !LoadFromURL_impl( m_xModel
, m_xDocSh
, aText
, true ))
933 throw RuntimeException("Failed to create document from URL: " + aText
, static_cast < cppu::OWeakObject
* > ( this ) );
934 m_aDocumentURL
= aText
;
936 else if (pData
== &m_aOutputURL
)
939 bOK
= rValue
>>= aText
;
940 if (!aText
.isEmpty())
942 if (!UCB_IsDirectory(aText
))
943 throw IllegalArgumentException("URL does not point to a directory: " + aText
, static_cast < cppu::OWeakObject
* > ( this ), 0 );
944 if (UCB_IsReadOnlyFileName(aText
))
945 throw IllegalArgumentException("URL is read-only: " + aText
, static_cast < cppu::OWeakObject
* > ( this ), 0 );
947 m_aOutputURL
= aText
;
949 else if (pData
== &m_nDataCommandType
)
950 bOK
= rValue
>>= m_nDataCommandType
;
951 else if (pData
== &m_nOutputType
)
952 bOK
= rValue
>>= m_nOutputType
;
953 else if (pData
== &m_bEscapeProcessing
)
954 bOK
= rValue
>>= m_bEscapeProcessing
;
955 else if (pData
== &m_bSinglePrintJobs
)
956 bOK
= rValue
>>= m_bSinglePrintJobs
;
957 else if (pData
== &m_bFileNameFromColumn
)
958 bOK
= rValue
>>= m_bFileNameFromColumn
;
959 else if (pData
== &m_aFileNamePrefix
)
960 bOK
= rValue
>>= m_aFileNamePrefix
;
961 else if (pData
== &m_sSubject
)
962 bOK
= rValue
>>= m_sSubject
;
963 else if (pData
== &m_sAddressFromColumn
)
964 bOK
= rValue
>>= m_sAddressFromColumn
;
965 else if (pData
== &m_bSendAsHTML
)
966 bOK
= rValue
>>= m_bSendAsHTML
;
967 else if (pData
== &m_bSendAsAttachment
)
968 bOK
= rValue
>>= m_bSendAsAttachment
;
969 else if (pData
== &m_sMailBody
)
970 bOK
= rValue
>>= m_sMailBody
;
971 else if (pData
== &m_sAttachmentName
)
972 bOK
= rValue
>>= m_sAttachmentName
;
973 else if (pData
== &m_sAttachmentFilter
)
974 bOK
= rValue
>>= m_sAttachmentFilter
;
975 else if (pData
== &m_aPrintSettings
)
976 bOK
= rValue
>>= m_aPrintSettings
;
977 else if (pData
== &m_bSaveAsSingleFile
)
978 bOK
= rValue
>>= m_bSaveAsSingleFile
;
979 else if (pData
== &m_sSaveFilter
)
980 bOK
= rValue
>>= m_sSaveFilter
;
981 else if (pData
== &m_sSaveFilterOptions
)
982 bOK
= rValue
>>= m_sSaveFilterOptions
;
983 else if (pData
== &m_aSaveFilterData
)
984 bOK
= rValue
>>= m_aSaveFilterData
;
985 else if (pData
== &m_aCopiesTo
)
986 bOK
= rValue
>>= m_aCopiesTo
;
987 else if (pData
== &m_aBlindCopiesTo
)
988 bOK
= rValue
>>= m_aBlindCopiesTo
;
989 else if(pData
== &m_sInServerPassword
)
990 bOK
= rValue
>>= m_sInServerPassword
;
991 else if(pData
== &m_sOutServerPassword
)
992 bOK
= rValue
>>= m_sOutServerPassword
;
994 OSL_FAIL("invalid pointer" );
996 OSL_ENSURE( bOK
, "set value failed" );
1000 throw IllegalArgumentException("Property type mismatch or property not set: " + rPropertyName
, static_cast < cppu::OWeakObject
* > ( this ), 0 );
1004 PropertyChangeEvent
aChgEvt( static_cast<XPropertySet
*>(this), rPropertyName
,
1005 false, pCur
->nWID
, aOld
, rValue
);
1006 launchEvent( aChgEvt
);
1011 uno::Any SAL_CALL
SwXMailMerge::getPropertyValue(
1012 const OUString
& rPropertyName
)
1014 SolarMutexGuard aGuard
;
1018 const SfxItemPropertyMapEntry
* pCur
= m_pPropSet
->getPropertyMap().getByName( rPropertyName
);
1020 throw UnknownPropertyException(rPropertyName
);
1024 case WID_SELECTION
: aRet
<<= m_aSelection
; break;
1025 case WID_RESULT_SET
: aRet
<<= m_xResultSet
; break;
1026 case WID_CONNECTION
: aRet
<<= m_xConnection
; break;
1027 case WID_MODEL
: aRet
<<= m_xModel
; break;
1028 case WID_DATA_SOURCE_NAME
: aRet
<<= m_aDataSourceName
; break;
1029 case WID_DATA_COMMAND
: aRet
<<= m_aDataCommand
; break;
1030 case WID_FILTER
: aRet
<<= m_aFilter
; break;
1031 case WID_DOCUMENT_URL
: aRet
<<= m_aDocumentURL
; break;
1032 case WID_OUTPUT_URL
: aRet
<<= m_aOutputURL
; break;
1033 case WID_DATA_COMMAND_TYPE
: aRet
<<= m_nDataCommandType
; break;
1034 case WID_OUTPUT_TYPE
: aRet
<<= m_nOutputType
; break;
1035 case WID_ESCAPE_PROCESSING
: aRet
<<= m_bEscapeProcessing
; break;
1036 case WID_SINGLE_PRINT_JOBS
: aRet
<<= m_bSinglePrintJobs
; break;
1037 case WID_FILE_NAME_FROM_COLUMN
: aRet
<<= m_bFileNameFromColumn
; break;
1038 case WID_FILE_NAME_PREFIX
: aRet
<<= m_aFileNamePrefix
; break;
1039 case WID_MAIL_SUBJECT
: aRet
<<= m_sSubject
; break;
1040 case WID_ADDRESS_FROM_COLUMN
: aRet
<<= m_sAddressFromColumn
; break;
1041 case WID_SEND_AS_HTML
: aRet
<<= m_bSendAsHTML
; break;
1042 case WID_SEND_AS_ATTACHMENT
: aRet
<<= m_bSendAsAttachment
; break;
1043 case WID_MAIL_BODY
: aRet
<<= m_sMailBody
; break;
1044 case WID_ATTACHMENT_NAME
: aRet
<<= m_sAttachmentName
; break;
1045 case WID_ATTACHMENT_FILTER
: aRet
<<= m_sAttachmentFilter
;break;
1046 case WID_PRINT_OPTIONS
: aRet
<<= m_aPrintSettings
; break;
1047 case WID_SAVE_AS_SINGLE_FILE
: aRet
<<= m_bSaveAsSingleFile
; break;
1048 case WID_SAVE_FILTER
: aRet
<<= m_sSaveFilter
; break;
1049 case WID_SAVE_FILTER_OPTIONS
: aRet
<<= m_sSaveFilterOptions
; break;
1050 case WID_SAVE_FILTER_DATA
: aRet
<<= m_aSaveFilterData
; break;
1051 case WID_COPIES_TO
: aRet
<<= m_aCopiesTo
; break;
1052 case WID_BLIND_COPIES_TO
: aRet
<<= m_aBlindCopiesTo
;break;
1053 case WID_IN_SERVER_PASSWORD
: aRet
<<= m_sInServerPassword
; break;
1054 case WID_OUT_SERVER_PASSWORD
: aRet
<<= m_sOutServerPassword
; break;
1056 OSL_FAIL("unknown WID");
1062 void SAL_CALL
SwXMailMerge::addPropertyChangeListener(
1063 const OUString
& rPropertyName
,
1064 const uno::Reference
< beans::XPropertyChangeListener
>& rListener
)
1066 SolarMutexGuard aGuard
;
1067 if (!m_bDisposing
&& rListener
.is())
1069 const SfxItemPropertyMapEntry
* pCur
= m_pPropSet
->getPropertyMap().getByName( rPropertyName
);
1071 throw UnknownPropertyException(rPropertyName
);
1072 m_aPropListeners
.addInterface( pCur
->nWID
, rListener
);
1076 void SAL_CALL
SwXMailMerge::removePropertyChangeListener(
1077 const OUString
& rPropertyName
,
1078 const uno::Reference
< beans::XPropertyChangeListener
>& rListener
)
1080 SolarMutexGuard aGuard
;
1081 if (!m_bDisposing
&& rListener
.is())
1083 const SfxItemPropertyMapEntry
* pCur
= m_pPropSet
->getPropertyMap().getByName( rPropertyName
);
1085 throw UnknownPropertyException(rPropertyName
);
1086 m_aPropListeners
.removeInterface( pCur
->nWID
, rListener
);
1090 void SAL_CALL
SwXMailMerge::addVetoableChangeListener(
1091 const OUString
& /*rPropertyName*/,
1092 const uno::Reference
< beans::XVetoableChangeListener
>& /*rListener*/ )
1094 // no vetoable property, thus no support for vetoable change listeners
1095 OSL_FAIL("not implemented");
1098 void SAL_CALL
SwXMailMerge::removeVetoableChangeListener(
1099 const OUString
& /*rPropertyName*/,
1100 const uno::Reference
< beans::XVetoableChangeListener
>& /*rListener*/ )
1102 // no vetoable property, thus no support for vetoable change listeners
1103 OSL_FAIL("not implemented");
1106 void SAL_CALL
SwXMailMerge::dispose()
1108 SolarMutexGuard aGuard
;
1112 m_bDisposing
= true;
1114 EventObject
aEvtObj( static_cast<XPropertySet
*>(this) );
1115 m_aEvtListeners
.disposeAndClear( aEvtObj
);
1116 m_aMergeListeners
.disposeAndClear( aEvtObj
);
1117 m_aPropListeners
.disposeAndClear( aEvtObj
);
1121 void SAL_CALL
SwXMailMerge::addEventListener(
1122 const Reference
< XEventListener
>& rxListener
)
1124 SolarMutexGuard aGuard
;
1125 if (!m_bDisposing
&& rxListener
.is())
1126 m_aEvtListeners
.addInterface( rxListener
);
1129 void SAL_CALL
SwXMailMerge::removeEventListener(
1130 const Reference
< XEventListener
>& rxListener
)
1132 SolarMutexGuard aGuard
;
1133 if (!m_bDisposing
&& rxListener
.is())
1134 m_aEvtListeners
.removeInterface( rxListener
);
1137 void SAL_CALL
SwXMailMerge::addMailMergeEventListener(
1138 const uno::Reference
< XMailMergeListener
>& rxListener
)
1140 SolarMutexGuard aGuard
;
1141 if (!m_bDisposing
&& rxListener
.is())
1142 m_aMergeListeners
.addInterface( rxListener
);
1145 void SAL_CALL
SwXMailMerge::removeMailMergeEventListener(
1146 const uno::Reference
< XMailMergeListener
>& rxListener
)
1148 SolarMutexGuard aGuard
;
1149 if (!m_bDisposing
&& rxListener
.is())
1150 m_aMergeListeners
.removeInterface( rxListener
);
1153 OUString SAL_CALL
SwXMailMerge::getImplementationName()
1155 return "SwXMailMerge";
1158 sal_Bool SAL_CALL
SwXMailMerge::supportsService( const OUString
& rServiceName
)
1160 return cppu::supportsService(this, rServiceName
);
1163 uno::Sequence
< OUString
> SAL_CALL
SwXMailMerge::getSupportedServiceNames()
1165 return { "com.sun.star.text.MailMerge", "com.sun.star.sdb.DataAccessDescriptor" };
1168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */