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