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