LibreOffice Module sw (master)  1
dbmgr.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 <sal/config.h>
21 
22 #include <cassert>
23 #include <cstdarg>
24 
25 #include <unotxdoc.hxx>
26 #include <sfx2/app.hxx>
27 #include <sfx2/printer.hxx>
28 #include <com/sun/star/sdb/CommandType.hpp>
29 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
30 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <com/sun/star/lang/XEventListener.hpp>
32 #include <com/sun/star/uri/UriReferenceFactory.hpp>
33 #include <com/sun/star/uri/VndSunStarPkgUrlReferenceFactory.hpp>
34 #include <com/sun/star/util/NumberFormatter.hpp>
35 #include <com/sun/star/sdb/DatabaseContext.hpp>
36 #include <com/sun/star/sdb/TextConnectionSettings.hpp>
37 #include <com/sun/star/sdb/XCompletedConnection.hpp>
38 #include <com/sun/star/sdb/XCompletedExecution.hpp>
39 #include <com/sun/star/container/XChild.hpp>
40 #include <com/sun/star/text/MailMergeEvent.hpp>
41 #include <com/sun/star/frame/XStorable.hpp>
42 #include <com/sun/star/task/InteractionHandler.hpp>
43 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
44 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
45 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <vcl/errinf.hxx>
48 #include <sfx2/fcontnr.hxx>
49 #include <sfx2/filedlghelper.hxx>
50 #include <sfx2/viewfrm.hxx>
51 #include <dbconfig.hxx>
52 #include <pagedesc.hxx>
53 #include <vcl/lstbox.hxx>
54 #include <unotools/tempfile.hxx>
55 #include <unotools/pathoptions.hxx>
56 #include <svl/urihelper.hxx>
57 #include <svl/zforlist.hxx>
58 #include <svl/zformat.hxx>
59 #include <svl/stritem.hxx>
60 #include <svl/eitem.hxx>
61 #include <vcl/oldprintadaptor.hxx>
62 #include <sfx2/docfile.hxx>
63 #include <sfx2/docfilt.hxx>
64 #include <sfx2/progress.hxx>
65 #include <sfx2/dispatch.hxx>
66 #include <cmdid.h>
67 #include <swmodule.hxx>
68 #include <view.hxx>
69 #include <docsh.hxx>
70 #include <edtwin.hxx>
71 #include <wrtsh.hxx>
72 #include <fldbas.hxx>
73 #include <initui.hxx>
74 #include <swundo.hxx>
75 #include <flddat.hxx>
76 #include <modcfg.hxx>
77 #include <shellio.hxx>
78 #include <dbui.hxx>
79 #include <dbmgr.hxx>
80 #include <doc.hxx>
85 #include <IDocumentUndoRedo.hxx>
86 #include <swwait.hxx>
87 #include <swunohelper.hxx>
88 #include <dbui.hrc>
89 #include <globals.hrc>
90 #include <strings.hrc>
91 #include <mmconfigitem.hxx>
92 #include <sfx2/request.hxx>
93 #include <hintids.hxx>
94 #include <com/sun/star/sdbc/XRowSet.hpp>
95 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
96 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
97 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
98 #include <com/sun/star/sdb/XColumn.hpp>
99 #include <com/sun/star/sdbc/DataType.hpp>
100 #include <com/sun/star/sdbc/ResultSetType.hpp>
101 #include <com/sun/star/sdbc/SQLException.hpp>
102 #include <com/sun/star/mail/MailAttachment.hpp>
104 #include <comphelper/property.hxx>
106 #include <comphelper/string.hxx>
107 #include <comphelper/types.hxx>
108 #include <mailmergehelper.hxx>
109 #include <maildispatcher.hxx>
110 #include <svtools/htmlcfg.hxx>
112 #include <com/sun/star/util/XNumberFormatTypes.hpp>
113 #include <editeng/langitem.hxx>
114 #include <svl/numuno.hxx>
115 #include <connectivity/dbtools.hxx>
117 #include <unotools/charclass.hxx>
118 #include <tools/diagnose_ex.h>
119 
120 #include <unomailmerge.hxx>
121 #include <sfx2/event.hxx>
123 #include <osl/mutex.hxx>
124 #include <rtl/textenc.h>
125 #include <rtl/tencinfo.h>
126 #include <cppuhelper/implbase.hxx>
127 #include <ndindex.hxx>
128 #include <pam.hxx>
129 #include <swcrsr.hxx>
130 #include <swevent.hxx>
131 #include <osl/file.hxx>
132 #include <sal/log.hxx>
133 #include <swabstdlg.hxx>
134 #include <fmthdft.hxx>
135 #include <vector>
136 #include <unomid.h>
137 #include <section.hxx>
138 #include <rootfrm.hxx>
139 #include <fmtpdsc.hxx>
140 #include <ndtxt.hxx>
141 #include <calc.hxx>
142 #include <dbfld.hxx>
143 #include <IDocumentState.hxx>
144 #include <imaildsplistener.hxx>
145 #include <iodetect.hxx>
146 #include <IDocumentDeviceAccess.hxx>
147 
148 #include <memory>
150 #include <officecfg/Office/Common.hxx>
151 
152 using namespace ::com::sun::star;
153 using namespace sw;
154 
155 #define DB_SEP_SPACE 0
156 #define DB_SEP_TAB 1
157 #define DB_SEP_RETURN 2
158 #define DB_SEP_NEWLINE 3
159 
160 namespace {
161 
162 void lcl_emitEvent(SfxEventHintId nEventId, sal_Int32 nStrId, SfxObjectShell* pDocShell)
163 {
164  SfxGetpApp()->NotifyEvent(SfxEventHint(nEventId,
165  SwDocShell::GetEventName(nStrId),
166  pDocShell));
167 }
168 
169 }
170 
171 std::vector<std::pair<SwDocShell*, OUString>> SwDBManager::m_aUncommittedRegistrations;
172 
173 enum class SwDBNextRecord { NEXT, FIRST };
174 static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action = SwDBNextRecord::NEXT );
175 
176 enum class WorkingDocType { SOURCE, TARGET, COPY };
178  const WorkingDocType aType, const SwWrtShell &rSourceWrtShell,
179  const vcl::Window *pSourceWindow,
180  SwDBManager** const ppDBManager,
181  SwView** const pView, SwWrtShell** const pWrtShell, SwDoc** const pDoc );
182 
183 static bool lcl_getCountFromResultSet( sal_Int32& rCount, const SwDSParam* pParam )
184 {
185  rCount = pParam->aSelection.getLength();
186  if ( rCount > 0 )
187  return true;
188 
189  uno::Reference<beans::XPropertySet> xPrSet(pParam->xResultSet, uno::UNO_QUERY);
190  if ( xPrSet.is() )
191  {
192  try
193  {
194  bool bFinal = false;
195  uno::Any aFinal = xPrSet->getPropertyValue("IsRowCountFinal");
196  aFinal >>= bFinal;
197  if(!bFinal)
198  {
199  pParam->xResultSet->last();
200  pParam->xResultSet->first();
201  }
202  uno::Any aCount = xPrSet->getPropertyValue("RowCount");
203  if( aCount >>= rCount )
204  return true;
205  }
206  catch(const uno::Exception&)
207  {
208  }
209  }
210  return false;
211 }
212 
214  : public cppu::WeakImplHelper< lang::XEventListener >
215 {
216 private:
218 
219  virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
220 
221 public:
223 
224  void Dispose() { m_pDBManager = nullptr; }
225 
226 };
227 
229 class SwDataSourceRemovedListener : public cppu::WeakImplHelper<sdb::XDatabaseRegistrationsListener>
230 {
231  uno::Reference<sdb::XDatabaseContext> m_xDatabaseContext;
233 
234 public:
235  explicit SwDataSourceRemovedListener(SwDBManager& rDBManager);
236  virtual ~SwDataSourceRemovedListener() override;
237  virtual void SAL_CALL registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
238  virtual void SAL_CALL revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
239  virtual void SAL_CALL changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
240  virtual void SAL_CALL disposing(const lang::EventObject& rObject) override;
241  void Dispose();
242 };
243 
245  : m_pDBManager(&rDBManager)
246 {
247  uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
248  m_xDatabaseContext = sdb::DatabaseContext::create(xComponentContext);
249  m_xDatabaseContext->addDatabaseRegistrationsListener(this);
250 }
251 
253 {
254  if (m_xDatabaseContext.is())
255  m_xDatabaseContext->removeDatabaseRegistrationsListener(this);
256 }
257 
258 void SAL_CALL SwDataSourceRemovedListener::registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& /*rEvent*/)
259 {
260 }
261 
262 void SAL_CALL SwDataSourceRemovedListener::revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent)
263 {
264  if (!m_pDBManager || m_pDBManager->getEmbeddedName().isEmpty())
265  return;
266 
267  SwDoc* pDoc = m_pDBManager->getDoc();
268  if (!pDoc)
269  return;
270 
271  SwDocShell* pDocShell = pDoc->GetDocShell();
272  if (!pDocShell)
273  return;
274 
276  OUString sTmpName = "vnd.sun.star.pkg://";
278  sTmpName += "/" + m_pDBManager->getEmbeddedName();
279 
280  if (sTmpName != rEvent.OldLocation)
281  return;
282 
283  // The revoked database location is inside this document, then remove the
284  // embedding, as otherwise it would be back on the next reload of the
285  // document.
286  pDocShell->GetStorage()->removeElement(m_pDBManager->getEmbeddedName());
287  m_pDBManager->setEmbeddedName(OUString(), *pDocShell);
288 }
289 
290 void SAL_CALL SwDataSourceRemovedListener::changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent)
291 {
292  if (rEvent.OldLocation != rEvent.NewLocation)
293  revokedDatabaseLocation(rEvent);
294 }
295 
296 void SwDataSourceRemovedListener::disposing(const lang::EventObject& /*rObject*/)
297 {
298  m_xDatabaseContext.clear();
299 }
300 
302 {
303  m_pDBManager = nullptr;
304 }
305 
307 {
308  std::unique_ptr<SwDSParam> pMergeData;
313  uno::Reference< mail::XMailMessage> m_xLastMessage;
314 
315  explicit SwDBManager_Impl(SwDBManager& rDBManager)
316  : m_xDisposeListener(new ConnectionDisposedListener_Impl(rDBManager))
317  {}
318 
320  {
321  m_xDisposeListener->Dispose();
322  if (m_xDataSourceRemovedListener.is())
323  m_xDataSourceRemovedListener->Dispose();
324  }
325 };
326 
327 static void lcl_InitNumberFormatter(SwDSParam& rParam, uno::Reference<sdbc::XDataSource> const & xSource)
328 {
329  uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
330  rParam.xFormatter.set(util::NumberFormatter::create(xContext), uno::UNO_QUERY);
331  uno::Reference<beans::XPropertySet> xSourceProps(
332  (xSource.is()
333  ? xSource
335  rParam.xConnection, rParam.sDataSource)),
336  uno::UNO_QUERY);
337  if(xSourceProps.is())
338  {
339  uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
340  if(aFormats.hasValue())
341  {
342  uno::Reference<util::XNumberFormatsSupplier> xSuppl;
343  aFormats >>= xSuppl;
344  if(xSuppl.is())
345  {
346  uno::Reference< beans::XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
347  uno::Any aNull = xSettings->getPropertyValue("NullDate");
348  aNull >>= rParam.aNullDate;
349  if(rParam.xFormatter.is())
350  rParam.xFormatter->attachNumberFormatsSupplier(xSuppl);
351  }
352  }
353  }
354 }
355 
356 static bool lcl_MoveAbsolute(SwDSParam* pParam, long nAbsPos)
357 {
358  bool bRet = false;
359  try
360  {
361  if(pParam->aSelection.hasElements())
362  {
363  if(pParam->aSelection.getLength() <= nAbsPos)
364  {
365  pParam->bEndOfDB = true;
366  bRet = false;
367  }
368  else
369  {
370  pParam->nSelectionIndex = nAbsPos;
371  sal_Int32 nPos = 0;
372  pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos;
373  pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
374  bRet = !pParam->bEndOfDB;
375  }
376  }
377  else if(pParam->bScrollable)
378  {
379  bRet = pParam->xResultSet->absolute( nAbsPos );
380  }
381  else
382  {
383  OSL_FAIL("no absolute positioning available");
384  }
385  }
386  catch(const uno::Exception&)
387  {
388  }
389  return bRet;
390 }
391 
392 static void lcl_GetColumnCnt(SwDSParam *pParam,
393  const uno::Reference< beans::XPropertySet > &rColumnProps,
394  LanguageType nLanguage, OUString &rResult, double* pNumber)
395 {
396  SwDBFormatData aFormatData;
397  if(!pParam->xFormatter.is())
398  {
399  uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(
400  pParam->xConnection,pParam->sDataSource);
401  lcl_InitNumberFormatter(*pParam, xSource );
402  }
403  aFormatData.aNullDate = pParam->aNullDate;
404  aFormatData.xFormatter = pParam->xFormatter;
405 
406  aFormatData.aLocale = LanguageTag( nLanguage ).getLocale();
407 
408  rResult = SwDBManager::GetDBField( rColumnProps, aFormatData, pNumber);
409 }
410 
411 static bool lcl_GetColumnCnt(SwDSParam* pParam, const OUString& rColumnName,
412  LanguageType nLanguage, OUString& rResult, double* pNumber)
413 {
414  uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pParam->xResultSet, uno::UNO_QUERY );
415  uno::Reference<container::XNameAccess> xCols;
416  try
417  {
418  xCols = xColsSupp->getColumns();
419  }
420  catch(const lang::DisposedException&)
421  {
422  }
423  if(!xCols.is() || !xCols->hasByName(rColumnName))
424  return false;
425  uno::Any aCol = xCols->getByName(rColumnName);
426  uno::Reference< beans::XPropertySet > xColumnProps;
427  aCol >>= xColumnProps;
428  lcl_GetColumnCnt( pParam, xColumnProps, nLanguage, rResult, pNumber );
429  return true;
430 };
431 
432 // import data
433 bool SwDBManager::Merge( const SwMergeDescriptor& rMergeDesc )
434 {
435  assert( !m_bInMerge && !m_pImpl->pMergeData && "merge already activated!" );
436 
437  SfxObjectShellLock xWorkObjSh;
438  SwWrtShell *pWorkShell = nullptr;
439  SwDoc *pWorkDoc = nullptr;
440  SwDBManager *pWorkDocOrigDBManager = nullptr;
441 
442  switch( rMergeDesc.nMergeType )
443  {
444  case DBMGR_MERGE_PRINTER:
445  case DBMGR_MERGE_EMAIL:
446  case DBMGR_MERGE_FILE:
447  case DBMGR_MERGE_SHELL:
448  {
449  SwDocShell *pSourceDocSh = rMergeDesc.rSh.GetView().GetDocShell();
450  if( pSourceDocSh->IsModified() )
451  {
452  pWorkDocOrigDBManager = this;
453  xWorkObjSh = lcl_CreateWorkingDocument(
454  WorkingDocType::SOURCE, rMergeDesc.rSh, nullptr,
455  &pWorkDocOrigDBManager, nullptr, &pWorkShell, &pWorkDoc );
456  }
457  [[fallthrough]];
458  }
459 
460  default:
461  if( !xWorkObjSh.Is() )
462  pWorkShell = &rMergeDesc.rSh;
463  break;
464  }
465 
466  SwDBData aData;
467  aData.nCommandType = sdb::CommandType::TABLE;
468  uno::Reference<sdbc::XResultSet> xResSet;
469  uno::Sequence<uno::Any> aSelection;
470  uno::Reference< sdbc::XConnection> xConnection;
471 
472  aData.sDataSource = rMergeDesc.rDescriptor.getDataSource();
475 
482 
483  if(aData.sDataSource.isEmpty() || aData.sCommand.isEmpty() || !xResSet.is())
484  {
485  return false;
486  }
487 
488  m_pImpl->pMergeData.reset(new SwDSParam(aData, xResSet, aSelection));
489  SwDSParam* pTemp = FindDSData(aData, false);
490  if(pTemp)
491  *pTemp = *m_pImpl->pMergeData;
492  else
493  {
494  // calls from the calculator may have added a connection with an invalid commandtype
495  //"real" data base connections added here have to re-use the already available
496  //DSData and set the correct CommandType
497  SwDBData aTempData(aData);
498  aData.nCommandType = -1;
499  pTemp = FindDSData(aData, false);
500  if(pTemp)
501  *pTemp = *m_pImpl->pMergeData;
502  else
503  {
504  m_DataSourceParams.push_back(std::make_unique<SwDSParam>(*m_pImpl->pMergeData));
505  try
506  {
507  uno::Reference<lang::XComponent> xComponent(m_DataSourceParams.back()->xConnection, uno::UNO_QUERY);
508  if(xComponent.is())
509  xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
510  }
511  catch(const uno::Exception&)
512  {
513  }
514  }
515  }
516  if(!m_pImpl->pMergeData->xConnection.is())
517  m_pImpl->pMergeData->xConnection = xConnection;
518  // add an XEventListener
519 
520  lcl_ToNextRecord(m_pImpl->pMergeData.get(), SwDBNextRecord::FIRST);
521 
522  uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection,aData.sDataSource);
523 
524  lcl_InitNumberFormatter(*m_pImpl->pMergeData, xSource);
525 
526  pWorkShell->ChgDBData(aData);
527  m_bInMerge = true;
528 
529  if (IsInitDBFields())
530  {
531  // with database fields without DB-Name, use DB-Name from Doc
532  std::vector<OUString> aDBNames;
533  aDBNames.emplace_back();
534  SwDBData aInsertData = pWorkShell->GetDBData();
535  OUString sDBName = aInsertData.sDataSource
536  + OUStringLiteral1(DB_DELIM) + aInsertData.sCommand
537  + OUStringLiteral1(DB_DELIM)
538  + OUString::number(aInsertData.nCommandType);
539  pWorkShell->ChangeDBFields( aDBNames, sDBName);
540  SetInitDBFields(false);
541  }
542 
543  bool bRet = true;
544  switch(rMergeDesc.nMergeType)
545  {
546  case DBMGR_MERGE:
547  pWorkShell->StartAllAction();
548  pWorkShell->SwViewShell::UpdateFields( true );
549  pWorkShell->SetModified();
550  pWorkShell->EndAllAction();
551  break;
552 
553  case DBMGR_MERGE_PRINTER:
554  case DBMGR_MERGE_EMAIL:
555  case DBMGR_MERGE_FILE:
556  case DBMGR_MERGE_SHELL:
557  // save files and send them as e-Mail if required
558  bRet = MergeMailFiles(pWorkShell, rMergeDesc);
559  break;
560 
561  default:
562  // insert selected entries
563  // (was: InsertRecord)
564  ImportFromConnection(pWorkShell);
565  break;
566  }
567 
568  m_pImpl->pMergeData.reset();
569 
570  if( xWorkObjSh.Is() )
571  {
572  pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
573  xWorkObjSh->DoClose();
574  }
575 
576  m_bInMerge = false;
577 
578  return bRet;
579 }
580 
582 {
583  if(m_pImpl->pMergeData && !m_pImpl->pMergeData->bEndOfDB)
584  {
585  pSh->StartAllAction();
586  pSh->StartUndo();
587  bool bGroupUndo(pSh->DoesGroupUndo());
588  pSh->DoGroupUndo(false);
589 
590  if( pSh->HasSelection() )
591  pSh->DelRight();
592 
593  std::unique_ptr<SwWait> pWait;
594 
595  {
596  sal_uLong i = 0;
597  do {
598 
599  ImportDBEntry(pSh);
600  if( 10 == ++i )
601  pWait.reset(new SwWait( *pSh->GetView().GetDocShell(), true));
602 
603  } while(ToNextMergeRecord());
604  }
605 
606  pSh->DoGroupUndo(bGroupUndo);
607  pSh->EndUndo();
608  pSh->EndAllAction();
609  }
610 }
611 
612 static OUString lcl_FindColumn(const OUString& sFormatStr,sal_uInt16 &nUsedPos, sal_uInt8 &nSeparator)
613 {
614  OUStringBuffer sReturn;
615  sal_uInt16 nLen = sFormatStr.getLength();
616  nSeparator = 0xff;
617  while(nUsedPos < nLen && nSeparator == 0xff)
618  {
619  sal_Unicode cCurrent = sFormatStr[nUsedPos];
620  switch(cCurrent)
621  {
622  case ',':
623  nSeparator = DB_SEP_SPACE;
624  break;
625  case ';':
626  nSeparator = DB_SEP_RETURN;
627  break;
628  case ':':
629  nSeparator = DB_SEP_TAB;
630  break;
631  case '#':
632  nSeparator = DB_SEP_NEWLINE;
633  break;
634  default:
635  sReturn.append(cCurrent);
636  }
637  nUsedPos++;
638 
639  }
640  return sReturn.makeStringAndClear();
641 }
642 
644 {
645  if(m_pImpl->pMergeData && !m_pImpl->pMergeData->bEndOfDB)
646  {
647  uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
648  uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
649  OUString sFormatStr;
650  sal_uInt16 nFormatLen = sFormatStr.getLength();
651  if( nFormatLen )
652  {
653  const char cSpace = ' ';
654  const char cTab = '\t';
655  sal_uInt16 nUsedPos = 0;
656  sal_uInt8 nSeparator;
657  OUString sColumn = lcl_FindColumn(sFormatStr, nUsedPos, nSeparator);
658  while( !sColumn.isEmpty() )
659  {
660  if(!xCols->hasByName(sColumn))
661  return;
662  uno::Any aCol = xCols->getByName(sColumn);
663  uno::Reference< beans::XPropertySet > xColumnProp;
664  aCol >>= xColumnProp;
665  if(xColumnProp.is())
666  {
667  SwDBFormatData aDBFormat;
668  OUString sInsert = GetDBField( xColumnProp, aDBFormat);
669  if( DB_SEP_SPACE == nSeparator )
670  sInsert += OUStringLiteral1(cSpace);
671  else if( DB_SEP_TAB == nSeparator)
672  sInsert += OUStringLiteral1(cTab);
673  pSh->Insert(sInsert);
674  if( DB_SEP_RETURN == nSeparator)
675  pSh->SplitNode();
676  else if(DB_SEP_NEWLINE == nSeparator)
677  pSh->InsertLineBreak();
678  }
679  else
680  {
681  // column not found -> show error
682  OUStringBuffer sInsert;
683  sInsert.append('?').append(sColumn).append('?');
684  pSh->Insert(sInsert.makeStringAndClear());
685  }
686  sColumn = lcl_FindColumn(sFormatStr, nUsedPos, nSeparator);
687  }
688  pSh->SplitNode();
689  }
690  else
691  {
692  OUStringBuffer sStr;
693  uno::Sequence<OUString> aColNames = xCols->getElementNames();
694  const OUString* pColNames = aColNames.getConstArray();
695  long nLength = aColNames.getLength();
696  for(long i = 0; i < nLength; i++)
697  {
698  uno::Any aCol = xCols->getByName(pColNames[i]);
699  uno::Reference< beans::XPropertySet > xColumnProp;
700  aCol >>= xColumnProp;
701  SwDBFormatData aDBFormat;
702  sStr.append(GetDBField( xColumnProp, aDBFormat));
703  if (i < nLength - 1)
704  sStr.append("\t");
705  }
706  pSh->SwEditShell::Insert2(sStr.makeStringAndClear());
707  pSh->SwFEShell::SplitNode(); // line feed
708  }
709  }
710 }
711 
712 bool SwDBManager::GetTableNames(weld::ComboBox& rBox, const OUString& rDBName)
713 {
714  bool bRet = false;
715  OUString sOldTableName(rBox.get_active_text());
716  rBox.clear();
717  SwDSParam* pParam = FindDSConnection(rDBName, false);
718  uno::Reference< sdbc::XConnection> xConnection;
719  if (pParam && pParam->xConnection.is())
720  xConnection = pParam->xConnection;
721  else
722  {
723  if ( !rDBName.isEmpty() )
724  xConnection = RegisterConnection( rDBName );
725  }
726  if (xConnection.is())
727  {
728  uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY);
729  if(xTSupplier.is())
730  {
731  uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
732  uno::Sequence<OUString> aTables = xTables->getElementNames();
733  const OUString* pTables = aTables.getConstArray();
734  for (sal_Int32 i = 0; i < aTables.getLength(); ++i)
735  rBox.append("0", pTables[i]);
736  }
737  uno::Reference<sdb::XQueriesSupplier> xQSupplier(xConnection, uno::UNO_QUERY);
738  if(xQSupplier.is())
739  {
740  uno::Reference<container::XNameAccess> xQueries = xQSupplier->getQueries();
741  uno::Sequence<OUString> aQueries = xQueries->getElementNames();
742  const OUString* pQueries = aQueries.getConstArray();
743  for (sal_Int32 i = 0; i < aQueries.getLength(); i++)
744  rBox.append("1", pQueries[i]);
745  }
746  if (!sOldTableName.isEmpty())
747  rBox.set_active_text(sOldTableName);
748  bRet = true;
749  }
750  return bRet;
751 }
752 
753 // fill Listbox with column names of a database
755  const OUString& rDBName, const OUString& rTableName)
756 {
757  SwDBData aData;
758  aData.sDataSource = rDBName;
759  aData.sCommand = rTableName;
760  aData.nCommandType = -1;
761  SwDSParam* pParam = FindDSData(aData, false);
762  uno::Reference< sdbc::XConnection> xConnection;
763  if(pParam && pParam->xConnection.is())
764  xConnection = pParam->xConnection;
765  else
766  {
767  xConnection = RegisterConnection( rDBName );
768  }
769  GetColumnNames(pListBox, xConnection, rTableName);
770 }
771 
773  const OUString& rDBName, const OUString& rTableName)
774 {
775  SwDBData aData;
776  aData.sDataSource = rDBName;
777  aData.sCommand = rTableName;
778  aData.nCommandType = -1;
779  SwDSParam* pParam = FindDSData(aData, false);
780  uno::Reference< sdbc::XConnection> xConnection;
781  if(pParam && pParam->xConnection.is())
782  xConnection = pParam->xConnection;
783  else
784  {
785  xConnection = RegisterConnection( rDBName );
786  }
787  GetColumnNames(rBox, xConnection, rTableName);
788 }
789 
790 void SwDBManager::GetColumnNames(ListBox* pListBox,
791  uno::Reference< sdbc::XConnection> const & xConnection,
792  const OUString& rTableName)
793 {
794  pListBox->Clear();
795  uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
796  if(xColsSupp.is())
797  {
798  uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
799  const uno::Sequence<OUString> aColNames = xCols->getElementNames();
800  const OUString* pColNames = aColNames.getConstArray();
801  for(int nCol = 0; nCol < aColNames.getLength(); nCol++)
802  {
803  pListBox->InsertEntry(pColNames[nCol]);
804  }
805  ::comphelper::disposeComponent( xColsSupp );
806  }
807 }
808 
810  uno::Reference< sdbc::XConnection> const & xConnection,
811  const OUString& rTableName)
812 {
813  rBox.clear();
814  uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
815  if(xColsSupp.is())
816  {
817  uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
818  const uno::Sequence<OUString> aColNames = xCols->getElementNames();
819  const OUString* pColNames = aColNames.getConstArray();
820  for (sal_Int32 nCol = 0; nCol < aColNames.getLength(); ++nCol)
821  {
822  rBox.append_text(pColNames[nCol]);
823  }
824  ::comphelper::disposeComponent( xColsSupp );
825  }
826 }
827 
829  : m_aMergeStatus( MergeStatus::Ok )
830  , m_bInitDBFields(false)
831  , m_bInMerge(false)
832  , m_bMergeSilent(false)
833  , m_pImpl(new SwDBManager_Impl(*this))
834  , m_pMergeEvtSrc(nullptr)
835  , m_pDoc(pDoc)
836 {
837 }
838 
839 SwDBManager::~SwDBManager() COVERITY_NOEXCEPT_FALSE
840 {
842 
843  // copy required, m_DataSourceParams can be modified while disposing components
844  std::vector<uno::Reference<sdbc::XConnection>> aCopiedConnections;
845  for (auto & pParam : m_DataSourceParams)
846  {
847  if(pParam->xConnection.is())
848  {
849  aCopiedConnections.push_back(pParam->xConnection);
850  }
851  }
852  for (auto & xConnection : aCopiedConnections)
853  {
854  try
855  {
856  uno::Reference<lang::XComponent> xComp(xConnection, uno::UNO_QUERY);
857  if(xComp.is())
858  xComp->dispose();
859  }
860  catch(const uno::RuntimeException&)
861  {
862  //may be disposed already since multiple entries may have used the same connection
863  }
864  }
865 }
866 
867 static void lcl_RemoveSectionLinks( SwWrtShell& rWorkShell )
868 {
869  //reset all links of the sections of synchronized labels
870  size_t nSections = rWorkShell.GetSectionFormatCount();
871  for (size_t nSection = 0; nSection < nSections; ++nSection)
872  {
873  SwSectionData aSectionData( *rWorkShell.GetSectionFormat( nSection ).GetSection() );
874  if( aSectionData.GetType() == FILE_LINK_SECTION )
875  {
876  aSectionData.SetType( CONTENT_SECTION );
877  aSectionData.SetLinkFileName( OUString() );
878  rWorkShell.UpdateSection( nSection, aSectionData );
879  }
880  }
881  rWorkShell.SetLabelDoc( false );
882 }
883 
884 static void lcl_SaveDebugDoc( SfxObjectShell *xTargetDocShell,
885  const char *name, int no = 0 )
886 {
887  static OUString sTempDirURL;
888  if( sTempDirURL.isEmpty() )
889  {
890  SvtPathOptions aPathOpt;
891  utl::TempFile aTempDir( &aPathOpt.GetTempPath(), true );
892  if( aTempDir.IsValid() )
893  {
894  INetURLObject aTempDirURL( aTempDir.GetURL() );
895  sTempDirURL = aTempDirURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
896  SAL_INFO( "sw.mailmerge", "Dump directory: " << sTempDirURL );
897  }
898  }
899  if( sTempDirURL.isEmpty() )
900  return;
901 
902  const OUString sExt( ".odt" );
903  OUString basename = OUString::createFromAscii( name );
904  if (no > 0)
905  basename += OUString::number(no) + "-";
906  // aTempFile is not deleted, but that seems to be intentional
907  utl::TempFile aTempFile( basename, true, &sExt, &sTempDirURL );
908  INetURLObject aTempFileURL( aTempFile.GetURL() );
909  auto pDstMed = std::make_unique<SfxMedium>(
910  aTempFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
911  StreamMode::STD_READWRITE );
912  bool bAnyError = !xTargetDocShell->DoSaveAs( *pDstMed );
913  // xObjectShell->DoSaveCompleted crashes the mail merge unit tests, so skip it
914  bAnyError |= (ERRCODE_NONE != xTargetDocShell->GetError());
915  if( bAnyError )
916  SAL_WARN( "sw.mailmerge", "Error saving: " << aTempFile.GetURL() );
917  else
918  SAL_INFO( "sw.mailmerge", "Saved doc as: " << aTempFile.GetURL() );
919 }
920 
921 static bool lcl_SaveDoc(
922  const INetURLObject* pFileURL,
923  const std::shared_ptr<const SfxFilter>& pStoreToFilter,
924  const OUString* pStoreToFilterOptions,
925  const uno::Sequence< beans::PropertyValue >* pSaveToFilterData,
926  const bool bIsPDFexport,
927  SfxObjectShell* xObjectShell,
928  SwWrtShell& rWorkShell,
929  OUString * const decodedURL = nullptr )
930 {
931  OUString url = pFileURL->GetMainURL( INetURLObject::DecodeMechanism::NONE );
932  if( decodedURL )
933  (*decodedURL) = url;
934 
935  SfxMedium* pDstMed = new SfxMedium( url, StreamMode::STD_READWRITE );
936  pDstMed->SetFilter( pStoreToFilter );
937  if( pDstMed->GetItemSet() )
938  {
939  if( pStoreToFilterOptions )
940  pDstMed->GetItemSet()->Put( SfxStringItem(SID_FILE_FILTEROPTIONS,
941  *pStoreToFilterOptions));
942  if( pSaveToFilterData->hasElements() )
943  pDstMed->GetItemSet()->Put( SfxUnoAnyItem(SID_FILTER_DATA,
944  uno::makeAny(*pSaveToFilterData)));
945  }
946 
947  // convert fields to text if we are exporting to PDF.
948  // this prevents a second merge while updating the fields
949  // in SwXTextDocument::getRendererCount()
950  if( bIsPDFexport )
951  rWorkShell.ConvertFieldsToText();
952 
953  bool bAnyError = !xObjectShell->DoSaveAs(*pDstMed);
954  // Actually this should be a bool... so in case of email and individual
955  // files, where this is set, we skip the recently used handling
956  bAnyError |= !xObjectShell->DoSaveCompleted( pDstMed, !decodedURL );
957  bAnyError |= (ERRCODE_NONE != xObjectShell->GetError());
958  if( bAnyError )
959  {
960  // error message ??
961  ErrorHandler::HandleError( xObjectShell->GetError() );
962  }
963  return !bAnyError;
964 }
965 
967  const uno::Sequence< beans::PropertyValue >& rInPrintOptions,
968  uno::Sequence< beans::PropertyValue >& rOutPrintOptions)
969 {
970  // printing should be done synchronously otherwise the document
971  // might already become invalid during the process
972 
973  const sal_Int32 nOffset = 1;
974  rOutPrintOptions.realloc( nOffset );
975  rOutPrintOptions[ 0 ].Name = "Wait";
976  rOutPrintOptions[ 0 ].Value <<= true;
977 
978  // copy print options
979  const beans::PropertyValue* pOptions = rInPrintOptions.getConstArray();
980  for( sal_Int32 n = 0, nIndex = nOffset ; n < rInPrintOptions.getLength(); ++n)
981  {
982  if( pOptions[n].Name == "CopyCount" || pOptions[n].Name == "FileName"
983  || pOptions[n].Name == "Collate" || pOptions[n].Name == "Pages"
984  || pOptions[n].Name == "Wait" || pOptions[n].Name == "PrinterName" )
985  {
986  // add an option
987  rOutPrintOptions.realloc( nIndex + 1 );
988  rOutPrintOptions[ nIndex ].Name = pOptions[n].Name;
989  rOutPrintOptions[ nIndex++ ].Value = pOptions[n].Value ;
990  }
991  }
992 }
993 
995  // input
996  const WorkingDocType aType, const SwWrtShell &rSourceWrtShell,
997  // optional input
998  const vcl::Window *pSourceWindow,
999  // optional in and output to swap the DB manager
1000  SwDBManager** const ppDBManager,
1001  // optional output
1002  SwView** const pView, SwWrtShell** const pWrtShell, SwDoc** const pDoc )
1003 {
1004  const SwDoc *pSourceDoc = rSourceWrtShell.GetDoc();
1005  SfxObjectShellRef xWorkObjectShell = pSourceDoc->CreateCopy( true, (aType == WorkingDocType::TARGET) );
1006  SfxViewFrame* pWorkFrame = SfxViewFrame::LoadHiddenDocument( *xWorkObjectShell, SFX_INTERFACE_NONE );
1007 
1008  if( pSourceWindow )
1009  {
1010  // the created window has to be located at the same position as the source window
1011  vcl::Window& rTargetWindow = pWorkFrame->GetFrame().GetWindow();
1012  rTargetWindow.SetPosPixel( pSourceWindow->GetPosPixel() );
1013  }
1014 
1015  SwView* pWorkView = static_cast< SwView* >( pWorkFrame->GetViewShell() );
1016  SwWrtShell* pWorkWrtShell = pWorkView->GetWrtShellPtr();
1017  pWorkWrtShell->GetViewOptions()->SetIdle( false );
1018  pWorkView->AttrChangedNotify( pWorkWrtShell );// in order for SelectShell to be called
1019  SwDoc* pWorkDoc = pWorkWrtShell->GetDoc();
1020  pWorkDoc->GetIDocumentUndoRedo().DoUndo( false );
1021  pWorkDoc->ReplaceDocumentProperties( *pSourceDoc );
1022 
1023  if( aType == WorkingDocType::TARGET )
1024  {
1025  assert( !ppDBManager );
1026  pWorkDoc->SetInMailMerge( true );
1027  pWorkWrtShell->SetLabelDoc( false );
1028  }
1029  else
1030  {
1031  // We have to swap the DBmanager of the new doc, so we also need input
1032  assert(ppDBManager && *ppDBManager);
1033  SwDBManager *pWorkDBManager = pWorkDoc->GetDBManager();
1034  pWorkDoc->SetDBManager( *ppDBManager );
1035  *ppDBManager = pWorkDBManager;
1036 
1037  if( aType == WorkingDocType::SOURCE )
1038  {
1039  // the GetDBData call constructs the data, if it's missing - kind of const...
1040  pWorkWrtShell->ChgDBData( const_cast<SwDoc*>(pSourceDoc)->GetDBData() );
1041  // some DocumentSettings are currently not copied by SwDoc::CreateCopy
1042  pWorkWrtShell->SetLabelDoc( rSourceWrtShell.IsLabelDoc() );
1043  pWorkDoc->getIDocumentState().ResetModified();
1044  }
1045  else
1047  }
1048 
1049  if( pView ) *pView = pWorkView;
1050  if( pWrtShell ) *pWrtShell = pWorkWrtShell;
1051  if( pDoc ) *pDoc = pWorkDoc;
1052 
1053  return xWorkObjectShell.get();
1054 }
1055 
1057  const SwMergeDescriptor &rMergeDescriptor,
1058  const OUString &sFileURL, const OUString &sMailRecipient,
1059  const OUString &sMailBodyMimeType, rtl_TextEncoding sMailEncoding,
1060  const OUString &sAttachmentMimeType )
1061 {
1062  SwMailMessage* pMessage = new SwMailMessage;
1063  if( rMergeDescriptor.pMailMergeConfigItem->IsMailReplyTo() )
1064  pMessage->setReplyToAddress(rMergeDescriptor.pMailMergeConfigItem->GetMailReplyTo());
1065  pMessage->addRecipient( sMailRecipient );
1066  pMessage->SetSenderAddress( rMergeDescriptor.pMailMergeConfigItem->GetMailAddress() );
1067 
1068  OUStringBuffer sBody;
1069  if( rMergeDescriptor.bSendAsAttachment )
1070  {
1071  sBody = rMergeDescriptor.sMailBody;
1072  mail::MailAttachment aAttach;
1073  aAttach.Data = new SwMailTransferable( sFileURL,
1074  rMergeDescriptor.sAttachmentName, sAttachmentMimeType );
1075  aAttach.ReadableName = rMergeDescriptor.sAttachmentName;
1076  pMessage->addAttachment( aAttach );
1077  }
1078  else
1079  {
1080  //read in the temporary file and use it as mail body
1081  SfxMedium aMedium( sFileURL, StreamMode::READ );
1082  SvStream* pInStream = aMedium.GetInStream();
1083  assert( pInStream && "no output file created?" );
1084  if( !pInStream )
1085  return pMessage;
1086 
1087  pInStream->SetStreamCharSet( sMailEncoding );
1088  OString sLine;
1089  while ( pInStream->ReadLine( sLine ) )
1090  {
1091  sBody.append(OStringToOUString( sLine, sMailEncoding ));
1092  sBody.append("\n");
1093  }
1094  }
1095  pMessage->setSubject( rMergeDescriptor.sSubject );
1096  uno::Reference< datatransfer::XTransferable> xBody =
1097  new SwMailTransferable( sBody.makeStringAndClear(), sMailBodyMimeType );
1098  pMessage->setBody( xBody );
1099 
1100  for( const OUString& sCcRecipient : rMergeDescriptor.aCopiesTo )
1101  pMessage->addCcRecipient( sCcRecipient );
1102  for( const OUString& sBccRecipient : rMergeDescriptor.aBlindCopiesTo )
1103  pMessage->addBccRecipient( sBccRecipient );
1104 
1105  return pMessage;
1106 }
1107 
1109 {
1111 
1112 public:
1114  : m_rDBManager( rDBManager ) {}
1115 
1116  virtual void started( ::rtl::Reference<MailDispatcher> ) override {};
1117  virtual void stopped( ::rtl::Reference<MailDispatcher> ) override {};
1118  virtual void idle( ::rtl::Reference<MailDispatcher> ) override {};
1119 
1121  uno::Reference< mail::XMailMessage> xMessage ) override
1122  {
1123  osl::MutexGuard aGuard( m_rDBManager.m_pImpl->m_aAllEmailSendMutex );
1124  if ( m_rDBManager.m_pImpl->m_xLastMessage == xMessage )
1125  m_rDBManager.m_pImpl->m_xLastMessage.clear();
1126  }
1127 
1128  virtual void mailDeliveryError( ::rtl::Reference<MailDispatcher> xMailDispatcher,
1129  uno::Reference< mail::XMailMessage>, const OUString& ) override
1130  {
1131  osl::MutexGuard aGuard( m_rDBManager.m_pImpl->m_aAllEmailSendMutex );
1132  m_rDBManager.m_aMergeStatus = MergeStatus::Error;
1133  m_rDBManager.m_pImpl->m_xLastMessage.clear();
1134  xMailDispatcher->stop();
1135  }
1136 };
1137 
1143  const SwMergeDescriptor& rMergeDescriptor)
1144 {
1145  // deconstruct mail merge type for better readability.
1146  // uppercase naming is intentional!
1147  const bool bMT_EMAIL = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL;
1148  const bool bMT_SHELL = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL;
1149  const bool bMT_PRINTER = rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER;
1150  const bool bMT_FILE = rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE;
1151 
1152  //check if the doc is synchronized and contains at least one linked section
1153  const bool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFormatCount() > 1;
1154  const bool bNeedsTempFiles = ( bMT_EMAIL || bMT_FILE );
1155  const bool bIsMergeSilent = IsMergeSilent();
1156 
1157  bool bCheckSingleFile_ = rMergeDescriptor.bCreateSingleFile;
1158  OUString sPrefix_ = rMergeDescriptor.sPrefix;
1159  if( bMT_EMAIL )
1160  {
1161  assert( !rMergeDescriptor.bPrefixIsFilename );
1162  assert(!bCheckSingleFile_);
1163  bCheckSingleFile_ = false;
1164  }
1165  else if( bMT_SHELL || bMT_PRINTER )
1166  {
1167  assert(bCheckSingleFile_);
1168  bCheckSingleFile_ = true;
1169  assert(sPrefix_.isEmpty());
1170  sPrefix_.clear();
1171  }
1172  const bool bCreateSingleFile = bCheckSingleFile_;
1173  const OUString sDescriptorPrefix = sPrefix_;
1174 
1175  // Setup for dumping debugging documents
1176  static const sal_Int32 nMaxDumpDocs = []() {
1177  if (const char* sEnv = getenv("SW_DEBUG_MAILMERGE_DOCS"))
1178  return OUString(sEnv, strlen(sEnv), osl_getThreadTextEncoding()).toInt32();
1179  else
1180  return sal_Int32(0);
1181  }();
1182 
1183  ::rtl::Reference< MailDispatcher > xMailDispatcher;
1185  OUString sMailBodyMimeType;
1186  rtl_TextEncoding sMailEncoding = ::osl_getThreadTextEncoding();
1187 
1188  uno::Reference< beans::XPropertySet > xColumnProp;
1189 
1190  // Check for (mandatory) email or (optional) filename column
1191  SwDBFormatData aColumnDBFormat;
1192  bool bColumnName = !rMergeDescriptor.sDBcolumn.isEmpty();
1193  if( ! bColumnName )
1194  {
1195  if( bMT_EMAIL )
1196  return false;
1197  }
1198  else
1199  {
1200  uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
1201  uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1202  if( !xCols->hasByName( rMergeDescriptor.sDBcolumn ) )
1203  return false;
1204  uno::Any aCol = xCols->getByName( rMergeDescriptor.sDBcolumn );
1205  aCol >>= xColumnProp;
1206 
1207  aColumnDBFormat.xFormatter = m_pImpl->pMergeData->xFormatter;
1208  aColumnDBFormat.aNullDate = m_pImpl->pMergeData->aNullDate;
1209 
1210  if( bMT_EMAIL )
1211  {
1212  // Reset internal mail accounting data
1213  m_pImpl->m_xLastMessage.clear();
1214 
1215  xMailDispatcher.set( new MailDispatcher(rMergeDescriptor.xSmtpServer) );
1216  xMailListener = new MailDispatcherListener_Impl( *this );
1217  xMailDispatcher->addListener( xMailListener );
1218  if(!rMergeDescriptor.bSendAsAttachment && rMergeDescriptor.bSendAsHTML)
1219  {
1220  sMailBodyMimeType = "text/html; charset=";
1221  sMailBodyMimeType += OUString::createFromAscii(
1222  rtl_getBestMimeCharsetFromTextEncoding( sMailEncoding ));
1223  SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
1224  sMailEncoding = rHtmlOptions.GetTextEncoding();
1225  }
1226  else
1227  sMailBodyMimeType = "text/plain; charset=UTF-8; format=flowed";
1228  }
1229  }
1230 
1231  SwDocShell *pSourceDocSh = pSourceShell->GetView().GetDocShell();
1232 
1233  // setup the output format
1234  std::shared_ptr<const SfxFilter> pStoreToFilter = SwIoSystem::GetFileFilter(
1236  SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer();
1237  const OUString* pStoreToFilterOptions = nullptr;
1238 
1239  // if a save_to filter is set then use it - otherwise use the default
1240  if( bMT_EMAIL && !rMergeDescriptor.bSendAsAttachment )
1241  {
1242  OUString sExtension = rMergeDescriptor.bSendAsHTML ? OUString("html") : OUString("txt");
1243  pStoreToFilter = pFilterContainer->GetFilter4Extension(sExtension, SfxFilterFlags::EXPORT);
1244  }
1245  else if( !rMergeDescriptor.sSaveToFilter.isEmpty())
1246  {
1247  std::shared_ptr<const SfxFilter> pFilter =
1248  pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter );
1249  if(pFilter)
1250  {
1251  pStoreToFilter = pFilter;
1252  if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty())
1253  pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions;
1254  }
1255  }
1256  const bool bIsPDFexport = pStoreToFilter && pStoreToFilter->GetFilterName() == "writer_pdf_Export";
1257 
1259 
1260  // in case of creating a single resulting file this has to be created here
1261  SwView* pTargetView = rMergeDescriptor.pMailMergeConfigItem ?
1262  rMergeDescriptor.pMailMergeConfigItem->GetTargetView() : nullptr;
1263  SwWrtShell* pTargetShell = nullptr;
1264  SwDoc* pTargetDoc = nullptr;
1265  SfxObjectShellRef xTargetDocShell;
1266 
1267  std::unique_ptr< utl::TempFile > aTempFile;
1268  sal_uInt16 nStartingPageNo = 0;
1269 
1270  vcl::Window *pSourceWindow = nullptr;
1271  std::shared_ptr<weld::GenericDialogController> xProgressDlg;
1272 
1273  try
1274  {
1275  if( !bIsMergeSilent )
1276  {
1277  // construct the process dialog
1278  pSourceWindow = &pSourceShell->GetView().GetEditWin();
1279  if (!bMT_PRINTER)
1280  xProgressDlg.reset(new CreateMonitor(pSourceWindow->GetFrameWeld()));
1281  else
1282  {
1283  xProgressDlg.reset(new PrintMonitor(pSourceWindow->GetFrameWeld()));
1284  static_cast<PrintMonitor*>(xProgressDlg.get())->set_title(
1285  pSourceDocSh->GetTitle(22));
1286  }
1287  weld::DialogController::runAsync(xProgressDlg, [this, &xProgressDlg](sal_Int32 nResult){
1288  if (nResult == RET_CANCEL)
1289  MergeCancel();
1290  xProgressDlg.reset();
1291  });
1292 
1293  Application::Reschedule( true );
1294  }
1295 
1296  if( bCreateSingleFile && !pTargetView )
1297  {
1298  // create a target docshell to put the merged document into
1300  *pSourceShell, bMT_SHELL ? pSourceWindow : nullptr,
1301  nullptr, &pTargetView, &pTargetShell, &pTargetDoc );
1302 
1303  // import current print settings
1304  const SwPrintData &rPrintData = pSourceShell->getIDocumentDeviceAccess().getPrintData();
1305  pTargetDoc->getIDocumentDeviceAccess().setPrintData(rPrintData);
1306 
1307  if (nMaxDumpDocs)
1308  lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
1309  }
1310  else if( pTargetView )
1311  {
1312  pTargetShell = pTargetView->GetWrtShellPtr();
1313  pTargetDoc = pTargetShell->GetDoc();
1314  xTargetDocShell = pTargetView->GetDocShell();
1315  }
1316 
1317  if( bCreateSingleFile )
1318  {
1319  // determine the page style and number used at the start of the source document
1320  pSourceShell->SttEndDoc(true);
1321  nStartingPageNo = pSourceShell->GetVirtPageNum();
1322  }
1323 
1324  // Progress, to prohibit KeyInputs
1325  SfxProgress aProgress(pSourceDocSh, OUString(), 1);
1326 
1327  // lock all dispatchers
1328  SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
1329  while (pViewFrame)
1330  {
1331  pViewFrame->GetDispatcher()->Lock(true);
1332  pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
1333  }
1334 
1335  sal_Int32 nDocNo = 1;
1336 
1337  // For single file mode, the number of pages in the target document so far, which is used
1338  // by AppendDoc() to adjust position of page-bound objects. Getting this information directly
1339  // from the target doc would require repeated layouts of the doc, which is expensive, but
1340  // it can be manually computed from the source documents (for which we do layouts, so the page
1341  // count is known, and there is a blank page between each of them in the target document).
1342  int targetDocPageCount = 0;
1343 
1344  if( !bIsMergeSilent && !bMT_PRINTER )
1345  {
1346  sal_Int32 nRecordCount = 1;
1347  lcl_getCountFromResultSet( nRecordCount, m_pImpl->pMergeData.get() );
1348 
1349  // Synchronized docs don't auto-advance the record set, but there is a
1350  // "security" check, which will always advance the record set, if there
1351  // is no "next record" field in a synchronized doc => nRecordPerDoc > 0
1352  sal_Int32 nRecordPerDoc = pSourceShell->GetDoc()
1354  if ( bSynchronizedDoc && (nRecordPerDoc > 1) )
1355  --nRecordPerDoc;
1356  assert( nRecordPerDoc > 0 );
1357 
1358  sal_Int32 nMaxDocs = nRecordCount / nRecordPerDoc;
1359  if ( 0 != nRecordCount % nRecordPerDoc )
1360  nMaxDocs += 1;
1361  static_cast<CreateMonitor*>(xProgressDlg.get())->SetTotalCount(nMaxDocs);
1362  }
1363 
1364  long nStartRow, nEndRow;
1365  bool bFreezedLayouts = false;
1366  // to collect temporary email files
1367  std::vector< OUString> aFilesToRemove;
1368 
1369  // The SfxObjectShell will be closed explicitly later but
1370  // it is more safe to use SfxObjectShellLock here
1371  SfxObjectShellLock xWorkDocSh;
1372  SwView* pWorkView = nullptr;
1373  SwDoc* pWorkDoc = nullptr;
1374  SwDBManager* pWorkDocOrigDBManager = nullptr;
1375  SwWrtShell* pWorkShell = nullptr;
1376  bool bWorkDocInitialized = false;
1377 
1378  do
1379  {
1380  nStartRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
1381 
1382  OUString sColumnData;
1383 
1384  // Read the indicated data column, which should contain a valid mail
1385  // address or an optional file name
1386  if( bMT_EMAIL || bColumnName )
1387  {
1388  sColumnData = GetDBField( xColumnProp, aColumnDBFormat );
1389  }
1390 
1391  // create a new temporary file name - only done once in case of bCreateSingleFile
1392  if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile ))
1393  {
1394  OUString sPrefix = sDescriptorPrefix;
1395  OUString sLeading;
1396 
1397  //#i97667# if the name is from a database field then it will be used _as is_
1398  if( bColumnName && !bMT_EMAIL )
1399  {
1400  if (!sColumnData.isEmpty())
1401  sLeading = sColumnData;
1402  else
1403  sLeading = "_";
1404  }
1405  else
1406  {
1407  INetURLObject aEntry( sPrefix );
1408  sLeading = aEntry.GetBase();
1409  aEntry.removeSegment();
1411  }
1412 
1413  OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
1414  aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPrefix, true) );
1415  if( !aTempFile->IsValid() )
1416  {
1419  }
1420  }
1421 
1422  if( IsMergeOk() )
1423  {
1424  std::unique_ptr< INetURLObject > aTempFileURL;
1425  if( bNeedsTempFiles )
1426  aTempFileURL.reset( new INetURLObject(aTempFile->GetURL()));
1427  if( !bIsMergeSilent ) {
1428  if( !bMT_PRINTER )
1429  static_cast<CreateMonitor*>(xProgressDlg.get())->SetCurrentPosition(nDocNo);
1430  else {
1431  PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>(xProgressDlg.get());
1432  pPrintMonDlg->m_xPrinter->set_label(bNeedsTempFiles
1433  ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 2));
1434  OUString sStat( SwResId(STR_STATSTR_LETTER) );
1435  sStat += " " + OUString::number( nDocNo );
1436  pPrintMonDlg->m_xPrintInfo->set_label(sStat);
1437  }
1438  //TODO xProgressDlg->queue_draw();
1439  }
1440 
1441  Application::Reschedule( true );
1442 
1443  // Create a copy of the source document and work with that one instead of the source.
1444  // If we're not in the single file mode (which requires modifying the document for the merging),
1445  // it is enough to do this just once. Currently PDF also has to be treated special.
1446  if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport )
1447  {
1448  assert( !xWorkDocSh.Is());
1449  pWorkDocOrigDBManager = this;
1451  *pSourceShell, nullptr, &pWorkDocOrigDBManager,
1452  &pWorkView, &pWorkShell, &pWorkDoc );
1453  if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1454  lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
1455 
1456  // #i69458# lock fields to prevent access to the result set while calculating layout
1457  // tdf#92324: and do not unlock: keep document locked during printing to avoid
1458  // ExpFields update during printing, generation of preview, etc.
1459  pWorkShell->LockExpFields();
1460  pWorkShell->CalcLayout();
1461  // tdf#121168: Now force correct page descriptions applied to page frames. Without
1462  // this, e.g., page frames starting with sections could have page descriptions set
1463  // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below.
1464  pWorkShell->GetViewOptions()->SetIdle(true);
1465  for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts())
1466  {
1467  aLayout->FreezeLayout(false);
1468  aLayout->AllCheckPageDescs();
1469  }
1470  }
1471 
1472  lcl_emitEvent(SfxEventHintId::SwEventFieldMerge, STR_SW_EVENT_FIELD_MERGE, xWorkDocSh);
1473 
1474  // tdf#92324: Allow ExpFields update only by explicit instruction to avoid
1475  // database cursor movement on any other fields update, for example during
1476  // print preview and other operations
1477  if ( pWorkShell->IsExpFieldsLocked() )
1478  pWorkShell->UnlockExpFields();
1479  pWorkShell->SwViewShell::UpdateFields();
1480  pWorkShell->LockExpFields();
1481 
1482  lcl_emitEvent(SfxEventHintId::SwEventFieldMergeFinished, STR_SW_EVENT_FIELD_MERGE_FINISHED, xWorkDocSh);
1483 
1484  // also emit MailMergeEvent on XInterface if possible
1485  const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
1486  if(pEvtSrc)
1487  {
1488  uno::Reference< uno::XInterface > xRef(
1489  static_cast<text::XMailMergeBroadcaster*>(const_cast<SwXMailMerge*>(pEvtSrc)) );
1490  text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() );
1491  pEvtSrc->LaunchMailMergeEvent( aEvt );
1492  }
1493 
1494  // working copy is merged - prepare final steps depending on merge options
1495 
1496  if( bCreateSingleFile )
1497  {
1498  assert( pTargetShell && "no target shell available!" );
1499 
1500  // prepare working copy and target to append
1501 
1502  pWorkDoc->RemoveInvisibleContent();
1503  // remove of invisible content has influence on page count and so on fields for page count,
1504  // therefore layout has to be updated before fields are converted to text
1505  pWorkShell->CalcLayout();
1506  pWorkShell->ConvertFieldsToText();
1507  pWorkShell->SetNumberingRestart();
1508  if( bSynchronizedDoc )
1509  {
1510  lcl_RemoveSectionLinks( *pWorkShell );
1511  }
1512 
1513  if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1514  lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
1515 
1516  // append the working document to the target document
1517  if( targetDocPageCount % 2 == 1 )
1518  ++targetDocPageCount; // Docs always start on odd pages (so offset must be even).
1519  SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc( *pWorkDoc,
1520  nStartingPageNo, !bWorkDocInitialized, targetDocPageCount, nDocNo);
1521  targetDocPageCount += pWorkShell->GetPageCnt();
1522 
1523  if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1524  lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
1525 
1526  if (bMT_SHELL)
1527  {
1528  SwDocMergeInfo aMergeInfo;
1529  // Name of the mark is actually irrelevant, UNO bookmarks have internals names.
1530  aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark(
1531  appendedDocStart, "", IDocumentMarkAccess::MarkType::UNO_BOOKMARK,
1533  aMergeInfo.nDBRow = nStartRow;
1534  rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo );
1535  }
1536  }
1537  else
1538  {
1539  assert( bNeedsTempFiles );
1540  assert( pWorkShell->IsExpFieldsLocked() );
1541 
1542  // fields are locked, so it's fine to
1543  // restore the old / empty DB manager for save
1544  pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1545 
1546  // save merged document
1547  OUString sFileURL;
1548  if( !lcl_SaveDoc( aTempFileURL.get(), pStoreToFilter, pStoreToFilterOptions,
1549  &rMergeDescriptor.aSaveToFilterData, bIsPDFexport,
1550  xWorkDocSh, *pWorkShell, &sFileURL ) )
1551  {
1553  }
1554 
1555  // back to the MM DB manager
1556  pWorkDoc->SetDBManager( this );
1557 
1558  if( bMT_EMAIL && !IsMergeError() )
1559  {
1560  // schedule file for later removal
1561  aFilesToRemove.push_back( sFileURL );
1562 
1563  if( !SwMailMergeHelper::CheckMailAddress( sColumnData ) )
1564  {
1565  OSL_FAIL("invalid e-Mail address in database column");
1566  }
1567  else
1568  {
1569  uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc(
1570  rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType,
1571  sMailEncoding, pStoreToFilter->GetMimeType() );
1572  if( xMessage.is() )
1573  {
1574  osl::MutexGuard aGuard( m_pImpl->m_aAllEmailSendMutex );
1575  m_pImpl->m_xLastMessage.set( xMessage );
1576  xMailDispatcher->enqueueMailMessage( xMessage );
1577  if( !xMailDispatcher->isStarted() )
1578  xMailDispatcher->start();
1579  }
1580  }
1581  }
1582  }
1583  if( bCreateSingleFile || bIsPDFexport )
1584  {
1585  pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1586  xWorkDocSh->DoClose();
1587  xWorkDocSh = nullptr;
1588  }
1589  }
1590 
1591  bWorkDocInitialized = true;
1592  nDocNo++;
1593  nEndRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
1594 
1595  // Freeze the layouts of the target document after the first inserted
1596  // sub-document, to get the correct PageDesc.
1597  if(!bFreezedLayouts && bCreateSingleFile)
1598  {
1599  for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
1600  aLayout->FreezeLayout(true);
1601  bFreezedLayouts = true;
1602  }
1603  } while( IsMergeOk() &&
1604  ((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord()));
1605 
1606  if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() )
1607  {
1608  // Unlock document fields after merge complete
1609  pWorkView->GetWrtShell().UnlockExpFields();
1610  }
1611 
1612  if( !bCreateSingleFile )
1613  {
1614  if( bMT_PRINTER )
1616  if( !bIsPDFexport )
1617  {
1618  pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1619  xWorkDocSh->DoClose();
1620  }
1621  }
1622  else if( IsMergeOk() ) // && bCreateSingleFile
1623  {
1624  Application::Reschedule( true );
1625 
1626  // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate
1627  // unique fly names, do it here once.
1628  pTargetDoc->SetInMailMerge(false);
1629  pTargetDoc->SetAllUniqueFlyNames();
1630 
1631  // Unfreeze target document layouts and correct all PageDescs.
1632  SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" );
1633  pTargetShell->CalcLayout();
1634  SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" );
1635  pTargetShell->GetViewOptions()->SetIdle( true );
1636  pTargetDoc->GetIDocumentUndoRedo().DoUndo( true );
1637  for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
1638  {
1639  aLayout->FreezeLayout(false);
1640  aLayout->AllCheckPageDescs();
1641  }
1642 
1643  Application::Reschedule( true );
1644 
1645  if( IsMergeOk() && bMT_FILE )
1646  {
1647  // save merged document
1648  assert( aTempFile.get() );
1649  INetURLObject aTempFileURL;
1650  if (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename)
1651  aTempFileURL.SetURL( aTempFile->GetURL() );
1652  else
1653  {
1654  aTempFileURL.SetURL(sDescriptorPrefix);
1655  // remove the unneeded temporary file
1656  aTempFile->EnableKillingFile();
1657  }
1658  if( !lcl_SaveDoc( &aTempFileURL, pStoreToFilter,
1659  pStoreToFilterOptions, &rMergeDescriptor.aSaveToFilterData,
1660  bIsPDFexport, xTargetDocShell.get(), *pTargetShell ) )
1661  {
1663  }
1664  }
1665  else if( IsMergeOk() && bMT_PRINTER )
1666  {
1667  // print the target document
1668  uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
1669  lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, aOptions );
1670  pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ );
1671  }
1672  }
1673 
1674  // we also show canceled documents, as long as there was no error
1675  if( !IsMergeError() && bMT_SHELL )
1676  // leave docshell available for caller (e.g. MM wizard)
1677  rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView );
1678  else if( xTargetDocShell.is() )
1679  xTargetDocShell->DoClose();
1680 
1681  Application::Reschedule( true );
1682 
1683  if (xProgressDlg)
1684  {
1685  xProgressDlg->response(RET_OK);
1686  }
1687 
1688  // unlock all dispatchers
1689  pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
1690  while (pViewFrame)
1691  {
1692  pViewFrame->GetDispatcher()->Lock(false);
1693  pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
1694  }
1695 
1696  SW_MOD()->SetView(&pSourceShell->GetView());
1697 
1698  if( xMailDispatcher.is() )
1699  {
1700  if( IsMergeOk() )
1701  {
1702  // TODO: Instead of polling via an AutoTimer, post an Idle event,
1703  // if the main loop has been made thread-safe.
1704  AutoTimer aEmailDispatcherPollTimer;
1705  aEmailDispatcherPollTimer.SetDebugName(
1706  "sw::SwDBManager aEmailDispatcherPollTimer" );
1707  aEmailDispatcherPollTimer.SetTimeout( 500 );
1708  aEmailDispatcherPollTimer.Start();
1709  while( IsMergeOk() && m_pImpl->m_xLastMessage.is() )
1711  aEmailDispatcherPollTimer.Stop();
1712  }
1713  xMailDispatcher->stop();
1714  xMailDispatcher->shutdown();
1715  }
1716 
1717  // remove the temporary files
1718  // has to be done after xMailDispatcher is finished, as mails may be
1719  // delivered as message attachments!
1720  for( const OUString &sFileURL : aFilesToRemove )
1721  SWUnoHelper::UCB_DeleteFile( sFileURL );
1722  }
1723  catch (const uno::Exception&)
1724  {
1725  if (xProgressDlg)
1726  {
1727  xProgressDlg->response(RET_CANCEL);
1728  }
1729  }
1730 
1731  return !IsMergeError();
1732 }
1733 
1735 {
1738 }
1739 
1740 // determine the column's Numberformat and transfer to the forwarded Formatter,
1741 // if applicable.
1742 sal_uLong SwDBManager::GetColumnFormat( const OUString& rDBName,
1743  const OUString& rTableName,
1744  const OUString& rColNm,
1745  SvNumberFormatter* pNFormatr,
1746  LanguageType nLanguage )
1747 {
1748  sal_uLong nRet = 0;
1749  if(pNFormatr)
1750  {
1751  uno::Reference< sdbc::XDataSource> xSource;
1752  uno::Reference< sdbc::XConnection> xConnection;
1753  bool bUseMergeData = false;
1754  uno::Reference< sdbcx::XColumnsSupplier> xColsSupp;
1755  bool bDisposeConnection = false;
1756  if(m_pImpl->pMergeData &&
1757  ((m_pImpl->pMergeData->sDataSource == rDBName && m_pImpl->pMergeData->sCommand == rTableName) ||
1758  (rDBName.isEmpty() && rTableName.isEmpty())))
1759  {
1760  xConnection = m_pImpl->pMergeData->xConnection;
1761  xSource = SwDBManager::getDataSourceAsParent(xConnection,rDBName);
1762  bUseMergeData = true;
1763  xColsSupp.set(m_pImpl->pMergeData->xResultSet, css::uno::UNO_QUERY);
1764  }
1765  if(!xConnection.is())
1766  {
1767  SwDBData aData;
1768  aData.sDataSource = rDBName;
1769  aData.sCommand = rTableName;
1770  aData.nCommandType = -1;
1771  SwDSParam* pParam = FindDSData(aData, false);
1772  if(pParam && pParam->xConnection.is())
1773  {
1774  xConnection = pParam->xConnection;
1775  xColsSupp.set(pParam->xResultSet, css::uno::UNO_QUERY);
1776  }
1777  else
1778  {
1779  xConnection = RegisterConnection( rDBName );
1780  bDisposeConnection = true;
1781  }
1782  if(bUseMergeData)
1783  m_pImpl->pMergeData->xConnection = xConnection;
1784  }
1785  bool bDispose = !xColsSupp.is();
1786  if(bDispose)
1787  {
1788  xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1789  }
1790  if(xColsSupp.is())
1791  {
1792  uno::Reference<container::XNameAccess> xCols;
1793  try
1794  {
1795  xCols = xColsSupp->getColumns();
1796  }
1797  catch (const uno::Exception& e)
1798  {
1799  SAL_WARN("sw.mailmerge", "Exception in getColumns(): " << e);
1800  }
1801  if(!xCols.is() || !xCols->hasByName(rColNm))
1802  return nRet;
1803  uno::Any aCol = xCols->getByName(rColNm);
1804  uno::Reference< beans::XPropertySet > xColumn;
1805  aCol >>= xColumn;
1806  nRet = GetColumnFormat(xSource, xConnection, xColumn, pNFormatr, nLanguage);
1807  if(bDispose)
1808  {
1809  ::comphelper::disposeComponent( xColsSupp );
1810  }
1811  if(bDisposeConnection)
1812  {
1813  ::comphelper::disposeComponent( xConnection );
1814  }
1815  }
1816  else
1817  nRet = pNFormatr->GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_SYSTEM );
1818  }
1819  return nRet;
1820 }
1821 
1822 sal_uLong SwDBManager::GetColumnFormat( uno::Reference< sdbc::XDataSource> const & xSource_in,
1823  uno::Reference< sdbc::XConnection> const & xConnection,
1824  uno::Reference< beans::XPropertySet> const & xColumn,
1825  SvNumberFormatter* pNFormatr,
1826  LanguageType nLanguage )
1827 {
1828  auto xSource = xSource_in;
1829 
1830  // set the NumberFormat in the doc if applicable
1831  sal_uLong nRet = 0;
1832 
1833  if(!xSource.is())
1834  {
1835  uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
1836  if ( xChild.is() )
1837  xSource.set(xChild->getParent(), uno::UNO_QUERY);
1838  }
1839  if(xSource.is() && xConnection.is() && xColumn.is() && pNFormatr)
1840  {
1841  SvNumberFormatsSupplierObj* pNumFormat = new SvNumberFormatsSupplierObj( pNFormatr );
1842  uno::Reference< util::XNumberFormatsSupplier > xDocNumFormatsSupplier = pNumFormat;
1843  uno::Reference< util::XNumberFormats > xDocNumberFormats = xDocNumFormatsSupplier->getNumberFormats();
1844  uno::Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, uno::UNO_QUERY);
1845 
1846  css::lang::Locale aLocale( LanguageTag( nLanguage ).getLocale());
1847 
1848  //get the number formatter of the data source
1849  uno::Reference<beans::XPropertySet> xSourceProps(xSource, uno::UNO_QUERY);
1850  uno::Reference< util::XNumberFormats > xNumberFormats;
1851  if(xSourceProps.is())
1852  {
1853  uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
1854  if(aFormats.hasValue())
1855  {
1856  uno::Reference<util::XNumberFormatsSupplier> xSuppl;
1857  aFormats >>= xSuppl;
1858  if(xSuppl.is())
1859  {
1860  xNumberFormats = xSuppl->getNumberFormats();
1861  }
1862  }
1863  }
1864  bool bUseDefault = true;
1865  try
1866  {
1867  uno::Any aFormatKey = xColumn->getPropertyValue("FormatKey");
1868  if(aFormatKey.hasValue())
1869  {
1870  sal_Int32 nFormat = 0;
1871  aFormatKey >>= nFormat;
1872  if(xNumberFormats.is())
1873  {
1874  try
1875  {
1876  uno::Reference<beans::XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat );
1877  uno::Any aFormatString = xNumProps->getPropertyValue("FormatString");
1878  uno::Any aLocaleVal = xNumProps->getPropertyValue("Locale");
1879  OUString sFormat;
1880  aFormatString >>= sFormat;
1881  lang::Locale aLoc;
1882  aLocaleVal >>= aLoc;
1883  nFormat = xDocNumberFormats->queryKey( sFormat, aLoc, false );
1884  if(NUMBERFORMAT_ENTRY_NOT_FOUND == sal::static_int_cast< sal_uInt32, sal_Int32>(nFormat))
1885  nFormat = xDocNumberFormats->addNew( sFormat, aLoc );
1886  nRet = nFormat;
1887  bUseDefault = false;
1888  }
1889  catch (const uno::Exception& e)
1890  {
1891  SAL_WARN("sw.mailmerge", "illegal number format key: " << e);
1892  }
1893  }
1894  }
1895  }
1896  catch(const uno::Exception&)
1897  {
1898  SAL_WARN("sw.mailmerge", "no FormatKey property found");
1899  }
1900  if(bUseDefault)
1901  nRet = dbtools::getDefaultNumberFormat(xColumn, xDocNumberFormatTypes, aLocale);
1902  }
1903  return nRet;
1904 }
1905 
1906 sal_Int32 SwDBManager::GetColumnType( const OUString& rDBName,
1907  const OUString& rTableName,
1908  const OUString& rColNm )
1909 {
1910  sal_Int32 nRet = sdbc::DataType::SQLNULL;
1911  SwDBData aData;
1912  aData.sDataSource = rDBName;
1913  aData.sCommand = rTableName;
1914  aData.nCommandType = -1;
1915  SwDSParam* pParam = FindDSData(aData, false);
1916  uno::Reference< sdbc::XConnection> xConnection;
1917  uno::Reference< sdbcx::XColumnsSupplier > xColsSupp;
1918  bool bDispose = false;
1919  if(pParam && pParam->xConnection.is())
1920  {
1921  xConnection = pParam->xConnection;
1922  xColsSupp.set( pParam->xResultSet, uno::UNO_QUERY );
1923  }
1924  else
1925  {
1926  xConnection = RegisterConnection( rDBName );
1927  }
1928  if( !xColsSupp.is() )
1929  {
1930  xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1931  bDispose = true;
1932  }
1933  if(xColsSupp.is())
1934  {
1935  uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1936  if(xCols->hasByName(rColNm))
1937  {
1938  uno::Any aCol = xCols->getByName(rColNm);
1939  uno::Reference<beans::XPropertySet> xCol;
1940  aCol >>= xCol;
1941  uno::Any aType = xCol->getPropertyValue("Type");
1942  aType >>= nRet;
1943  }
1944  if(bDispose)
1945  ::comphelper::disposeComponent( xColsSupp );
1946  }
1947  return nRet;
1948 }
1949 
1950 uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rDataSource,
1951  uno::Reference<sdbc::XDataSource>& rxSource, const SwView *pView)
1952 {
1953  uno::Reference< sdbc::XConnection> xConnection;
1954  uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1955  try
1956  {
1957  uno::Reference<sdb::XCompletedConnection> xComplConnection(dbtools::getDataSource(rDataSource, xContext), uno::UNO_QUERY);
1958  if ( xComplConnection.is() )
1959  {
1960  rxSource.set(xComplConnection, uno::UNO_QUERY);
1961  weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr;
1962  uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(xContext, pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW );
1963  xConnection = xComplConnection->connectWithCompletion( xHandler );
1964  }
1965  }
1966  catch(const uno::Exception&)
1967  {
1968  }
1969 
1970  return xConnection;
1971 }
1972 
1973 uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference<sdbc::XConnection> const & xConnection,
1974  const OUString& rTableOrQuery,
1975  SwDBSelect eTableOrQuery)
1976 {
1977  uno::Reference< sdbcx::XColumnsSupplier> xRet;
1978  try
1979  {
1980  if(eTableOrQuery == SwDBSelect::UNKNOWN)
1981  {
1982  //search for a table with the given command name
1983  uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY);
1984  if(xTSupplier.is())
1985  {
1986  uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
1987  eTableOrQuery = xTables->hasByName(rTableOrQuery) ?
1989  }
1990  }
1991  sal_Int32 nCommandType = SwDBSelect::TABLE == eTableOrQuery ?
1992  sdb::CommandType::TABLE : sdb::CommandType::QUERY;
1993  uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
1994  uno::Reference<sdbc::XRowSet> xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), uno::UNO_QUERY);
1995 
1996  OUString sDataSource;
1997  uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection, sDataSource);
1998  uno::Reference<beans::XPropertySet> xSourceProperties(xSource, uno::UNO_QUERY);
1999  if(xSourceProperties.is())
2000  {
2001  xSourceProperties->getPropertyValue("Name") >>= sDataSource;
2002  }
2003 
2004  uno::Reference<beans::XPropertySet> xRowProperties(xRowSet, uno::UNO_QUERY);
2005  xRowProperties->setPropertyValue("DataSourceName", uno::makeAny(sDataSource));
2006  xRowProperties->setPropertyValue("Command", uno::makeAny(rTableOrQuery));
2007  xRowProperties->setPropertyValue("CommandType", uno::makeAny(nCommandType));
2008  xRowProperties->setPropertyValue("FetchSize", uno::makeAny(sal_Int32(10)));
2009  xRowProperties->setPropertyValue("ActiveConnection", uno::makeAny(xConnection));
2010  xRowSet->execute();
2011  xRet.set( xRowSet, uno::UNO_QUERY );
2012  }
2013  catch (const uno::Exception& e)
2014  {
2015  SAL_WARN("sw.mailmerge", "Exception in SwDBManager::GetColumnSupplier: " << e);
2016  }
2017 
2018  return xRet;
2019 }
2020 
2021 OUString SwDBManager::GetDBField(uno::Reference<beans::XPropertySet> const & xColumnProps,
2022  const SwDBFormatData& rDBFormatData,
2023  double* pNumber)
2024 {
2025  uno::Reference< sdb::XColumn > xColumn(xColumnProps, uno::UNO_QUERY);
2026  OUString sRet;
2027  assert( xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments" );
2028  if(!xColumn.is())
2029  return sRet;
2030 
2031  uno::Any aType = xColumnProps->getPropertyValue("Type");
2032  sal_Int32 eDataType = sdbc::DataType::SQLNULL;
2033  aType >>= eDataType;
2034  switch(eDataType)
2035  {
2036  case sdbc::DataType::CHAR:
2037  case sdbc::DataType::VARCHAR:
2038  case sdbc::DataType::LONGVARCHAR:
2039  try
2040  {
2041  sRet = xColumn->getString();
2042  sRet = sRet.replace( '\xb', '\n' ); // MSWord uses \xb as a newline
2043  }
2044  catch(const sdbc::SQLException&)
2045  {
2046  }
2047  break;
2048  case sdbc::DataType::BIT:
2049  case sdbc::DataType::BOOLEAN:
2050  case sdbc::DataType::TINYINT:
2051  case sdbc::DataType::SMALLINT:
2052  case sdbc::DataType::INTEGER:
2053  case sdbc::DataType::BIGINT:
2054  case sdbc::DataType::FLOAT:
2055  case sdbc::DataType::REAL:
2056  case sdbc::DataType::DOUBLE:
2057  case sdbc::DataType::NUMERIC:
2058  case sdbc::DataType::DECIMAL:
2059  case sdbc::DataType::DATE:
2060  case sdbc::DataType::TIME:
2061  case sdbc::DataType::TIMESTAMP:
2062  {
2063 
2064  try
2065  {
2067  xColumnProps,
2068  rDBFormatData.xFormatter,
2069  rDBFormatData.aLocale,
2070  rDBFormatData.aNullDate);
2071  if (pNumber)
2072  {
2073  double fVal = xColumn->getDouble();
2074  if(!xColumn->wasNull())
2075  {
2076  *pNumber = fVal;
2077  }
2078  }
2079  }
2080  catch (const uno::Exception&)
2081  {
2082  css::uno::Any ex( cppu::getCaughtException() );
2083  SAL_WARN("sw.mailmerge", "exception caught: " << exceptionToString(ex));
2084  }
2085 
2086  }
2087  break;
2088  }
2089 
2090  return sRet;
2091 }
2092 
2093 // checks if a desired data source table or query is open
2094 bool SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
2095  const OUString& rTableOrQuery, bool bMergeShell)
2096 {
2097  if(m_pImpl->pMergeData)
2098  {
2099  return ((rDataSource == m_pImpl->pMergeData->sDataSource
2100  && rTableOrQuery == m_pImpl->pMergeData->sCommand)
2101  || (rDataSource.isEmpty() && rTableOrQuery.isEmpty()))
2102  && m_pImpl->pMergeData->xResultSet.is();
2103  }
2104  else if(!bMergeShell)
2105  {
2106  SwDBData aData;
2107  aData.sDataSource = rDataSource;
2108  aData.sCommand = rTableOrQuery;
2109  aData.nCommandType = -1;
2110  SwDSParam* pFound = FindDSData(aData, false);
2111  return (pFound && pFound->xResultSet.is());
2112  }
2113  return false;
2114 }
2115 
2116 // read column data at a specified position
2117 bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
2118  const OUString& rColumnName, sal_uInt32 nAbsRecordId,
2119  LanguageType nLanguage,
2120  OUString& rResult, double* pNumber)
2121 {
2122  bool bRet = false;
2123  SwDSParam* pFound = nullptr;
2124  //check if it's the merge data source
2125  if(m_pImpl->pMergeData &&
2126  rSourceName == m_pImpl->pMergeData->sDataSource &&
2127  rTableName == m_pImpl->pMergeData->sCommand)
2128  {
2129  pFound = m_pImpl->pMergeData.get();
2130  }
2131  else
2132  {
2133  SwDBData aData;
2134  aData.sDataSource = rSourceName;
2135  aData.sCommand = rTableName;
2136  aData.nCommandType = -1;
2137  pFound = FindDSData(aData, false);
2138  }
2139  if (!pFound)
2140  return false;
2141  //check validity of supplied record Id
2142  if(pFound->aSelection.hasElements())
2143  {
2144  //the destination has to be an element of the selection
2145  const uno::Any* pSelection = pFound->aSelection.getConstArray();
2146  bool bFound = false;
2147  for(sal_Int32 nPos = 0; !bFound && nPos < pFound->aSelection.getLength(); nPos++)
2148  {
2149  sal_Int32 nSelection = 0;
2150  pSelection[nPos] >>= nSelection;
2151  if(nSelection == static_cast<sal_Int32>(nAbsRecordId))
2152  bFound = true;
2153  }
2154  if(!bFound)
2155  return false;
2156  }
2157  if( pFound->HasValidRecord() )
2158  {
2159  sal_Int32 nOldRow = 0;
2160  try
2161  {
2162  nOldRow = pFound->xResultSet->getRow();
2163  }
2164  catch(const uno::Exception&)
2165  {
2166  return false;
2167  }
2168  //position to the desired index
2169  bool bMove = true;
2170  if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2171  bMove = lcl_MoveAbsolute(pFound, nAbsRecordId);
2172  if(bMove)
2173  bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber);
2174  if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2175  lcl_MoveAbsolute(pFound, nOldRow);
2176  }
2177  return bRet;
2178 }
2179 
2180 // reads the column data at the current position
2181 bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage,
2182  OUString &rResult, double *pNumber)
2183 {
2184  if( !IsValidMergeRecord() )
2185  {
2186  rResult.clear();
2187  return false;
2188  }
2189 
2190  bool bRet = lcl_GetColumnCnt(m_pImpl->pMergeData.get(), rColumnName, nLanguage, rResult, pNumber);
2191  return bRet;
2192 }
2193 
2195 {
2196  assert( m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" );
2197  return lcl_ToNextRecord( m_pImpl->pMergeData.get() );
2198 }
2199 
2201  LanguageType nLanguage, SwCalc &rCalc )
2202 {
2203  if( !IsValidMergeRecord() )
2204  return false;
2205 
2206  uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
2207  if( !xColsSupp.is() )
2208  return false;
2209 
2210  {
2211  uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
2212  const uno::Sequence<OUString> aColNames = xCols->getElementNames();
2213  const OUString* pColNames = aColNames.getConstArray();
2214  OUString aString;
2215 
2216  // add the "record number" variable, as SwCalc::VarLook would.
2217  rCalc.VarChange( GetAppCharClass().lowercase(
2219 
2220  for( int nCol = 0; nCol < aColNames.getLength(); nCol++ )
2221  {
2222  // get the column type
2223  sal_Int32 nColumnType = sdbc::DataType::SQLNULL;
2224  uno::Any aCol = xCols->getByName( pColNames[nCol] );
2225  uno::Reference<beans::XPropertySet> xColumnProps;
2226  aCol >>= xColumnProps;
2227  uno::Any aType = xColumnProps->getPropertyValue( "Type" );
2228  aType >>= nColumnType;
2229  double aNumber = DBL_MAX;
2230 
2231  lcl_GetColumnCnt( m_pImpl->pMergeData.get(), xColumnProps, nLanguage, aString, &aNumber );
2232 
2233  sal_uInt32 nFormat = GetColumnFormat( m_pImpl->pMergeData->sDataSource,
2234  m_pImpl->pMergeData->sCommand,
2235  pColNames[nCol], pDocFormatter, nLanguage );
2236  // aNumber is overwritten by SwDBField::FormatValue, so store initial status
2237  bool colIsNumber = aNumber != DBL_MAX;
2238  bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFormat,
2239  aNumber, nColumnType );
2240  if( colIsNumber )
2241  {
2242  if( bValidValue )
2243  {
2244  SwSbxValue aValue;
2245  aValue.PutDouble( aNumber );
2246  aValue.SetDBvalue( true );
2247  SAL_INFO( "sw.ui", "'" << pColNames[nCol] << "': " << aNumber << " / " << aString );
2248  rCalc.VarChange( pColNames[nCol], aValue );
2249  }
2250  }
2251  else
2252  {
2253  SwSbxValue aValue;
2254  aValue.PutString( aString );
2255  aValue.SetDBvalue( true );
2256  SAL_INFO( "sw.ui", "'" << pColNames[nCol] << "': " << aString );
2257  rCalc.VarChange( pColNames[nCol], aValue );
2258  }
2259  }
2260  }
2261 
2262  return true;
2263 }
2264 
2266  const OUString& rDataSource, const OUString& rCommand)
2267 {
2268  SwDSParam* pFound = nullptr;
2269  if(m_pImpl->pMergeData &&
2270  rDataSource == m_pImpl->pMergeData->sDataSource &&
2271  rCommand == m_pImpl->pMergeData->sCommand)
2272  {
2273  pFound = m_pImpl->pMergeData.get();
2274  }
2275  else
2276  {
2277  SwDBData aData;
2278  aData.sDataSource = rDataSource;
2279  aData.sCommand = rCommand;
2280  aData.nCommandType = -1;
2281  pFound = FindDSData(aData, false);
2282  }
2283  lcl_ToNextRecord( pFound );
2284 }
2285 
2286 static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action )
2287 {
2288  bool bRet = true;
2289 
2290  assert( SwDBNextRecord::NEXT == action ||
2291  (SwDBNextRecord::FIRST == action && pParam) );
2292  if( nullptr == pParam )
2293  return false;
2294 
2295  if( action == SwDBNextRecord::FIRST )
2296  {
2297  pParam->nSelectionIndex = 0;
2298  pParam->bEndOfDB = false;
2299  }
2300 
2301  if( !pParam->HasValidRecord() )
2302  return false;
2303 
2304  try
2305  {
2306  if( pParam->aSelection.hasElements() )
2307  {
2308  if( pParam->nSelectionIndex >= pParam->aSelection.getLength() )
2309  pParam->bEndOfDB = true;
2310  else
2311  {
2312  sal_Int32 nPos = 0;
2313  pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos;
2314  pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
2315  }
2316  }
2317  else if( action == SwDBNextRecord::FIRST )
2318  {
2319  pParam->bEndOfDB = !pParam->xResultSet->first();
2320  }
2321  else
2322  {
2323  sal_Int32 nBefore = pParam->xResultSet->getRow();
2324  pParam->bEndOfDB = !pParam->xResultSet->next();
2325  if( !pParam->bEndOfDB && nBefore == pParam->xResultSet->getRow() )
2326  {
2327  // next returned true but it didn't move
2328  ::dbtools::throwFunctionSequenceException( pParam->xResultSet );
2329  }
2330  }
2331 
2332  ++pParam->nSelectionIndex;
2333  bRet = !pParam->bEndOfDB;
2334  }
2335  catch( const uno::Exception &e )
2336  {
2337  pParam->bEndOfDB = true;
2338  bRet = false;
2339  // we allow merging with empty databases, so don't warn on init
2341  "sw.mailmerge", "exception in ToNextRecord(): " << e);
2342  }
2343  return bRet;
2344 }
2345 
2346 // synchronized labels contain a next record field at their end
2347 // to assure that the next page can be created in mail merge
2348 // the cursor position must be validated
2350 {
2351  return( m_pImpl->pMergeData && m_pImpl->pMergeData->HasValidRecord() );
2352 }
2353 
2355 {
2356  sal_uInt32 nRet = 0;
2357  assert( m_pImpl->pMergeData &&
2358  m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" );
2359  if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is())
2360  return 0;
2361  try
2362  {
2363  nRet = m_pImpl->pMergeData->xResultSet->getRow();
2364  }
2365  catch(const uno::Exception&)
2366  {
2367  }
2368  return nRet;
2369 }
2370 
2371 bool SwDBManager::ToRecordId(sal_Int32 nSet)
2372 {
2373  assert( m_pImpl->pMergeData &&
2374  m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" );
2375  if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is()|| nSet < 0)
2376  return false;
2377  bool bRet = false;
2378  sal_Int32 nAbsPos = nSet;
2379  assert(nAbsPos >= 0);
2380  bRet = lcl_MoveAbsolute(m_pImpl->pMergeData.get(), nAbsPos);
2381  m_pImpl->pMergeData->bEndOfDB = !bRet;
2382  return bRet;
2383 }
2384 
2385 bool SwDBManager::OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery)
2386 {
2387  SwDBData aData;
2388  aData.sDataSource = rDataSource;
2389  aData.sCommand = rTableOrQuery;
2390  aData.nCommandType = -1;
2391 
2392  SwDSParam* pFound = FindDSData(aData, true);
2393  if(pFound->xResultSet.is())
2394  return true;
2395  SwDSParam* pParam = FindDSConnection(rDataSource, false);
2396  if(pParam && pParam->xConnection.is())
2397  pFound->xConnection = pParam->xConnection;
2398  if(pFound->xConnection.is())
2399  {
2400  try
2401  {
2402  uno::Reference< sdbc::XDatabaseMetaData > xMetaData = pFound->xConnection->getMetaData();
2403  try
2404  {
2405  pFound->bScrollable = xMetaData
2406  ->supportsResultSetType(sal_Int32(sdbc::ResultSetType::SCROLL_INSENSITIVE));
2407  }
2408  catch(const uno::Exception&)
2409  {
2410  // DB driver may not be ODBC 3.0 compliant
2411  pFound->bScrollable = true;
2412  }
2413  pFound->xStatement = pFound->xConnection->createStatement();
2414  OUString aQuoteChar = xMetaData->getIdentifierQuoteString();
2415  OUString sStatement("SELECT * FROM ");
2416  sStatement = "SELECT * FROM ";
2417  sStatement += aQuoteChar;
2418  sStatement += rTableOrQuery;
2419  sStatement += aQuoteChar;
2420  pFound->xResultSet = pFound->xStatement->executeQuery( sStatement );
2421 
2422  //after executeQuery the cursor must be positioned
2423  pFound->bEndOfDB = !pFound->xResultSet->next();
2424  ++pFound->nSelectionIndex;
2425  }
2426  catch (const uno::Exception&)
2427  {
2428  pFound->xResultSet = nullptr;
2429  pFound->xStatement = nullptr;
2430  pFound->xConnection = nullptr;
2431  }
2432  }
2433  return pFound->xResultSet.is();
2434 }
2435 
2436 uno::Reference< sdbc::XConnection> const & SwDBManager::RegisterConnection(OUString const& rDataSource)
2437 {
2438  SwDSParam* pFound = SwDBManager::FindDSConnection(rDataSource, true);
2439  uno::Reference< sdbc::XDataSource> xSource;
2440  if(!pFound->xConnection.is())
2441  {
2442  SwView* pView = (m_pDoc && m_pDoc->GetDocShell()) ? m_pDoc->GetDocShell()->GetView() : nullptr;
2443  pFound->xConnection = SwDBManager::GetConnection(rDataSource, xSource, pView);
2444  try
2445  {
2446  uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2447  if(xComponent.is())
2448  xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2449  }
2450  catch(const uno::Exception&)
2451  {
2452  }
2453  }
2454  return pFound->xConnection;
2455 }
2456 
2458  const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType)
2459 {
2460  sal_uInt32 nRet = 0xffffffff;
2461  //check for merge data source first
2462  if(m_pImpl->pMergeData &&
2463  ((rDataSource == m_pImpl->pMergeData->sDataSource &&
2464  rTableOrQuery == m_pImpl->pMergeData->sCommand) ||
2465  (rDataSource.isEmpty() && rTableOrQuery.isEmpty())) &&
2466  (nCommandType == -1 || nCommandType == m_pImpl->pMergeData->nCommandType) &&
2467  m_pImpl->pMergeData->xResultSet.is())
2468  {
2469  nRet = GetSelectedRecordId();
2470  }
2471  else
2472  {
2473  SwDBData aData;
2474  aData.sDataSource = rDataSource;
2475  aData.sCommand = rTableOrQuery;
2476  aData.nCommandType = nCommandType;
2477  SwDSParam* pFound = FindDSData(aData, false);
2478  if(pFound && pFound->xResultSet.is())
2479  {
2480  try
2481  { //if a selection array is set the current row at the result set may not be set yet
2482  if(pFound->aSelection.hasElements())
2483  {
2484  sal_Int32 nSelIndex = pFound->nSelectionIndex;
2485  if(nSelIndex >= pFound->aSelection.getLength())
2486  nSelIndex = pFound->aSelection.getLength() -1;
2487  pFound->aSelection.getConstArray()[nSelIndex] >>= nRet;
2488 
2489  }
2490  else
2491  nRet = pFound->xResultSet->getRow();
2492  }
2493  catch(const uno::Exception&)
2494  {
2495  }
2496  }
2497  }
2498  return nRet;
2499 }
2500 
2501 // close all data sources - after fields were updated
2502 void SwDBManager::CloseAll(bool bIncludingMerge)
2503 {
2504  //the only thing done here is to reset the selection index
2505  //all connections stay open
2506  for (auto & pParam : m_DataSourceParams)
2507  {
2508  if (bIncludingMerge || pParam.get() != m_pImpl->pMergeData.get())
2509  {
2510  pParam->nSelectionIndex = 0;
2511  pParam->bEndOfDB = false;
2512  try
2513  {
2514  if(!m_bInMerge && pParam->xResultSet.is())
2515  pParam->xResultSet->first();
2516  }
2517  catch(const uno::Exception&)
2518  {}
2519  }
2520  }
2521 }
2522 
2523 SwDSParam* SwDBManager::FindDSData(const SwDBData& rData, bool bCreate)
2524 {
2525  //prefer merge data if available
2526  if(m_pImpl->pMergeData &&
2527  ((rData.sDataSource == m_pImpl->pMergeData->sDataSource &&
2528  rData.sCommand == m_pImpl->pMergeData->sCommand) ||
2529  (rData.sDataSource.isEmpty() && rData.sCommand.isEmpty())) &&
2530  (rData.nCommandType == -1 || rData.nCommandType == m_pImpl->pMergeData->nCommandType ||
2531  (bCreate && m_pImpl->pMergeData->nCommandType == -1)))
2532  {
2533  return m_pImpl->pMergeData.get();
2534  }
2535 
2536  SwDSParam* pFound = nullptr;
2537  for (size_t nPos = m_DataSourceParams.size(); nPos; nPos--)
2538  {
2539  SwDSParam* pParam = m_DataSourceParams[nPos - 1].get();
2540  if(rData.sDataSource == pParam->sDataSource &&
2541  rData.sCommand == pParam->sCommand &&
2542  (rData.nCommandType == -1 || rData.nCommandType == pParam->nCommandType ||
2543  (bCreate && pParam->nCommandType == -1)))
2544  {
2545  // calls from the calculator may add a connection with an invalid commandtype
2546  //later added "real" data base connections have to re-use the already available
2547  //DSData and set the correct CommandType
2548  if(bCreate && pParam->nCommandType == -1)
2549  pParam->nCommandType = rData.nCommandType;
2550  pFound = pParam;
2551  break;
2552  }
2553  }
2554  if(bCreate && !pFound)
2555  {
2556  pFound = new SwDSParam(rData);
2557  m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound));
2558  try
2559  {
2560  uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2561  if(xComponent.is())
2562  xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2563  }
2564  catch(const uno::Exception&)
2565  {
2566  }
2567  }
2568  return pFound;
2569 }
2570 
2571 SwDSParam* SwDBManager::FindDSConnection(const OUString& rDataSource, bool bCreate)
2572 {
2573  //prefer merge data if available
2574  if(m_pImpl->pMergeData && rDataSource == m_pImpl->pMergeData->sDataSource )
2575  {
2576  SetAsUsed(rDataSource);
2577  return m_pImpl->pMergeData.get();
2578  }
2579  SwDSParam* pFound = nullptr;
2580  for (auto & pParam : m_DataSourceParams)
2581  {
2582  if(rDataSource == pParam->sDataSource)
2583  {
2584  SetAsUsed(rDataSource);
2585  pFound = pParam.get();
2586  break;
2587  }
2588  }
2589  if(bCreate && !pFound)
2590  {
2591  SwDBData aData;
2592  aData.sDataSource = rDataSource;
2593  pFound = new SwDSParam(aData);
2594  SetAsUsed(rDataSource);
2595  m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound));
2596  try
2597  {
2598  uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2599  if(xComponent.is())
2600  xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2601  }
2602  catch(const uno::Exception&)
2603  {
2604  }
2605  }
2606  return pFound;
2607 }
2608 
2610 {
2611  return SW_MOD()->GetDBConfig()->GetAddressSource();
2612 }
2613 
2614 uno::Sequence<OUString> SwDBManager::GetExistingDatabaseNames()
2615 {
2616  uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2617  uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2618  return xDBContext->getElementNames();
2619 }
2620 
2621 namespace sw
2622 {
2624 {
2625  OUString sExt(rURL.GetExtension());
2627 
2628  if (sExt == "odb")
2629  {
2630  type = DBConnURIType::ODB;
2631  }
2632  else if (sExt.equalsIgnoreAsciiCase("sxc")
2633  || sExt.equalsIgnoreAsciiCase("ods")
2634  || sExt.equalsIgnoreAsciiCase("xls")
2635  || sExt.equalsIgnoreAsciiCase("xlsx"))
2636  {
2637  type = DBConnURIType::CALC;
2638  }
2639  else if (sExt.equalsIgnoreAsciiCase("sxw") || sExt.equalsIgnoreAsciiCase("odt") || sExt.equalsIgnoreAsciiCase("doc") || sExt.equalsIgnoreAsciiCase("docx"))
2640  {
2641  type = DBConnURIType::WRITER;
2642  }
2643  else if (sExt.equalsIgnoreAsciiCase("dbf"))
2644  {
2645  type = DBConnURIType::DBASE;
2646  }
2647  else if (sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
2648  {
2649  type = DBConnURIType::FLAT;
2650  }
2651 #ifdef _WIN32
2652  else if (sExt.equalsIgnoreAsciiCase("mdb") || sExt.equalsIgnoreAsciiCase("mde"))
2653  {
2654  type = DBConnURIType::MSJET;
2655  }
2656  else if (sExt.equalsIgnoreAsciiCase("accdb") || sExt.equalsIgnoreAsciiCase("accde"))
2657  {
2658  type = DBConnURIType::MSACE;
2659  }
2660 #endif
2661  return type;
2662 }
2663 }
2664 
2665 namespace
2666 {
2667 uno::Any GetDBunoURI(const INetURLObject &rURL, DBConnURIType& rType)
2668 {
2669  uno::Any aURLAny;
2670 
2671  if (rType == DBConnURIType::UNKNOWN)
2672  rType = GetDBunoType(rURL);
2673 
2674  switch (rType) {
2675  case DBConnURIType::UNKNOWN:
2676  case DBConnURIType::ODB:
2677  break;
2678  case DBConnURIType::CALC:
2679  {
2680  OUString sDBURL("sdbc:calc:");
2682  aURLAny <<= sDBURL;
2683  }
2684  break;
2685  case DBConnURIType::WRITER:
2686  {
2687  OUString sDBURL("sdbc:writer:");
2689  aURLAny <<= sDBURL;
2690  }
2691  break;
2692  case DBConnURIType::DBASE:
2693  {
2694  INetURLObject aUrlTmp(rURL);
2695  aUrlTmp.removeSegment();
2696  aUrlTmp.removeFinalSlash();
2697  OUString sDBURL("sdbc:dbase:");
2698  sDBURL += aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2699  aURLAny <<= sDBURL;
2700  }
2701  break;
2702  case DBConnURIType::FLAT:
2703  {
2704  INetURLObject aUrlTmp(rURL);
2705  aUrlTmp.removeSegment();
2706  aUrlTmp.removeFinalSlash();
2707  OUString sDBURL("sdbc:flat:");
2708  //only the 'path' has to be added
2709  sDBURL += aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2710  aURLAny <<= sDBURL;
2711  }
2712  break;
2713  case DBConnURIType::MSJET:
2714 #ifdef _WIN32
2715  {
2716  OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=");
2717  sDBURL += rURL.PathToFileName();
2718  aURLAny <<= sDBURL;
2719  }
2720 #endif
2721  break;
2722  case DBConnURIType::MSACE:
2723 #ifdef _WIN32
2724  {
2725  OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=");
2726  sDBURL += rURL.PathToFileName();
2727  aURLAny <<= sDBURL;
2728  }
2729 #endif
2730  break;
2731  }
2732  return aURLAny;
2733 }
2734 
2736 OUString getOwnURL(SfxObjectShell const * pDocShell)
2737 {
2738  OUString aRet;
2739 
2740  if (!pDocShell)
2741  return aRet;
2742 
2743  const INetURLObject& rURLObject = pDocShell->GetMedium()->GetURLObject();
2745  return aRet;
2746 }
2747 
2754 OUString LoadAndRegisterDataSource_Impl(DBConnURIType type, const uno::Reference< beans::XPropertySet > *pSettings,
2755  const INetURLObject &rURL, const OUString *pDestDir, SfxObjectShell* pDocShell)
2756 {
2757  OUString sExt(rURL.GetExtension());
2758  uno::Any aTableFilterAny;
2759  uno::Any aSuppressVersionsAny;
2760  uno::Any aInfoAny;
2761  bool bStore = true;
2762  OUString sFind;
2763  uno::Sequence<OUString> aFilters(1);
2764 
2765  uno::Any aURLAny = GetDBunoURI(rURL, type);
2766  switch (type) {
2767  case DBConnURIType::UNKNOWN:
2768  case DBConnURIType::CALC:
2769  case DBConnURIType::WRITER:
2770  break;
2771  case DBConnURIType::ODB:
2772  bStore = false;
2773  break;
2774  case DBConnURIType::FLAT:
2775  case DBConnURIType::DBASE:
2776  //set the filter to the file name without extension
2777  aFilters[0] = rURL.getBase();
2778  aTableFilterAny <<= aFilters;
2779  break;
2780  case DBConnURIType::MSJET:
2781  case DBConnURIType::MSACE:
2782  aSuppressVersionsAny <<= true;
2783  break;
2784  }
2785 
2786  try
2787  {
2788  uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
2789  uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2790 
2791  OUString sNewName = INetURLObject::decode(rURL.getName(),
2793  sal_Int32 nExtLen = sExt.getLength();
2794  sNewName = sNewName.replaceAt(sNewName.getLength() - nExtLen - 1, nExtLen + 1, "");
2795 
2796  //find a unique name if sNewName already exists
2797  sFind = sNewName;
2798  sal_Int32 nIndex = 0;
2799  while (xDBContext->hasByName(sFind))
2800  sFind = sNewName + OUString::number(++nIndex);
2801 
2802  uno::Reference<uno::XInterface> xNewInstance;
2803  if (!bStore)
2804  {
2805  //odb-file
2806  uno::Any aDataSource = xDBContext->getByName(rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
2807  aDataSource >>= xNewInstance;
2808  }
2809  else
2810  {
2811  xNewInstance = xDBContext->createInstance();
2812  uno::Reference<beans::XPropertySet> xDataProperties(xNewInstance, uno::UNO_QUERY);
2813 
2814  if (aURLAny.hasValue())
2815  xDataProperties->setPropertyValue("URL", aURLAny);
2816  if (aTableFilterAny.hasValue())
2817  xDataProperties->setPropertyValue("TableFilter", aTableFilterAny);
2818  if (aSuppressVersionsAny.hasValue())
2819  xDataProperties->setPropertyValue("SuppressVersionColumns", aSuppressVersionsAny);
2820  if (aInfoAny.hasValue())
2821  xDataProperties->setPropertyValue("Info", aInfoAny);
2822 
2823  if (DBConnURIType::FLAT == type && pSettings)
2824  {
2825  uno::Any aSettings = xDataProperties->getPropertyValue("Settings");
2826  uno::Reference < beans::XPropertySet > xDSSettings;
2827  aSettings >>= xDSSettings;
2828  ::comphelper::copyProperties(*pSettings, xDSSettings);
2829  xDSSettings->setPropertyValue("Extension", uno::makeAny(sExt));
2830  }
2831 
2832  uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, uno::UNO_QUERY_THROW);
2833  uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), uno::UNO_QUERY_THROW);
2834  OUString aOwnURL = getOwnURL(pDocShell);
2835  if (aOwnURL.isEmpty())
2836  {
2837  // Cannot embed, as embedded data source would need the URL of the parent document.
2838  OUString const sOutputExt = ".odb";
2839  OUString sHomePath(SvtPathOptions().GetWorkPath());
2840  utl::TempFile aTempFile(sNewName, true, &sOutputExt, pDestDir ? pDestDir : &sHomePath);
2841  const OUString& sTmpName = aTempFile.GetURL();
2842  xStore->storeAsURL(sTmpName, uno::Sequence<beans::PropertyValue>());
2843  }
2844  else
2845  {
2846  // Embed.
2847  OUString aStreamRelPath = "EmbeddedDatabase";
2848  uno::Reference<embed::XStorage> xStorage = pDocShell->GetStorage();
2849 
2850  // Refer to the sub-storage name in the document settings, so
2851  // we can load it again next time the file is imported.
2852  uno::Reference<lang::XMultiServiceFactory> xFactory(pDocShell->GetModel(), uno::UNO_QUERY);
2853  uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
2854  xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::makeAny(aStreamRelPath));
2855 
2856  // Store it only after setting the above property, so that only one data source gets registered.
2857  SwDBManager::StoreEmbeddedDataSource(xStore, xStorage, aStreamRelPath, aOwnURL);
2858  }
2859  }
2860  xDBContext->registerObject(sFind, xNewInstance);
2861  }
2862  catch (const uno::Exception&)
2863  {
2864  sFind.clear();
2865  }
2866  return sFind;
2867 }
2868 
2869 // Construct vnd.sun.star.pkg:// URL
2870 OUString ConstructVndSunStarPkgUrl(const OUString& rMainURL, const OUString& rStreamRelPath)
2871 {
2872  auto xContext(comphelper::getProcessComponentContext());
2873  auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(rMainURL);
2874  assert(xUri.is());
2875  xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)
2876  ->createVndSunStarPkgUrlReference(xUri);
2877  assert(xUri.is());
2878  return xUri->getUriReference() + "/"
2880  rStreamRelPath, INetURLObject::PART_FPATH,
2882 }
2883 }
2884 
2886 {
2887  sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, pParent);
2888  uno::Reference < ui::dialogs::XFilePicker3 > xFP = aDlgHelper.GetFilePicker();
2889 
2890  OUString sHomePath(SvtPathOptions().GetWorkPath());
2891  aDlgHelper.SetDisplayDirectory( sHomePath );
2892 
2893  uno::Reference<ui::dialogs::XFilterManager> xFltMgr(xFP, uno::UNO_QUERY);
2894 
2895  OUString sFilterAll(SwResId(STR_FILTER_ALL));
2896  OUString sFilterAllData(SwResId(STR_FILTER_ALL_DATA));
2897  OUString sFilterSXB(SwResId(STR_FILTER_SXB));
2898  OUString sFilterSXC(SwResId(STR_FILTER_SXC));
2899  OUString sFilterSXW(SwResId(STR_FILTER_SXW));
2900  OUString sFilterDBF(SwResId(STR_FILTER_DBF));
2901  OUString sFilterXLS(SwResId(STR_FILTER_XLS));
2902  OUString sFilterDOC(SwResId(STR_FILTER_DOC));
2903  OUString sFilterTXT(SwResId(STR_FILTER_TXT));
2904  OUString sFilterCSV(SwResId(STR_FILTER_CSV));
2905 #ifdef _WIN32
2906  OUString sFilterMDB(SwResId(STR_FILTER_MDB));
2907  OUString sFilterACCDB(SwResId(STR_FILTER_ACCDB));
2908 #endif
2909  xFltMgr->appendFilter( sFilterAll, "*" );
2910  xFltMgr->appendFilter( sFilterAllData, "*.ods;*.sxc;*.odt;*.sxw;*.dbf;*.xls;*.xlsx;*.doc;*.docx;*.txt;*.csv");
2911 
2912  xFltMgr->appendFilter( sFilterSXB, "*.odb" );
2913  xFltMgr->appendFilter( sFilterSXC, "*.ods;*.sxc" );
2914  xFltMgr->appendFilter( sFilterSXW, "*.odt;*.sxw" );
2915  xFltMgr->appendFilter( sFilterDBF, "*.dbf" );
2916  xFltMgr->appendFilter( sFilterXLS, "*.xls;*.xlsx" );
2917  xFltMgr->appendFilter( sFilterDOC, "*.doc;*.docx" );
2918  xFltMgr->appendFilter( sFilterTXT, "*.txt" );
2919  xFltMgr->appendFilter( sFilterCSV, "*.csv" );
2920 #ifdef _WIN32
2921  xFltMgr->appendFilter(sFilterMDB, "*.mdb;*.mde");
2922  xFltMgr->appendFilter(sFilterACCDB, "*.accdb;*.accde");
2923 #endif
2924 
2925  xFltMgr->setCurrentFilter( sFilterAll ) ;
2926  OUString sFind;
2927  if( ERRCODE_NONE == aDlgHelper.Execute() )
2928  {
2929  uno::Reference< beans::XPropertySet > aSettings;
2930  const INetURLObject aURL( xFP->getSelectedFiles().getConstArray()[0] );
2931  const DBConnURIType type = GetDBunoType( aURL );
2932 
2933  if( DBConnURIType::FLAT == type )
2934  {
2935  uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2936  uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
2937  if( xSettingsDlg->execute() )
2938  aSettings.set( uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ) );
2939  }
2940  sFind = LoadAndRegisterDataSource_Impl( type, DBConnURIType::FLAT == type ? &aSettings : nullptr, aURL, nullptr, pDocShell );
2941 
2942  m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(pDocShell, sFind));
2943  }
2944  return sFind;
2945 }
2946 
2947 void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>& xStorable,
2948  const uno::Reference<embed::XStorage>& xStorage,
2949  const OUString& rStreamRelPath,
2950  const OUString& rOwnURL, bool bCopyTo)
2951 {
2952  // Construct vnd.sun.star.pkg:// URL for later loading, and TargetStorage/StreamRelPath for storing.
2953  OUString const sTmpName = ConstructVndSunStarPkgUrl(rOwnURL, rStreamRelPath);
2954 
2955  uno::Sequence<beans::PropertyValue> aSequence = comphelper::InitPropertySequence(
2956  {
2957  {"TargetStorage", uno::makeAny(xStorage)},
2958  {"StreamRelPath", uno::makeAny(rStreamRelPath)},
2959  {"BaseURI", uno::makeAny(rOwnURL)}
2960  });
2961  if (bCopyTo)
2962  xStorable->storeToURL(sTmpName, aSequence);
2963  else
2964  xStorable->storeAsURL(sTmpName, aSequence);
2965 }
2966 
2967 OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pDestDir)
2968 {
2969  return LoadAndRegisterDataSource_Impl( DBConnURIType::UNKNOWN, nullptr, INetURLObject(rURI), pDestDir, nullptr );
2970 }
2971 
2972 namespace
2973 {
2974  // tdf#117824 switch the embedded database away from using its current storage and point it to temporary storage
2975  // which allows the original storage to be deleted
2976  void switchEmbeddedDatabaseStorage(const uno::Reference<sdb::XDatabaseContext>& rDatabaseContext, const OUString& rName)
2977  {
2978  uno::Reference<sdb::XDocumentDataSource> xDS(rDatabaseContext->getByName(rName), uno::UNO_QUERY);
2979  if (!xDS)
2980  return;
2981  uno::Reference<document::XStorageBasedDocument> xStorageDoc(xDS->getDatabaseDocument(), uno::UNO_QUERY);
2982  if (!xStorageDoc)
2983  return;
2984  xStorageDoc->switchToStorage(comphelper::OStorageHelper::GetTemporaryStorage());
2985  }
2986 }
2987 
2988 void SwDBManager::RevokeDataSource(const OUString& rName)
2989 {
2990  uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2991  if (xDatabaseContext->hasByName(rName))
2992  {
2993  switchEmbeddedDatabaseStorage(xDatabaseContext, rName);
2994  xDatabaseContext->revokeObject(rName);
2995  }
2996 }
2997 
2999 {
3000  uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
3001 
3002  OUString sDataSource = rData.sDataSource;
3003 
3004  // Fallback, just in case the document would contain an embedded data source, but no DB fields.
3005  if (sDataSource.isEmpty())
3006  sDataSource = "EmbeddedDatabase";
3007 
3008  SwDBManager::RevokeDataSource( sDataSource );
3009 
3010  // Encode the stream name and the real path into a single URL.
3011  const INetURLObject& rURLObject = rDocShell.GetMedium()->GetURLObject();
3012  OUString const aURL = ConstructVndSunStarPkgUrl(
3014  m_sEmbeddedName);
3015 
3016  uno::Reference<uno::XInterface> xDataSource(xDatabaseContext->getByName(aURL), uno::UNO_QUERY);
3017  xDatabaseContext->registerObject( sDataSource, xDataSource );
3018 
3019  // temp file - don't remember connection
3020  if (rData.sDataSource.isEmpty())
3021  m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(nullptr, sDataSource));
3022 }
3023 
3025  const uno::Sequence<beans::PropertyValue>& rProperties)
3026 {
3027  //prevent second call
3028  if(m_pImpl->pMergeDialog)
3029  return ;
3030  OUString sDataSource, sDataTableOrQuery;
3031  uno::Sequence<uno::Any> aSelection;
3032 
3033  sal_Int32 nCmdType = sdb::CommandType::TABLE;
3034  uno::Reference< sdbc::XConnection> xConnection;
3035 
3036  svx::ODataAccessDescriptor aDescriptor(rProperties);
3037  sDataSource = aDescriptor.getDataSource();
3038  OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::Command] >>= sDataTableOrQuery);
3039  OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= nCmdType);
3040 
3042  aDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection;
3044  aDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection;
3045 
3046  if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty())
3047  {
3048  OSL_FAIL("PropertyValues missing or unset");
3049  return;
3050  }
3051 
3052  //always create a connection for the dialog and dispose it after the dialog has been closed
3053  SwDSParam* pFound = nullptr;
3054  if(!xConnection.is())
3055  {
3056  xConnection = SwDBManager::RegisterConnection(sDataSource);
3057  pFound = FindDSConnection(sDataSource, true);
3058  }
3060  m_pImpl->pMergeDialog = pFact->CreateMailMergeDlg( &rSh.GetView().GetViewFrame()->GetWindow(), rSh,
3061  sDataSource,
3062  sDataTableOrQuery,
3063  nCmdType,
3064  xConnection);
3065  if(m_pImpl->pMergeDialog->Execute() == RET_OK)
3066  {
3067  aDescriptor[svx::DataAccessDescriptorProperty::Selection] <<= m_pImpl->pMergeDialog->GetSelection();
3068 
3069  uno::Reference<sdbc::XResultSet> xResSet = m_pImpl->pMergeDialog->GetResultSet();
3070  if(xResSet.is())
3071  aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
3072 
3073  // SfxObjectShellRef is ok, since there should be no control over the document lifetime here
3074  SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame()->GetObjectShell();
3075 
3076  lcl_emitEvent(SfxEventHintId::SwMailMerge, STR_SW_EVENT_MAIL_MERGE, xDocShell.get());
3077 
3078  // prepare mail merge descriptor
3079  SwMergeDescriptor aMergeDesc( m_pImpl->pMergeDialog->GetMergeType(), rSh, aDescriptor );
3080  aMergeDesc.sSaveToFilter = m_pImpl->pMergeDialog->GetSaveFilter();
3081  aMergeDesc.bCreateSingleFile = m_pImpl->pMergeDialog->IsSaveSingleDoc();
3082  aMergeDesc.bPrefixIsFilename = aMergeDesc.bCreateSingleFile;
3083  aMergeDesc.sPrefix = m_pImpl->pMergeDialog->GetTargetURL();
3084  if( !aMergeDesc.bCreateSingleFile && m_pImpl->pMergeDialog->IsGenerateFromDataBase() )
3085  {
3086  aMergeDesc.sDBcolumn = m_pImpl->pMergeDialog->GetColumnName();
3087  }
3088 
3089  Merge( aMergeDesc );
3090 
3091  lcl_emitEvent(SfxEventHintId::SwMailMergeEnd, STR_SW_EVENT_MAIL_MERGE_END, xDocShell.get());
3092 
3093  // reset the cursor inside
3094  xResSet = nullptr;
3095  aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
3096  }
3097  if(pFound)
3098  {
3099  for (auto & pParam : m_DataSourceParams)
3100  {
3101  if (pParam.get() == pFound)
3102  {
3103  try
3104  {
3105  uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY);
3106  if(xComp.is())
3107  xComp->dispose();
3108  }
3109  catch(const uno::RuntimeException&)
3110  {
3111  //may be disposed already since multiple entries may have used the same connection
3112  }
3113  break;
3114  }
3115  //pFound doesn't need to be removed/deleted -
3116  //this has been done by the SwConnectionDisposedListener_Impl already
3117  }
3118  }
3119  m_pImpl->pMergeDialog.disposeAndClear();
3120 }
3121 
3123  const uno::Sequence< beans::PropertyValue>& rProperties)
3124 {
3125  OUString sDataSource, sDataTableOrQuery;
3126  uno::Reference<sdbc::XResultSet> xResSet;
3127  uno::Sequence<uno::Any> aSelection;
3128  sal_Int16 nCmdType = sdb::CommandType::TABLE;
3129  const beans::PropertyValue* pValues = rProperties.getConstArray();
3130  uno::Reference< sdbc::XConnection> xConnection;
3131  for(sal_Int32 nPos = 0; nPos < rProperties.getLength(); nPos++)
3132  {
3133  if ( pValues[nPos].Name == "DataSourceName" )
3134  pValues[nPos].Value >>= sDataSource;
3135  else if ( pValues[nPos].Name == "Command" )
3136  pValues[nPos].Value >>= sDataTableOrQuery;
3137  else if ( pValues[nPos].Name == "Cursor" )
3138  pValues[nPos].Value >>= xResSet;
3139  else if ( pValues[nPos].Name == "Selection" )
3140  pValues[nPos].Value >>= aSelection;
3141  else if ( pValues[nPos].Name == "CommandType" )
3142  pValues[nPos].Value >>= nCmdType;
3143  else if ( pValues[nPos].Name == "ActiveConnection" )
3144  pValues[nPos].Value >>= xConnection;
3145  }
3146  if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty() || !xResSet.is())
3147  {
3148  OSL_FAIL("PropertyValues missing or unset");
3149  return;
3150  }
3151  uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
3152  uno::Reference<sdbc::XDataSource> xSource;
3153  uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
3154  if(xChild.is())
3155  xSource.set(xChild->getParent(), uno::UNO_QUERY);
3156  if(!xSource.is())
3157  xSource = dbtools::getDataSource(sDataSource, xContext);
3158  uno::Reference< sdbcx::XColumnsSupplier > xColSupp( xResSet, uno::UNO_QUERY );
3159  SwDBData aDBData;
3160  aDBData.sDataSource = sDataSource;
3161  aDBData.sCommand = sDataTableOrQuery;
3162  aDBData.nCommandType = nCmdType;
3163 
3166  xSource,
3167  xColSupp,
3168  aDBData ));
3169  if( RET_OK == pDlg->Execute() )
3170  {
3171  OUString sDummy;
3172  if(!xConnection.is())
3173  xConnection = xSource->getConnection(sDummy, sDummy);
3174  try
3175  {
3176  pDlg->DataToDoc( aSelection , xSource, xConnection, xResSet);
3177  }
3178  catch (const uno::Exception&)
3179  {
3180  css::uno::Any ex( cppu::getCaughtException() );
3181  SAL_WARN("sw.mailmerge", "exception caught: " << exceptionToString(ex));
3182  }
3183  }
3184 }
3185 
3186 uno::Reference<sdbc::XDataSource> SwDBManager::getDataSourceAsParent(const uno::Reference< sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName)
3187 {
3188  uno::Reference<sdbc::XDataSource> xSource;
3189  try
3190  {
3191  uno::Reference<container::XChild> xChild(_xConnection, uno::UNO_QUERY);
3192  if ( xChild.is() )
3193  xSource.set(xChild->getParent(), uno::UNO_QUERY);
3194  if ( !xSource.is() )
3195  xSource = dbtools::getDataSource(_sDataSourceName, ::comphelper::getProcessComponentContext());
3196  }
3197  catch (const uno::Exception&)
3198  {
3199  css::uno::Any ex( cppu::getCaughtException() );
3200  SAL_WARN("sw.mailmerge", "exception caught in getDataSourceAsParent(): " << exceptionToString(ex));
3201  }
3202  return xSource;
3203 }
3204 
3205 uno::Reference<sdbc::XResultSet> SwDBManager::createCursor(const OUString& _sDataSourceName,
3206  const OUString& _sCommand,
3207  sal_Int32 _nCommandType,
3208  const uno::Reference<sdbc::XConnection>& _xConnection,
3209  const SwView* pView)
3210 {
3211  uno::Reference<sdbc::XResultSet> xResultSet;
3212  try
3213  {
3214  uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
3215  if( xMgr.is() )
3216  {
3217  uno::Reference<uno::XInterface> xInstance = xMgr->createInstance("com.sun.star.sdb.RowSet");
3218  uno::Reference<beans::XPropertySet> xRowSetPropSet(xInstance, uno::UNO_QUERY);
3219  if(xRowSetPropSet.is())
3220  {
3221  xRowSetPropSet->setPropertyValue("DataSourceName", uno::makeAny(_sDataSourceName));
3222  xRowSetPropSet->setPropertyValue("ActiveConnection", uno::makeAny(_xConnection));
3223  xRowSetPropSet->setPropertyValue("Command", uno::makeAny(_sCommand));
3224  xRowSetPropSet->setPropertyValue("CommandType", uno::makeAny(_nCommandType));
3225 
3226  uno::Reference< sdb::XCompletedExecution > xRowSet(xInstance, uno::UNO_QUERY);
3227 
3228  if ( xRowSet.is() )
3229  {
3230  weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr;
3231  uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(comphelper::getComponentContext(xMgr), pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW );
3232  xRowSet->executeWithCompletion(xHandler);
3233  }
3234  xResultSet.set(xRowSet, uno::UNO_QUERY);
3235  }
3236  }
3237  }
3238  catch (const uno::Exception&)
3239  {
3240  css::uno::Any ex( cppu::getCaughtException() );
3241  SAL_WARN("sw.mailmerge", "Caught exception while creating a new RowSet: " << exceptionToString(ex));
3242  }
3243  return xResultSet;
3244 }
3245 
3246 void SwDBManager::setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell)
3247 {
3248  bool bLoad = m_sEmbeddedName != rEmbeddedName && !rEmbeddedName.isEmpty();
3249  bool bRegisterListener = m_sEmbeddedName.isEmpty() && !rEmbeddedName.isEmpty();
3250 
3251  m_sEmbeddedName = rEmbeddedName;
3252 
3253  if (bLoad)
3254  {
3255  uno::Reference<embed::XStorage> xStorage = rDocShell.GetStorage();
3256  // It's OK that we don't have the named sub-storage yet, in case
3257  // we're in the process of creating it.
3258  if (xStorage->hasByName(rEmbeddedName))
3259  LoadAndRegisterEmbeddedDataSource(rDocShell.GetDoc()->GetDBData(), rDocShell);
3260  }
3261 
3262  if (bRegisterListener)
3263  // Register a remove listener, so we know when the embedded data source is removed.
3264  m_pImpl->m_xDataSourceRemovedListener = new SwDataSourceRemovedListener(*this);
3265 }
3266 
3267 const OUString& SwDBManager::getEmbeddedName() const
3268 {
3269  return m_sEmbeddedName;
3270 }
3271 
3273 {
3274  return m_pDoc;
3275 }
3276 
3278 {
3279  if (m_pImpl->m_xDataSourceRemovedListener.is())
3280  {
3281  m_pImpl->m_xDataSourceRemovedListener->Dispose();
3282  m_pImpl->m_xDataSourceRemovedListener.clear();
3283  }
3284 }
3285 
3287  : m_pDBManager(&rManager)
3288 {
3289 }
3290 
3291 void SwDBManager::ConnectionDisposedListener_Impl::disposing( const lang::EventObject& rSource )
3292 {
3293  ::SolarMutexGuard aGuard;
3294 
3295  if (!m_pDBManager) return; // we're disposed too!
3296 
3297  uno::Reference<sdbc::XConnection> xSource(rSource.Source, uno::UNO_QUERY);
3298  for (size_t nPos = m_pDBManager->m_DataSourceParams.size(); nPos; nPos--)
3299  {
3300  SwDSParam* pParam = m_pDBManager->m_DataSourceParams[nPos - 1].get();
3301  if(pParam->xConnection.is() &&
3302  (xSource == pParam->xConnection))
3303  {
3304  m_pDBManager->m_DataSourceParams.erase(
3305  m_pDBManager->m_DataSourceParams.begin() + nPos - 1);
3306  }
3307  }
3308 }
3309 
3310 std::shared_ptr<SwMailMergeConfigItem> SwDBManager::PerformMailMerge(SwView const * pView)
3311 {
3312  std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem();
3313  if (!xConfigItem)
3314  return xConfigItem;
3315 
3316  svx::ODataAccessDescriptor aDescriptor;
3317  aDescriptor.setDataSource(xConfigItem->GetCurrentDBData().sDataSource);
3318  aDescriptor[ svx::DataAccessDescriptorProperty::Connection ] <<= xConfigItem->GetConnection().getTyped();
3319  aDescriptor[ svx::DataAccessDescriptorProperty::Cursor ] <<= xConfigItem->GetResultSet();
3320  aDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= xConfigItem->GetCurrentDBData().sCommand;
3321  aDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= xConfigItem->GetCurrentDBData().nCommandType;
3322  aDescriptor[ svx::DataAccessDescriptorProperty::Selection ] <<= xConfigItem->GetSelection();
3323 
3324  SwWrtShell& rSh = pView->GetWrtShell();
3325  xConfigItem->SetTargetView(nullptr);
3326 
3327  SwMergeDescriptor aMergeDesc(DBMGR_MERGE_SHELL, rSh, aDescriptor);
3328  aMergeDesc.pMailMergeConfigItem = xConfigItem.get();
3329  aMergeDesc.bCreateSingleFile = true;
3330  rSh.GetDBManager()->Merge(aMergeDesc);
3331 
3332  return xConfigItem;
3333 }
3334 
3336 {
3337  if (!m_aUncommittedRegistrations.empty())
3338  {
3339  SwView* pView = ( m_pDoc && m_pDoc->GetDocShell() ) ? m_pDoc->GetDocShell()->GetView() : nullptr;
3340  if (pView)
3341  {
3342  const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem();
3343  if (xConfigItem)
3344  {
3345  xConfigItem->DisposeResultSet();
3346  xConfigItem->DocumentReloaded();
3347  }
3348  }
3349 
3350  for (auto it = m_aUncommittedRegistrations.begin(); it != m_aUncommittedRegistrations.end();)
3351  {
3352  if ((m_pDoc && it->first == m_pDoc->GetDocShell()) || it->first == nullptr)
3353  {
3354  RevokeDataSource(it->second);
3355  it = m_aUncommittedRegistrations.erase(it);
3356  }
3357  else
3358  ++it;
3359  }
3360  }
3361 }
3362 
3364 {
3365  for (auto aIt = m_aUncommittedRegistrations.begin(); aIt != m_aUncommittedRegistrations.end();)
3366  {
3367  if (aIt->first == m_pDoc->GetDocShell() || aIt->first == nullptr)
3368  {
3369  m_aNotUsedConnections.push_back(aIt->second);
3370  aIt = m_aUncommittedRegistrations.erase(aIt);
3371  }
3372  else
3373  aIt++;
3374  }
3375 }
3376 
3377 void SwDBManager::SetAsUsed(const OUString& rName)
3378 {
3379  auto aFound = std::find(m_aNotUsedConnections.begin(), m_aNotUsedConnections.end(), rName);
3380  if (aFound != m_aNotUsedConnections.end())
3381  m_aNotUsedConnections.erase(aFound);
3382 }
3383 
3385 {
3386  for (auto aIt = m_aNotUsedConnections.begin(); aIt != m_aNotUsedConnections.end();)
3387  {
3388  RevokeDataSource(*aIt);
3389  aIt = m_aNotUsedConnections.erase(aIt);
3390  }
3391 }
3392 
3393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void InsertLineBreak()
Definition: wrtsh1.cxx:890
virtual Point GetPosPixel() const
static bool lcl_ToNextRecord(SwDSParam *pParam, const SwDBNextRecord action=SwDBNextRecord::NEXT)
Definition: dbmgr.cxx:2286
SfxViewFrame * GetViewFrame() const
void GetColumnNames(ListBox *pListBox, const OUString &rDBName, const OUString &rTableName)
Fill listbox with all column names of a database table.
Definition: dbmgr.cxx:754
css::uno::Reference< css::sdbc::XResultSet > xResultSet
Definition: dbmgr.hxx:107
bool is() const
virtual void mailDelivered(::rtl::Reference< MailDispatcher >, uno::Reference< mail::XMailMessage > xMessage) override
Definition: dbmgr.cxx:1120
SwNodeIndex AppendDoc(const SwDoc &rSource, sal_uInt16 nStartPageNumber, bool bDeletePrevious, int physicalPageOffset, const sal_uLong nDocNo)
Definition: docnew.cxx:985
bool bCreateSingleFile
Create a single or multiple results.
Definition: dbmgr.hxx:149
Definition: calc.hxx:184
SAL_DLLPRIVATE void ImportDBEntry(SwWrtShell *pSh)
Insert a single data record as text into document.
Definition: dbmgr.cxx:643
void RevokeLastRegistrations()
Revoke not committed registrations in case of mail merge cancel.
Definition: dbmgr.cxx:3335
virtual void SAL_CALL setBody(const css::uno::Reference< css::datatransfer::XTransferable > &_body) override
const SwXMailMerge * GetMailMergeEvtSrc() const
MailMergeEvent source.
Definition: dbmgr.hxx:292
osl::Mutex m_aAllEmailSendMutex
Definition: dbmgr.cxx:312
bool hasValue()
sal_Int32 nCommandType
Definition: swdbdata.hxx:32
void MergeCancel()
Definition: dbmgr.cxx:1734
void SplitNode(bool bAutoFormat=false)
Definition: wrtsh1.cxx:966
virtual css::uno::Reference< css::awt::XWindow > GetXWindow()=0
const OUString & GetTempPath() const
void SetType(SectionType const eNew)
Definition: section.hxx:96
virtual void idle(::rtl::Reference< MailDispatcher >) override
Called when there are no more mail messages to deliver.
Definition: dbmgr.cxx:1118
virtual bool DoSaveCompleted(SfxMedium *pNewStor=nullptr, bool bRegisterRecent=true)
css::util::Date aNullDate
Definition: dbmgr.hxx:65
static bool FormatValue(SvNumberFormatter const *pDocFormatter, OUString const &aString, sal_uInt32 nFormat, double &aNumber, sal_Int32 nColumnType, SwDBField *pField=nullptr)
Definition: dbfld.cxx:269
OUString GetTitle(sal_uInt16 nMaxLen=0) const
SwDSParams_t m_DataSourceParams
Definition: dbmgr.hxx:250
SwMailMergeConfigItem * pMailMergeConfigItem
Definition: dbmgr.hxx:214
css::uno::Reference< css::sdbc::XConnection > const & RegisterConnection(OUString const &rSource)
create and store or find an already stored connection to a data source for use in SwFieldMgr and SwDB...
Definition: dbmgr.cxx:2436
void setDataSource(const OUString &_sDataSourceNameOrLocation)
static css::uno::Reference< css::sdbcx::XColumnsSupplier > GetColumnSupplier(css::uno::Reference< css::sdbc::XConnection > const &xConnection, const OUString &rTableOrQuery, SwDBSelect eTableOrQuery=SwDBSelect::UNKNOWN)
Definition: dbmgr.cxx:1973
bool SttEndDoc(bool bStt)
Definition: crsrsh.cxx:563
OUString const & GetMailAddress() const
bool bEndOfDB
Definition: dbmgr.hxx:110
SwDocShell * GetDocShell()
Definition: doc.hxx:1340
std::shared_ptr< SwMailMergeConfigItem > const & GetMailMergeConfigItem() const
Definition: view0.cxx:139
bool GetTableNames(weld::ComboBox &rBox, const OUString &rDBName)
Fill listbox with all table names of a database.
Definition: dbmgr.cxx:712
IDocumentDeviceAccess const & getIDocumentDeviceAccess() const
Definition: doc.cxx:270
Listens to removed data sources, and if it's one that's embedded into this document, triggers embedding removal.
Definition: dbmgr.cxx:229
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
SAL_DLLPRIVATE bool ToNextMergeRecord()
Definition: dbmgr.cxx:2194
static const SwDBData & GetAddressDBName()
Definition: dbmgr.cxx:2609
void Insert(SwField const &)
Definition: wrtsh2.cxx:71
bool Is() const
OUString getBase(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
static bool lcl_SaveDoc(const INetURLObject *pFileURL, const std::shared_ptr< const SfxFilter > &pStoreToFilter, const OUString *pStoreToFilterOptions, const uno::Sequence< beans::PropertyValue > *pSaveToFilterData, const bool bIsPDFexport, SfxObjectShell *xObjectShell, SwWrtShell &rWorkShell, OUString *const decodedURL=nullptr)
Definition: dbmgr.cxx:921
SfxDispatcher * GetDispatcher()
bool OpenDataSource(const OUString &rDataSource, const OUString &rTableOrQuery)
open the source while fields are updated - for the calculator only!
Definition: dbmgr.cxx:2385
sal_uIntPtr sal_uLong
#define DB_SEP_NEWLINE
Definition: dbmgr.cxx:158
OUString sDataSource
Definition: swdbdata.hxx:30
sal_Int32 toInt32(OUString const &rStr)
css::uno::Reference< css::mail::XSmtpService > xSmtpServer
Definition: dbmgr.hxx:192
SwDataSourceRemovedListener(SwDBManager &rDBManager)
Definition: dbmgr.cxx:244
MailDispatcher listener interface.
Definition: doc.hxx:185
SAL_DLLPRIVATE bool IsValidMergeRecord() const
Definition: dbmgr.cxx:2349
bool HasValidRecord() const
Definition: dbmgr.hxx:131
IDocumentLinksAdministration const & getIDocumentLinksAdministration() const
Definition: doc.cxx:292
sal_uInt32 GetSelectedRecordId()
Definition: dbmgr.cxx:2354
css::util::Date aNullDate
Definition: dbmgr.hxx:102
SwDBManager * m_pDBManager
Definition: dbmgr.cxx:232
bool bSendAsAttachment
Definition: dbmgr.hxx:194
SwUndoId EndUndo(SwUndoId eUndoId=SwUndoId::EMPTY, const SwRewriter *pRewriter=nullptr)
Closes parenthesis of nUndoId, not used by UI.
Definition: edws.cxx:233
void SetTargetView(SwView *pView)
uno::Reference< mail::XMailMessage > m_xLastMessage
Definition: dbmgr.cxx:313
virtual ::sw::mark::IMark * makeMark(const SwPaM &rPaM, const OUString &rProposedName, MarkType eMark,::sw::mark::InsertMode eMode)=0
Generates a new mark in the document for a certain selection.
SwEditWin & GetEditWin()
Definition: view.hxx:403
static void StoreEmbeddedDataSource(const css::uno::Reference< css::frame::XStorable > &xStorable, const css::uno::Reference< css::embed::XStorage > &xStorage, const OUString &rStreamRelPath, const OUString &rOwnURL, bool bCopyTo=false)
Definition: dbmgr.cxx:2947
Data records in fields.
Definition: dbmgr.hxx:87
static std::vector< std::pair< SwDocShell *, OUString > > m_aUncommittedRegistrations
Store last registrations to revoke or commit.
Definition: dbmgr.hxx:257
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1348
Dialog to specify the properties of drop-down form field.
Definition: accframe.hxx:34
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
void Clear()
OUString Name
css::uno::Reference< css::frame::XModel > GetModel() const
rtl::Reference< SwDataSourceRemovedListener > m_xDataSourceRemovedListener
Definition: dbmgr.cxx:311
void SetModified()
Definition: edws.cxx:69
bool UCB_DeleteFile(const OUString &rURL)
Definition: swunohelper.cxx:58
bool m_bInMerge
merge process active
Definition: dbmgr.hxx:248
css::uno::Reference< css::sdbc::XConnection > xConnection
Definition: dbmgr.hxx:105
void SetLabelDoc(bool bFlag)
Labels: Synchronize ranges.
Definition: edfld.cxx:380
void SetDisplayDirectory(const OUString &rPath)
virtual short Execute()=0
virtual SfxObjectShell * GetObjectShell() override
void EndAllAction()
Definition: edws.cxx:96
static void FinishPrintJob(const std::shared_ptr< vcl::PrinterController > &i_pController)
RET_CANCEL
css::uno::Sequence< css::beans::PropertyValue > aSaveToFilterData
Definition: dbmgr.hxx:157
virtual void SAL_CALL disposing(const lang::EventObject &Source) override
Definition: dbmgr.cxx:3291
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
SwDBSelect
Definition: dbmgr.hxx:95
bool DelRight()
Definition: delete.cxx:292
virtual void SAL_CALL registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent &rEvent) override
Definition: dbmgr.cxx:258
SwWrtShell & GetWrtShell() const
Definition: view.hxx:400
OUString m_sEmbeddedName
Name of the embedded database that's included in the current document.
Definition: dbmgr.hxx:254
SfxApplication * SfxGetpApp()
OOO_DLLPUBLIC_DBTOOLS OUString getFormattedValue(const css::uno::Reference< css::beans::XPropertySet > &_xColumn, const css::uno::Reference< css::util::XNumberFormatter > &xFormatter, const css::lang::Locale &_rLocale, const css::util::Date &rNullDate)
OUString PathToFileName() const
void UpdateSection(size_t const nSect, SwSectionData &, SfxItemSet const *const =nullptr)
Definition: edsect.cxx:156
css::uno::Reference< css::embed::XStorage > const & GetStorage()
OUString GetBase() const
Used by the UI to modify the document model.
Definition: wrtsh.hxx:86
static css::uno::Sequence< OUString > GetExistingDatabaseNames()
Definition: dbmgr.cxx:2614
std::unique_ptr< SwDSParam > pMergeData
Definition: dbmgr.cxx:308
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:389
sal_uInt16 GetVirtPageNum()
Definition: fews.cxx:344
virtual void mailDeliveryError(::rtl::Reference< MailDispatcher > xMailDispatcher, uno::Reference< mail::XMailMessage >, const OUString &) override
Definition: dbmgr.cxx:1128
virtual void SAL_CALL disposing(const lang::EventObject &rObject) override
Definition: dbmgr.cxx:296
static bool runAsync(const std::shared_ptr< DialogController > &rController, const std::function< void(sal_Int32)> &)
weld::Window * GetFrameWeld() const
NF_NUMBER_STANDARD
sal_uInt16 sal_Unicode
sw::mark::IMark * startPageInTarget
vcl::Window & GetWindow() const
bool IsMergeOk()
Definition: dbmgr.hxx:302
constexpr auto SFX_INTERFACE_NONE
const SwView & GetView() const
Definition: wrtsh.hxx:424
bool ConvertFieldsToText()
Replace fields by text - mailmerge support.
Definition: editsh.cxx:755
bool IsInitDBFields() const
Initialize data fields that lack name of database.
Definition: dbmgr.hxx:308
virtual void SAL_CALL revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent &rEvent) override
Definition: dbmgr.cxx:262
void VarChange(const OUString &rStr, const SwSbxValue &rValue)
Definition: calc.cxx:577
static void Yield()
bool IsMergeError()
Definition: dbmgr.hxx:303
Any SAL_CALL getCaughtException()
#define STR_SW_EVENT_FIELD_MERGE
Definition: swevent.hxx:30
virtual VclPtr< AbstractMailMergeDlg > CreateMailMergeDlg(vcl::Window *pParent, SwWrtShell &rSh, const OUString &rSourceName, const OUString &rTableName, sal_Int32 nCommandType, const css::uno::Reference< css::sdbc::XConnection > &xConnection)=0
Print mail merge.
Definition: dbmgr.hxx:88
bool ReadLine(OString &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
SfxFrame & GetFrame() const
SAL_DLLPRIVATE SwDSParam * FindDSConnection(const OUString &rSource, bool bCreate)
Definition: dbmgr.cxx:2571
void setEmbeddedName(const OUString &rEmbeddedName, SwDocShell &rDocShell)
Definition: dbmgr.cxx:3246
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
Send mail merge as email.
Definition: dbmgr.hxx:89
static void lcl_SaveDebugDoc(SfxObjectShell *xTargetDocShell, const char *name, int no=0)
Definition: dbmgr.cxx:884
OUString sSaveToFilter
Definition: dbmgr.hxx:155
void CommitLastRegistrations()
Accept not committed registrations.
Definition: dbmgr.cxx:3363
SwDoc * GetDoc() const
Definition: viewsh.hxx:284
bool IsLabelDoc() const
Definition: edfld.cxx:385
ConnectionDisposedListener_Impl(SwDBManager &rMgr)
Definition: dbmgr.cxx:3286
void DoGroupUndo(bool bUn)
Definition: edws.cxx:205
sal_Int32 GetColumnType(const OUString &rDBName, const OUString &rTableName, const OUString &rColNm)
Definition: dbmgr.cxx:1906
css::lang::Locale aLocale
Definition: dbmgr.hxx:67
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Create merge doc and keep the doc shell.
Definition: dbmgr.hxx:91
SAL_DLLPRIVATE SwDSParam * FindDSData(const SwDBData &rData, bool bCreate)
Definition: dbmgr.cxx:2523
const SwSectionFormat & GetSectionFormat(size_t nFormat) const
Definition: edsect.cxx:142
if(nullptr==pCandidateA||nullptr==pCandidateB)
OUString sMailBody
Definition: dbmgr.hxx:188
static css::uno::Reference< css::sdbc::XResultSet > createCursor(const OUString &_sDataSourceName, const OUString &_sCommand, sal_Int32 _nCommandType, const css::uno::Reference< css::sdbc::XConnection > &_xConnection, const SwView *pView)
creates a RowSet, which must be disposed after use.
Definition: dbmgr.cxx:3205
void AddMergedDocument(SwDocMergeInfo const &rInfo)
css::uno::Reference< css::lang::XComponent > xComponent
SwWrtShell & rSh
Definition: dbmgr.hxx:140
static OUString lcl_FindColumn(const OUString &sFormatStr, sal_uInt16 &nUsedPos, sal_uInt8 &nSeparator)
Definition: dbmgr.cxx:612
static css::uno::Reference< css::sdbc::XDataSource > getDataSourceAsParent(const css::uno::Reference< css::sdbc::XConnection > &_xConnection, const OUString &_sDataSourceName)
try to get the data source from the given connection through the XChild interface.
Definition: dbmgr.cxx:3186
static void RevokeDataSource(const OUString &rName)
Unregister a data source.
Definition: dbmgr.cxx:2988
#define ERRCODE_IO_NOTSUPPORTED
const std::shared_ptr< vcl::PrinterController > & GetPrinterController() const
static SvxHtmlOptions & Get()
void SetDBvalue(bool bSet)
Definition: calc.hxx:120
bool Merge(const SwMergeDescriptor &rMergeDesc)
Merging of data records into fields.
Definition: dbmgr.cxx:433
SwDoc * m_pDoc
The document that owns this manager.
Definition: dbmgr.hxx:266
bool bPrefixIsFilename
Use the sPrefix as the target filename also overwriting an existing target file.
Definition: dbmgr.hxx:180
SwDBManager * GetDBManager() const
For evaluation of DB fields (new DB-manager).
Definition: edfld.cxx:340
SwDoc * GetDoc()
returns Doc. But be careful!
Definition: docsh.hxx:202
OUString sPrefix
Basename incl.
Definition: dbmgr.hxx:172
virtual void started(::rtl::Reference< MailDispatcher >) override
Called when the MailDispatcher is started.
Definition: dbmgr.cxx:1116
const IDocumentDeviceAccess & getIDocumentDeviceAccess() const
Provides access to the document device interface.
Definition: viewsh.cxx:2590
uno::Reference< sdb::XDatabaseContext > m_xDatabaseContext
Definition: dbmgr.cxx:231
OUString sSaveToFilterOptions
Definition: dbmgr.hxx:156
T * get() const
static css::uno::Reference< css::embed::XStorage > GetTemporaryStorage(const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >())
#define STR_SW_EVENT_MAIL_MERGE_END
Definition: swevent.hxx:29
void LoadAndRegisterEmbeddedDataSource(const SwDBData &rData, const SwDocShell &rDocShell)
Load the embedded data source of the document and also register it.
Definition: dbmgr.cxx:2998
vcl::Window & GetWindow() const
bool HasSelection() const
Definition: wrtsh.hxx:137
#define SW_MOD()
Definition: swmodule.hxx:255
static bool Reschedule(bool bHandleAllCurrentEvents=false)
OUString GetExtension() const
SwDBData const & GetDBData()
Definition: docfld.cxx:354
OUString sSubject
Definition: dbmgr.hxx:187
void SetDBManager(SwDBManager *pNewMgr)
Definition: doc.hxx:663
sal_uInt16 GetPageCnt()
Definition: crsrsh.cxx:1279
bool bScrollable
Definition: dbmgr.hxx:109
virtual const SwPrintData & getPrintData() const =0
Returns the PrintData.
OUString const & GetURL() const
void SetAsUsed(const OUString &rName)
Set connection as used.
Definition: dbmgr.cxx:3377
#define LANGUAGE_SYSTEM
bool GetMergeColumnCnt(const OUString &rColumnName, LanguageType nLanguage, OUString &rResult, double *pNumber)
Definition: dbmgr.cxx:2181
#define DB_SEP_SPACE
Definition: dbmgr.cxx:155
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
static DialogMask HandleError(ErrCode nId, weld::Window *pParent=nullptr, DialogMask nMask=DialogMask::MAX)
bool GetColumnCnt(const OUString &rSourceName, const OUString &rTableName, const OUString &rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage, OUString &rResult, double *pNumber)
Definition: dbmgr.cxx:2117
SwDBManager_Impl(SwDBManager &rDBManager)
Definition: dbmgr.cxx:315
SfxObjectShell * CreateCopy(bool bCallInitNew, bool bEmpty) const
Definition: docnew.cxx:881
int i
void ExecPrint(const css::uno::Sequence< css::beans::PropertyValue > &, bool, bool)
OUString sAttachmentName
Definition: dbmgr.hxx:189
static void lcl_GetColumnCnt(SwDSParam *pParam, const uno::Reference< beans::XPropertySet > &rColumnProps, LanguageType nLanguage, OUString &rResult, double *pNumber)
Definition: dbmgr.cxx:392
static css::uno::Reference< css::sdbc::XConnection > GetConnection(const OUString &rDataSource, css::uno::Reference< css::sdbc::XDataSource > &rxSource, const SwView *pView)
Definition: dbmgr.cxx:1950
bool DoesGroupUndo() const
Definition: edws.cxx:208
static SfxViewFrame * GetNext(const SfxViewFrame &rPrev, const SfxObjectShell *pDoc=nullptr, bool bOnlyVisible=true)
SwUndoId StartUndo(SwUndoId eUndoId=SwUndoId::EMPTY, const SwRewriter *pRewriter=nullptr)
Undo: set up Undo parenthesis, return nUndoId of this parenthesis.
Definition: edws.cxx:222
OString stripStart(const OString &rIn, sal_Char c)
virtual void SAL_CALL addCcRecipient(const OUString &sRecipientAddress) override
static void InsertText(SwWrtShell &rSh, const css::uno::Sequence< css::beans::PropertyValue > &rProperties)
Definition: dbmgr.cxx:3122
void NotifyEvent(const SfxEventHint &rEvent, bool bSynchron=true)
std::unique_ptr< SwDBManager_Impl > m_pImpl
Definition: dbmgr.hxx:251
void CloseAll(bool bIncludingMerge=true)
close all data sources - after fields were updated
Definition: dbmgr.cxx:2502
SwDBData const & GetDBData() const
Database information.
Definition: edfld.cxx:298
virtual sal_Int32 GetRecordsPerDocument() const =0
virtual void Start() override
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:426
sal_Int32 InsertEntry(const OUString &rStr, sal_Int32 nPos=LISTBOX_APPEND)
void LaunchMailMergeEvent(const css::text::MailMergeEvent &rData) const
std::set< SwRootFrame * > GetAllLayouts()
Definition: doclay.cxx:1673
void RevokeNotUsedConnections()
Remove not used connections.
Definition: dbmgr.cxx:3384
VclPtr< AbstractMailMergeDlg > pMergeDialog
Definition: dbmgr.cxx:309
SfxItemSet * GetItemSet() const
static SwAbstractDialogFactory * Create()
Definition: swabstdlg.cxx:36
OUString const & GetMailReplyTo() const
Marks a node in the document model.
Definition: ndindex.hxx:31
static sal_uLong GetColumnFormat(css::uno::Reference< css::sdbc::XDataSource > const &xSource, css::uno::Reference< css::sdbc::XConnection > const &xConnection, css::uno::Reference< css::beans::XPropertySet > const &xColumn, SvNumberFormatter *pNFormatr, LanguageType nLanguage)
void Lock(bool bLock)
GUIDCNamePair const aData
OUString SwResId(const char *pId)
Definition: swmodule.cxx:191
virtual void clear()=0
SAL_DLLPRIVATE void ImportFromConnection(SwWrtShell *pSh)
Insert data record as text into document.
Definition: dbmgr.cxx:581
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
virtual ~SwDataSourceRemovedListener() override
Definition: dbmgr.cxx:252
void UnlockExpFields()
Definition: edfld.cxx:360
void SetTimeout(sal_uInt64 nTimeoutMs)
static void lcl_RemoveSectionLinks(SwWrtShell &rWorkShell)
Definition: dbmgr.cxx:867
#define DB_DELIM
Definition: swtypes.hxx:141
SfxViewShell * GetViewShell() const
SwDocShell * GetDocShell()
Definition: view.cxx:1115
OString exceptionToString(const css::uno::Any &caught)
virtual void SAL_CALL addRecipient(const OUString &sRecipientAddress) override
static void lcl_PreparePrinterOptions(const uno::Sequence< beans::PropertyValue > &rInPrintOptions, uno::Sequence< beans::PropertyValue > &rOutPrintOptions)
Definition: dbmgr.cxx:966
bool ToRecordId(sal_Int32 nSet)
Definition: dbmgr.cxx:2371
WorkingDocType
Definition: dbmgr.cxx:176
std::vector< OUString > m_aNotUsedConnections
Not used connections.
Definition: dbmgr.hxx:260
OUString getDataSource() const
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
sal_Int32 getDefaultNumberFormat(const Reference< XPropertySet > &_xColumn, const Reference< XNumberFormatTypes > &_xTypes, const Locale &_rLocale)
bool FillCalcWithMergeData(SvNumberFormatter *pDocFormatter, LanguageType nLanguage, SwCalc &aCalc)
Definition: dbmgr.cxx:2200
static std::shared_ptr< SwMailMergeConfigItem > PerformMailMerge(SwView const *pView)
Definition: dbmgr.cxx:3310
NEXT
std::unique_ptr< weld::Label > m_xPrinter
Definition: dbui.hxx:32
size_t GetSectionFormatCount() const
Definition: edsect.cxx:114
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const DBManagerOptions nMergeType
Definition: dbmgr.hxx:139
SvStream * GetInStream()
Reference< XMultiServiceFactory > getProcessServiceFactory()
css::uno::Sequence< OUString > aCopiesTo
Definition: dbmgr.hxx:190
SwWrtShell * GetWrtShellPtr() const
Definition: view.hxx:401
void releaseRevokeListener()
Stop reacting to removed database registrations.
Definition: dbmgr.cxx:3277
css::uno::Sequence< css::beans::PropertyValue > aPrintOptions
Definition: dbmgr.hxx:211
bool DoSaveAs(SfxMedium &rNewStor)
css::uno::Reference< css::util::XNumberFormatter > xFormatter
Definition: dbmgr.hxx:104
virtual bool EmbedAllLinks()=0
Embed all local links (ranges/graphics).
bool has(DataAccessDescriptorProperty _eWhich) const
void Stop()
weld::Window * GetFrameWeld() const
Save mail merge as files.
Definition: dbmgr.hxx:90
virtual void DataToDoc(const css::uno::Sequence< css::uno::Any > &rSelection, css::uno::Reference< css::sdbc::XDataSource > rxSource, css::uno::Reference< css::sdbc::XConnection > xConnection, css::uno::Reference< css::sdbc::XResultSet > xResultSet)=0
#define SAL_WARN_IF(condition, area, stream)
#define ERRCODE_NONE
static SfxViewFrame * LoadHiddenDocument(SfxObjectShell const &i_rDoc, SfxInterfaceId i_nViewId)
virtual void stopped(::rtl::Reference< MailDispatcher >) override
Called when the MailDispatcher is stopped.
Definition: dbmgr.cxx:1117
unsigned char sal_uInt8
const svx::ODataAccessDescriptor & rDescriptor
Definition: dbmgr.hxx:141
static OUString GetTypeStr(sal_uInt16 nTypeId)
Definition: fldbas.cxx:128
DBConnURIType GetDBunoType(const INetURLObject &rURL)
Definition: dbmgr.cxx:2623
#define STR_SW_EVENT_FIELD_MERGE_FINISHED
Definition: swevent.hxx:31
std::unique_ptr< weld::Label > m_xPrintInfo
Definition: dbui.hxx:33
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:426
#define STR_SW_EVENT_MAIL_MERGE
Definition: swevent.hxx:28
static bool lcl_getCountFromResultSet(sal_Int32 &rCount, const SwDSParam *pParam)
Definition: dbmgr.cxx:183
~SwDBManager() COVERITY_NOEXCEPT_FALSE
Definition: dbmgr.cxx:839
rtl::Reference< SwDBManager::ConnectionDisposedListener_Impl > m_xDisposeListener
Definition: dbmgr.cxx:310
void SetIdle(bool b) const
Definition: viewopt.hxx:208
#define SAL_INFO(area, stream)
bool PutString(const OUString &)
SfxEventHintId
SwDoc * getDoc() const
Definition: dbmgr.cxx:3272
void SetInitDBFields(bool b)
Definition: dbmgr.hxx:309
virtual void SAL_CALL changedDatabaseLocation(const sdb::DatabaseRegistrationEvent &rEvent) override
Definition: dbmgr.cxx:290
virtual void SAL_CALL addBccRecipient(const OUString &sRecipientAddress) override
RET_OK
bool IsMergeSilent() const
Definition: dbmgr.hxx:295
static SfxObjectShell * lcl_CreateWorkingDocument(const WorkingDocType aType, const SwWrtShell &rSourceWrtShell, const vcl::Window *pSourceWindow, SwDBManager **const ppDBManager, SwView **const pView, SwWrtShell **const pWrtShell, SwDoc **const pDoc)
Definition: dbmgr.cxx:994
virtual void SAL_CALL setReplyToAddress(const OUString &_replytoaddress) override
bool PutDouble(double)
void SetStreamCharSet(rtl_TextEncoding eCharSet)
virtual void setPrintData(const SwPrintData &rPrtData)=0
Sets the PrintData.
SAL_DLLPRIVATE bool MergeMailFiles(SwWrtShell *pSh, const SwMergeDescriptor &rMergeDescriptor)
Run the mail merge for defined modes, except DBMGR_MERGE.
Definition: dbmgr.cxx:1142
const INetURLObject & GetURLObject() const
#define DB_SEP_RETURN
Definition: dbmgr.cxx:157
css::uno::Sequence< OUString > aBlindCopiesTo
Definition: dbmgr.hxx:191
Reference< XComponentContext > getProcessComponentContext()
static OUString GetDBField(css::uno::Reference< css::beans::XPropertySet > const &xColumnProp, const SwDBFormatData &rDBFormatData, double *pNumber=nullptr)
Definition: dbmgr.cxx:2021
css::uno::Reference< css::util::XNumberFormatter > xFormatter
Definition: dbmgr.hxx:66
MailDispatcherListener_Impl(SwDBManager &rDBManager)
Definition: dbmgr.cxx:1113
bool RemoveInvisibleContent()
Remove the invisible content from the document e.g. hidden areas, hidden paragraphs.
Definition: doc.cxx:1394
OUString sDBcolumn
DB column to fetch EMail of Filename from.
Definition: dbmgr.hxx:203
virtual VclPtr< AbstractSwInsertDBColAutoPilot > CreateSwInsertDBColAutoPilot(SwView &rView, css::uno::Reference< css::sdbc::XDataSource > rxSource, css::uno::Reference< css::sdbcx::XColumnsSupplier > xColSupp, const SwDBData &rData)=0
static bool lcl_MoveAbsolute(SwDSParam *pParam, long nAbsPos)
Definition: dbmgr.cxx:356
SwDBNextRecord
Definition: dbmgr.cxx:173
DBConnURIType
Definition: dbmgr.hxx:479
static void lcl_InitNumberFormatter(SwDSParam &rParam, uno::Reference< sdbc::XDataSource > const &xSource)
Definition: dbmgr.cxx:327
static OUString GetEventName(sal_Int32 nId)
Definition: docsh.cxx:1341
Reference< XDataSource > getDataSource(const OUString &_rsTitleOrPath, const Reference< XComponentContext > &_rxContext)
virtual void CalcLayout() override
To enable set up of StartActions and EndActions.
Definition: edws.cxx:107
css::uno::Sequence< css::uno::Any > aSelection
Definition: dbmgr.hxx:108
ErrCode GetError() const
const short COPY
bool IsDataSourceOpen(const OUString &rDataSource, const OUString &rTableOrQuery, bool bMergeShell)
check if a data source is open
Definition: dbmgr.cxx:2094
virtual void SAL_CALL addAttachment(const css::mail::MailAttachment &aMailAttachment) override
static SfxViewFrame * GetFirst(const SfxObjectShell *pDoc=nullptr, bool bOnlyVisible=true)
static std::shared_ptr< const SfxFilter > GetFileFilter(const OUString &rFileName)
Detect for the given file which filter should be used.
Definition: iodetect.cxx:149
#define SAL_WARN(area, stream)
void ReplaceDocumentProperties(const SwDoc &rSource, bool mailMerge=false)
Replace document properties with those from rSource.
Definition: docglos.cxx:83
SwDBManager(SwDBManager const &)=delete
bool SetURL(OUString const &rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
bool CheckMailAddress(const OUString &rMailAddress)
void append_text(const OUString &rStr)
static OUString LoadAndRegisterDataSource(weld::Window *pParent, SwDocShell *pDocShell=nullptr)
Loads a data source from file and registers it.
Definition: dbmgr.cxx:2885
rtl_TextEncoding GetTextEncoding() const
const SwView * GetView() const
Definition: docsh.hxx:219
void Dispose(const T &xInterface)
css::uno::Reference< css::sdbc::XStatement > xStatement
Definition: dbmgr.hxx:106
void ChgDBData(const SwDBData &SwDBData)
Definition: wrtsh1.cxx:1726
A MailDispatcher should be used for sending a bunch a mail messages asynchronously.
static SwMailMessage * lcl_CreateMailFromDoc(const SwMergeDescriptor &rMergeDescriptor, const OUString &sFileURL, const OUString &sMailRecipient, const OUString &sMailBodyMimeType, rtl_TextEncoding sMailEncoding, const OUString &sAttachmentMimeType)
Definition: dbmgr.cxx:1056
MergeStatus m_aMergeStatus
current / last merge status
Definition: dbmgr.hxx:246
virtual void SAL_CALL setSubject(const OUString &_subject) override
void SetInMailMerge(bool bNew)
Definition: doc.hxx:952
sal_Int32 const nLength
SwSection * GetSection() const
Definition: section.cxx:675
void SetNumberingRestart()
Set all numbering start points to a fixed value - mailmerge support.
Definition: editsh.cxx:763
virtual css::uno::Reference< css::util::XNumberFormats > SAL_CALL getNumberFormats() override
void ChangeDBFields(const std::vector< OUString > &rOldNames, const OUString &rNewName)
Definition: edfld.cxx:319
void StartAllAction()
For all views of this document.
Definition: edws.cxx:85
const css::uno::Reference< css::ui::dialogs::XFilePicker3 > & GetFilePicker() const
bool IsExpFieldsLocked() const
Definition: edfld.cxx:365
bool IsMailReplyTo() const
sal_Int32 nPos
#define DB_SEP_TAB
Definition: dbmgr.cxx:156
void ExecuteFormLetter(SwWrtShell &rSh, const css::uno::Sequence< css::beans::PropertyValue > &rProperties)
Definition: dbmgr.cxx:3024
CharClass & GetAppCharClass()
Definition: init.cxx:740
OUString sCommand
Definition: swdbdata.hxx:31
virtual void SetPosPixel(const Point &rNewPos)
void SetFilter(const std::shared_ptr< const SfxFilter > &pFilter)
void SetAllUniqueFlyNames()
Definition: doclay.cxx:1450
SwDBManager * GetDBManager() const
Definition: doc.hxx:664
void LockExpFields()
Definition: edfld.cxx:355
Definition: view.hxx:146
void SetSenderAddress(const OUString &rSenderAddress)
static OUString encode(OUString const &rText, Part ePart, EncodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
long nSelectionIndex
Definition: dbmgr.hxx:111
virtual OUString get_active_text() const =0
void SetDebugName(const sal_Char *pDebugName)
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
virtual void ResetModified()=0
const OUString & getEmbeddedName() const
Definition: dbmgr.cxx:3267
void ToNextRecord(const OUString &rDataSource, const OUString &rTableOrQuery)
Definition: dbmgr.cxx:2265
SfxMedium * GetMedium() const
static OUString decode(OUString const &rText, DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)