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