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