xref: /trunk/main/sw/source/ui/uno/unomailmerge.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 
GetMailMergeMutex()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 };
CloseModelAndDocSh(Reference<frame::XModel> & rxModel,SfxObjectShellRef & rxDocSh)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 
LoadFromURL_impl(Reference<frame::XModel> & rxModel,SfxObjectShellRef & rxDocSh,const String & rURL,sal_Bool bClose)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 
DBG_NAME(DelayedFileDeletion)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     //--------------------------------------------------------------------
IMPL_LINK(DelayedFileDeletion,OnTryDeleteFile,void *,EMPTYARG)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     //--------------------------------------------------------------------
implTakeOwnership()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     //--------------------------------------------------------------------
queryClosing(const EventObject &,sal_Bool _bGetsOwnership)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     //--------------------------------------------------------------------
notifyClosing(const EventObject &)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     //------------------------------------------------------
disposing(const EventObject &)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     //------------------------------------------------------
~DelayedFileDeletion()364     DelayedFileDeletion::~DelayedFileDeletion( )
365     {
366         DBG_DTOR( DelayedFileDeletion, NULL );
367     }
368 }
369 
370 ////////////////////////////////////////////////////////////
371 
DeleteTmpFile_Impl(Reference<frame::XModel> & rxModel,SfxObjectShellRef & rxDocSh,const String & rTmpFileURL)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 
SwXMailMerge()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 
~SwXMailMerge()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 
execute(const uno::Sequence<beans::NamedValue> & rArguments)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 
LaunchMailMergeEvent(const MailMergeEvent & rEvt) const848 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 
launchEvent(const PropertyChangeEvent & rEvt) const859 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 
getPropertySetInfo()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 
setPropertyValue(const OUString & rPropertyName,const uno::Any & rValue)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 
getPropertyValue(const OUString & rPropertyName)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 
addPropertyChangeListener(const OUString & rPropertyName,const uno::Reference<beans::XPropertyChangeListener> & rListener)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 
removePropertyChangeListener(const OUString & rPropertyName,const uno::Reference<beans::XPropertyChangeListener> & rListener)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 
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)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 
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)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 
dispose()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 
addEventListener(const Reference<XEventListener> & rxListener)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 
removeEventListener(const Reference<XEventListener> & rxListener)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 
addMailMergeEventListener(const uno::Reference<XMailMergeListener> & rxListener)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 
removeMailMergeEventListener(const uno::Reference<XMailMergeListener> & rxListener)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 
getImplementationName()1184 OUString SAL_CALL SwXMailMerge::getImplementationName()
1185 {
1186     vos::OGuard aGuard( Application::GetSolarMutex() );
1187     return SwXMailMerge_getImplementationName();
1188 }
1189 
supportsService(const OUString & rServiceName)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 
getSupportedServiceNames()1197 uno::Sequence< OUString > SAL_CALL SwXMailMerge::getSupportedServiceNames()
1198 {
1199     vos::OGuard aGuard( Application::GetSolarMutex() );
1200     return SwXMailMerge_getSupportedServiceNames();
1201 }
1202 
1203 ////////////////////////////////////////////////////////////
1204 
SwXMailMerge_getSupportedServiceNames()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 
SwXMailMerge_getImplementationName()1215 OUString SAL_CALL SwXMailMerge_getImplementationName()
1216     throw()
1217 {
1218     return OUString( C2U( "SwXMailMerge" ) );
1219 }
1220 
SwXMailMerge_createInstance(const uno::Reference<XMultiServiceFactory> &)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