LibreOffice Module sw (master)  1
unomailmerge.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/svapp.hxx>
21 #include <osl/mutex.hxx>
22 #include <svl/itemprop.hxx>
24 #include <unotools/tempfile.hxx>
25 #include <sfx2/app.hxx>
26 #include <sfx2/docfilt.hxx>
27 #include <tools/urlobj.hxx>
28 #include <tools/diagnose_ex.h>
30 #include <comphelper/string.hxx>
32 #include <vcl/timer.hxx>
33 #include <com/sun/star/sdb/CommandType.hpp>
34 #include <com/sun/star/text/MailMergeType.hpp>
35 #include <com/sun/star/text/MailMergeEvent.hpp>
36 #include <com/sun/star/text/XMailMergeListener.hpp>
37 #include <com/sun/star/beans/PropertyAttribute.hpp>
38 #include <com/sun/star/sdbc/XResultSet.hpp>
39 #include <com/sun/star/sdbc/XConnection.hpp>
40 #include <com/sun/star/sdbc/XRowSet.hpp>
41 #include <com/sun/star/frame/Desktop.hpp>
42 #include <com/sun/star/util/XCloseable.hpp>
43 #include <com/sun/star/util/CloseVetoException.hpp>
44 #include <com/sun/star/sdbcx/XRowLocate.hpp>
45 #include <com/sun/star/frame/XStorable.hpp>
46 #include <com/sun/star/mail/XSmtpService.hpp>
47 #include <sfx2/viewfrm.hxx>
48 #include <sfx2/event.hxx>
49 #include <cppuhelper/implbase.hxx>
50 #include <printdata.hxx>
51 #include <swevent.hxx>
52 #include <unomailmerge.hxx>
53 #include <unoprnms.hxx>
54 #include <unomap.hxx>
55 #include <swunohelper.hxx>
56 #include <docsh.hxx>
58 #include <view.hxx>
59 #include <dbmgr.hxx>
60 #include <unotxdoc.hxx>
61 #include <wrtsh.hxx>
62 #include <mmconfigitem.hxx>
63 #include <mailmergehelper.hxx>
64 
65 #include <iodetect.hxx>
66 
67 #include <memory>
68 
69 using namespace ::com::sun::star;
70 using namespace ::com::sun::star::frame;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::lang;
73 using namespace ::com::sun::star::beans;
74 using namespace ::com::sun::star::text;
75 using namespace SWUnoHelper;
76 
77 typedef ::utl::SharedUNOComponent< XInterface > SharedComponent;
78 
79 static osl::Mutex & GetMailMergeMutex()
80 {
81  static osl::Mutex aMutex;
82  return aMutex;
83 }
84 
85 namespace {
86 
88 {
89  eSuccess, // successfully closed
90  eVetoed, // vetoed, ownership transferred to the vetoing instance
91  eFailed // failed for some unknown reason
92 };
93 
94 }
95 
97  Reference< frame::XModel > const &rxModel,
98  SfxObjectShellRef &rxDocSh )
99 {
100  CloseResult eResult = eSuccess;
101 
102  rxDocSh = nullptr;
103 
107  Reference< util::XCloseable > xClose( rxModel, UNO_QUERY );
108  if (xClose.is())
109  {
110  try
111  {
114  xClose->close( true );
115  }
116  catch (const util::CloseVetoException&)
117  {
120  eResult = eVetoed;
121  }
122  catch (const uno::RuntimeException&)
123  {
124  eResult = eFailed;
125  }
126  }
127  return eResult;
128 }
129 
131 static bool LoadFromURL_impl(
133  SfxObjectShellRef &rxDocSh,
134  const OUString &rURL,
135  bool bClose )
136 {
137  // try to open the document readonly and hidden
138  Reference< frame::XModel > xTmpModel;
139  Sequence < PropertyValue > aArgs( 1 );
140  aArgs[0].Name = "Hidden";
141  aArgs[0].Value <<= true;
142  try
143  {
144  Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
145  xTmpModel.set( xDesktop->loadComponentFromURL( rURL, "_blank", 0, aArgs ), UNO_QUERY );
146  }
147  catch (const Exception&)
148  {
149  return false;
150  }
151 
152  // try to get the DocShell
153  SwDocShell *pTmpDocShell = nullptr;
154  if (auto pTextDoc = comphelper::getUnoTunnelImplementation<SwXTextDocument>(xTmpModel); pTextDoc)
155  pTmpDocShell = pTextDoc->GetDocShell();
156 
157  bool bRes = false;
158  if (xTmpModel.is() && pTmpDocShell) // everything available?
159  {
160  if (bClose)
161  CloseModelAndDocSh( rxModel, rxDocSh );
162  // set new stuff
163  rxModel = xTmpModel;
164  rxDocSh = pTmpDocShell;
165  bRes = true;
166  }
167  else
168  {
169  // SfxObjectShellRef is ok here, since the document will be explicitly closed
170  SfxObjectShellRef xTmpDocSh = pTmpDocShell;
171  CloseModelAndDocSh( xTmpModel, xTmpDocSh );
172  }
173 
174  return bRes;
175 }
176 
177 namespace
178 {
179  class DelayedFileDeletion : public ::cppu::WeakImplHelper<util::XCloseListener>
180  {
181  protected:
182  ::osl::Mutex m_aMutex;
183  Reference< util::XCloseable > m_xDocument;
184  Timer m_aDeleteTimer;
185  OUString m_sTemporaryFile;
186  sal_Int32 m_nPendingDeleteAttempts;
187 
188  DelayedFileDeletion(DelayedFileDeletion const&) = delete;
189  DelayedFileDeletion& operator=(DelayedFileDeletion const&) = delete;
190 
191  public:
192  DelayedFileDeletion( const Reference< XModel >& _rxModel,
193  const OUString& _rTemporaryFile );
194 
195  protected:
196  virtual ~DelayedFileDeletion( ) override;
197 
198  // XCloseListener
199  virtual void SAL_CALL queryClosing( const EventObject& _rSource, sal_Bool _bGetsOwnership ) override;
200  virtual void SAL_CALL notifyClosing( const EventObject& _rSource ) override;
201 
202  // XEventListener
203  virtual void SAL_CALL disposing( const EventObject& Source ) override;
204 
205  private:
206  void implTakeOwnership( );
207  DECL_LINK( OnTryDeleteFile, Timer*, void );
208  };
209 
210  DelayedFileDeletion::DelayedFileDeletion( const Reference< XModel >& _rxModel, const OUString& _rTemporaryFile )
211  :
212  m_xDocument( _rxModel, UNO_QUERY )
213  ,m_sTemporaryFile( _rTemporaryFile )
214  ,m_nPendingDeleteAttempts( 0 )
215  {
216  osl_atomic_increment( &m_refCount );
217  try
218  {
219  if ( m_xDocument.is() )
220  {
221  m_xDocument->addCloseListener( this );
222  // successfully added -> keep ourself alive
223  acquire();
224  }
225  else {
226  OSL_FAIL("DelayedFileDeletion::DelayedFileDeletion: model is no component!" );
227  }
228  }
229  catch (const Exception&)
230  {
231  OSL_FAIL("DelayedFileDeletion::DelayedFileDeletion: could not register as event listener at the model!" );
232  }
233  osl_atomic_decrement( &m_refCount );
234  }
235 
236  IMPL_LINK_NOARG(DelayedFileDeletion, OnTryDeleteFile, Timer *, void)
237  {
238  ::osl::ClearableMutexGuard aGuard( m_aMutex );
239 
240  bool bSuccess = false;
241  try
242  {
243  bool bDeliverOwnership = ( 0 == m_nPendingDeleteAttempts );
244  // if this is our last attempt, then anybody which vetoes this has to take the consequences
245  // (means take the ownership)
246  m_xDocument->close( bDeliverOwnership );
247  bSuccess = true;
248  }
249  catch (const util::CloseVetoException&)
250  {
251  // somebody vetoed -> next try
252  if ( m_nPendingDeleteAttempts )
253  {
254  // next attempt
255  --m_nPendingDeleteAttempts;
256  m_aDeleteTimer.Start();
257  }
258  else
259  bSuccess = true; // can't do anything here ...
260  }
261  catch (const Exception&)
262  {
263  TOOLS_WARN_EXCEPTION( "sw", "DelayedFileDeletion::OnTryDeleteFile: caught a strange exception!" );
264  bSuccess = true;
265  // can't do anything here ...
266  }
267 
268  if ( bSuccess )
269  {
270  SWUnoHelper::UCB_DeleteFile( m_sTemporaryFile );
271  aGuard.clear();
272  release(); // this should be our last reference, we should be dead after this
273  }
274  }
275 
276  void DelayedFileDeletion::implTakeOwnership( )
277  {
278  // revoke ourself as listener
279  try
280  {
281  m_xDocument->removeCloseListener( this );
282  }
283  catch (const Exception&)
284  {
285  OSL_FAIL("DelayedFileDeletion::implTakeOwnership: could not revoke the listener!" );
286  }
287 
288  m_aDeleteTimer.SetTimeout( 3000 ); // 3 seconds
289  m_aDeleteTimer.SetInvokeHandler( LINK( this, DelayedFileDeletion, OnTryDeleteFile ) );
290  m_nPendingDeleteAttempts = 3; // try 3 times at most
291  m_aDeleteTimer.Start( );
292  }
293 
294  void SAL_CALL DelayedFileDeletion::queryClosing( const EventObject& , sal_Bool _bGetsOwnership )
295  {
296  ::osl::MutexGuard aGuard( m_aMutex );
297  if ( _bGetsOwnership )
298  implTakeOwnership( );
299 
300  // always veto: We want to take the ownership ourself, as this is the only chance to delete
301  // the temporary file which the model is based on
302  throw util::CloseVetoException( );
303  }
304 
305  void SAL_CALL DelayedFileDeletion::notifyClosing( const EventObject& )
306  {
307  OSL_FAIL("DelayedFileDeletion::notifyClosing: how this?" );
308  // this should not happen:
309  // Either, a foreign instance closes the document, then we should veto this, and take the ownership
310  // Or, we ourself close the document, then we should not be a listener anymore
311  }
312 
313  void SAL_CALL DelayedFileDeletion::disposing( const EventObject& )
314  {
315  OSL_FAIL("DelayedFileDeletion::disposing: how this?" );
316  // this should not happen:
317  // Either, a foreign instance closes the document, then we should veto this, and take the ownership
318  // Or, we ourself close the document, then we should not be a listener anymore
319  }
320 
321  DelayedFileDeletion::~DelayedFileDeletion( )
322  {
323  }
324 }
325 
326 static bool DeleteTmpFile_Impl(
328  SfxObjectShellRef &rxDocSh,
329  const OUString &rTmpFileURL )
330 {
331  bool bRes = false;
332  if (!rTmpFileURL.isEmpty())
333  {
334  bool bDelete = true;
335  if ( eVetoed == CloseModelAndDocSh( rxModel, rxDocSh ) )
336  {
337  // somebody vetoed the closing, and took the ownership of the document
338  // -> ensure that the temporary file is deleted later on
339  new DelayedFileDeletion( rxModel, rTmpFileURL );
340  // note: as soon as #106931# is fixed, the whole DelayedFileDeletion is to be superseded by
341  // a better solution
342  bDelete = false;
343  }
344 
345  rxModel = nullptr;
346  rxDocSh = nullptr; // destroy doc shell
347 
348  if ( bDelete )
349  {
350  if ( !SWUnoHelper::UCB_DeleteFile( rTmpFileURL ) )
351  {
352  new DelayedFileDeletion( rxModel, rTmpFileURL );
353  // same not as above: as soon as #106931#, ...
354  }
355  }
356  else
357  bRes = true; // file will be deleted delayed
358  }
359  return bRes;
360 }
361 
363  m_aEvtListeners ( GetMailMergeMutex() ),
364  m_aMergeListeners ( GetMailMergeMutex() ),
365  m_aPropListeners ( GetMailMergeMutex() ),
366  m_pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_MAILMERGE ) ),
367  m_nDataCommandType(sdb::CommandType::TABLE),
368  m_nOutputType(MailMergeType::PRINTER),
369  m_bEscapeProcessing(true),
370  m_bSinglePrintJobs(false),
371  m_bFileNameFromColumn(false),
372  m_bSendAsHTML(false),
373  m_bSendAsAttachment(false),
374  m_bSaveAsSingleFile(false),
375  m_bDisposing(false),
376  m_pMgr(nullptr)
377 {
378  // create empty document
379  // like in: SwModule::InsertEnv (appenv.cxx)
380  m_xDocSh = new SwDocShell( SfxObjectCreateMode::STANDARD );
381  m_xDocSh->DoInitNew();
383  SwView *pView = static_cast<SwView*>( pFrame->GetViewShell() );
384  pView->AttrChangedNotify(nullptr); //So that SelectShell is called.
386 }
387 
389 {
390  if (!m_aTmpFileName.isEmpty())
392  else // there was no temporary file in use
393  {
397  if ( eVetoed == CloseModelAndDocSh( m_xModel, m_xDocSh ) )
398  OSL_FAIL("ownership transferred to vetoing object!" );
399 
400  m_xModel = nullptr;
401  m_xDocSh = nullptr; // destroy doc shell
402  }
403 }
404 
405 // Guarantee object consistence in case of an exception
407 {
408 public:
410  : m_pMailMerge(mailmerge)
411  {
412  assert(m_pMailMerge); //mailmerge object missing
413  }
415  {
416  osl::MutexGuard aMgrGuard( GetMailMergeMutex() );
417  m_pMailMerge->m_pMgr = nullptr;
418  }
419 
420 private:
423 
425 };
426 
428  const uno::Sequence< beans::NamedValue >& rArguments )
429 {
430  SolarMutexGuard aGuard;
431  MailMergeExecuteFinalizer aFinalizer(this);
432 
433  // get property values to be used
434  // (use values from the service as default and override them with
435  // the values that are provided as arguments)
436 
437  uno::Sequence< uno::Any > aCurSelection = m_aSelection;
438  uno::Reference< sdbc::XResultSet > xCurResultSet = m_xResultSet;
439  uno::Reference< sdbc::XConnection > xCurConnection = m_xConnection;
440  uno::Reference< frame::XModel > xCurModel = m_xModel;
441  OUString aCurDataSourceName = m_aDataSourceName;
442  OUString aCurDataCommand = m_aDataCommand;
443  OUString aCurFilter = m_aFilter;
444  OUString aCurDocumentURL = m_aDocumentURL;
445  OUString aCurOutputURL = m_aOutputURL;
446  OUString aCurFileNamePrefix = m_aFileNamePrefix;
447  sal_Int32 nCurDataCommandType = m_nDataCommandType;
448  sal_Int16 nCurOutputType = m_nOutputType;
449  bool bCurEscapeProcessing = m_bEscapeProcessing;
450  bool bCurSinglePrintJobs = m_bSinglePrintJobs;
451  bool bCurFileNameFromColumn = m_bFileNameFromColumn;
452 
453  SfxObjectShellRef xCurDocSh = m_xDocSh; // the document
454 
455  for (const beans::NamedValue& rArgument : rArguments)
456  {
457  const OUString &rName = rArgument.Name;
458  const Any &rValue = rArgument.Value;
459 
460  bool bOK = true;
461  if (rName == UNO_NAME_SELECTION)
462  bOK = rValue >>= aCurSelection;
463  else if (rName == UNO_NAME_RESULT_SET)
464  bOK = rValue >>= xCurResultSet;
465  else if (rName == UNO_NAME_CONNECTION)
466  bOK = rValue >>= xCurConnection;
467  else if (rName == UNO_NAME_MODEL)
468  throw PropertyVetoException("Property is read-only: " + rName, static_cast < cppu::OWeakObject * > ( this ) );
469  else if (rName == UNO_NAME_DATA_SOURCE_NAME)
470  bOK = rValue >>= aCurDataSourceName;
471  else if (rName == UNO_NAME_DAD_COMMAND)
472  bOK = rValue >>= aCurDataCommand;
473  else if (rName == UNO_NAME_FILTER)
474  bOK = rValue >>= aCurFilter;
475  else if (rName == UNO_NAME_DOCUMENT_URL)
476  {
477  bOK = rValue >>= aCurDocumentURL;
478  if (!aCurDocumentURL.isEmpty()
479  && !LoadFromURL_impl( xCurModel, xCurDocSh, aCurDocumentURL, false ))
480  throw RuntimeException("Failed to create document from URL: " + aCurDocumentURL, static_cast < cppu::OWeakObject * > ( this ) );
481  }
482  else if (rName == UNO_NAME_OUTPUT_URL)
483  {
484  bOK = rValue >>= aCurOutputURL;
485  if (!aCurOutputURL.isEmpty())
486  {
487  if (!UCB_IsDirectory(aCurOutputURL))
488  throw IllegalArgumentException("URL does not point to a directory: " + aCurOutputURL, static_cast < cppu::OWeakObject * > ( this ), 0 );
489  if (UCB_IsReadOnlyFileName(aCurOutputURL))
490  throw IllegalArgumentException("URL is read-only: " + aCurOutputURL, static_cast < cppu::OWeakObject * > ( this ), 0 );
491  }
492  }
493  else if (rName == UNO_NAME_FILE_NAME_PREFIX)
494  bOK = rValue >>= aCurFileNamePrefix;
495  else if (rName == UNO_NAME_DAD_COMMAND_TYPE)
496  bOK = rValue >>= nCurDataCommandType;
497  else if (rName == UNO_NAME_OUTPUT_TYPE)
498  bOK = rValue >>= nCurOutputType;
499  else if (rName == UNO_NAME_ESCAPE_PROCESSING)
500  bOK = rValue >>= bCurEscapeProcessing;
501  else if (rName == UNO_NAME_SINGLE_PRINT_JOBS)
502  bOK = rValue >>= bCurSinglePrintJobs;
503  else if (rName == UNO_NAME_FILE_NAME_FROM_COLUMN)
504  bOK = rValue >>= bCurFileNameFromColumn;
505  else if (rName == UNO_NAME_SUBJECT)
506  bOK = rValue >>= m_sSubject;
507  else if (rName == UNO_NAME_ADDRESS_FROM_COLUMN)
508  bOK = rValue >>= m_sAddressFromColumn;
509  else if (rName == UNO_NAME_SEND_AS_HTML)
510  bOK = rValue >>= m_bSendAsHTML;
511  else if (rName == UNO_NAME_MAIL_BODY)
512  bOK = rValue >>= m_sMailBody;
513  else if (rName == UNO_NAME_ATTACHMENT_NAME)
514  bOK = rValue >>= m_sAttachmentName;
515  else if (rName == UNO_NAME_ATTACHMENT_FILTER)
516  bOK = rValue >>= m_sAttachmentFilter;
517  else if (rName == UNO_NAME_COPIES_TO)
518  bOK = rValue >>= m_aCopiesTo;
519  else if (rName == UNO_NAME_BLIND_COPIES_TO)
520  bOK = rValue >>= m_aBlindCopiesTo;
521  else if (rName == UNO_NAME_SEND_AS_ATTACHMENT)
522  bOK = rValue >>= m_bSendAsAttachment;
523  else if (rName == UNO_NAME_PRINT_OPTIONS)
524  bOK = rValue >>= m_aPrintSettings;
525  else if (rName == UNO_NAME_SAVE_AS_SINGLE_FILE)
526  bOK = rValue >>= m_bSaveAsSingleFile;
527  else if (rName == UNO_NAME_SAVE_FILTER)
528  bOK = rValue >>= m_sSaveFilter;
529  else if (rName == UNO_NAME_SAVE_FILTER_OPTIONS)
530  bOK = rValue >>= m_sSaveFilterOptions;
531  else if (rName == UNO_NAME_SAVE_FILTER_DATA)
532  bOK = rValue >>= m_aSaveFilterData;
533  else if (rName == UNO_NAME_IN_SERVER_PASSWORD)
534  bOK = rValue >>= m_sInServerPassword;
535  else if (rName == UNO_NAME_OUT_SERVER_PASSWORD)
536  bOK = rValue >>= m_sOutServerPassword;
537  else
538  throw UnknownPropertyException( "Property is unknown: " + rName, static_cast < cppu::OWeakObject * > ( this ) );
539 
540  if (!bOK)
541  throw IllegalArgumentException("Property type mismatch or property not set: " + rName, static_cast < cppu::OWeakObject * > ( this ), 0 );
542  }
543 
544  // need to translate the selection: the API here requires a sequence of bookmarks, but the Merge
545  // method we will call below requires a sequence of indices.
546  if ( aCurSelection.hasElements() )
547  {
548  Sequence< Any > aTranslated( aCurSelection.getLength() );
549 
550  bool bValid = false;
551  Reference< sdbcx::XRowLocate > xRowLocate( xCurResultSet, UNO_QUERY );
552  if ( xRowLocate.is() )
553  {
554  Any* pTranslated = aTranslated.getArray();
555 
556  try
557  {
558  bool bEverythingsFine = true;
559  for ( const Any& rBookmark : std::as_const(aCurSelection) )
560  {
561  bEverythingsFine = xRowLocate->moveToBookmark( rBookmark );
562  if ( !bEverythingsFine )
563  break;
564  *pTranslated <<= xCurResultSet->getRow();
565  ++pTranslated;
566  }
567  if ( bEverythingsFine )
568  bValid = true;
569  }
570  catch (const Exception&)
571  {
572  bValid = false;
573  }
574  }
575 
576  if ( !bValid )
577  {
578  throw IllegalArgumentException(
579  "The current 'Selection' does not describe a valid array of bookmarks, relative to the current 'ResultSet'.",
580  static_cast < cppu::OWeakObject * > ( this ),
581  0
582  );
583  }
584 
585  aCurSelection = aTranslated;
586  }
587 
588  SfxViewFrame* pFrame = SfxViewFrame::GetFirst( xCurDocSh.get(), false);
589  SwView *pView = pFrame ? dynamic_cast<SwView*>( pFrame->GetViewShell() ) : nullptr;
590  if (!pView)
591  throw RuntimeException();
592  SwWrtShell &rSh = *pView->GetWrtShellPtr();
593 
594  // avoid assertion in 'Update' from Sfx by supplying a shell
595  // and thus avoiding the SelectShell call in Writers GetState function
596  // while still in Update of Sfx.
597  // (GetSelection in Update is not allowed)
598  if (!aCurDocumentURL.isEmpty())
599  pView->AttrChangedNotify(nullptr);//So that SelectShell is called.
600 
601  SharedComponent aRowSetDisposeHelper;
602  if (!xCurResultSet.is())
603  {
604  if (aCurDataSourceName.isEmpty() || aCurDataCommand.isEmpty() )
605  {
606  OSL_FAIL("PropertyValues missing or unset");
607  throw IllegalArgumentException("Either the ResultSet or DataSourceName and DataCommand must be set.", static_cast < cppu::OWeakObject * > ( this ), 0 );
608  }
609 
610  // build ResultSet from DataSourceName, DataCommand and DataCommandType
611 
612  Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
613  if (xMgr.is())
614  {
615  Reference< XInterface > xInstance = xMgr->createInstance( "com.sun.star.sdb.RowSet" );
616  aRowSetDisposeHelper.reset( xInstance, SharedComponent::TakeOwnership );
617  Reference< XPropertySet > xRowSetPropSet( xInstance, UNO_QUERY );
618  OSL_ENSURE( xRowSetPropSet.is(), "failed to get XPropertySet interface from RowSet" );
619  if (xRowSetPropSet.is())
620  {
621  if (xCurConnection.is())
622  xRowSetPropSet->setPropertyValue( "ActiveConnection", makeAny( xCurConnection ) );
623  xRowSetPropSet->setPropertyValue( "DataSourceName", makeAny( aCurDataSourceName ) );
624  xRowSetPropSet->setPropertyValue( "Command", makeAny( aCurDataCommand ) );
625  xRowSetPropSet->setPropertyValue( "CommandType", makeAny( nCurDataCommandType ) );
626  xRowSetPropSet->setPropertyValue( "EscapeProcessing", makeAny( bCurEscapeProcessing ) );
627  xRowSetPropSet->setPropertyValue( "ApplyFilter", makeAny( true ) );
628  xRowSetPropSet->setPropertyValue( "Filter", makeAny( aCurFilter ) );
629 
630  Reference< sdbc::XRowSet > xRowSet( xInstance, UNO_QUERY );
631  if (xRowSet.is())
632  xRowSet->execute(); // build ResultSet from properties
633  if( !xCurConnection.is() )
634  xCurConnection.set( xRowSetPropSet->getPropertyValue( "ActiveConnection" ), UNO_QUERY );
635  xCurResultSet = xRowSet;
636  OSL_ENSURE( xCurResultSet.is(), "failed to build ResultSet" );
637  }
638  }
639  }
640 
641  svx::ODataAccessDescriptor aDescriptor;
642  aDescriptor.setDataSource(aCurDataSourceName);
643  aDescriptor[ svx::DataAccessDescriptorProperty::Connection ] <<= xCurConnection;
644  aDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= aCurDataCommand;
645  aDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= nCurDataCommandType;
646  aDescriptor[ svx::DataAccessDescriptorProperty::EscapeProcessing ] <<= bCurEscapeProcessing;
647  aDescriptor[ svx::DataAccessDescriptorProperty::Cursor ] <<= xCurResultSet;
648  // aDescriptor[ svx::DataAccessDescriptorProperty::ColumnName ] not used
649  // aDescriptor[ svx::DataAccessDescriptorProperty::ColumnObject ] not used
650  aDescriptor[ svx::DataAccessDescriptorProperty::Selection ] <<= aCurSelection;
651 
652  DBManagerOptions nMergeType;
653  switch (nCurOutputType)
654  {
655  case MailMergeType::PRINTER : nMergeType = DBMGR_MERGE_PRINTER; break;
656  case MailMergeType::FILE : nMergeType = DBMGR_MERGE_FILE; break;
657  case MailMergeType::MAIL : nMergeType = DBMGR_MERGE_EMAIL; break;
658  case MailMergeType::SHELL : nMergeType = DBMGR_MERGE_SHELL; break;
659  default:
660  throw IllegalArgumentException("Invalid value of property: OutputType", static_cast < cppu::OWeakObject * > ( this ), 0 );
661  }
662 
663  SwDBManager* pMgr = rSh.GetDBManager();
664  //force layout creation
665  rSh.CalcLayout();
666  OSL_ENSURE( pMgr, "database manager missing" );
667  m_pMgr = pMgr;
668 
669  SwMergeDescriptor aMergeDesc( nMergeType, rSh, aDescriptor );
670 
671  std::unique_ptr< SwMailMergeConfigItem > pMMConfigItem;
672  uno::Reference< mail::XMailService > xInService;
673  switch (nCurOutputType)
674  {
675  case MailMergeType::PRINTER:
676  {
678  SwPrintData aPrtData( rIDDA.getPrintData() );
679  aPrtData.SetPrintSingleJobs( bCurSinglePrintJobs );
680  rIDDA.setPrintData( aPrtData );
681  // #i25686# printing should not be done asynchronously to prevent dangling offices
682  // when mail merge is called as command line macro
683  aMergeDesc.aPrintOptions = m_aPrintSettings;
684  aMergeDesc.bCreateSingleFile = true;
685  }
686  break;
687  case MailMergeType::SHELL:
688  aMergeDesc.bCreateSingleFile = true;
689  pMMConfigItem.reset(new SwMailMergeConfigItem);
690  aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get();
691  break;
692  case MailMergeType::FILE:
693  {
694  INetURLObject aURLObj;
695  aURLObj.SetSmartProtocol( INetProtocol::File );
696 
697  if (!aCurDocumentURL.isEmpty())
698  {
699  // if OutputURL or FileNamePrefix are missing get
700  // them from DocumentURL
701  aURLObj.SetSmartURL( aCurDocumentURL );
702  if (aCurFileNamePrefix.isEmpty())
703  aCurFileNamePrefix = aURLObj.GetBase(); // filename without extension
704  if (aCurOutputURL.isEmpty())
705  {
706  aURLObj.removeSegment();
707  aCurOutputURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
708  }
709  }
710  else // default empty document without URL
711  {
712  if (aCurOutputURL.isEmpty())
713  throw RuntimeException("OutputURL is not set and can not be obtained.", static_cast < cppu::OWeakObject * > ( this ) );
714  }
715 
716  aURLObj.SetSmartURL( aCurOutputURL );
717  OUString aPath = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
718 
719  const OUString aDelim( "/" );
720  if (!aPath.isEmpty() && !aPath.endsWith(aDelim))
721  aPath += aDelim;
722  if (bCurFileNameFromColumn)
723  aMergeDesc.sDBcolumn = aCurFileNamePrefix;
724  else
725  {
726  aPath += aCurFileNamePrefix;
727  }
728 
729  aMergeDesc.sPrefix = aPath;
730  aMergeDesc.sSaveToFilter = m_sSaveFilter;
734  }
735  break;
736  case MailMergeType::MAIL:
737  {
738  aMergeDesc.sDBcolumn = m_sAddressFromColumn;
739  if(m_sAddressFromColumn.isEmpty())
740  throw RuntimeException("Mail address column not set.", static_cast < cppu::OWeakObject * > ( this ) );
741  aMergeDesc.sSaveToFilter = m_sAttachmentFilter;
742  aMergeDesc.sSubject = m_sSubject;
743  aMergeDesc.sMailBody = m_sMailBody;
744  aMergeDesc.sAttachmentName = m_sAttachmentName;
745  aMergeDesc.aCopiesTo = m_aCopiesTo;
746  aMergeDesc.aBlindCopiesTo = m_aBlindCopiesTo;
747  aMergeDesc.bSendAsHTML = m_bSendAsHTML;
749 
750  aMergeDesc.bCreateSingleFile = false;
751  pMMConfigItem.reset(new SwMailMergeConfigItem);
752  aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get();
754  *pMMConfigItem,
755  xInService,
757  if( !aMergeDesc.xSmtpServer.is() || !aMergeDesc.xSmtpServer->isConnected())
758  throw RuntimeException("Failed to connect to mail server.", static_cast < cppu::OWeakObject * > ( this ) );
759  }
760  break;
761  }
762 
763  // save document with temporary filename
764  std::shared_ptr<const SfxFilter> pSfxFlt = SwIoSystem::GetFilterOfFormat(
765  FILTER_XML,
766  SwDocShell::Factory().GetFilterContainer() );
767  OUString aExtension(comphelper::string::stripStart(pSfxFlt->GetDefaultExtension(), '*'));
768  utl::TempFile aTempFile( "SwMM", true, &aExtension );
769  m_aTmpFileName = aTempFile.GetURL();
770 
771  Reference< XStorable > xStorable( xCurModel, UNO_QUERY );
772  bool bStoredAsTemporary = false;
773  if ( xStorable.is() )
774  {
775  try
776  {
777  xStorable->storeAsURL( m_aTmpFileName, Sequence< PropertyValue >() );
778  bStoredAsTemporary = true;
779  }
780  catch (const Exception&)
781  {
782  }
783  }
784  if ( !bStoredAsTemporary )
785  throw RuntimeException("Failed to save temporary file.", static_cast < cppu::OWeakObject * > ( this ) );
786 
787  pMgr->SetMergeSilent( true ); // suppress dialogs, message boxes, etc.
788  const SwXMailMerge *pOldSrc = pMgr->GetMailMergeEvtSrc();
789  OSL_ENSURE( !pOldSrc || pOldSrc == this, "Ooops... different event source already set." );
790  pMgr->SetMailMergeEvtSrc( this ); // launch events for listeners
791 
792  SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwMailMerge, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE), xCurDocSh.get()));
793  bool bSucc = pMgr->Merge( aMergeDesc );
794  SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwMailMergeEnd, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END), xCurDocSh.get()));
795 
796  pMgr->SetMailMergeEvtSrc( pOldSrc );
797 
798  if ( xCurModel.get() != m_xModel.get() )
799  { // in case it was a temporary model -> close it, and delete the file
800  DeleteTmpFile_Impl( xCurModel, xCurDocSh, m_aTmpFileName );
801  m_aTmpFileName.clear();
802  }
803  // (in case it wasn't a temporary model, it will be closed in the dtor, at the latest)
804 
805  if (!bSucc)
806  throw Exception("Mail merge failed. Sorry, no further information available.", static_cast < cppu::OWeakObject * > ( this ) );
807 
808  //de-initialize services
809  if(xInService.is() && xInService->isConnected())
810  xInService->disconnect();
811  if(aMergeDesc.xSmtpServer.is() && aMergeDesc.xSmtpServer->isConnected())
812  aMergeDesc.xSmtpServer->disconnect();
813 
814  if (DBMGR_MERGE_SHELL == nMergeType)
815  {
816  return makeAny( aMergeDesc.pMailMergeConfigItem->GetTargetView()->GetDocShell()->GetBaseModel() );
817  }
818  else
819  return makeAny( true );
820 }
821 
822 void SAL_CALL SwXMailMerge::cancel()
823 {
824  // Cancel may be called from a second thread, so this protects from m_pMgr
826  osl::MutexGuard aMgrGuard( GetMailMergeMutex() );
827  if (m_pMgr)
828  m_pMgr->MergeCancel();
829 }
830 
831 void SwXMailMerge::LaunchMailMergeEvent( const MailMergeEvent &rEvt ) const
832 {
833  comphelper::OInterfaceIteratorHelper2 aIt( const_cast<SwXMailMerge *>(this)->m_aMergeListeners );
834  while (aIt.hasMoreElements())
835  {
836  Reference< XMailMergeListener > xRef( aIt.next(), UNO_QUERY );
837  if (xRef.is())
838  xRef->notifyMailMergeEvent( rEvt );
839  }
840 }
841 
842 void SwXMailMerge::launchEvent( const PropertyChangeEvent &rEvt ) const
843 {
844  cppu::OInterfaceContainerHelper *pContainer =
845  m_aPropListeners.getContainer( rEvt.PropertyHandle );
846  if (pContainer)
847  {
848  cppu::OInterfaceIteratorHelper aIt( *pContainer );
849  while (aIt.hasMoreElements())
850  {
851  Reference< XPropertyChangeListener > xRef( aIt.next(), UNO_QUERY );
852  if (xRef.is())
853  xRef->propertyChange( rEvt );
854  }
855  }
856 }
857 
858 uno::Reference< beans::XPropertySetInfo > SAL_CALL SwXMailMerge::getPropertySetInfo( )
859 {
860  SolarMutexGuard aGuard;
861  static Reference< XPropertySetInfo > aRef = m_pPropSet->getPropertySetInfo();
862  return aRef;
863 }
864 
866  const OUString& rPropertyName, const uno::Any& rValue )
867 {
868  SolarMutexGuard aGuard;
869 
870  const SfxItemPropertySimpleEntry* pCur = m_pPropSet->getPropertyMap().getByName( rPropertyName );
871  if (!pCur)
872  throw UnknownPropertyException(rPropertyName);
873  else if (pCur->nFlags & PropertyAttribute::READONLY)
874  throw PropertyVetoException();
875  else
876  {
877  void *pData = nullptr;
878  switch (pCur->nWID)
879  {
880  case WID_SELECTION : pData = &m_aSelection; break;
881  case WID_RESULT_SET : pData = &m_xResultSet; break;
882  case WID_CONNECTION : pData = &m_xConnection; break;
883  case WID_MODEL : pData = &m_xModel; break;
884  case WID_DATA_SOURCE_NAME : pData = &m_aDataSourceName; break;
885  case WID_DATA_COMMAND : pData = &m_aDataCommand; break;
886  case WID_FILTER : pData = &m_aFilter; break;
887  case WID_DOCUMENT_URL : pData = &m_aDocumentURL; break;
888  case WID_OUTPUT_URL : pData = &m_aOutputURL; break;
889  case WID_DATA_COMMAND_TYPE : pData = &m_nDataCommandType; break;
890  case WID_OUTPUT_TYPE : pData = &m_nOutputType; break;
891  case WID_ESCAPE_PROCESSING : pData = &m_bEscapeProcessing; break;
892  case WID_SINGLE_PRINT_JOBS : pData = &m_bSinglePrintJobs; break;
893  case WID_FILE_NAME_FROM_COLUMN : pData = &m_bFileNameFromColumn; break;
894  case WID_FILE_NAME_PREFIX : pData = &m_aFileNamePrefix; break;
895  case WID_MAIL_SUBJECT: pData = &m_sSubject; break;
896  case WID_ADDRESS_FROM_COLUMN: pData = &m_sAddressFromColumn; break;
897  case WID_SEND_AS_HTML: pData = &m_bSendAsHTML; break;
898  case WID_SEND_AS_ATTACHMENT: pData = &m_bSendAsAttachment; break;
899  case WID_MAIL_BODY: pData = &m_sMailBody; break;
900  case WID_ATTACHMENT_NAME: pData = &m_sAttachmentName; break;
901  case WID_ATTACHMENT_FILTER: pData = &m_sAttachmentFilter;break;
902  case WID_PRINT_OPTIONS: pData = &m_aPrintSettings; break;
903  case WID_SAVE_AS_SINGLE_FILE: pData = &m_bSaveAsSingleFile; break;
904  case WID_SAVE_FILTER: pData = &m_sSaveFilter; break;
905  case WID_SAVE_FILTER_OPTIONS: pData = &m_sSaveFilterOptions; break;
906  case WID_SAVE_FILTER_DATA: pData = &m_aSaveFilterData; break;
907  case WID_COPIES_TO: pData = &m_aCopiesTo; break;
908  case WID_BLIND_COPIES_TO: pData = &m_aBlindCopiesTo;break;
909  case WID_IN_SERVER_PASSWORD: pData = &m_sInServerPassword; break;
910  case WID_OUT_SERVER_PASSWORD: pData = &m_sOutServerPassword; break;
911  default :
912  OSL_FAIL("unknown WID");
913  }
914  Any aOld( pData, pCur->aType );
915 
916  bool bChanged = false;
917  bool bOK = true;
918  if (aOld != rValue)
919  {
920  if (pData == &m_aSelection)
921  bOK = rValue >>= m_aSelection;
922  else if (pData == &m_xResultSet)
923  bOK = rValue >>= m_xResultSet;
924  else if (pData == &m_xConnection)
925  bOK = rValue >>= m_xConnection;
926  else if (pData == &m_xModel)
927  bOK = rValue >>= m_xModel;
928  else if (pData == &m_aDataSourceName)
929  bOK = rValue >>= m_aDataSourceName;
930  else if (pData == &m_aDataCommand)
931  bOK = rValue >>= m_aDataCommand;
932  else if (pData == &m_aFilter)
933  bOK = rValue >>= m_aFilter;
934  else if (pData == &m_aDocumentURL)
935  {
936  OUString aText;
937  bOK = rValue >>= aText;
938  if (!aText.isEmpty()
939  && !LoadFromURL_impl( m_xModel, m_xDocSh, aText, true ))
940  throw RuntimeException("Failed to create document from URL: " + aText, static_cast < cppu::OWeakObject * > ( this ) );
941  m_aDocumentURL = aText;
942  }
943  else if (pData == &m_aOutputURL)
944  {
945  OUString aText;
946  bOK = rValue >>= aText;
947  if (!aText.isEmpty())
948  {
949  if (!UCB_IsDirectory(aText))
950  throw IllegalArgumentException("URL does not point to a directory: " + aText, static_cast < cppu::OWeakObject * > ( this ), 0 );
951  if (UCB_IsReadOnlyFileName(aText))
952  throw IllegalArgumentException("URL is read-only: " + aText, static_cast < cppu::OWeakObject * > ( this ), 0 );
953  }
954  m_aOutputURL = aText;
955  }
956  else if (pData == &m_nDataCommandType)
957  bOK = rValue >>= m_nDataCommandType;
958  else if (pData == &m_nOutputType)
959  bOK = rValue >>= m_nOutputType;
960  else if (pData == &m_bEscapeProcessing)
961  bOK = rValue >>= m_bEscapeProcessing;
962  else if (pData == &m_bSinglePrintJobs)
963  bOK = rValue >>= m_bSinglePrintJobs;
964  else if (pData == &m_bFileNameFromColumn)
965  bOK = rValue >>= m_bFileNameFromColumn;
966  else if (pData == &m_aFileNamePrefix)
967  bOK = rValue >>= m_aFileNamePrefix;
968  else if (pData == &m_sSubject)
969  bOK = rValue >>= m_sSubject;
970  else if (pData == &m_sAddressFromColumn)
971  bOK = rValue >>= m_sAddressFromColumn;
972  else if (pData == &m_bSendAsHTML)
973  bOK = rValue >>= m_bSendAsHTML;
974  else if (pData == &m_bSendAsAttachment)
975  bOK = rValue >>= m_bSendAsAttachment;
976  else if (pData == &m_sMailBody)
977  bOK = rValue >>= m_sMailBody;
978  else if (pData == &m_sAttachmentName)
979  bOK = rValue >>= m_sAttachmentName;
980  else if (pData == &m_sAttachmentFilter)
981  bOK = rValue >>= m_sAttachmentFilter;
982  else if (pData == &m_aPrintSettings)
983  bOK = rValue >>= m_aPrintSettings;
984  else if (pData == &m_bSaveAsSingleFile)
985  bOK = rValue >>= m_bSaveAsSingleFile;
986  else if (pData == &m_sSaveFilter)
987  bOK = rValue >>= m_sSaveFilter;
988  else if (pData == &m_sSaveFilterOptions)
989  bOK = rValue >>= m_sSaveFilterOptions;
990  else if (pData == &m_aSaveFilterData)
991  bOK = rValue >>= m_aSaveFilterData;
992  else if (pData == &m_aCopiesTo)
993  bOK = rValue >>= m_aCopiesTo;
994  else if (pData == &m_aBlindCopiesTo)
995  bOK = rValue >>= m_aBlindCopiesTo;
996  else if(pData == &m_sInServerPassword)
997  bOK = rValue >>= m_sInServerPassword;
998  else if(pData == &m_sOutServerPassword)
999  bOK = rValue >>= m_sOutServerPassword;
1000  else {
1001  OSL_FAIL("invalid pointer" );
1002  }
1003  OSL_ENSURE( bOK, "set value failed" );
1004  bChanged = true;
1005  }
1006  if (!bOK)
1007  throw IllegalArgumentException("Property type mismatch or property not set: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ), 0 );
1008 
1009  if (bChanged)
1010  {
1011  PropertyChangeEvent aChgEvt( static_cast<XPropertySet *>(this), rPropertyName,
1012  false, pCur->nWID, aOld, rValue );
1013  launchEvent( aChgEvt );
1014  }
1015  }
1016 }
1017 
1019  const OUString& rPropertyName )
1020 {
1021  SolarMutexGuard aGuard;
1022 
1023  Any aRet;
1024 
1025  const SfxItemPropertySimpleEntry* pCur = m_pPropSet->getPropertyMap().getByName( rPropertyName );
1026  if (!pCur)
1027  throw UnknownPropertyException(rPropertyName);
1028 
1029  switch (pCur->nWID)
1030  {
1031  case WID_SELECTION : aRet <<= m_aSelection; break;
1032  case WID_RESULT_SET : aRet <<= m_xResultSet; break;
1033  case WID_CONNECTION : aRet <<= m_xConnection; break;
1034  case WID_MODEL : aRet <<= m_xModel; break;
1035  case WID_DATA_SOURCE_NAME : aRet <<= m_aDataSourceName; break;
1036  case WID_DATA_COMMAND : aRet <<= m_aDataCommand; break;
1037  case WID_FILTER : aRet <<= m_aFilter; break;
1038  case WID_DOCUMENT_URL : aRet <<= m_aDocumentURL; break;
1039  case WID_OUTPUT_URL : aRet <<= m_aOutputURL; break;
1040  case WID_DATA_COMMAND_TYPE : aRet <<= m_nDataCommandType; break;
1041  case WID_OUTPUT_TYPE : aRet <<= m_nOutputType; break;
1042  case WID_ESCAPE_PROCESSING : aRet <<= m_bEscapeProcessing; break;
1043  case WID_SINGLE_PRINT_JOBS : aRet <<= m_bSinglePrintJobs; break;
1044  case WID_FILE_NAME_FROM_COLUMN : aRet <<= m_bFileNameFromColumn; break;
1045  case WID_FILE_NAME_PREFIX : aRet <<= m_aFileNamePrefix; break;
1046  case WID_MAIL_SUBJECT: aRet <<= m_sSubject; break;
1047  case WID_ADDRESS_FROM_COLUMN: aRet <<= m_sAddressFromColumn; break;
1048  case WID_SEND_AS_HTML: aRet <<= m_bSendAsHTML; break;
1049  case WID_SEND_AS_ATTACHMENT: aRet <<= m_bSendAsAttachment; break;
1050  case WID_MAIL_BODY: aRet <<= m_sMailBody; break;
1051  case WID_ATTACHMENT_NAME: aRet <<= m_sAttachmentName; break;
1052  case WID_ATTACHMENT_FILTER: aRet <<= m_sAttachmentFilter;break;
1053  case WID_PRINT_OPTIONS: aRet <<= m_aPrintSettings; break;
1054  case WID_SAVE_AS_SINGLE_FILE: aRet <<= m_bSaveAsSingleFile; break;
1055  case WID_SAVE_FILTER: aRet <<= m_sSaveFilter; break;
1056  case WID_SAVE_FILTER_OPTIONS: aRet <<= m_sSaveFilterOptions; break;
1057  case WID_SAVE_FILTER_DATA: aRet <<= m_aSaveFilterData; break;
1058  case WID_COPIES_TO: aRet <<= m_aCopiesTo; break;
1059  case WID_BLIND_COPIES_TO: aRet <<= m_aBlindCopiesTo;break;
1060  case WID_IN_SERVER_PASSWORD: aRet <<= m_sInServerPassword; break;
1061  case WID_OUT_SERVER_PASSWORD: aRet <<= m_sOutServerPassword; break;
1062  default :
1063  OSL_FAIL("unknown WID");
1064  }
1065 
1066  return aRet;
1067 }
1068 
1070  const OUString& rPropertyName,
1071  const uno::Reference< beans::XPropertyChangeListener >& rListener )
1072 {
1073  SolarMutexGuard aGuard;
1074  if (!m_bDisposing && rListener.is())
1075  {
1076  const SfxItemPropertySimpleEntry* pCur = m_pPropSet->getPropertyMap().getByName( rPropertyName );
1077  if (!pCur)
1078  throw UnknownPropertyException(rPropertyName);
1079  m_aPropListeners.addInterface( pCur->nWID, rListener );
1080  }
1081 }
1082 
1084  const OUString& rPropertyName,
1085  const uno::Reference< beans::XPropertyChangeListener >& rListener )
1086 {
1087  SolarMutexGuard aGuard;
1088  if (!m_bDisposing && rListener.is())
1089  {
1090  const SfxItemPropertySimpleEntry* pCur = m_pPropSet->getPropertyMap().getByName( rPropertyName );
1091  if (!pCur)
1092  throw UnknownPropertyException(rPropertyName);
1093  m_aPropListeners.removeInterface( pCur->nWID, rListener );
1094  }
1095 }
1096 
1098  const OUString& /*rPropertyName*/,
1099  const uno::Reference< beans::XVetoableChangeListener >& /*rListener*/ )
1100 {
1101  // no vetoable property, thus no support for vetoable change listeners
1102  OSL_FAIL("not implemented");
1103 }
1104 
1106  const OUString& /*rPropertyName*/,
1107  const uno::Reference< beans::XVetoableChangeListener >& /*rListener*/ )
1108 {
1109  // no vetoable property, thus no support for vetoable change listeners
1110  OSL_FAIL("not implemented");
1111 }
1112 
1113 void SAL_CALL SwXMailMerge::dispose()
1114 {
1115  SolarMutexGuard aGuard;
1116 
1117  if (!m_bDisposing)
1118  {
1119  m_bDisposing = true;
1120 
1121  EventObject aEvtObj( static_cast<XPropertySet *>(this) );
1122  m_aEvtListeners.disposeAndClear( aEvtObj );
1124  m_aPropListeners.disposeAndClear( aEvtObj );
1125  }
1126 }
1127 
1129  const Reference< XEventListener >& rxListener )
1130 {
1131  SolarMutexGuard aGuard;
1132  if (!m_bDisposing && rxListener.is())
1133  m_aEvtListeners.addInterface( rxListener );
1134 }
1135 
1137  const Reference< XEventListener >& rxListener )
1138 {
1139  SolarMutexGuard aGuard;
1140  if (!m_bDisposing && rxListener.is())
1141  m_aEvtListeners.removeInterface( rxListener );
1142 }
1143 
1145  const uno::Reference< XMailMergeListener >& rxListener )
1146 {
1147  SolarMutexGuard aGuard;
1148  if (!m_bDisposing && rxListener.is())
1149  m_aMergeListeners.addInterface( rxListener );
1150 }
1151 
1153  const uno::Reference< XMailMergeListener >& rxListener )
1154 {
1155  SolarMutexGuard aGuard;
1156  if (!m_bDisposing && rxListener.is())
1157  m_aMergeListeners.removeInterface( rxListener );
1158 }
1159 
1161 {
1162  return "SwXMailMerge";
1163 }
1164 
1165 sal_Bool SAL_CALL SwXMailMerge::supportsService( const OUString& rServiceName )
1166 {
1167  return cppu::supportsService(this, rServiceName);
1168 }
1169 
1170 uno::Sequence< OUString > SAL_CALL SwXMailMerge::getSupportedServiceNames()
1171 {
1172  return { "com.sun.star.text.MailMerge", "com.sun.star.sdb.DataAccessDescriptor" };
1173 }
1174 
1175 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString m_aDocumentURL
virtual void SAL_CALL removeMailMergeEventListener(const css::uno::Reference< css::text::XMailMergeListener > &xListener) override
const SfxItemPropertySimpleEntry * getByName(std::u16string_view rName) const
bool bCreateSingleFile
Create a single or multiple results.
Definition: dbmgr.hxx:150
const SwXMailMerge * GetMailMergeEvtSrc() const
MailMergeEvent source.
Definition: dbmgr.hxx:297
void MergeCancel()
Definition: dbmgr.cxx:1640
exports com.sun.star. sdb
uno::Reference< mail::XSmtpService > ConnectToSmtpServer(SwMailMergeConfigItem const &rConfigItem, uno::Reference< mail::XMailService > &rxInMailService, const OUString &rInMailServerPassword, const OUString &rOutMailServerPassword, weld::Window *pDialogParentWindow)
void SetMailMergeEvtSrc(const SwXMailMerge *pSrc)
Definition: dbmgr.hxx:298
#define WID_DATA_COMMAND_TYPE
Definition: unomap.hxx:264
OUString m_sAttachmentName
osl::Mutex m_aMutex
#define UNO_NAME_OUTPUT_TYPE
Definition: unoprnms.hxx:722
SwMailMergeConfigItem * pMailMergeConfigItem
Definition: dbmgr.hxx:219
OUString m_sOutServerPassword
void setDataSource(const OUString &_sDataSourceNameOrLocation)
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
#define UNO_NAME_SUBJECT
Definition: unoprnms.hxx:752
std::unique_ptr< ContentProperties > pData
static CloseResult CloseModelAndDocSh(Reference< frame::XModel > const &rxModel, SfxObjectShellRef &rxDocSh)
Reference< XOfficeDatabaseDocument > m_xDocument
const SfxItemPropertySet * m_pPropSet
OUString m_sSaveFilter
#define WID_OUT_SERVER_PASSWORD
Definition: unomap.hxx:283
#define UNO_NAME_CONNECTION
Definition: unoprnms.hxx:716
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &PropertyName) override
bool UCB_IsReadOnlyFileName(const OUString &rURL)
#define WID_ATTACHMENT_NAME
Definition: unomap.hxx:275
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
static bool LoadFromURL_impl(Reference< frame::XModel > &rxModel, SfxObjectShellRef &rxDocSh, const OUString &rURL, bool bClose)
sal_Int32 addInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
css::uno::Reference< css::mail::XSmtpService > xSmtpServer
Definition: dbmgr.hxx:193
OUString m_sAddressFromColumn
#define UNO_NAME_DATA_SOURCE_NAME
Definition: unoprnms.hxx:718
#define WID_SINGLE_PRINT_JOBS
Definition: unomap.hxx:267
#define WID_PRINT_OPTIONS
Definition: unomap.hxx:277
void disposeAndClear(const css::lang::EventObject &rEvt)
bool bSendAsAttachment
Definition: dbmgr.hxx:195
sal_Int16 m_nOutputType
eSuccess
OUString m_sMailBody
#define UNO_NAME_BLIND_COPIES_TO
Definition: unoprnms.hxx:763
virtual css::uno::Any SAL_CALL execute(const css::uno::Sequence< css::beans::NamedValue > &Arguments) override
#define WID_FILE_NAME_FROM_COLUMN
Definition: unomap.hxx:268
css::uno::Reference< css::frame::XModel > m_xModel
css::uno::Reference< css::frame::XModel > GetModel() const
bool UCB_DeleteFile(const OUString &rURL)
Definition: swunohelper.cxx:59
sal_Int32 removeInterface(const css::uno::Reference< css::uno::XInterface > &rxIFace)
#define UNO_NAME_ESCAPE_PROCESSING
Definition: unoprnms.hxx:723
#define WID_SELECTION
Definition: unomap.hxx:255
css::uno::XInterface *SAL_CALL next()
css::uno::Sequence< css::beans::PropertyValue > aSaveToFilterData
Definition: dbmgr.hxx:158
css::uno::Reference< css::beans::XPropertySetInfo > const & getPropertySetInfo() const
#define UNO_NAME_DOCUMENT_URL
Definition: unoprnms.hxx:720
virtual ~SwXMailMerge() override
#define UNO_NAME_SAVE_FILTER_DATA
Definition: unoprnms.hxx:767
SfxApplication * SfxGetpApp()
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &aListener) override
#define UNO_NAME_MODEL
Definition: unoprnms.hxx:717
OUString GetBase() const
Used by the UI to modify the document model.
Definition: wrtsh.hxx:91
OUString m_sAttachmentFilter
IMPL_LINK_NOARG(FormFieldButton, FieldPopupModeEndHdl, weld::Popover &, void)
css::uno::Any const & rValue
bool m_bSendAsAttachment
constexpr auto SFX_INTERFACE_NONE
#define WID_RESULT_SET
Definition: unomap.hxx:256
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
#define WID_COPIES_TO
Definition: unomap.hxx:280
virtual void SAL_CALL addPropertyChangeListener(const OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Print mail merge.
Definition: dbmgr.hxx:89
#define UNO_NAME_RESULT_SET
Definition: unoprnms.hxx:715
#define UNO_NAME_MAIL_BODY
Definition: unoprnms.hxx:756
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
#define UNO_NAME_SAVE_FILTER_OPTIONS
Definition: unoprnms.hxx:766
#define UNO_NAME_COPIES_TO
Definition: unoprnms.hxx:762
Mutex aMutex
DBManagerOptions
Definition: dbmgr.hxx:86
Send mail merge as email.
Definition: dbmgr.hxx:90
#define WID_FILTER
Definition: unomap.hxx:261
#define UNO_NAME_ATTACHMENT_FILTER
Definition: unoprnms.hxx:758
OUString sSaveToFilter
Definition: dbmgr.hxx:156
sal_Int32 SAL_CALL removeInterface(const key &rKey, const css::uno::Reference< css::uno::XInterface > &rxIFace)
void launchEvent(const css::beans::PropertyChangeEvent &rEvt) const
Create merge doc and keep the doc shell.
Definition: dbmgr.hxx:92
css::uno::Reference< css::frame::XModel > GetBaseModel() const
OUString sMailBody
Definition: dbmgr.hxx:189
virtual void SAL_CALL addMailMergeEventListener(const css::uno::Reference< css::text::XMailMergeListener > &xListener) override
css::uno::Sequence< css::beans::PropertyValue > m_aSaveFilterData
#define WID_SEND_AS_HTML
Definition: unomap.hxx:272
virtual void SAL_CALL removePropertyChangeListener(const OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &aListener) override
#define UNO_NAME_SAVE_FILTER
Definition: unoprnms.hxx:761
css::uno::Reference< css::sdbc::XConnection > m_xConnection
OUString m_sSubject
bool Merge(const SwMergeDescriptor &rMergeDesc)
Merging of data records into fields.
Definition: dbmgr.cxx:415
SwDBManager * GetDBManager() const
For evaluation of DB fields (new DB-manager).
Definition: edfld.cxx:331
OUString sPrefix
Basename incl.
Definition: dbmgr.hxx:173
const IDocumentDeviceAccess & getIDocumentDeviceAccess() const
Provides access to the document device interface.
Definition: viewsh.cxx:2669
OUString sSaveToFilterOptions
Definition: dbmgr.hxx:157
T * get() const
#define WID_SAVE_FILTER
Definition: unomap.hxx:279
static SW_DLLPUBLIC std::shared_ptr< const SfxFilter > GetFilterOfFormat(std::u16string_view rFormat, const SfxFilterContainer *pCnt=nullptr)
find for an internal format name the corresponding filter entry
Definition: iodetect.cxx:68
#define STR_SW_EVENT_MAIL_MERGE_END
Definition: swevent.hxx:29
#define TOOLS_WARN_EXCEPTION(area, stream)
sal_Int32 m_nDataCommandType
#define WID_ESCAPE_PROCESSING
Definition: unomap.hxx:266
OUString sSubject
Definition: dbmgr.hxx:188
OUString m_aFileNamePrefix
virtual OUString SAL_CALL getImplementationName() override
virtual const SwPrintData & getPrintData() const =0
Returns the PrintData.
#define WID_DOCUMENT_URL
Definition: unomap.hxx:262
OUString const & GetURL() const
void SetSmartProtocol(INetProtocol eTheSmartScheme)
void SAL_CALL disposeAndClear(const css::lang::EventObject &rEvt)
#define UNO_NAME_PRINT_OPTIONS
Definition: unoprnms.hxx:759
virtual void SAL_CALL removeVetoableChangeListener(const OUString &PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) override
static osl::Mutex & GetMailMergeMutex()
void SetMergeSilent(bool bVal)
Definition: dbmgr.hxx:301
OUString m_aDataSourceName
#define UNO_NAME_SINGLE_PRINT_JOBS
Definition: unoprnms.hxx:724
OUString sAttachmentName
Definition: dbmgr.hxx:190
#define UNO_NAME_SEND_AS_HTML
Definition: unoprnms.hxx:754
#define WID_SEND_AS_ATTACHMENT
Definition: unomap.hxx:273
#define UNO_NAME_FILE_NAME_PREFIX
Definition: unoprnms.hxx:726
#define WID_SAVE_AS_SINGLE_FILE
Definition: unomap.hxx:278
void NotifyEvent(const SfxEventHint &rEvent, bool bSynchron=true)
OUString m_aOutputURL
unsigned char sal_Bool
SfxObjectShellRef m_xDocSh
const SfxItemPropertyMap & getPropertyMap() const
#define WID_MAIL_BODY
Definition: unomap.hxx:274
void LaunchMailMergeEvent(const css::text::MailMergeEvent &rData) const
bool m_bEscapeProcessing
#define WID_BLIND_COPIES_TO
Definition: unomap.hxx:281
virtual void SAL_CALL dispose() override
css::uno::Sequence< OUString > m_aCopiesTo
bool UCB_IsDirectory(const OUString &rURL)
SfxViewShell * GetViewShell() const
#define WID_OUTPUT_TYPE
Definition: unomap.hxx:265
CloseResult
css::uno::Sequence< css::beans::PropertyValue > m_aPrintSettings
SwDocShell * GetDocShell()
Definition: view.cxx:1110
#define UNO_NAME_ATTACHMENT_NAME
Definition: unoprnms.hxx:757
#define WID_SAVE_FILTER_DATA
Definition: unomap.hxx:285
#define WID_SAVE_FILTER_OPTIONS
Definition: unomap.hxx:284
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
Provides access to the formatting devices of a document.
MailMergeExecuteFinalizer(SwXMailMerge *mailmerge)
#define WID_DATA_COMMAND
Definition: unomap.hxx:260
virtual void SAL_CALL setPropertyValue(const OUString &aPropertyName, const css::uno::Any &aValue) override
sal_Int32 SAL_CALL addInterface(const key &rKey, const css::uno::Reference< css::uno::XInterface > &r)
#define WID_MODEL
Definition: unomap.hxx:258
#define WID_IN_SERVER_PASSWORD
Definition: unomap.hxx:282
Reference< XMultiServiceFactory > getProcessServiceFactory()
css::uno::Sequence< OUString > aCopiesTo
Definition: dbmgr.hxx:191
#define UNO_NAME_SAVE_AS_SINGLE_FILE
Definition: unoprnms.hxx:760
css::uno::Sequence< css::beans::PropertyValue > aPrintOptions
Definition: dbmgr.hxx:216
void SetPrintSingleJobs(bool b)
Definition: printdata.hxx:164
::utl::SharedUNOComponent< XInterface > SharedComponent
MailMergeExecuteFinalizer & operator=(MailMergeExecuteFinalizer const &)=delete
Save mail merge as files.
Definition: dbmgr.hxx:91
static SfxViewFrame * LoadHiddenDocument(SfxObjectShell const &i_rDoc, SfxInterfaceId i_nViewId)
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
OUString m_sInServerPassword
#define STR_SW_EVENT_MAIL_MERGE
Definition: swevent.hxx:28
#define FILTER_XML
XML filter.
Definition: iodetect.hxx:35
#define UNO_NAME_OUTPUT_URL
Definition: unoprnms.hxx:721
#define WID_DATA_SOURCE_NAME
Definition: unomap.hxx:259
bool m_bSinglePrintJobs
#define UNO_NAME_FILTER
Definition: unoprnms.hxx:719
#define WID_FILE_NAME_PREFIX
Definition: unomap.hxx:269
bool DoInitNew(SfxMedium *pMedium=nullptr)
OUString m_sSaveFilterOptions
virtual void setPrintData(const SwPrintData &rPrtData)=0
Sets the PrintData.
comphelper::OInterfaceContainerHelper2 m_aMergeListeners
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
css::uno::Sequence< OUString > m_aBlindCopiesTo
css::uno::Sequence< OUString > aBlindCopiesTo
Definition: dbmgr.hxx:192
Reference< XComponentContext > getProcessComponentContext()
SwUnoPropertyMapProvider aSwMapProvider
Definition: unomap1.cxx:87
OString stripStart(const OString &rIn, char c)
#define WID_CONNECTION
Definition: unomap.hxx:257
TABLE
OUString sDBcolumn
DB column to fetch EMail of Filename from.
Definition: dbmgr.hxx:204
OUString m_aDataCommand
#define UNO_NAME_DAD_COMMAND
Definition: unoprnms.hxx:728
OUString m_aTmpFileName
static OUString GetEventName(sal_Int32 nId)
Definition: docsh.cxx:1314
virtual void CalcLayout() override
To enable set up of StartActions and EndActions.
Definition: edws.cxx:108
OUString m_aFilter
static SfxViewFrame * GetFirst(const SfxObjectShell *pDoc=nullptr, bool bOnlyVisible=true)
#define WID_ADDRESS_FROM_COLUMN
Definition: unomap.hxx:271
#define UNO_NAME_OUT_SERVER_PASSWORD
Definition: unoprnms.hxx:765
#define WID_OUTPUT_URL
Definition: unomap.hxx:263
OPropertyListenerContainerHelper m_aPropListeners
css::uno::XInterface * next()
void reset(const css::uno::Reference< INTERFACE > &_rxComponent, AssignmentMode _eMode=TakeOwnership)
#define UNO_NAME_SEND_AS_ATTACHMENT
Definition: unoprnms.hxx:755
virtual void SAL_CALL cancel() override
bool m_bSaveAsSingleFile
#define WID_ATTACHMENT_FILTER
Definition: unomap.hxx:276
#define WID_MAIL_SUBJECT
Definition: unomap.hxx:270
css::uno::Reference< css::sdbc::XResultSet > m_xResultSet
css::uno::Sequence< css::uno::Any > m_aSelection
OInterfaceContainerHelper *SAL_CALL getContainer(const key &) const
#define UNO_NAME_IN_SERVER_PASSWORD
Definition: unoprnms.hxx:764
comphelper::OInterfaceContainerHelper2 m_aEvtListeners
#define UNO_NAME_SELECTION
Definition: unoprnms.hxx:714
#define UNO_NAME_ADDRESS_FROM_COLUMN
Definition: unoprnms.hxx:753
#define PROPERTY_MAP_MAILMERGE
Definition: unomap.hxx:115
Definition: view.hxx:144
#define UNO_NAME_FILE_NAME_FROM_COLUMN
Definition: unoprnms.hxx:725
static bool DeleteTmpFile_Impl(Reference< frame::XModel > &rxModel, SfxObjectShellRef &rxDocSh, const OUString &rTmpFileURL)
virtual void SAL_CALL addVetoableChangeListener(const OUString &PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) override
bool SetSmartURL(OUString const &rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, FSysStyle eStyle=FSysStyle::Detect)
bool m_bFileNameFromColumn
bool SAL_CALL hasMoreElements() const
SwDBManager * m_pMgr
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
#define UNO_NAME_DAD_COMMAND_TYPE
Definition: unoprnms.hxx:730
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)