File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 192, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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> | |||
69 | #include <IDocumentLinksAdministration.hxx> | |||
70 | #include <IDocumentFieldsAccess.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> | |||
85 | #include <comphelper/processfactory.hxx> | |||
86 | #include <comphelper/property.hxx> | |||
87 | #include <comphelper/storagehelper.hxx> | |||
88 | #include <comphelper/string.hxx> | |||
89 | #include <comphelper/types.hxx> | |||
90 | #include <mailmergehelper.hxx> | |||
91 | #include <maildispatcher.hxx> | |||
92 | #include <svtools/htmlcfg.hxx> | |||
93 | #include <i18nlangtag/languagetag.hxx> | |||
94 | #include <com/sun/star/util/XNumberFormatTypes.hpp> | |||
95 | #include <svl/numuno.hxx> | |||
96 | #include <connectivity/dbtools.hxx> | |||
97 | #include <connectivity/dbconversion.hxx> | |||
98 | #include <unotools/charclass.hxx> | |||
99 | #include <tools/diagnose_ex.h> | |||
100 | ||||
101 | #include <unomailmerge.hxx> | |||
102 | #include <sfx2/event.hxx> | |||
103 | #include <svx/dataaccessdescriptor.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> | |||
123 | #include <comphelper/propertysequence.hxx> | |||
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 | ||||
155 | static SfxObjectShell* lcl_CreateWorkingDocument( | |||
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 | ||||
191 | class SwDBManager::ConnectionDisposedListener_Impl | |||
192 | : public cppu::WeakImplHelper< lang::XEventListener > | |||
193 | { | |||
194 | private: | |||
195 | SwDBManager * m_pDBManager; | |||
196 | ||||
197 | virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; | |||
198 | ||||
199 | public: | |||
200 | explicit ConnectionDisposedListener_Impl(SwDBManager& rMgr); | |||
201 | ||||
202 | void Dispose() { m_pDBManager = nullptr; } | |||
203 | ||||
204 | }; | |||
205 | ||||
206 | namespace { | |||
207 | ||||
208 | /// Listens to removed data sources, and if it's one that's embedded into this document, triggers embedding removal. | |||
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 | ||||
257 | OUString aOwnURL = pDocShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::WithCharset); | |||
258 | OUString sTmpName = "vnd.sun.star.pkg://" + | |||
259 | INetURLObject::encode(aOwnURL, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All); | |||
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 | ||||
288 | struct SwDBManager::SwDBManager_Impl | |||
289 | { | |||
290 | std::unique_ptr<SwDSParam> pMergeData; | |||
291 | VclPtr<AbstractMailMergeDlg> pMergeDialog; | |||
292 | rtl::Reference<SwDBManager::ConnectionDisposedListener_Impl> m_xDisposeListener; | |||
293 | rtl::Reference<SwDataSourceRemovedListener> m_xDataSourceRemovedListener; | |||
294 | osl::Mutex m_aAllEmailSendMutex; | |||
295 | uno::Reference< mail::XMailMessage> m_xLastMessage; | |||
296 | ||||
297 | explicit SwDBManager_Impl(SwDBManager& rDBManager) | |||
298 | : m_xDisposeListener(new ConnectionDisposedListener_Impl(rDBManager)) | |||
299 | {} | |||
300 | ||||
301 | ~SwDBManager_Impl() | |||
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 | |||
316 | : SwDBManager::getDataSourceAsParent( | |||
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")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "365" ": "), "%s", "no absolute positioning available"); } } while (false); | |||
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!" )(static_cast <bool> (!m_bInMerge && !m_pImpl-> pMergeData && "merge already activated!") ? void (0) : __assert_fail ("!m_bInMerge && !m_pImpl->pMergeData && \"merge already activated!\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 417, __extension__ __PRETTY_FUNCTION__)); | |||
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(); | |||
455 | rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Command] >>= aData.sCommand; | |||
456 | rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= aData.nCommandType; | |||
457 | ||||
458 | if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Cursor) ) | |||
459 | rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Cursor] >>= xResSet; | |||
460 | if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Selection) ) | |||
461 | rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection; | |||
462 | if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Connection) ) | |||
463 | rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection; | |||
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_DELIMu'\x00ff') + aInsertData.sCommand | |||
518 | + OUStringChar(DB_DELIMu'\x00ff') | |||
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 | ||||
562 | void SwDBManager::ImportFromConnection( SwWrtShell* pSh ) | |||
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 | ||||
593 | void SwDBManager::ImportDBEntry(SwWrtShell* pSh) | |||
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 | |||
658 | void SwDBManager::GetColumnNames(weld::ComboBox& rBox, | |||
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 | ||||
676 | void SwDBManager::GetColumnNames(weld::ComboBox& rBox, | |||
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 | ||||
694 | SwDBManager::SwDBManager(SwDoc* pDoc) | |||
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 | { | |||
707 | RevokeLastRegistrations(); | |||
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 )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Dump directory: " << sTempDirURL) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "762" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Dump directory: " << sTempDirURL ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Dump directory: " << sTempDirURL; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "762" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Dump directory: " << sTempDirURL) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "762" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Dump directory: " << sTempDirURL ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Dump directory: " << sTempDirURL; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "762" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
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_NONEErrCode(0) != xTargetDocShell->GetError()); | |||
781 | if( bAnyError ) | |||
782 | SAL_WARN( "sw.mailmerge", "Error saving: " << aTempFile.GetURL() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Error saving: " << aTempFile.GetURL()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "782" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Error saving: " << aTempFile.GetURL ()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Error saving: " << aTempFile.GetURL(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "782" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Error saving: " << aTempFile.GetURL()) == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "782" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Error saving: " << aTempFile.GetURL ()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Error saving: " << aTempFile.GetURL(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "782" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
783 | else | |||
784 | SAL_INFO( "sw.mailmerge", "Saved doc as: " << aTempFile.GetURL() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Saved doc as: " << aTempFile.GetURL()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "784" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Saved doc as: " << aTempFile.GetURL ()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Saved doc as: " << aTempFile.GetURL(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "784" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Saved doc as: " << aTempFile.GetURL()) == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "784" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Saved doc as: " << aTempFile.GetURL ()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Saved doc as: " << aTempFile.GetURL(); ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "784" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
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(5000 + 527), | |||
807 | *pStoreToFilterOptions)); | |||
808 | if( pSaveToFilterData->hasElements() ) | |||
809 | pDstMed->GetItemSet()->Put( SfxUnoAnyItem(SID_FILTER_DATA(5000 + 1375), | |||
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_NONEErrCode(0) != xObjectShell->GetError()); | |||
824 | if( bAnyError ) | |||
825 | { | |||
826 | // error message ?? | |||
827 | ErrorHandler::HandleError( xObjectShell->GetError() ); | |||
828 | } | |||
829 | return !bAnyError; | |||
830 | } | |||
831 | ||||
832 | static void lcl_PreparePrinterOptions( | |||
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 | ||||
860 | static void lcl_PrepareSaveFilterDataOptions( | |||
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 | ||||
884 | static SfxObjectShell* lcl_CreateWorkingDocument( | |||
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 )(static_cast <bool> (!ppDBManager) ? void (0) : __assert_fail ("!ppDBManager", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 922, __extension__ __PRETTY_FUNCTION__)); | |||
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)(static_cast <bool> (ppDBManager && *ppDBManager ) ? void (0) : __assert_fail ("ppDBManager && *ppDBManager" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 929, __extension__ __PRETTY_FUNCTION__)); | |||
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 | |||
943 | pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks(); | |||
944 | } | |||
945 | ||||
946 | if( pView ) *pView = pWorkView; | |||
947 | if( pWrtShell ) *pWrtShell = pWorkWrtShell; | |||
948 | if( pDoc ) *pDoc = pWorkDoc; | |||
949 | ||||
950 | return xWorkObjectShell.get(); | |||
951 | } | |||
952 | ||||
953 | static SwMailMessage* lcl_CreateMailFromDoc( | |||
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?" )(static_cast <bool> (pInStream && "no output file created?" ) ? void (0) : __assert_fail ("pInStream && \"no output file created?\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 980, __extension__ __PRETTY_FUNCTION__)); | |||
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 | ||||
1005 | class SwDBManager::MailDispatcherListener_Impl : public IMailDispatcherListener | |||
1006 | { | |||
1007 | SwDBManager &m_rDBManager; | |||
1008 | ||||
1009 | public: | |||
1010 | explicit MailDispatcherListener_Impl( SwDBManager &rDBManager ) | |||
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 | ||||
1032 | /** | |||
1033 | * Please have a look at the README in the same directory, before you make | |||
1034 | * larger changes in this function! | |||
1035 | */ | |||
1036 | bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, | |||
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 )(static_cast <bool> (!rMergeDescriptor.bPrefixIsFilename ) ? void (0) : __assert_fail ("!rMergeDescriptor.bPrefixIsFilename" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1055, __extension__ __PRETTY_FUNCTION__)); | |||
1056 | assert(!bCheckSingleFile_)(static_cast <bool> (!bCheckSingleFile_) ? void (0) : __assert_fail ("!bCheckSingleFile_", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1056, __extension__ __PRETTY_FUNCTION__)); | |||
1057 | bCheckSingleFile_ = false; | |||
1058 | } | |||
1059 | else if( bMT_SHELL || bMT_PRINTER ) | |||
1060 | { | |||
1061 | assert(bCheckSingleFile_)(static_cast <bool> (bCheckSingleFile_) ? void (0) : __assert_fail ("bCheckSingleFile_", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1061, __extension__ __PRETTY_FUNCTION__)); | |||
1062 | bCheckSingleFile_ = true; | |||
1063 | assert(sPrefix_.isEmpty())(static_cast <bool> (sPrefix_.isEmpty()) ? void (0) : __assert_fail ("sPrefix_.isEmpty()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1063, __extension__ __PRETTY_FUNCTION__)); | |||
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; | |||
1078 | ::rtl::Reference< IMailDispatcherListener > xMailListener; | |||
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( | |||
1137 | pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE)); | |||
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 | ||||
1160 | m_aMergeStatus = MergeStatus::Ok; | |||
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 | std::shared_ptr<weld::GenericDialogController> xProgressDlg; | |||
1173 | ||||
1174 | try | |||
1175 | { | |||
1176 | vcl::Window *pSourceWindow = nullptr; | |||
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() | |||
1251 | ->getIDocumentFieldsAccess().GetRecordsPerDocument(); | |||
1252 | if ( bSynchronizedDoc && (nRecordPerDoc > 1) ) | |||
1253 | --nRecordPerDoc; | |||
1254 | assert( nRecordPerDoc > 0 )(static_cast <bool> (nRecordPerDoc > 0) ? void (0) : __assert_fail ("nRecordPerDoc > 0", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1254, __extension__ __PRETTY_FUNCTION__)); | |||
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(); | |||
1308 | sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ); | |||
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 | { | |||
1315 | ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTEDErrCode( ErrCodeArea::Io, ErrCodeClass::NotSupported, 12 ) ); | |||
1316 | m_aMergeStatus = MergeStatus::Error; | |||
1317 | } | |||
1318 | } | |||
1319 | ||||
1320 | uno::Sequence< beans::PropertyValue > aSaveToFilterDataOptions( rMergeDescriptor.aSaveToFilterData ); | |||
1321 | ||||
1322 | if( bMT_EMAIL || bPasswordColumnName ) | |||
1323 | { | |||
1324 | OUString sPasswordColumnData = GetDBField( xPasswordColumnProp, aColumnDBFormat ); | |||
1325 | lcl_PrepareSaveFilterDataOptions( rMergeDescriptor.aSaveToFilterData, aSaveToFilterDataOptions, sPasswordColumnData ); | |||
1326 | } | |||
1327 | ||||
1328 | if( IsMergeOk() ) | |||
1329 | { | |||
1330 | std::unique_ptr< INetURLObject > aTempFileURL; | |||
1331 | if( bNeedsTempFiles ) | |||
1332 | aTempFileURL.reset( new INetURLObject(aTempFile->GetURL())); | |||
1333 | if( !bIsMergeSilent ) { | |||
1334 | if( !bMT_PRINTER ) | |||
1335 | static_cast<CreateMonitor*>(xProgressDlg.get())->SetCurrentPosition(nDocNo); | |||
1336 | else { | |||
1337 | PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>(xProgressDlg.get()); | |||
1338 | pPrintMonDlg->m_xPrinter->set_label(bNeedsTempFiles | |||
1339 | ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 2)); | |||
1340 | OUString sStat = SwResId(STR_STATSTR_LETTERreinterpret_cast<char const *>("STR_STATSTR_LETTER" "\004" u8"Letter")) + " " + OUString::number( nDocNo ); | |||
1341 | pPrintMonDlg->m_xPrintInfo->set_label(sStat); | |||
1342 | } | |||
1343 | //TODO xProgressDlg->queue_draw(); | |||
1344 | } | |||
1345 | ||||
1346 | Scheduler::ProcessEventsToIdle(); | |||
1347 | ||||
1348 | // Create a copy of the source document and work with that one instead of the source. | |||
1349 | // If we're not in the single file mode (which requires modifying the document for the merging), | |||
1350 | // it is enough to do this just once. Currently PDF also has to be treated special. | |||
1351 | if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport ) | |||
1352 | { | |||
1353 | assert( !xWorkDocSh.Is())(static_cast <bool> (!xWorkDocSh.Is()) ? void (0) : __assert_fail ("!xWorkDocSh.Is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1353, __extension__ __PRETTY_FUNCTION__)); | |||
1354 | pWorkDocOrigDBManager = this; | |||
1355 | xWorkDocSh = lcl_CreateWorkingDocument( WorkingDocType::COPY, | |||
1356 | *pSourceShell, nullptr, &pWorkDocOrigDBManager, | |||
1357 | &pWorkView, &pWorkShell, &pWorkDoc ); | |||
1358 | if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) | |||
1359 | lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo ); | |||
1360 | ||||
1361 | // #i69458# lock fields to prevent access to the result set while calculating layout | |||
1362 | // tdf#92324: and do not unlock: keep document locked during printing to avoid | |||
1363 | // ExpFields update during printing, generation of preview, etc. | |||
1364 | pWorkShell->LockExpFields(); | |||
1365 | pWorkShell->CalcLayout(); | |||
1366 | // tdf#121168: Now force correct page descriptions applied to page frames. Without | |||
1367 | // this, e.g., page frames starting with sections could have page descriptions set | |||
1368 | // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below. | |||
1369 | pWorkShell->GetViewOptions()->SetIdle(true); | |||
1370 | for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts()) | |||
1371 | { | |||
1372 | aLayout->FreezeLayout(false); | |||
1373 | aLayout->AllCheckPageDescs(); | |||
1374 | } | |||
1375 | } | |||
1376 | ||||
1377 | lcl_emitEvent(SfxEventHintId::SwEventFieldMerge, STR_SW_EVENT_FIELD_MERGE3, xWorkDocSh); | |||
1378 | ||||
1379 | // tdf#92324: Allow ExpFields update only by explicit instruction to avoid | |||
1380 | // database cursor movement on any other fields update, for example during | |||
1381 | // print preview and other operations | |||
1382 | if ( pWorkShell->IsExpFieldsLocked() ) | |||
1383 | pWorkShell->UnlockExpFields(); | |||
1384 | pWorkShell->SwViewShell::UpdateFields(); | |||
1385 | pWorkShell->LockExpFields(); | |||
1386 | ||||
1387 | lcl_emitEvent(SfxEventHintId::SwEventFieldMergeFinished, STR_SW_EVENT_FIELD_MERGE_FINISHED4, xWorkDocSh); | |||
1388 | ||||
1389 | // also emit MailMergeEvent on XInterface if possible | |||
1390 | const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc(); | |||
1391 | if(pEvtSrc) | |||
1392 | { | |||
1393 | rtl::Reference< SwXMailMerge > xRef( | |||
1394 | const_cast<SwXMailMerge*>(pEvtSrc) ); | |||
1395 | text::MailMergeEvent aEvt( static_cast<text::XMailMergeBroadcaster*>(xRef.get()), xWorkDocSh->GetModel() ); | |||
1396 | SolarMutexReleaser rel; | |||
1397 | xRef->LaunchMailMergeEvent( aEvt ); | |||
1398 | } | |||
1399 | ||||
1400 | // working copy is merged - prepare final steps depending on merge options | |||
1401 | ||||
1402 | if( bCreateSingleFile ) | |||
1403 | { | |||
1404 | assert( pTargetShell && "no target shell available!" )(static_cast <bool> (pTargetShell && "no target shell available!" ) ? void (0) : __assert_fail ("pTargetShell && \"no target shell available!\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1404, __extension__ __PRETTY_FUNCTION__)); | |||
1405 | ||||
1406 | // prepare working copy and target to append | |||
1407 | ||||
1408 | pWorkDoc->RemoveInvisibleContent(); | |||
1409 | // remove of invisible content has influence on page count and so on fields for page count, | |||
1410 | // therefore layout has to be updated before fields are converted to text | |||
1411 | pWorkShell->CalcLayout(); | |||
1412 | pWorkShell->ConvertFieldsToText(); | |||
1413 | pWorkShell->SetNumberingRestart(); | |||
1414 | if( bSynchronizedDoc ) | |||
1415 | { | |||
1416 | lcl_RemoveSectionLinks( *pWorkShell ); | |||
1417 | } | |||
1418 | ||||
1419 | if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) | |||
1420 | lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo ); | |||
1421 | ||||
1422 | // append the working document to the target document | |||
1423 | if( targetDocPageCount % 2 == 1 ) | |||
1424 | ++targetDocPageCount; // Docs always start on odd pages (so offset must be even). | |||
1425 | SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc( *pWorkDoc, | |||
1426 | nStartingPageNo, !bWorkDocInitialized, targetDocPageCount, nDocNo); | |||
1427 | targetDocPageCount += pWorkShell->GetPageCnt(); | |||
1428 | ||||
1429 | if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) | |||
1430 | lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" ); | |||
1431 | ||||
1432 | if (bMT_SHELL) | |||
1433 | { | |||
1434 | SwDocMergeInfo aMergeInfo; | |||
1435 | // Name of the mark is actually irrelevant, UNO bookmarks have internals names. | |||
1436 | aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark( | |||
1437 | appendedDocStart, "", IDocumentMarkAccess::MarkType::UNO_BOOKMARK, | |||
1438 | ::sw::mark::InsertMode::New); | |||
1439 | aMergeInfo.nDBRow = nStartRow; | |||
1440 | rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo ); | |||
1441 | } | |||
1442 | } | |||
1443 | else | |||
1444 | { | |||
1445 | assert( bNeedsTempFiles )(static_cast <bool> (bNeedsTempFiles) ? void (0) : __assert_fail ("bNeedsTempFiles", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1445, __extension__ __PRETTY_FUNCTION__)); | |||
1446 | assert( pWorkShell->IsExpFieldsLocked() )(static_cast <bool> (pWorkShell->IsExpFieldsLocked() ) ? void (0) : __assert_fail ("pWorkShell->IsExpFieldsLocked()" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1446, __extension__ __PRETTY_FUNCTION__)); | |||
1447 | ||||
1448 | // fields are locked, so it's fine to | |||
1449 | // restore the old / empty DB manager for save | |||
1450 | pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); | |||
1451 | ||||
1452 | // save merged document | |||
1453 | OUString sFileURL; | |||
1454 | if( !lcl_SaveDoc( aTempFileURL.get(), pStoreToFilter, pStoreToFilterOptions, | |||
1455 | &aSaveToFilterDataOptions, bIsPDFexport, | |||
1456 | xWorkDocSh, *pWorkShell, &sFileURL ) ) | |||
1457 | { | |||
1458 | m_aMergeStatus = MergeStatus::Error; | |||
1459 | } | |||
1460 | ||||
1461 | // back to the MM DB manager | |||
1462 | pWorkDoc->SetDBManager( this ); | |||
1463 | ||||
1464 | if( bMT_EMAIL && !IsMergeError() ) | |||
1465 | { | |||
1466 | // schedule file for later removal | |||
1467 | aFilesToRemove.push_back( sFileURL ); | |||
1468 | ||||
1469 | if( !SwMailMergeHelper::CheckMailAddress( sColumnData ) ) | |||
1470 | { | |||
1471 | OSL_FAIL("invalid e-Mail address in database column")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1471" ": "), "%s", "invalid e-Mail address in database column" ); } } while (false); | |||
1472 | } | |||
1473 | else | |||
1474 | { | |||
1475 | uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc( | |||
1476 | rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType, | |||
1477 | sMailEncoding, pStoreToFilter->GetMimeType() ); | |||
1478 | if( xMessage.is() ) | |||
1479 | { | |||
1480 | osl::MutexGuard aGuard( m_pImpl->m_aAllEmailSendMutex ); | |||
1481 | m_pImpl->m_xLastMessage.set( xMessage ); | |||
1482 | xMailDispatcher->enqueueMailMessage( xMessage ); | |||
1483 | if( !xMailDispatcher->isStarted() ) | |||
1484 | xMailDispatcher->start(); | |||
1485 | } | |||
1486 | } | |||
1487 | } | |||
1488 | } | |||
1489 | if( bCreateSingleFile || bIsPDFexport ) | |||
1490 | { | |||
1491 | pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); | |||
1492 | xWorkDocSh->DoClose(); | |||
1493 | xWorkDocSh = nullptr; | |||
1494 | } | |||
1495 | } | |||
1496 | ||||
1497 | bWorkDocInitialized = true; | |||
1498 | nDocNo++; | |||
1499 | nEndRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0; | |||
1500 | ||||
1501 | // Freeze the layouts of the target document after the first inserted | |||
1502 | // sub-document, to get the correct PageDesc. | |||
1503 | if(!bFreezedLayouts && bCreateSingleFile) | |||
1504 | { | |||
1505 | for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) | |||
1506 | aLayout->FreezeLayout(true); | |||
1507 | bFreezedLayouts = true; | |||
1508 | } | |||
1509 | } while( IsMergeOk() && | |||
1510 | ((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord())); | |||
1511 | ||||
1512 | if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() ) | |||
1513 | { | |||
1514 | // Unlock document fields after merge complete | |||
1515 | pWorkView->GetWrtShell().UnlockExpFields(); | |||
1516 | } | |||
1517 | ||||
1518 | if( !bCreateSingleFile ) | |||
1519 | { | |||
1520 | if( bMT_PRINTER ) | |||
1521 | Printer::FinishPrintJob( pWorkView->GetPrinterController()); | |||
1522 | if( !bIsPDFexport ) | |||
1523 | { | |||
1524 | pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); | |||
1525 | xWorkDocSh->DoClose(); | |||
1526 | } | |||
1527 | } | |||
1528 | else if( IsMergeOk() ) // && bCreateSingleFile | |||
1529 | { | |||
1530 | Application::Reschedule( true ); | |||
1531 | ||||
1532 | // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate | |||
1533 | // unique fly names, do it here once. | |||
1534 | pTargetDoc->SetInMailMerge(false); | |||
1535 | pTargetDoc->SetAllUniqueFlyNames(); | |||
1536 | ||||
1537 | // Unfreeze target document layouts and correct all PageDescs. | |||
1538 | SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.pageframe")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1538" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "(MergeMailFiles pTargetShell->CalcLayout in"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1538" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "(MergeMailFiles pTargetShell->CalcLayout in") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1538" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "(MergeMailFiles pTargetShell->CalcLayout in"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1538" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1539 | pTargetShell->CalcLayout(); | |||
1540 | SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.pageframe")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1540" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "MergeMailFiles pTargetShell->CalcLayout out)"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1540" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "MergeMailFiles pTargetShell->CalcLayout out)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1540" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "MergeMailFiles pTargetShell->CalcLayout out)"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1540" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1541 | pTargetShell->GetViewOptions()->SetIdle( true ); | |||
1542 | pTargetDoc->GetIDocumentUndoRedo().DoUndo( true ); | |||
1543 | for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) | |||
1544 | { | |||
1545 | aLayout->FreezeLayout(false); | |||
1546 | aLayout->AllCheckPageDescs(); | |||
1547 | } | |||
1548 | ||||
1549 | Application::Reschedule( true ); | |||
1550 | ||||
1551 | if( IsMergeOk() && bMT_FILE ) | |||
1552 | { | |||
1553 | // save merged document | |||
1554 | assert( aTempFile )(static_cast <bool> (aTempFile) ? void (0) : __assert_fail ("aTempFile", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1554, __extension__ __PRETTY_FUNCTION__)); | |||
1555 | INetURLObject aTempFileURL; | |||
1556 | if (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename) | |||
1557 | aTempFileURL.SetURL( aTempFile->GetURL() ); | |||
1558 | else | |||
1559 | { | |||
1560 | aTempFileURL.SetURL(sDescriptorPrefix); | |||
1561 | // remove the unneeded temporary file | |||
1562 | aTempFile->EnableKillingFile(); | |||
1563 | } | |||
1564 | if( !lcl_SaveDoc( &aTempFileURL, pStoreToFilter, | |||
1565 | pStoreToFilterOptions, &rMergeDescriptor.aSaveToFilterData, | |||
1566 | bIsPDFexport, xTargetDocShell.get(), *pTargetShell ) ) | |||
1567 | { | |||
1568 | m_aMergeStatus = MergeStatus::Error; | |||
1569 | } | |||
1570 | } | |||
1571 | else if( IsMergeOk() && bMT_PRINTER ) | |||
1572 | { | |||
1573 | // print the target document | |||
1574 | uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions ); | |||
1575 | lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, aOptions ); | |||
1576 | pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ ); | |||
1577 | } | |||
1578 | } | |||
1579 | ||||
1580 | // we also show canceled documents, as long as there was no error | |||
1581 | if( !IsMergeError() && bMT_SHELL ) | |||
1582 | // leave docshell available for caller (e.g. MM wizard) | |||
1583 | rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); | |||
1584 | else if( xTargetDocShell.is() ) | |||
1585 | xTargetDocShell->DoClose(); | |||
1586 | ||||
1587 | Application::Reschedule( true ); | |||
1588 | ||||
1589 | if (xProgressDlg) | |||
1590 | { | |||
1591 | xProgressDlg->response(RET_OK); | |||
1592 | } | |||
1593 | ||||
1594 | // unlock all dispatchers | |||
1595 | pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); | |||
1596 | while (pViewFrame) | |||
1597 | { | |||
1598 | pViewFrame->GetDispatcher()->Lock(false); | |||
1599 | pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); | |||
1600 | } | |||
1601 | ||||
1602 | SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule ::Writer)))->SetView(&pSourceShell->GetView()); | |||
1603 | ||||
1604 | if( xMailDispatcher.is() ) | |||
1605 | { | |||
1606 | if( IsMergeOk() ) | |||
1607 | { | |||
1608 | // TODO: Instead of polling via an AutoTimer, post an Idle event, | |||
1609 | // if the main loop has been made thread-safe. | |||
1610 | AutoTimer aEmailDispatcherPollTimer; | |||
1611 | aEmailDispatcherPollTimer.SetDebugName( | |||
1612 | "sw::SwDBManager aEmailDispatcherPollTimer" ); | |||
1613 | aEmailDispatcherPollTimer.SetTimeout( 500 ); | |||
1614 | aEmailDispatcherPollTimer.Start(); | |||
1615 | while( IsMergeOk() && m_pImpl->m_xLastMessage.is() ) | |||
1616 | Application::Yield(); | |||
1617 | aEmailDispatcherPollTimer.Stop(); | |||
1618 | } | |||
1619 | xMailDispatcher->stop(); | |||
1620 | xMailDispatcher->shutdown(); | |||
1621 | } | |||
1622 | ||||
1623 | // remove the temporary files | |||
1624 | // has to be done after xMailDispatcher is finished, as mails may be | |||
1625 | // delivered as message attachments! | |||
1626 | for( const OUString &sFileURL : aFilesToRemove ) | |||
1627 | SWUnoHelper::UCB_DeleteFile( sFileURL ); | |||
1628 | } | |||
1629 | catch (const uno::Exception&) | |||
1630 | { | |||
1631 | if (xProgressDlg) | |||
1632 | { | |||
1633 | xProgressDlg->response(RET_CANCEL); | |||
1634 | } | |||
1635 | } | |||
1636 | ||||
1637 | return !IsMergeError(); | |||
1638 | } | |||
1639 | ||||
1640 | void SwDBManager::MergeCancel() | |||
1641 | { | |||
1642 | if (m_aMergeStatus < MergeStatus::Cancel) | |||
1643 | m_aMergeStatus = MergeStatus::Cancel; | |||
1644 | } | |||
1645 | ||||
1646 | // determine the column's Numberformat and transfer to the forwarded Formatter, | |||
1647 | // if applicable. | |||
1648 | sal_uLong SwDBManager::GetColumnFormat( const OUString& rDBName, | |||
1649 | const OUString& rTableName, | |||
1650 | const OUString& rColNm, | |||
1651 | SvNumberFormatter* pNFormatr, | |||
1652 | LanguageType nLanguage ) | |||
1653 | { | |||
1654 | sal_uLong nRet = 0; | |||
1655 | if(pNFormatr) | |||
1656 | { | |||
1657 | uno::Reference< sdbc::XDataSource> xSource; | |||
1658 | uno::Reference< sdbc::XConnection> xConnection; | |||
1659 | bool bUseMergeData = false; | |||
1660 | uno::Reference< sdbcx::XColumnsSupplier> xColsSupp; | |||
1661 | bool bDisposeConnection = false; | |||
1662 | if(m_pImpl->pMergeData && | |||
1663 | ((m_pImpl->pMergeData->sDataSource == rDBName && m_pImpl->pMergeData->sCommand == rTableName) || | |||
1664 | (rDBName.isEmpty() && rTableName.isEmpty()))) | |||
1665 | { | |||
1666 | xConnection = m_pImpl->pMergeData->xConnection; | |||
1667 | xSource = SwDBManager::getDataSourceAsParent(xConnection,rDBName); | |||
1668 | bUseMergeData = true; | |||
1669 | xColsSupp.set(m_pImpl->pMergeData->xResultSet, css::uno::UNO_QUERY); | |||
1670 | } | |||
1671 | if(!xConnection.is()) | |||
1672 | { | |||
1673 | SwDBData aData; | |||
1674 | aData.sDataSource = rDBName; | |||
1675 | aData.sCommand = rTableName; | |||
1676 | aData.nCommandType = -1; | |||
1677 | SwDSParam* pParam = FindDSData(aData, false); | |||
1678 | if(pParam && pParam->xConnection.is()) | |||
1679 | { | |||
1680 | xConnection = pParam->xConnection; | |||
1681 | xColsSupp.set(pParam->xResultSet, css::uno::UNO_QUERY); | |||
1682 | } | |||
1683 | else | |||
1684 | { | |||
1685 | xConnection = RegisterConnection( rDBName ); | |||
1686 | bDisposeConnection = true; | |||
1687 | } | |||
1688 | if(bUseMergeData) | |||
1689 | m_pImpl->pMergeData->xConnection = xConnection; | |||
1690 | } | |||
1691 | bool bDispose = !xColsSupp.is(); | |||
1692 | if(bDispose) | |||
1693 | { | |||
1694 | xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName); | |||
1695 | } | |||
1696 | if(xColsSupp.is()) | |||
1697 | { | |||
1698 | uno::Reference<container::XNameAccess> xCols; | |||
1699 | try | |||
1700 | { | |||
1701 | xCols = xColsSupp->getColumns(); | |||
1702 | } | |||
1703 | catch (const uno::Exception&) | |||
1704 | { | |||
1705 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "Exception in getColumns()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Exception in getColumns()" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1705" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Exception in getColumns()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Exception in getColumns()" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1705" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Exception in getColumns()" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1705" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Exception in getColumns()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Exception in getColumns()" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1705" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
1706 | } | |||
1707 | if(!xCols.is() || !xCols->hasByName(rColNm)) | |||
1708 | return nRet; | |||
1709 | uno::Any aCol = xCols->getByName(rColNm); | |||
1710 | uno::Reference< beans::XPropertySet > xColumn; | |||
1711 | aCol >>= xColumn; | |||
1712 | nRet = GetColumnFormat(xSource, xConnection, xColumn, pNFormatr, nLanguage); | |||
1713 | if(bDispose) | |||
1714 | { | |||
1715 | ::comphelper::disposeComponent( xColsSupp ); | |||
1716 | } | |||
1717 | if(bDisposeConnection) | |||
1718 | { | |||
1719 | ::comphelper::disposeComponent( xConnection ); | |||
1720 | } | |||
1721 | } | |||
1722 | else | |||
1723 | nRet = pNFormatr->GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_SYSTEMLanguageType(0x0000) ); | |||
1724 | } | |||
1725 | return nRet; | |||
1726 | } | |||
1727 | ||||
1728 | sal_uLong SwDBManager::GetColumnFormat( uno::Reference< sdbc::XDataSource> const & xSource_in, | |||
1729 | uno::Reference< sdbc::XConnection> const & xConnection, | |||
1730 | uno::Reference< beans::XPropertySet> const & xColumn, | |||
1731 | SvNumberFormatter* pNFormatr, | |||
1732 | LanguageType nLanguage ) | |||
1733 | { | |||
1734 | auto xSource = xSource_in; | |||
1735 | ||||
1736 | // set the NumberFormat in the doc if applicable | |||
1737 | sal_uLong nRet = 0; | |||
1738 | ||||
1739 | if(!xSource.is()) | |||
1740 | { | |||
1741 | uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY); | |||
1742 | if ( xChild.is() ) | |||
1743 | xSource.set(xChild->getParent(), uno::UNO_QUERY); | |||
1744 | } | |||
1745 | if(xSource.is() && xConnection.is() && xColumn.is() && pNFormatr) | |||
1746 | { | |||
1747 | SvNumberFormatsSupplierObj* pNumFormat = new SvNumberFormatsSupplierObj( pNFormatr ); | |||
1748 | uno::Reference< util::XNumberFormatsSupplier > xDocNumFormatsSupplier = pNumFormat; | |||
1749 | uno::Reference< util::XNumberFormats > xDocNumberFormats = xDocNumFormatsSupplier->getNumberFormats(); | |||
1750 | uno::Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, uno::UNO_QUERY); | |||
1751 | ||||
1752 | css::lang::Locale aLocale( LanguageTag( nLanguage ).getLocale()); | |||
1753 | ||||
1754 | //get the number formatter of the data source | |||
1755 | uno::Reference<beans::XPropertySet> xSourceProps(xSource, uno::UNO_QUERY); | |||
1756 | uno::Reference< util::XNumberFormats > xNumberFormats; | |||
1757 | if(xSourceProps.is()) | |||
1758 | { | |||
1759 | uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier"); | |||
1760 | if(aFormats.hasValue()) | |||
1761 | { | |||
1762 | uno::Reference<util::XNumberFormatsSupplier> xSuppl; | |||
1763 | aFormats >>= xSuppl; | |||
1764 | if(xSuppl.is()) | |||
1765 | { | |||
1766 | xNumberFormats = xSuppl->getNumberFormats(); | |||
1767 | } | |||
1768 | } | |||
1769 | } | |||
1770 | bool bUseDefault = true; | |||
1771 | try | |||
1772 | { | |||
1773 | uno::Any aFormatKey = xColumn->getPropertyValue("FormatKey"); | |||
1774 | if(aFormatKey.hasValue()) | |||
1775 | { | |||
1776 | sal_Int32 nFormat = 0; | |||
1777 | aFormatKey >>= nFormat; | |||
1778 | if(xNumberFormats.is()) | |||
1779 | { | |||
1780 | try | |||
1781 | { | |||
1782 | uno::Reference<beans::XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat ); | |||
1783 | uno::Any aFormatString = xNumProps->getPropertyValue("FormatString"); | |||
1784 | uno::Any aLocaleVal = xNumProps->getPropertyValue("Locale"); | |||
1785 | OUString sFormat; | |||
1786 | aFormatString >>= sFormat; | |||
1787 | lang::Locale aLoc; | |||
1788 | aLocaleVal >>= aLoc; | |||
1789 | nFormat = xDocNumberFormats->queryKey( sFormat, aLoc, false ); | |||
1790 | if(NUMBERFORMAT_ENTRY_NOT_FOUND == sal::static_int_cast< sal_uInt32, sal_Int32>(nFormat)) | |||
1791 | nFormat = xDocNumberFormats->addNew( sFormat, aLoc ); | |||
1792 | nRet = nFormat; | |||
1793 | bUseDefault = false; | |||
1794 | } | |||
1795 | catch (const uno::Exception&) | |||
1796 | { | |||
1797 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "illegal number format key")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "illegal number format key" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1797" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal number format key" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal number format key" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1797" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal number format key" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1797" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal number format key" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal number format key" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1797" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
1798 | } | |||
1799 | } | |||
1800 | } | |||
1801 | } | |||
1802 | catch(const uno::Exception&) | |||
1803 | { | |||
1804 | SAL_WARN("sw.mailmerge", "no FormatKey property found")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "no FormatKey property found" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1804" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "no FormatKey property found"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "no FormatKey property found"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1804" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "no FormatKey property found") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1804" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "no FormatKey property found"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "no FormatKey property found"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1804" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1805 | } | |||
1806 | if(bUseDefault) | |||
1807 | nRet = dbtools::getDefaultNumberFormat(xColumn, xDocNumberFormatTypes, aLocale); | |||
1808 | } | |||
1809 | return nRet; | |||
1810 | } | |||
1811 | ||||
1812 | sal_Int32 SwDBManager::GetColumnType( const OUString& rDBName, | |||
1813 | const OUString& rTableName, | |||
1814 | const OUString& rColNm ) | |||
1815 | { | |||
1816 | sal_Int32 nRet = sdbc::DataType::SQLNULL; | |||
1817 | SwDBData aData; | |||
1818 | aData.sDataSource = rDBName; | |||
1819 | aData.sCommand = rTableName; | |||
1820 | aData.nCommandType = -1; | |||
1821 | SwDSParam* pParam = FindDSData(aData, false); | |||
1822 | uno::Reference< sdbc::XConnection> xConnection; | |||
1823 | uno::Reference< sdbcx::XColumnsSupplier > xColsSupp; | |||
1824 | bool bDispose = false; | |||
1825 | if(pParam && pParam->xConnection.is()) | |||
1826 | { | |||
1827 | xConnection = pParam->xConnection; | |||
1828 | xColsSupp.set( pParam->xResultSet, uno::UNO_QUERY ); | |||
1829 | } | |||
1830 | else | |||
1831 | { | |||
1832 | xConnection = RegisterConnection( rDBName ); | |||
1833 | } | |||
1834 | if( !xColsSupp.is() ) | |||
1835 | { | |||
1836 | xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName); | |||
1837 | bDispose = true; | |||
1838 | } | |||
1839 | if(xColsSupp.is()) | |||
1840 | { | |||
1841 | uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns(); | |||
1842 | if(xCols->hasByName(rColNm)) | |||
1843 | { | |||
1844 | uno::Any aCol = xCols->getByName(rColNm); | |||
1845 | uno::Reference<beans::XPropertySet> xCol; | |||
1846 | aCol >>= xCol; | |||
1847 | uno::Any aType = xCol->getPropertyValue("Type"); | |||
1848 | aType >>= nRet; | |||
1849 | } | |||
1850 | if(bDispose) | |||
1851 | ::comphelper::disposeComponent( xColsSupp ); | |||
1852 | } | |||
1853 | return nRet; | |||
1854 | } | |||
1855 | ||||
1856 | uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rDataSource, | |||
1857 | uno::Reference<sdbc::XDataSource>& rxSource, const SwView *pView) | |||
1858 | { | |||
1859 | uno::Reference< sdbc::XConnection> xConnection; | |||
1860 | uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); | |||
1861 | try | |||
1862 | { | |||
1863 | uno::Reference<sdb::XCompletedConnection> xComplConnection(dbtools::getDataSource(rDataSource, xContext), uno::UNO_QUERY); | |||
1864 | if ( xComplConnection.is() ) | |||
1865 | { | |||
1866 | rxSource.set(xComplConnection, uno::UNO_QUERY); | |||
1867 | weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr; | |||
1868 | uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(xContext, pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW ); | |||
1869 | xConnection = xComplConnection->connectWithCompletion( xHandler ); | |||
1870 | } | |||
1871 | } | |||
1872 | catch(const uno::Exception&) | |||
1873 | { | |||
1874 | } | |||
1875 | ||||
1876 | return xConnection; | |||
1877 | } | |||
1878 | ||||
1879 | uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference<sdbc::XConnection> const & xConnection, | |||
1880 | const OUString& rTableOrQuery, | |||
1881 | SwDBSelect eTableOrQuery) | |||
1882 | { | |||
1883 | uno::Reference< sdbcx::XColumnsSupplier> xRet; | |||
1884 | try | |||
1885 | { | |||
1886 | if(eTableOrQuery == SwDBSelect::UNKNOWN) | |||
1887 | { | |||
1888 | //search for a table with the given command name | |||
1889 | uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY); | |||
1890 | if(xTSupplier.is()) | |||
1891 | { | |||
1892 | uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables(); | |||
1893 | eTableOrQuery = xTables->hasByName(rTableOrQuery) ? | |||
1894 | SwDBSelect::TABLE : SwDBSelect::QUERY; | |||
1895 | } | |||
1896 | } | |||
1897 | sal_Int32 nCommandType = SwDBSelect::TABLE == eTableOrQuery ? | |||
1898 | sdb::CommandType::TABLE : sdb::CommandType::QUERY; | |||
1899 | uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); | |||
1900 | uno::Reference<sdbc::XRowSet> xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), uno::UNO_QUERY); | |||
1901 | ||||
1902 | OUString sDataSource; | |||
1903 | uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection, sDataSource); | |||
1904 | uno::Reference<beans::XPropertySet> xSourceProperties(xSource, uno::UNO_QUERY); | |||
1905 | if(xSourceProperties.is()) | |||
1906 | { | |||
1907 | xSourceProperties->getPropertyValue("Name") >>= sDataSource; | |||
1908 | } | |||
1909 | ||||
1910 | uno::Reference<beans::XPropertySet> xRowProperties(xRowSet, uno::UNO_QUERY); | |||
1911 | xRowProperties->setPropertyValue("DataSourceName", uno::makeAny(sDataSource)); | |||
1912 | xRowProperties->setPropertyValue("Command", uno::makeAny(rTableOrQuery)); | |||
1913 | xRowProperties->setPropertyValue("CommandType", uno::makeAny(nCommandType)); | |||
1914 | xRowProperties->setPropertyValue("FetchSize", uno::makeAny(sal_Int32(10))); | |||
1915 | xRowProperties->setPropertyValue("ActiveConnection", uno::makeAny(xConnection)); | |||
1916 | xRowSet->execute(); | |||
1917 | xRet.set( xRowSet, uno::UNO_QUERY ); | |||
1918 | } | |||
1919 | catch (const uno::Exception&) | |||
1920 | { | |||
1921 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "Exception in SwDBManager::GetColumnSupplier")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Exception in SwDBManager::GetColumnSupplier" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1921" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Exception in SwDBManager::GetColumnSupplier" << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Exception in SwDBManager::GetColumnSupplier" << " " << exceptionToString(tools_warn_exception); ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1921" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Exception in SwDBManager::GetColumnSupplier" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1921" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Exception in SwDBManager::GetColumnSupplier" << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Exception in SwDBManager::GetColumnSupplier" << " " << exceptionToString(tools_warn_exception); ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1921" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
1922 | } | |||
1923 | ||||
1924 | return xRet; | |||
1925 | } | |||
1926 | ||||
1927 | OUString SwDBManager::GetDBField(uno::Reference<beans::XPropertySet> const & xColumnProps, | |||
1928 | const SwDBFormatData& rDBFormatData, | |||
1929 | double* pNumber) | |||
1930 | { | |||
1931 | uno::Reference< sdb::XColumn > xColumn(xColumnProps, uno::UNO_QUERY); | |||
1932 | OUString sRet; | |||
1933 | assert( xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments" )(static_cast <bool> (xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments" ) ? void (0) : __assert_fail ("xColumn.is() && \"SwDBManager::::ImportDBField: illegal arguments\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 1933, __extension__ __PRETTY_FUNCTION__)); | |||
1934 | if(!xColumn.is()) | |||
1935 | return sRet; | |||
1936 | ||||
1937 | uno::Any aType = xColumnProps->getPropertyValue("Type"); | |||
1938 | sal_Int32 eDataType = sdbc::DataType::SQLNULL; | |||
1939 | aType >>= eDataType; | |||
1940 | switch(eDataType) | |||
1941 | { | |||
1942 | case sdbc::DataType::CHAR: | |||
1943 | case sdbc::DataType::VARCHAR: | |||
1944 | case sdbc::DataType::LONGVARCHAR: | |||
1945 | try | |||
1946 | { | |||
1947 | sRet = xColumn->getString(); | |||
1948 | sRet = sRet.replace( '\xb', '\n' ); // MSWord uses \xb as a newline | |||
1949 | } | |||
1950 | catch(const sdbc::SQLException&) | |||
1951 | { | |||
1952 | } | |||
1953 | break; | |||
1954 | case sdbc::DataType::BIT: | |||
1955 | case sdbc::DataType::BOOLEAN: | |||
1956 | case sdbc::DataType::TINYINT: | |||
1957 | case sdbc::DataType::SMALLINT: | |||
1958 | case sdbc::DataType::INTEGER: | |||
1959 | case sdbc::DataType::BIGINT: | |||
1960 | case sdbc::DataType::FLOAT: | |||
1961 | case sdbc::DataType::REAL: | |||
1962 | case sdbc::DataType::DOUBLE: | |||
1963 | case sdbc::DataType::NUMERIC: | |||
1964 | case sdbc::DataType::DECIMAL: | |||
1965 | case sdbc::DataType::DATE: | |||
1966 | case sdbc::DataType::TIME: | |||
1967 | case sdbc::DataType::TIMESTAMP: | |||
1968 | { | |||
1969 | ||||
1970 | try | |||
1971 | { | |||
1972 | sRet = dbtools::DBTypeConversion::getFormattedValue( | |||
1973 | xColumnProps, | |||
1974 | rDBFormatData.xFormatter, | |||
1975 | rDBFormatData.aLocale, | |||
1976 | rDBFormatData.aNullDate); | |||
1977 | if (pNumber) | |||
1978 | { | |||
1979 | double fVal = xColumn->getDouble(); | |||
1980 | if(!xColumn->wasNull()) | |||
1981 | { | |||
1982 | *pNumber = fVal; | |||
1983 | } | |||
1984 | } | |||
1985 | } | |||
1986 | catch (const uno::Exception&) | |||
1987 | { | |||
1988 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1988" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "" << " " << exceptionToString (tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1988" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1988" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "" << " " << exceptionToString (tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "1988" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
1989 | } | |||
1990 | ||||
1991 | } | |||
1992 | break; | |||
1993 | } | |||
1994 | ||||
1995 | return sRet; | |||
1996 | } | |||
1997 | ||||
1998 | // checks if a desired data source table or query is open | |||
1999 | bool SwDBManager::IsDataSourceOpen(const OUString& rDataSource, | |||
2000 | const OUString& rTableOrQuery, bool bMergeShell) | |||
2001 | { | |||
2002 | if(m_pImpl->pMergeData) | |||
2003 | { | |||
2004 | return ((rDataSource == m_pImpl->pMergeData->sDataSource | |||
2005 | && rTableOrQuery == m_pImpl->pMergeData->sCommand) | |||
2006 | || (rDataSource.isEmpty() && rTableOrQuery.isEmpty())) | |||
2007 | && m_pImpl->pMergeData->xResultSet.is(); | |||
2008 | } | |||
2009 | else if(!bMergeShell) | |||
2010 | { | |||
2011 | SwDBData aData; | |||
2012 | aData.sDataSource = rDataSource; | |||
2013 | aData.sCommand = rTableOrQuery; | |||
2014 | aData.nCommandType = -1; | |||
2015 | SwDSParam* pFound = FindDSData(aData, false); | |||
2016 | return (pFound && pFound->xResultSet.is()); | |||
2017 | } | |||
2018 | return false; | |||
2019 | } | |||
2020 | ||||
2021 | // read column data at a specified position | |||
2022 | bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName, | |||
2023 | const OUString& rColumnName, sal_uInt32 nAbsRecordId, | |||
2024 | LanguageType nLanguage, | |||
2025 | OUString& rResult, double* pNumber) | |||
2026 | { | |||
2027 | bool bRet = false; | |||
2028 | SwDSParam* pFound = nullptr; | |||
2029 | //check if it's the merge data source | |||
2030 | if(m_pImpl->pMergeData && | |||
2031 | rSourceName == m_pImpl->pMergeData->sDataSource && | |||
2032 | rTableName == m_pImpl->pMergeData->sCommand) | |||
2033 | { | |||
2034 | pFound = m_pImpl->pMergeData.get(); | |||
2035 | } | |||
2036 | else | |||
2037 | { | |||
2038 | SwDBData aData; | |||
2039 | aData.sDataSource = rSourceName; | |||
2040 | aData.sCommand = rTableName; | |||
2041 | aData.nCommandType = -1; | |||
2042 | pFound = FindDSData(aData, false); | |||
2043 | } | |||
2044 | if (!pFound) | |||
2045 | return false; | |||
2046 | //check validity of supplied record Id | |||
2047 | if(pFound->aSelection.hasElements()) | |||
2048 | { | |||
2049 | //the destination has to be an element of the selection | |||
2050 | bool bFound = std::any_of(pFound->aSelection.begin(), pFound->aSelection.end(), | |||
2051 | [nAbsRecordId](const uno::Any& rSelection) { | |||
2052 | sal_Int32 nSelection = 0; | |||
2053 | rSelection >>= nSelection; | |||
2054 | return nSelection == static_cast<sal_Int32>(nAbsRecordId); | |||
2055 | }); | |||
2056 | if(!bFound) | |||
2057 | return false; | |||
2058 | } | |||
2059 | if( pFound->HasValidRecord() ) | |||
2060 | { | |||
2061 | sal_Int32 nOldRow = 0; | |||
2062 | try | |||
2063 | { | |||
2064 | nOldRow = pFound->xResultSet->getRow(); | |||
2065 | } | |||
2066 | catch(const uno::Exception&) | |||
2067 | { | |||
2068 | return false; | |||
2069 | } | |||
2070 | //position to the desired index | |||
2071 | bool bMove = true; | |||
2072 | if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) ) | |||
2073 | bMove = lcl_MoveAbsolute(pFound, nAbsRecordId); | |||
2074 | if(bMove) | |||
2075 | bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber); | |||
2076 | if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) ) | |||
2077 | lcl_MoveAbsolute(pFound, nOldRow); | |||
2078 | } | |||
2079 | return bRet; | |||
2080 | } | |||
2081 | ||||
2082 | // reads the column data at the current position | |||
2083 | bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage, | |||
2084 | OUString &rResult, double *pNumber) | |||
2085 | { | |||
2086 | if( !IsValidMergeRecord() ) | |||
2087 | { | |||
2088 | rResult.clear(); | |||
2089 | return false; | |||
2090 | } | |||
2091 | ||||
2092 | bool bRet = lcl_GetColumnCnt(m_pImpl->pMergeData.get(), rColumnName, nLanguage, rResult, pNumber); | |||
2093 | return bRet; | |||
2094 | } | |||
2095 | ||||
2096 | bool SwDBManager::ToNextMergeRecord() | |||
2097 | { | |||
2098 | assert( m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl ->pMergeData->xResultSet.is() && "no data source in merge" ) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2098, __extension__ __PRETTY_FUNCTION__)); | |||
2099 | return lcl_ToNextRecord( m_pImpl->pMergeData.get() ); | |||
2100 | } | |||
2101 | ||||
2102 | bool SwDBManager::FillCalcWithMergeData( SvNumberFormatter *pDocFormatter, | |||
2103 | LanguageType nLanguage, SwCalc &rCalc ) | |||
2104 | { | |||
2105 | if( !IsValidMergeRecord() ) | |||
2106 | return false; | |||
2107 | ||||
2108 | uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY ); | |||
2109 | if( !xColsSupp.is() ) | |||
2110 | return false; | |||
2111 | ||||
2112 | { | |||
2113 | uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns(); | |||
2114 | const uno::Sequence<OUString> aColNames = xCols->getElementNames(); | |||
2115 | OUString aString; | |||
2116 | ||||
2117 | // add the "record number" variable, as SwCalc::VarLook would. | |||
2118 | rCalc.VarChange( GetAppCharClass().lowercase( | |||
2119 | SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber) ), GetSelectedRecordId() ); | |||
2120 | ||||
2121 | for( const OUString& rColName : aColNames ) | |||
2122 | { | |||
2123 | // get the column type | |||
2124 | sal_Int32 nColumnType = sdbc::DataType::SQLNULL; | |||
2125 | uno::Any aCol = xCols->getByName( rColName ); | |||
2126 | uno::Reference<beans::XPropertySet> xColumnProps; | |||
2127 | aCol >>= xColumnProps; | |||
2128 | uno::Any aType = xColumnProps->getPropertyValue( "Type" ); | |||
2129 | aType >>= nColumnType; | |||
2130 | double aNumber = DBL_MAX1.7976931348623157e+308; | |||
2131 | ||||
2132 | lcl_GetColumnCnt( m_pImpl->pMergeData.get(), xColumnProps, nLanguage, aString, &aNumber ); | |||
2133 | ||||
2134 | sal_uInt32 nFormat = GetColumnFormat( m_pImpl->pMergeData->sDataSource, | |||
2135 | m_pImpl->pMergeData->sCommand, | |||
2136 | rColName, pDocFormatter, nLanguage ); | |||
2137 | // aNumber is overwritten by SwDBField::FormatValue, so store initial status | |||
2138 | bool colIsNumber = aNumber != DBL_MAX1.7976931348623157e+308; | |||
2139 | bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFormat, | |||
2140 | aNumber, nColumnType ); | |||
2141 | if( colIsNumber ) | |||
2142 | { | |||
2143 | if( bValidValue ) | |||
2144 | { | |||
2145 | SwSbxValue aValue; | |||
2146 | aValue.PutDouble( aNumber ); | |||
2147 | aValue.SetDBvalue( true ); | |||
2148 | SAL_INFO( "sw.ui", "'" << rColName << "': " << aNumber << " / " << aString )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "'" << rColName << "': " << aNumber << " / " << aString) == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2148" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "'" << rColName << "': " << aNumber << " / " << aString), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "'" << rColName << "': " << aNumber << " / " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2148" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "'" << rColName << "': " << aNumber << " / " << aString) == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2148" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "'" << rColName << "': " << aNumber << " / " << aString), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "'" << rColName << "': " << aNumber << " / " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2148" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2149 | rCalc.VarChange( rColName, aValue ); | |||
2150 | } | |||
2151 | } | |||
2152 | else | |||
2153 | { | |||
2154 | SwSbxValue aValue; | |||
2155 | aValue.PutString( aString ); | |||
2156 | aValue.SetDBvalue( true ); | |||
2157 | SAL_INFO( "sw.ui", "'" << rColName << "': " << aString )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sw.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "'" << rColName << "': " << aString ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2157" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "'" << rColName << "': " << aString), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "'" << rColName << "': " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2157" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "'" << rColName << "': " << aString ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2157" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "'" << rColName << "': " << aString), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "'" << rColName << "': " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2157" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2158 | rCalc.VarChange( rColName, aValue ); | |||
2159 | } | |||
2160 | } | |||
2161 | } | |||
2162 | ||||
2163 | return true; | |||
2164 | } | |||
2165 | ||||
2166 | void SwDBManager::ToNextRecord( | |||
2167 | const OUString& rDataSource, const OUString& rCommand) | |||
2168 | { | |||
2169 | SwDSParam* pFound = nullptr; | |||
2170 | if(m_pImpl->pMergeData && | |||
2171 | rDataSource == m_pImpl->pMergeData->sDataSource && | |||
2172 | rCommand == m_pImpl->pMergeData->sCommand) | |||
2173 | { | |||
2174 | pFound = m_pImpl->pMergeData.get(); | |||
2175 | } | |||
2176 | else | |||
2177 | { | |||
2178 | SwDBData aData; | |||
2179 | aData.sDataSource = rDataSource; | |||
2180 | aData.sCommand = rCommand; | |||
2181 | aData.nCommandType = -1; | |||
2182 | pFound = FindDSData(aData, false); | |||
2183 | } | |||
2184 | lcl_ToNextRecord( pFound ); | |||
2185 | } | |||
2186 | ||||
2187 | static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action ) | |||
2188 | { | |||
2189 | bool bRet = true; | |||
2190 | ||||
2191 | assert( SwDBNextRecord::NEXT == action ||(static_cast <bool> (SwDBNextRecord::NEXT == action || ( SwDBNextRecord::FIRST == action && pParam)) ? void (0 ) : __assert_fail ("SwDBNextRecord::NEXT == action || (SwDBNextRecord::FIRST == action && pParam)" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2192, __extension__ __PRETTY_FUNCTION__)) | |||
2192 | (SwDBNextRecord::FIRST == action && pParam) )(static_cast <bool> (SwDBNextRecord::NEXT == action || ( SwDBNextRecord::FIRST == action && pParam)) ? void (0 ) : __assert_fail ("SwDBNextRecord::NEXT == action || (SwDBNextRecord::FIRST == action && pParam)" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2192, __extension__ __PRETTY_FUNCTION__)); | |||
2193 | if( nullptr == pParam ) | |||
2194 | return false; | |||
2195 | ||||
2196 | if( action == SwDBNextRecord::FIRST ) | |||
2197 | { | |||
2198 | pParam->nSelectionIndex = 0; | |||
2199 | pParam->bEndOfDB = false; | |||
2200 | } | |||
2201 | ||||
2202 | if( !pParam->HasValidRecord() ) | |||
2203 | return false; | |||
2204 | ||||
2205 | try | |||
2206 | { | |||
2207 | if( pParam->aSelection.hasElements() ) | |||
2208 | { | |||
2209 | if( pParam->nSelectionIndex >= pParam->aSelection.getLength() ) | |||
2210 | pParam->bEndOfDB = true; | |||
2211 | else | |||
2212 | { | |||
2213 | sal_Int32 nPos = 0; | |||
2214 | pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos; | |||
2215 | pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos ); | |||
2216 | } | |||
2217 | } | |||
2218 | else if( action == SwDBNextRecord::FIRST ) | |||
2219 | { | |||
2220 | pParam->bEndOfDB = !pParam->xResultSet->first(); | |||
2221 | } | |||
2222 | else | |||
2223 | { | |||
2224 | sal_Int32 nBefore = pParam->xResultSet->getRow(); | |||
2225 | pParam->bEndOfDB = !pParam->xResultSet->next(); | |||
2226 | if( !pParam->bEndOfDB && nBefore == pParam->xResultSet->getRow() ) | |||
2227 | { | |||
2228 | // next returned true but it didn't move | |||
2229 | ::dbtools::throwFunctionSequenceException( pParam->xResultSet ); | |||
2230 | } | |||
2231 | } | |||
2232 | ||||
2233 | ++pParam->nSelectionIndex; | |||
2234 | bRet = !pParam->bEndOfDB; | |||
2235 | } | |||
2236 | catch( const uno::Exception & ) | |||
2237 | { | |||
2238 | // we allow merging with empty databases, so don't warn on init | |||
2239 | TOOLS_WARN_EXCEPTION_IF(action == SwDBNextRecord::NEXT,do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true && (action == SwDBNextRecord::NEXT )) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false) | |||
2240 | "sw.mailmerge", "exception in ToNextRecord()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true && (action == SwDBNextRecord::NEXT )) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "exception in ToNextRecord()" << " " << exceptionToString(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2240" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
2241 | pParam->bEndOfDB = true; | |||
2242 | bRet = false; | |||
2243 | } | |||
2244 | return bRet; | |||
2245 | } | |||
2246 | ||||
2247 | // synchronized labels contain a next record field at their end | |||
2248 | // to assure that the next page can be created in mail merge | |||
2249 | // the cursor position must be validated | |||
2250 | bool SwDBManager::IsValidMergeRecord() const | |||
2251 | { | |||
2252 | return( m_pImpl->pMergeData && m_pImpl->pMergeData->HasValidRecord() ); | |||
2253 | } | |||
2254 | ||||
2255 | sal_uInt32 SwDBManager::GetSelectedRecordId() | |||
2256 | { | |||
2257 | sal_uInt32 nRet = 0; | |||
2258 | assert( m_pImpl->pMergeData &&(static_cast <bool> (m_pImpl->pMergeData && m_pImpl ->pMergeData->xResultSet.is() && "no data source in merge" ) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2259, __extension__ __PRETTY_FUNCTION__)) | |||
2259 | m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl ->pMergeData->xResultSet.is() && "no data source in merge" ) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2259, __extension__ __PRETTY_FUNCTION__)); | |||
2260 | if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is()) | |||
2261 | return 0; | |||
2262 | try | |||
2263 | { | |||
2264 | nRet = m_pImpl->pMergeData->xResultSet->getRow(); | |||
2265 | } | |||
2266 | catch(const uno::Exception&) | |||
2267 | { | |||
2268 | } | |||
2269 | return nRet; | |||
2270 | } | |||
2271 | ||||
2272 | bool SwDBManager::ToRecordId(sal_Int32 nSet) | |||
2273 | { | |||
2274 | assert( m_pImpl->pMergeData &&(static_cast <bool> (m_pImpl->pMergeData && m_pImpl ->pMergeData->xResultSet.is() && "no data source in merge" ) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2275, __extension__ __PRETTY_FUNCTION__)) | |||
2275 | m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl ->pMergeData->xResultSet.is() && "no data source in merge" ) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\"" , "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2275, __extension__ __PRETTY_FUNCTION__)); | |||
2276 | if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is()|| nSet < 0) | |||
2277 | return false; | |||
2278 | bool bRet = false; | |||
2279 | sal_Int32 nAbsPos = nSet; | |||
2280 | assert(nAbsPos >= 0)(static_cast <bool> (nAbsPos >= 0) ? void (0) : __assert_fail ("nAbsPos >= 0", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2280, __extension__ __PRETTY_FUNCTION__)); | |||
2281 | bRet = lcl_MoveAbsolute(m_pImpl->pMergeData.get(), nAbsPos); | |||
2282 | m_pImpl->pMergeData->bEndOfDB = !bRet; | |||
2283 | return bRet; | |||
2284 | } | |||
2285 | ||||
2286 | bool SwDBManager::OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery) | |||
2287 | { | |||
2288 | SwDBData aData; | |||
2289 | aData.sDataSource = rDataSource; | |||
2290 | aData.sCommand = rTableOrQuery; | |||
2291 | aData.nCommandType = -1; | |||
2292 | ||||
2293 | SwDSParam* pFound = FindDSData(aData, true); | |||
2294 | if(pFound->xResultSet.is()) | |||
2295 | return true; | |||
2296 | SwDSParam* pParam = FindDSConnection(rDataSource, false); | |||
2297 | if(pParam && pParam->xConnection.is()) | |||
2298 | pFound->xConnection = pParam->xConnection; | |||
2299 | if(pFound->xConnection.is()) | |||
2300 | { | |||
2301 | try | |||
2302 | { | |||
2303 | uno::Reference< sdbc::XDatabaseMetaData > xMetaData = pFound->xConnection->getMetaData(); | |||
2304 | try | |||
2305 | { | |||
2306 | pFound->bScrollable = xMetaData | |||
2307 | ->supportsResultSetType(sal_Int32(sdbc::ResultSetType::SCROLL_INSENSITIVE)); | |||
2308 | } | |||
2309 | catch(const uno::Exception&) | |||
2310 | { | |||
2311 | // DB driver may not be ODBC 3.0 compliant | |||
2312 | pFound->bScrollable = true; | |||
2313 | } | |||
2314 | pFound->xStatement = pFound->xConnection->createStatement(); | |||
2315 | OUString aQuoteChar = xMetaData->getIdentifierQuoteString(); | |||
2316 | OUString sStatement = "SELECT * FROM " + aQuoteChar + rTableOrQuery + aQuoteChar; | |||
2317 | pFound->xResultSet = pFound->xStatement->executeQuery( sStatement ); | |||
2318 | ||||
2319 | //after executeQuery the cursor must be positioned | |||
2320 | pFound->bEndOfDB = !pFound->xResultSet->next(); | |||
2321 | ++pFound->nSelectionIndex; | |||
2322 | } | |||
2323 | catch (const uno::Exception&) | |||
2324 | { | |||
2325 | pFound->xResultSet = nullptr; | |||
2326 | pFound->xStatement = nullptr; | |||
2327 | pFound->xConnection = nullptr; | |||
2328 | } | |||
2329 | } | |||
2330 | return pFound->xResultSet.is(); | |||
2331 | } | |||
2332 | ||||
2333 | uno::Reference< sdbc::XConnection> const & SwDBManager::RegisterConnection(OUString const& rDataSource) | |||
2334 | { | |||
2335 | SwDSParam* pFound = SwDBManager::FindDSConnection(rDataSource, true); | |||
2336 | uno::Reference< sdbc::XDataSource> xSource; | |||
2337 | if(!pFound->xConnection.is()) | |||
2338 | { | |||
2339 | SwView* pView = (m_pDoc && m_pDoc->GetDocShell()) ? m_pDoc->GetDocShell()->GetView() : nullptr; | |||
2340 | pFound->xConnection = SwDBManager::GetConnection(rDataSource, xSource, pView); | |||
2341 | try | |||
2342 | { | |||
2343 | uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY); | |||
2344 | if(xComponent.is()) | |||
2345 | xComponent->addEventListener(m_pImpl->m_xDisposeListener.get()); | |||
2346 | } | |||
2347 | catch(const uno::Exception&) | |||
2348 | { | |||
2349 | } | |||
2350 | } | |||
2351 | return pFound->xConnection; | |||
2352 | } | |||
2353 | ||||
2354 | sal_uInt32 SwDBManager::GetSelectedRecordId( | |||
2355 | const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType) | |||
2356 | { | |||
2357 | sal_uInt32 nRet = 0xffffffff; | |||
2358 | //check for merge data source first | |||
2359 | if(m_pImpl->pMergeData && | |||
2360 | ((rDataSource == m_pImpl->pMergeData->sDataSource && | |||
2361 | rTableOrQuery == m_pImpl->pMergeData->sCommand) || | |||
2362 | (rDataSource.isEmpty() && rTableOrQuery.isEmpty())) && | |||
2363 | (nCommandType == -1 || nCommandType == m_pImpl->pMergeData->nCommandType) && | |||
2364 | m_pImpl->pMergeData->xResultSet.is()) | |||
2365 | { | |||
2366 | nRet = GetSelectedRecordId(); | |||
2367 | } | |||
2368 | else | |||
2369 | { | |||
2370 | SwDBData aData; | |||
2371 | aData.sDataSource = rDataSource; | |||
2372 | aData.sCommand = rTableOrQuery; | |||
2373 | aData.nCommandType = nCommandType; | |||
2374 | SwDSParam* pFound = FindDSData(aData, false); | |||
2375 | if(pFound && pFound->xResultSet.is()) | |||
2376 | { | |||
2377 | try | |||
2378 | { //if a selection array is set the current row at the result set may not be set yet | |||
2379 | if(pFound->aSelection.hasElements()) | |||
2380 | { | |||
2381 | sal_Int32 nSelIndex = pFound->nSelectionIndex; | |||
2382 | if(nSelIndex >= pFound->aSelection.getLength()) | |||
2383 | nSelIndex = pFound->aSelection.getLength() -1; | |||
2384 | pFound->aSelection.getConstArray()[nSelIndex] >>= nRet; | |||
2385 | ||||
2386 | } | |||
2387 | else | |||
2388 | nRet = pFound->xResultSet->getRow(); | |||
2389 | } | |||
2390 | catch(const uno::Exception&) | |||
2391 | { | |||
2392 | } | |||
2393 | } | |||
2394 | } | |||
2395 | return nRet; | |||
2396 | } | |||
2397 | ||||
2398 | // close all data sources - after fields were updated | |||
2399 | void SwDBManager::CloseAll(bool bIncludingMerge) | |||
2400 | { | |||
2401 | //the only thing done here is to reset the selection index | |||
2402 | //all connections stay open | |||
2403 | for (auto & pParam : m_DataSourceParams) | |||
2404 | { | |||
2405 | if (bIncludingMerge || pParam.get() != m_pImpl->pMergeData.get()) | |||
2406 | { | |||
2407 | pParam->nSelectionIndex = 0; | |||
2408 | pParam->bEndOfDB = false; | |||
2409 | try | |||
2410 | { | |||
2411 | if(!m_bInMerge && pParam->xResultSet.is()) | |||
2412 | pParam->xResultSet->first(); | |||
2413 | } | |||
2414 | catch(const uno::Exception&) | |||
2415 | {} | |||
2416 | } | |||
2417 | } | |||
2418 | } | |||
2419 | ||||
2420 | SwDSParam* SwDBManager::FindDSData(const SwDBData& rData, bool bCreate) | |||
2421 | { | |||
2422 | //prefer merge data if available | |||
2423 | if(m_pImpl->pMergeData && | |||
2424 | ((rData.sDataSource == m_pImpl->pMergeData->sDataSource && | |||
2425 | rData.sCommand == m_pImpl->pMergeData->sCommand) || | |||
2426 | (rData.sDataSource.isEmpty() && rData.sCommand.isEmpty())) && | |||
2427 | (rData.nCommandType == -1 || rData.nCommandType == m_pImpl->pMergeData->nCommandType || | |||
2428 | (bCreate && m_pImpl->pMergeData->nCommandType == -1))) | |||
2429 | { | |||
2430 | return m_pImpl->pMergeData.get(); | |||
2431 | } | |||
2432 | ||||
2433 | SwDSParam* pFound = nullptr; | |||
2434 | for (size_t nPos = m_DataSourceParams.size(); nPos; nPos--) | |||
2435 | { | |||
2436 | SwDSParam* pParam = m_DataSourceParams[nPos - 1].get(); | |||
2437 | if(rData.sDataSource == pParam->sDataSource && | |||
2438 | rData.sCommand == pParam->sCommand && | |||
2439 | (rData.nCommandType == -1 || rData.nCommandType == pParam->nCommandType || | |||
2440 | (bCreate && pParam->nCommandType == -1))) | |||
2441 | { | |||
2442 | // calls from the calculator may add a connection with an invalid commandtype | |||
2443 | //later added "real" data base connections have to re-use the already available | |||
2444 | //DSData and set the correct CommandType | |||
2445 | if(bCreate && pParam->nCommandType == -1) | |||
2446 | pParam->nCommandType = rData.nCommandType; | |||
2447 | pFound = pParam; | |||
2448 | break; | |||
2449 | } | |||
2450 | } | |||
2451 | if(bCreate && !pFound) | |||
2452 | { | |||
2453 | pFound = new SwDSParam(rData); | |||
2454 | m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound)); | |||
2455 | try | |||
2456 | { | |||
2457 | uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY); | |||
2458 | if(xComponent.is()) | |||
2459 | xComponent->addEventListener(m_pImpl->m_xDisposeListener.get()); | |||
2460 | } | |||
2461 | catch(const uno::Exception&) | |||
2462 | { | |||
2463 | } | |||
2464 | } | |||
2465 | return pFound; | |||
2466 | } | |||
2467 | ||||
2468 | SwDSParam* SwDBManager::FindDSConnection(const OUString& rDataSource, bool bCreate) | |||
2469 | { | |||
2470 | //prefer merge data if available | |||
2471 | if(m_pImpl->pMergeData && rDataSource == m_pImpl->pMergeData->sDataSource ) | |||
2472 | { | |||
2473 | SetAsUsed(rDataSource); | |||
2474 | return m_pImpl->pMergeData.get(); | |||
2475 | } | |||
2476 | SwDSParam* pFound = nullptr; | |||
2477 | for (const auto & pParam : m_DataSourceParams) | |||
2478 | { | |||
2479 | if(rDataSource == pParam->sDataSource) | |||
2480 | { | |||
2481 | SetAsUsed(rDataSource); | |||
2482 | pFound = pParam.get(); | |||
2483 | break; | |||
2484 | } | |||
2485 | } | |||
2486 | if(bCreate && !pFound) | |||
2487 | { | |||
2488 | SwDBData aData; | |||
2489 | aData.sDataSource = rDataSource; | |||
2490 | pFound = new SwDSParam(aData); | |||
2491 | SetAsUsed(rDataSource); | |||
2492 | m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound)); | |||
2493 | try | |||
2494 | { | |||
2495 | uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY); | |||
2496 | if(xComponent.is()) | |||
2497 | xComponent->addEventListener(m_pImpl->m_xDisposeListener.get()); | |||
2498 | } | |||
2499 | catch(const uno::Exception&) | |||
2500 | { | |||
2501 | } | |||
2502 | } | |||
2503 | return pFound; | |||
2504 | } | |||
2505 | ||||
2506 | const SwDBData& SwDBManager::GetAddressDBName() | |||
2507 | { | |||
2508 | return SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule ::Writer)))->GetDBConfig()->GetAddressSource(); | |||
2509 | } | |||
2510 | ||||
2511 | uno::Sequence<OUString> SwDBManager::GetExistingDatabaseNames() | |||
2512 | { | |||
2513 | uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); | |||
2514 | uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext); | |||
2515 | return xDBContext->getElementNames(); | |||
2516 | } | |||
2517 | ||||
2518 | namespace sw | |||
2519 | { | |||
2520 | DBConnURIType GetDBunoType(const INetURLObject &rURL) | |||
2521 | { | |||
2522 | OUString sExt(rURL.GetFileExtension()); | |||
2523 | DBConnURIType type = DBConnURIType::UNKNOWN; | |||
2524 | ||||
2525 | if (sExt == "odb") | |||
2526 | { | |||
2527 | type = DBConnURIType::ODB; | |||
2528 | } | |||
2529 | else if (sExt.equalsIgnoreAsciiCase("sxc") | |||
2530 | || sExt.equalsIgnoreAsciiCase("ods") | |||
2531 | || sExt.equalsIgnoreAsciiCase("xls") | |||
2532 | || sExt.equalsIgnoreAsciiCase("xlsx")) | |||
2533 | { | |||
2534 | type = DBConnURIType::CALC; | |||
2535 | } | |||
2536 | else if (sExt.equalsIgnoreAsciiCase("sxw") || sExt.equalsIgnoreAsciiCase("odt") || sExt.equalsIgnoreAsciiCase("doc") || sExt.equalsIgnoreAsciiCase("docx")) | |||
2537 | { | |||
2538 | type = DBConnURIType::WRITER; | |||
2539 | } | |||
2540 | else if (sExt.equalsIgnoreAsciiCase("dbf")) | |||
2541 | { | |||
2542 | type = DBConnURIType::DBASE; | |||
2543 | } | |||
2544 | else if (sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt")) | |||
2545 | { | |||
2546 | type = DBConnURIType::FLAT; | |||
2547 | } | |||
2548 | #ifdef _WIN32 | |||
2549 | else if (sExt.equalsIgnoreAsciiCase("mdb") || sExt.equalsIgnoreAsciiCase("mde")) | |||
2550 | { | |||
2551 | type = DBConnURIType::MSJET; | |||
2552 | } | |||
2553 | else if (sExt.equalsIgnoreAsciiCase("accdb") || sExt.equalsIgnoreAsciiCase("accde")) | |||
2554 | { | |||
2555 | type = DBConnURIType::MSACE; | |||
2556 | } | |||
2557 | #endif | |||
2558 | return type; | |||
2559 | } | |||
2560 | } | |||
2561 | ||||
2562 | namespace | |||
2563 | { | |||
2564 | uno::Any GetDBunoURI(const INetURLObject &rURL, DBConnURIType& rType) | |||
2565 | { | |||
2566 | uno::Any aURLAny; | |||
2567 | ||||
2568 | if (rType == DBConnURIType::UNKNOWN) | |||
2569 | rType = GetDBunoType(rURL); | |||
2570 | ||||
2571 | switch (rType) { | |||
2572 | case DBConnURIType::UNKNOWN: | |||
2573 | case DBConnURIType::ODB: | |||
2574 | break; | |||
2575 | case DBConnURIType::CALC: | |||
2576 | { | |||
2577 | OUString sDBURL = "sdbc:calc:" + | |||
2578 | rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); | |||
2579 | aURLAny <<= sDBURL; | |||
2580 | } | |||
2581 | break; | |||
2582 | case DBConnURIType::WRITER: | |||
2583 | { | |||
2584 | OUString sDBURL = "sdbc:writer:" + | |||
2585 | rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); | |||
2586 | aURLAny <<= sDBURL; | |||
2587 | } | |||
2588 | break; | |||
2589 | case DBConnURIType::DBASE: | |||
2590 | { | |||
2591 | INetURLObject aUrlTmp(rURL); | |||
2592 | aUrlTmp.removeSegment(); | |||
2593 | aUrlTmp.removeFinalSlash(); | |||
2594 | OUString sDBURL = "sdbc:dbase:" + | |||
2595 | aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE); | |||
2596 | aURLAny <<= sDBURL; | |||
2597 | } | |||
2598 | break; | |||
2599 | case DBConnURIType::FLAT: | |||
2600 | { | |||
2601 | INetURLObject aUrlTmp(rURL); | |||
2602 | aUrlTmp.removeSegment(); | |||
2603 | aUrlTmp.removeFinalSlash(); | |||
2604 | OUString sDBURL = "sdbc:flat:" + | |||
2605 | //only the 'path' has to be added | |||
2606 | aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE); | |||
2607 | aURLAny <<= sDBURL; | |||
2608 | } | |||
2609 | break; | |||
2610 | case DBConnURIType::MSJET: | |||
2611 | #ifdef _WIN32 | |||
2612 | { | |||
2613 | OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" + rURL.PathToFileName()); | |||
2614 | aURLAny <<= sDBURL; | |||
2615 | } | |||
2616 | #endif | |||
2617 | break; | |||
2618 | case DBConnURIType::MSACE: | |||
2619 | #ifdef _WIN32 | |||
2620 | { | |||
2621 | OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=" + rURL.PathToFileName()); | |||
2622 | aURLAny <<= sDBURL; | |||
2623 | } | |||
2624 | #endif | |||
2625 | break; | |||
2626 | } | |||
2627 | return aURLAny; | |||
2628 | } | |||
2629 | ||||
2630 | /// Returns the URL of this SwDoc. | |||
2631 | OUString getOwnURL(SfxObjectShell const * pDocShell) | |||
2632 | { | |||
2633 | OUString aRet; | |||
2634 | ||||
2635 | if (!pDocShell) | |||
2636 | return aRet; | |||
2637 | ||||
2638 | const INetURLObject& rURLObject = pDocShell->GetMedium()->GetURLObject(); | |||
2639 | aRet = rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE); | |||
2640 | return aRet; | |||
2641 | } | |||
2642 | ||||
2643 | /** | |||
2644 | Loads a data source from file and registers it. | |||
2645 | ||||
2646 | In case of success it returns the registered name, otherwise an empty string. | |||
2647 | Optionally add a prefix to the registered DB name. | |||
2648 | */ | |||
2649 | OUString LoadAndRegisterDataSource_Impl(DBConnURIType type, const uno::Reference< beans::XPropertySet > *pSettings, | |||
2650 | const INetURLObject &rURL, const OUString *pDestDir, SfxObjectShell* pDocShell) | |||
2651 | { | |||
2652 | OUString sExt(rURL.GetFileExtension()); | |||
2653 | uno::Any aTableFilterAny; | |||
2654 | uno::Any aSuppressVersionsAny; | |||
2655 | uno::Any aInfoAny; | |||
2656 | bool bStore = true; | |||
2657 | OUString sFind; | |||
2658 | uno::Sequence<OUString> aFilters(1); | |||
2659 | ||||
2660 | uno::Any aURLAny = GetDBunoURI(rURL, type); | |||
2661 | switch (type) { | |||
2662 | case DBConnURIType::UNKNOWN: | |||
2663 | case DBConnURIType::CALC: | |||
2664 | case DBConnURIType::WRITER: | |||
2665 | break; | |||
2666 | case DBConnURIType::ODB: | |||
2667 | bStore = false; | |||
2668 | break; | |||
2669 | case DBConnURIType::FLAT: | |||
2670 | case DBConnURIType::DBASE: | |||
2671 | //set the filter to the file name without extension | |||
2672 | aFilters[0] = rURL.getBase(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset); | |||
2673 | aTableFilterAny <<= aFilters; | |||
2674 | break; | |||
2675 | case DBConnURIType::MSJET: | |||
2676 | case DBConnURIType::MSACE: | |||
2677 | aSuppressVersionsAny <<= true; | |||
2678 | break; | |||
2679 | } | |||
2680 | ||||
2681 | try | |||
2682 | { | |||
2683 | uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext()); | |||
2684 | uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext); | |||
2685 | ||||
2686 | OUString sNewName = rURL.getName( | |||
2687 | INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous); | |||
2688 | sal_Int32 nExtLen = sExt.getLength(); | |||
2689 | sNewName = sNewName.replaceAt(sNewName.getLength() - nExtLen - 1, nExtLen + 1, ""); | |||
2690 | ||||
2691 | //find a unique name if sNewName already exists | |||
2692 | sFind = sNewName; | |||
2693 | sal_Int32 nIndex = 0; | |||
2694 | while (xDBContext->hasByName(sFind)) | |||
2695 | sFind = sNewName + OUString::number(++nIndex); | |||
2696 | ||||
2697 | uno::Reference<uno::XInterface> xNewInstance; | |||
2698 | if (!bStore) | |||
2699 | { | |||
2700 | //odb-file | |||
2701 | uno::Any aDataSource = xDBContext->getByName(rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); | |||
2702 | aDataSource >>= xNewInstance; | |||
2703 | } | |||
2704 | else | |||
2705 | { | |||
2706 | xNewInstance = xDBContext->createInstance(); | |||
2707 | uno::Reference<beans::XPropertySet> xDataProperties(xNewInstance, uno::UNO_QUERY); | |||
2708 | ||||
2709 | if (aURLAny.hasValue()) | |||
2710 | xDataProperties->setPropertyValue("URL", aURLAny); | |||
2711 | if (aTableFilterAny.hasValue()) | |||
2712 | xDataProperties->setPropertyValue("TableFilter", aTableFilterAny); | |||
2713 | if (aSuppressVersionsAny.hasValue()) | |||
2714 | xDataProperties->setPropertyValue("SuppressVersionColumns", aSuppressVersionsAny); | |||
2715 | if (aInfoAny.hasValue()) | |||
2716 | xDataProperties->setPropertyValue("Info", aInfoAny); | |||
2717 | ||||
2718 | if (DBConnURIType::FLAT == type && pSettings) | |||
2719 | { | |||
2720 | uno::Any aSettings = xDataProperties->getPropertyValue("Settings"); | |||
2721 | uno::Reference < beans::XPropertySet > xDSSettings; | |||
2722 | aSettings >>= xDSSettings; | |||
2723 | ::comphelper::copyProperties(*pSettings, xDSSettings); | |||
2724 | xDSSettings->setPropertyValue("Extension", uno::makeAny(sExt)); | |||
2725 | } | |||
2726 | ||||
2727 | uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, uno::UNO_QUERY_THROW); | |||
2728 | uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), uno::UNO_QUERY_THROW); | |||
2729 | OUString aOwnURL = getOwnURL(pDocShell); | |||
2730 | if (aOwnURL.isEmpty()) | |||
2731 | { | |||
2732 | // Cannot embed, as embedded data source would need the URL of the parent document. | |||
2733 | OUString const sOutputExt = ".odb"; | |||
2734 | OUString sHomePath(SvtPathOptions().GetWorkPath()); | |||
2735 | utl::TempFile aTempFile(sNewName, true, &sOutputExt, pDestDir ? pDestDir : &sHomePath); | |||
2736 | const OUString& sTmpName = aTempFile.GetURL(); | |||
2737 | xStore->storeAsURL(sTmpName, uno::Sequence<beans::PropertyValue>()); | |||
2738 | } | |||
2739 | else | |||
2740 | { | |||
2741 | // Embed. | |||
2742 | OUString aStreamRelPath = "EmbeddedDatabase"; | |||
2743 | uno::Reference<embed::XStorage> xStorage = pDocShell->GetStorage(); | |||
2744 | ||||
2745 | // Refer to the sub-storage name in the document settings, so | |||
2746 | // we can load it again next time the file is imported. | |||
2747 | uno::Reference<lang::XMultiServiceFactory> xFactory(pDocShell->GetModel(), uno::UNO_QUERY); | |||
2748 | uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); | |||
2749 | xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::makeAny(aStreamRelPath)); | |||
2750 | ||||
2751 | // Store it only after setting the above property, so that only one data source gets registered. | |||
2752 | SwDBManager::StoreEmbeddedDataSource(xStore, xStorage, aStreamRelPath, aOwnURL); | |||
2753 | } | |||
2754 | } | |||
2755 | xDBContext->registerObject(sFind, xNewInstance); | |||
2756 | } | |||
2757 | catch (const uno::Exception&) | |||
2758 | { | |||
2759 | sFind.clear(); | |||
2760 | } | |||
2761 | return sFind; | |||
2762 | } | |||
2763 | ||||
2764 | // Construct vnd.sun.star.pkg:// URL | |||
2765 | OUString ConstructVndSunStarPkgUrl(const OUString& rMainURL, const OUString& rStreamRelPath) | |||
2766 | { | |||
2767 | auto xContext(comphelper::getProcessComponentContext()); | |||
2768 | auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(rMainURL); | |||
2769 | assert(xUri.is())(static_cast <bool> (xUri.is()) ? void (0) : __assert_fail ("xUri.is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2769, __extension__ __PRETTY_FUNCTION__)); | |||
2770 | xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext) | |||
2771 | ->createVndSunStarPkgUrlReference(xUri); | |||
2772 | assert(xUri.is())(static_cast <bool> (xUri.is()) ? void (0) : __assert_fail ("xUri.is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" , 2772, __extension__ __PRETTY_FUNCTION__)); | |||
2773 | return xUri->getUriReference() + "/" | |||
2774 | + INetURLObject::encode( | |||
2775 | rStreamRelPath, INetURLObject::PART_FPATH, | |||
2776 | INetURLObject::EncodeMechanism::All); | |||
2777 | } | |||
2778 | } | |||
2779 | ||||
2780 | OUString SwDBManager::LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell) | |||
2781 | { | |||
2782 | sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, pParent); | |||
2783 | uno::Reference < ui::dialogs::XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); | |||
2784 | ||||
2785 | OUString sHomePath(SvtPathOptions().GetWorkPath()); | |||
2786 | aDlgHelper.SetDisplayDirectory( sHomePath ); | |||
2787 | ||||
2788 | OUString sFilterAll(SwResId(STR_FILTER_ALLreinterpret_cast<char const *>("STR_FILTER_ALL" "\004" u8"All files" ))); | |||
2789 | OUString sFilterAllData(SwResId(STR_FILTER_ALL_DATAreinterpret_cast<char const *>("STR_FILTER_ALL_DATA" "\004" u8"Address lists(*.*)"))); | |||
2790 | OUString sFilterSXB(SwResId(STR_FILTER_SXBreinterpret_cast<char const *>("STR_FILTER_SXB" "\004" u8"%PRODUCTNAME Base (*.odb)" ))); | |||
2791 | OUString sFilterSXC(SwResId(STR_FILTER_SXCreinterpret_cast<char const *>("STR_FILTER_SXC" "\004" u8"%PRODUCTNAME Calc (*.ods;*.sxc)" ))); | |||
2792 | OUString sFilterSXW(SwResId(STR_FILTER_SXWreinterpret_cast<char const *>("STR_FILTER_SXW" "\004" u8"%PRODUCTNAME Writer (*.odt;*.sxw)" ))); | |||
2793 | OUString sFilterDBF(SwResId(STR_FILTER_DBFreinterpret_cast<char const *>("STR_FILTER_DBF" "\004" u8"dBase (*.dbf)" ))); | |||
2794 | OUString sFilterXLS(SwResId(STR_FILTER_XLSreinterpret_cast<char const *>("STR_FILTER_XLS" "\004" u8"Microsoft Excel (*.xls;*.xlsx)" ))); | |||
2795 | OUString sFilterDOC(SwResId(STR_FILTER_DOCreinterpret_cast<char const *>("STR_FILTER_DOC" "\004" u8"Microsoft Word (*.doc;*.docx)" ))); | |||
2796 | OUString sFilterTXT(SwResId(STR_FILTER_TXTreinterpret_cast<char const *>("STR_FILTER_TXT" "\004" u8"Plain text (*.txt)" ))); | |||
2797 | OUString sFilterCSV(SwResId(STR_FILTER_CSVreinterpret_cast<char const *>("STR_FILTER_CSV" "\004" u8"Text Comma Separated (*.csv)" ))); | |||
2798 | #ifdef _WIN32 | |||
2799 | OUString sFilterMDB(SwResId(STR_FILTER_MDBreinterpret_cast<char const *>("STR_FILTER_MDB" "\004" u8"Microsoft Access (*.mdb;*.mde)" ))); | |||
2800 | OUString sFilterACCDB(SwResId(STR_FILTER_ACCDBreinterpret_cast<char const *>("STR_FILTER_ACCDB" "\004" u8"Microsoft Access 2007 (*.accdb,*.accde)"))); | |||
2801 | #endif | |||
2802 | xFP->appendFilter( sFilterAll, "*" ); | |||
2803 | xFP->appendFilter( sFilterAllData, "*.ods;*.sxc;*.odt;*.sxw;*.dbf;*.xls;*.xlsx;*.doc;*.docx;*.txt;*.csv"); | |||
2804 | ||||
2805 | xFP->appendFilter( sFilterSXB, "*.odb" ); | |||
2806 | xFP->appendFilter( sFilterSXC, "*.ods;*.sxc" ); | |||
2807 | xFP->appendFilter( sFilterSXW, "*.odt;*.sxw" ); | |||
2808 | xFP->appendFilter( sFilterDBF, "*.dbf" ); | |||
2809 | xFP->appendFilter( sFilterXLS, "*.xls;*.xlsx" ); | |||
2810 | xFP->appendFilter( sFilterDOC, "*.doc;*.docx" ); | |||
2811 | xFP->appendFilter( sFilterTXT, "*.txt" ); | |||
2812 | xFP->appendFilter( sFilterCSV, "*.csv" ); | |||
2813 | #ifdef _WIN32 | |||
2814 | xFP->appendFilter(sFilterMDB, "*.mdb;*.mde"); | |||
2815 | xFP->appendFilter(sFilterACCDB, "*.accdb;*.accde"); | |||
2816 | #endif | |||
2817 | ||||
2818 | xFP->setCurrentFilter( sFilterAll ) ; | |||
2819 | OUString sFind; | |||
2820 | if( ERRCODE_NONEErrCode(0) == aDlgHelper.Execute() ) | |||
2821 | { | |||
2822 | uno::Reference< beans::XPropertySet > aSettings; | |||
2823 | const INetURLObject aURL( xFP->getSelectedFiles().getConstArray()[0] ); | |||
2824 | const DBConnURIType type = GetDBunoType( aURL ); | |||
2825 | ||||
2826 | if( DBConnURIType::FLAT == type ) | |||
2827 | { | |||
2828 | uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); | |||
2829 | uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext); | |||
2830 | if( xSettingsDlg->execute() ) | |||
2831 | aSettings.set( uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ) ); | |||
2832 | } | |||
2833 | sFind = LoadAndRegisterDataSource_Impl( type, DBConnURIType::FLAT == type ? &aSettings : nullptr, aURL, nullptr, pDocShell ); | |||
2834 | ||||
2835 | m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(pDocShell, sFind)); | |||
2836 | } | |||
2837 | return sFind; | |||
2838 | } | |||
2839 | ||||
2840 | void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>& xStorable, | |||
2841 | const uno::Reference<embed::XStorage>& xStorage, | |||
2842 | const OUString& rStreamRelPath, | |||
2843 | const OUString& rOwnURL, bool bCopyTo) | |||
2844 | { | |||
2845 | // Construct vnd.sun.star.pkg:// URL for later loading, and TargetStorage/StreamRelPath for storing. | |||
2846 | OUString const sTmpName = ConstructVndSunStarPkgUrl(rOwnURL, rStreamRelPath); | |||
2847 | ||||
2848 | uno::Sequence<beans::PropertyValue> aSequence = comphelper::InitPropertySequence( | |||
2849 | { | |||
2850 | {"TargetStorage", uno::makeAny(xStorage)}, | |||
2851 | {"StreamRelPath", uno::makeAny(rStreamRelPath)}, | |||
2852 | {"BaseURI", uno::makeAny(rOwnURL)} | |||
2853 | }); | |||
2854 | if (bCopyTo) | |||
2855 | xStorable->storeToURL(sTmpName, aSequence); | |||
2856 | else | |||
2857 | xStorable->storeAsURL(sTmpName, aSequence); | |||
2858 | } | |||
2859 | ||||
2860 | OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pDestDir) | |||
2861 | { | |||
2862 | return LoadAndRegisterDataSource_Impl( DBConnURIType::UNKNOWN, nullptr, INetURLObject(rURI), pDestDir, nullptr ); | |||
2863 | } | |||
2864 | ||||
2865 | namespace | |||
2866 | { | |||
2867 | // tdf#117824 switch the embedded database away from using its current storage and point it to temporary storage | |||
2868 | // which allows the original storage to be deleted | |||
2869 | void switchEmbeddedDatabaseStorage(const uno::Reference<sdb::XDatabaseContext>& rDatabaseContext, const OUString& rName) | |||
2870 | { | |||
2871 | uno::Reference<sdb::XDocumentDataSource> xDS(rDatabaseContext->getByName(rName), uno::UNO_QUERY); | |||
2872 | if (!xDS) | |||
2873 | return; | |||
2874 | uno::Reference<document::XStorageBasedDocument> xStorageDoc(xDS->getDatabaseDocument(), uno::UNO_QUERY); | |||
2875 | if (!xStorageDoc) | |||
2876 | return; | |||
2877 | xStorageDoc->switchToStorage(comphelper::OStorageHelper::GetTemporaryStorage()); | |||
2878 | } | |||
2879 | } | |||
2880 | ||||
2881 | void SwDBManager::RevokeDataSource(const OUString& rName) | |||
2882 | { | |||
2883 | uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext()); | |||
2884 | if (xDatabaseContext->hasByName(rName)) | |||
2885 | { | |||
2886 | switchEmbeddedDatabaseStorage(xDatabaseContext, rName); | |||
2887 | xDatabaseContext->revokeObject(rName); | |||
2888 | } | |||
2889 | } | |||
2890 | ||||
2891 | void SwDBManager::LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell) | |||
2892 | { | |||
2893 | uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext()); | |||
2894 | ||||
2895 | OUString sDataSource = rData.sDataSource; | |||
2896 | ||||
2897 | // Fallback, just in case the document would contain an embedded data source, but no DB fields. | |||
2898 | if (sDataSource.isEmpty()) | |||
2899 | sDataSource = "EmbeddedDatabase"; | |||
2900 | ||||
2901 | SwDBManager::RevokeDataSource( sDataSource ); | |||
2902 | ||||
2903 | // Encode the stream name and the real path into a single URL. | |||
2904 | const INetURLObject& rURLObject = rDocShell.GetMedium()->GetURLObject(); | |||
2905 | OUString const aURL = ConstructVndSunStarPkgUrl( | |||
2906 | rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE), | |||
2907 | m_sEmbeddedName); | |||
2908 | ||||
2909 | uno::Reference<uno::XInterface> xDataSource(xDatabaseContext->getByName(aURL), uno::UNO_QUERY); | |||
2910 | xDatabaseContext->registerObject( sDataSource, xDataSource ); | |||
2911 | ||||
2912 | // temp file - don't remember connection | |||
2913 | if (rData.sDataSource.isEmpty()) | |||
2914 | m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(nullptr, sDataSource)); | |||
2915 | } | |||
2916 | ||||
2917 | void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh, | |||
2918 | const uno::Sequence<beans::PropertyValue>& rProperties) | |||
2919 | { | |||
2920 | //prevent second call | |||
2921 | if(m_pImpl->pMergeDialog) | |||
2922 | return ; | |||
2923 | OUString sDataSource, sDataTableOrQuery; | |||
2924 | uno::Sequence<uno::Any> aSelection; | |||
2925 | ||||
2926 | sal_Int32 nCmdType = sdb::CommandType::TABLE; | |||
2927 | uno::Reference< sdbc::XConnection> xConnection; | |||
2928 | ||||
2929 | svx::ODataAccessDescriptor aDescriptor(rProperties); | |||
2930 | sDataSource = aDescriptor.getDataSource(); | |||
2931 | OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::Command] >>= sDataTableOrQuery)do { if (!(aDescriptor[svx::DataAccessDescriptorProperty::Command ] >>= sDataTableOrQuery)) do { if (true && (!(0 ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2931" ": "), "OSL_ASSERT: %s", "0"); } } while (false); } while (0); | |||
2932 | OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= nCmdType)do { if (!(aDescriptor[svx::DataAccessDescriptorProperty::CommandType ] >>= nCmdType)) do { if (true && (!(0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2932" ": "), "OSL_ASSERT: %s", "0"); } } while (false); } while (0); | |||
2933 | ||||
2934 | if ( aDescriptor.has(svx::DataAccessDescriptorProperty::Selection) ) | |||
2935 | aDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection; | |||
2936 | if ( aDescriptor.has(svx::DataAccessDescriptorProperty::Connection) ) | |||
2937 | aDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection; | |||
2938 | ||||
2939 | if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty()) | |||
2940 | { | |||
2941 | OSL_FAIL("PropertyValues missing or unset")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "2941" ": "), "%s", "PropertyValues missing or unset"); } } while (false); | |||
2942 | return; | |||
2943 | } | |||
2944 | ||||
2945 | //always create a connection for the dialog and dispose it after the dialog has been closed | |||
2946 | SwDSParam* pFound = nullptr; | |||
2947 | if(!xConnection.is()) | |||
2948 | { | |||
2949 | xConnection = SwDBManager::RegisterConnection(sDataSource); | |||
2950 | pFound = FindDSConnection(sDataSource, true); | |||
2951 | } | |||
2952 | SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); | |||
2953 | m_pImpl->pMergeDialog = pFact->CreateMailMergeDlg(rSh.GetView().GetViewFrame()->GetWindow().GetFrameWeld(), rSh, | |||
2954 | sDataSource, | |||
2955 | sDataTableOrQuery, | |||
2956 | nCmdType, | |||
2957 | xConnection); | |||
2958 | if(m_pImpl->pMergeDialog->Execute() == RET_OK) | |||
2959 | { | |||
2960 | aDescriptor[svx::DataAccessDescriptorProperty::Selection] <<= m_pImpl->pMergeDialog->GetSelection(); | |||
2961 | ||||
2962 | uno::Reference<sdbc::XResultSet> xResSet = m_pImpl->pMergeDialog->GetResultSet(); | |||
2963 | if(xResSet.is()) | |||
2964 | aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet; | |||
2965 | ||||
2966 | // SfxObjectShellRef is ok, since there should be no control over the document lifetime here | |||
2967 | SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame()->GetObjectShell(); | |||
2968 | ||||
2969 | lcl_emitEvent(SfxEventHintId::SwMailMerge, STR_SW_EVENT_MAIL_MERGE1, xDocShell.get()); | |||
2970 | ||||
2971 | // prepare mail merge descriptor | |||
2972 | SwMergeDescriptor aMergeDesc( m_pImpl->pMergeDialog->GetMergeType(), rSh, aDescriptor ); | |||
2973 | aMergeDesc.sSaveToFilter = m_pImpl->pMergeDialog->GetSaveFilter(); | |||
2974 | aMergeDesc.bCreateSingleFile = m_pImpl->pMergeDialog->IsSaveSingleDoc(); | |||
2975 | aMergeDesc.bPrefixIsFilename = aMergeDesc.bCreateSingleFile; | |||
2976 | aMergeDesc.sPrefix = m_pImpl->pMergeDialog->GetTargetURL(); | |||
2977 | ||||
2978 | if(!aMergeDesc.bCreateSingleFile) | |||
2979 | { | |||
2980 | if(m_pImpl->pMergeDialog->IsGenerateFromDataBase()) | |||
2981 | aMergeDesc.sDBcolumn = m_pImpl->pMergeDialog->GetColumnName(); | |||
2982 | ||||
2983 | if(m_pImpl->pMergeDialog->IsFileEncryptedFromDataBase()) | |||
2984 | aMergeDesc.sDBPasswordColumn = m_pImpl->pMergeDialog->GetPasswordColumnName(); | |||
2985 | } | |||
2986 | ||||
2987 | Merge( aMergeDesc ); | |||
2988 | ||||
2989 | lcl_emitEvent(SfxEventHintId::SwMailMergeEnd, STR_SW_EVENT_MAIL_MERGE_END2, xDocShell.get()); | |||
2990 | ||||
2991 | // reset the cursor inside | |||
2992 | xResSet = nullptr; | |||
2993 | aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet; | |||
2994 | } | |||
2995 | if(pFound) | |||
2996 | { | |||
2997 | for (const auto & pParam : m_DataSourceParams) | |||
2998 | { | |||
2999 | if (pParam.get() == pFound) | |||
3000 | { | |||
3001 | try | |||
3002 | { | |||
3003 | uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY); | |||
3004 | if(xComp.is()) | |||
3005 | xComp->dispose(); | |||
3006 | } | |||
3007 | catch(const uno::RuntimeException&) | |||
3008 | { | |||
3009 | //may be disposed already since multiple entries may have used the same connection | |||
3010 | } | |||
3011 | break; | |||
3012 | } | |||
3013 | //pFound doesn't need to be removed/deleted - | |||
3014 | //this has been done by the SwConnectionDisposedListener_Impl already | |||
3015 | } | |||
3016 | } | |||
3017 | m_pImpl->pMergeDialog.disposeAndClear(); | |||
3018 | } | |||
3019 | ||||
3020 | void SwDBManager::InsertText(SwWrtShell& rSh, | |||
3021 | const uno::Sequence< beans::PropertyValue>& rProperties) | |||
3022 | { | |||
3023 | OUString sDataSource, sDataTableOrQuery; | |||
3024 | uno::Reference<sdbc::XResultSet> xResSet; | |||
3025 | uno::Sequence<uno::Any> aSelection; | |||
3026 | sal_Int16 nCmdType = sdb::CommandType::TABLE; | |||
3027 | uno::Reference< sdbc::XConnection> xConnection; | |||
3028 | for(const beans::PropertyValue& rValue : rProperties) | |||
| ||||
3029 | { | |||
3030 | if ( rValue.Name == "DataSourceName" ) | |||
3031 | rValue.Value >>= sDataSource; | |||
3032 | else if ( rValue.Name == "Command" ) | |||
3033 | rValue.Value >>= sDataTableOrQuery; | |||
3034 | else if ( rValue.Name == "Cursor" ) | |||
3035 | rValue.Value >>= xResSet; | |||
3036 | else if ( rValue.Name == "Selection" ) | |||
3037 | rValue.Value >>= aSelection; | |||
3038 | else if ( rValue.Name == "CommandType" ) | |||
3039 | rValue.Value >>= nCmdType; | |||
3040 | else if ( rValue.Name == "ActiveConnection" ) | |||
3041 | rValue.Value >>= xConnection; | |||
3042 | } | |||
3043 | if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty() || !xResSet.is()) | |||
3044 | { | |||
3045 | OSL_FAIL("PropertyValues missing or unset")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3045" ": "), "%s", "PropertyValues missing or unset"); } } while (false); | |||
3046 | return; | |||
3047 | } | |||
3048 | uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); | |||
3049 | uno::Reference<sdbc::XDataSource> xSource; | |||
3050 | uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY); | |||
3051 | if(xChild.is()) | |||
3052 | xSource.set(xChild->getParent(), uno::UNO_QUERY); | |||
3053 | if(!xSource.is()) | |||
3054 | xSource = dbtools::getDataSource(sDataSource, xContext); | |||
3055 | uno::Reference< sdbcx::XColumnsSupplier > xColSupp( xResSet, uno::UNO_QUERY ); | |||
3056 | SwDBData aDBData; | |||
3057 | aDBData.sDataSource = sDataSource; | |||
3058 | aDBData.sCommand = sDataTableOrQuery; | |||
3059 | aDBData.nCommandType = nCmdType; | |||
3060 | ||||
3061 | SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); | |||
3062 | ScopedVclPtr<AbstractSwInsertDBColAutoPilot> pDlg(pFact->CreateSwInsertDBColAutoPilot( rSh.GetView(), | |||
3063 | xSource, | |||
3064 | xColSupp, | |||
3065 | aDBData )); | |||
3066 | if( RET_OK != pDlg->Execute() ) | |||
3067 | return; | |||
3068 | ||||
3069 | OUString sDummy; | |||
3070 | if(!xConnection.is()) | |||
3071 | xConnection = xSource->getConnection(sDummy, sDummy); | |||
3072 | try | |||
3073 | { | |||
3074 | pDlg->DataToDoc( aSelection , xSource, xConnection, xResSet); | |||
3075 | } | |||
3076 | catch (const uno::Exception&) | |||
3077 | { | |||
3078 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3078" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "" << " " << exceptionToString (tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3078" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3078" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "" << " " << exceptionToString (tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3078" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
3079 | } | |||
3080 | } | |||
3081 | ||||
3082 | uno::Reference<sdbc::XDataSource> SwDBManager::getDataSourceAsParent(const uno::Reference< sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName) | |||
3083 | { | |||
3084 | uno::Reference<sdbc::XDataSource> xSource; | |||
3085 | try | |||
3086 | { | |||
3087 | uno::Reference<container::XChild> xChild(_xConnection, uno::UNO_QUERY); | |||
3088 | if ( xChild.is() ) | |||
3089 | xSource.set(xChild->getParent(), uno::UNO_QUERY); | |||
3090 | if ( !xSource.is() ) | |||
3091 | xSource = dbtools::getDataSource(_sDataSourceName, ::comphelper::getProcessComponentContext()); | |||
3092 | } | |||
3093 | catch (const uno::Exception&) | |||
3094 | { | |||
3095 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "getDataSourceAsParent()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "getDataSourceAsParent()" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3095" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getDataSourceAsParent()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "getDataSourceAsParent()" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3095" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "getDataSourceAsParent()" << " " << exceptionToString (tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3095" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "getDataSourceAsParent()" << " " << exceptionToString(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "getDataSourceAsParent()" << " " << exceptionToString (tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3095" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
3096 | } | |||
3097 | return xSource; | |||
3098 | } | |||
3099 | ||||
3100 | uno::Reference<sdbc::XResultSet> SwDBManager::createCursor(const OUString& _sDataSourceName, | |||
3101 | const OUString& _sCommand, | |||
3102 | sal_Int32 _nCommandType, | |||
3103 | const uno::Reference<sdbc::XConnection>& _xConnection, | |||
3104 | const SwView* pView) | |||
3105 | { | |||
3106 | uno::Reference<sdbc::XResultSet> xResultSet; | |||
3107 | try | |||
3108 | { | |||
3109 | uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); | |||
3110 | if( xMgr.is() ) | |||
3111 | { | |||
3112 | uno::Reference<uno::XInterface> xInstance = xMgr->createInstance("com.sun.star.sdb.RowSet"); | |||
3113 | uno::Reference<beans::XPropertySet> xRowSetPropSet(xInstance, uno::UNO_QUERY); | |||
3114 | if(xRowSetPropSet.is()) | |||
3115 | { | |||
3116 | xRowSetPropSet->setPropertyValue("DataSourceName", uno::makeAny(_sDataSourceName)); | |||
3117 | xRowSetPropSet->setPropertyValue("ActiveConnection", uno::makeAny(_xConnection)); | |||
3118 | xRowSetPropSet->setPropertyValue("Command", uno::makeAny(_sCommand)); | |||
3119 | xRowSetPropSet->setPropertyValue("CommandType", uno::makeAny(_nCommandType)); | |||
3120 | ||||
3121 | uno::Reference< sdb::XCompletedExecution > xRowSet(xInstance, uno::UNO_QUERY); | |||
3122 | ||||
3123 | if ( xRowSet.is() ) | |||
3124 | { | |||
3125 | weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr; | |||
3126 | uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(comphelper::getComponentContext(xMgr), pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW ); | |||
3127 | xRowSet->executeWithCompletion(xHandler); | |||
3128 | } | |||
3129 | xResultSet.set(xRowSet, uno::UNO_QUERY); | |||
3130 | } | |||
3131 | } | |||
3132 | } | |||
3133 | catch (const uno::Exception&) | |||
3134 | { | |||
3135 | TOOLS_WARN_EXCEPTION("sw.mailmerge", "Caught exception while creating a new RowSet")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Caught exception while creating a new RowSet" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3135" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Caught exception while creating a new RowSet" << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Caught exception while creating a new RowSet" << " " << exceptionToString(tools_warn_exception); ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3135" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Caught exception while creating a new RowSet" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge" ), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3135" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Caught exception while creating a new RowSet" << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Caught exception while creating a new RowSet" << " " << exceptionToString(tools_warn_exception); ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx" ":" "3135" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
3136 | } | |||
3137 | return xResultSet; | |||
3138 | } | |||
3139 | ||||
3140 | void SwDBManager::setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell) | |||
3141 | { | |||
3142 | bool bLoad = m_sEmbeddedName != rEmbeddedName && !rEmbeddedName.isEmpty(); | |||
3143 | bool bRegisterListener = m_sEmbeddedName.isEmpty() && !rEmbeddedName.isEmpty(); | |||
3144 | ||||
3145 | m_sEmbeddedName = rEmbeddedName; | |||
3146 | ||||
3147 | if (bLoad) | |||
3148 | { | |||
3149 | uno::Reference<embed::XStorage> xStorage = rDocShell.GetStorage(); | |||
3150 | // It's OK that we don't have the named sub-storage yet, in case | |||
3151 | // we're in the process of creating it. | |||
3152 | if (xStorage->hasByName(rEmbeddedName)) | |||
3153 | LoadAndRegisterEmbeddedDataSource(rDocShell.GetDoc()->GetDBData(), rDocShell); | |||
3154 | } | |||
3155 | ||||
3156 | if (bRegisterListener) | |||
3157 | // Register a remove listener, so we know when the embedded data source is removed. | |||
3158 | m_pImpl->m_xDataSourceRemovedListener = new SwDataSourceRemovedListener(*this); | |||
3159 | } | |||
3160 | ||||
3161 | const OUString& SwDBManager::getEmbeddedName() const | |||
3162 | { | |||
3163 | return m_sEmbeddedName; | |||
3164 | } | |||
3165 | ||||
3166 | SwDoc* SwDBManager::getDoc() const | |||
3167 | { | |||
3168 | return m_pDoc; | |||
3169 | } | |||
3170 | ||||
3171 | void SwDBManager::releaseRevokeListener() | |||
3172 | { | |||
3173 | if (m_pImpl->m_xDataSourceRemovedListener.is()) | |||
3174 | { | |||
3175 | m_pImpl->m_xDataSourceRemovedListener->Dispose(); | |||
3176 | m_pImpl->m_xDataSourceRemovedListener.clear(); | |||
3177 | } | |||
3178 | } | |||
3179 | ||||
3180 | SwDBManager::ConnectionDisposedListener_Impl::ConnectionDisposedListener_Impl(SwDBManager& rManager) | |||
3181 | : m_pDBManager(&rManager) | |||
3182 | { | |||
3183 | } | |||
3184 | ||||
3185 | void SwDBManager::ConnectionDisposedListener_Impl::disposing( const lang::EventObject& rSource ) | |||
3186 | { | |||
3187 | ::SolarMutexGuard aGuard; | |||
3188 | ||||
3189 | if (!m_pDBManager) return; // we're disposed too! | |||
3190 | ||||
3191 | uno::Reference<sdbc::XConnection> xSource(rSource.Source, uno::UNO_QUERY); | |||
3192 | for (size_t nPos = m_pDBManager->m_DataSourceParams.size(); nPos; nPos--) | |||
3193 | { | |||
3194 | SwDSParam* pParam = m_pDBManager->m_DataSourceParams[nPos - 1].get(); | |||
3195 | if(pParam->xConnection.is() && | |||
3196 | (xSource == pParam->xConnection)) | |||
3197 | { | |||
3198 | m_pDBManager->m_DataSourceParams.erase( | |||
3199 | m_pDBManager->m_DataSourceParams.begin() + nPos - 1); | |||
3200 | } | |||
3201 | } | |||
3202 | } | |||
3203 | ||||
3204 | std::shared_ptr<SwMailMergeConfigItem> SwDBManager::PerformMailMerge(SwView const * pView) | |||
3205 | { | |||
3206 | std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem(); | |||
3207 | if (!xConfigItem) | |||
3208 | return xConfigItem; | |||
3209 | ||||
3210 | svx::ODataAccessDescriptor aDescriptor; | |||
3211 | aDescriptor.setDataSource(xConfigItem->GetCurrentDBData().sDataSource); | |||
3212 | aDescriptor[ svx::DataAccessDescriptorProperty::Connection ] <<= xConfigItem->GetConnection().getTyped(); | |||
3213 | aDescriptor[ svx::DataAccessDescriptorProperty::Cursor ] <<= xConfigItem->GetResultSet(); | |||
3214 | aDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= xConfigItem->GetCurrentDBData().sCommand; | |||
3215 | aDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= xConfigItem->GetCurrentDBData().nCommandType; | |||
3216 | aDescriptor[ svx::DataAccessDescriptorProperty::Selection ] <<= xConfigItem->GetSelection(); | |||
3217 | ||||
3218 | SwWrtShell& rSh = pView->GetWrtShell(); | |||
3219 | xConfigItem->SetTargetView(nullptr); | |||
3220 | ||||
3221 | SwMergeDescriptor aMergeDesc(DBMGR_MERGE_SHELL, rSh, aDescriptor); | |||
3222 | aMergeDesc.pMailMergeConfigItem = xConfigItem.get(); | |||
3223 | aMergeDesc.bCreateSingleFile = true; | |||
3224 | rSh.GetDBManager()->Merge(aMergeDesc); | |||
3225 | ||||
3226 | return xConfigItem; | |||
3227 | } | |||
3228 | ||||
3229 | void SwDBManager::RevokeLastRegistrations() | |||
3230 | { | |||
3231 | if (m_aUncommittedRegistrations.empty()) | |||
3232 | return; | |||
3233 | ||||
3234 | SwView* pView = ( m_pDoc && m_pDoc->GetDocShell() ) ? m_pDoc->GetDocShell()->GetView() : nullptr; | |||
3235 | if (pView) | |||
3236 | { | |||
3237 | const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem(); | |||
3238 | if (xConfigItem) | |||
3239 | { | |||
3240 | xConfigItem->DisposeResultSet(); | |||
3241 | xConfigItem->DocumentReloaded(); | |||
3242 | } | |||
3243 | } | |||
3244 | ||||
3245 | for (auto it = m_aUncommittedRegistrations.begin(); it != m_aUncommittedRegistrations.end();) | |||
3246 | { | |||
3247 | if ((m_pDoc && it->first == m_pDoc->GetDocShell()) || it->first == nullptr) | |||
3248 | { | |||
3249 | RevokeDataSource(it->second); | |||
3250 | it = m_aUncommittedRegistrations.erase(it); | |||
3251 | } | |||
3252 | else | |||
3253 | ++it; | |||
3254 | } | |||
3255 | } | |||
3256 | ||||
3257 | void SwDBManager::CommitLastRegistrations() | |||
3258 | { | |||
3259 | for (auto aIt = m_aUncommittedRegistrations.begin(); aIt != m_aUncommittedRegistrations.end();) | |||
3260 | { | |||
3261 | if (aIt->first == m_pDoc->GetDocShell() || aIt->first == nullptr) | |||
3262 | { | |||
3263 | m_aNotUsedConnections.push_back(aIt->second); | |||
3264 | aIt = m_aUncommittedRegistrations.erase(aIt); | |||
3265 | } | |||
3266 | else | |||
3267 | aIt++; | |||
3268 | } | |||
3269 | } | |||
3270 | ||||
3271 | void SwDBManager::SetAsUsed(const OUString& rName) | |||
3272 | { | |||
3273 | auto aFound = std::find(m_aNotUsedConnections.begin(), m_aNotUsedConnections.end(), rName); | |||
3274 | if (aFound != m_aNotUsedConnections.end()) | |||
3275 | m_aNotUsedConnections.erase(aFound); | |||
3276 | } | |||
3277 | ||||
3278 | void SwDBManager::RevokeNotUsedConnections() | |||
3279 | { | |||
3280 | for (auto aIt = m_aNotUsedConnections.begin(); aIt != m_aNotUsedConnections.end();) | |||
3281 | { | |||
3282 | RevokeDataSource(*aIt); | |||
3283 | aIt = m_aNotUsedConnections.erase(aIt); | |||
3284 | } | |||
3285 | } | |||
3286 | ||||
3287 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_VCL_PTR_HXX |
21 | #define INCLUDED_VCL_PTR_HXX |
22 | |
23 | #include <sal/config.h> |
24 | |
25 | #include <rtl/ref.hxx> |
26 | |
27 | #include <utility> |
28 | #include <type_traits> |
29 | |
30 | #ifdef DBG_UTIL |
31 | #ifndef _WIN32 |
32 | #include <vcl/vclmain.hxx> |
33 | #endif |
34 | #endif |
35 | |
36 | class VclReferenceBase; |
37 | |
38 | namespace vcl::detail { |
39 | |
40 | template<typename> |
41 | constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; } |
42 | |
43 | template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase( |
44 | int (*)[sizeof(T)]) |
45 | { return std::is_base_of<VclReferenceBase, T>::value; } |
46 | |
47 | } // namespace vcl::detail |
48 | |
49 | /** |
50 | * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses. |
51 | * |
52 | * For more details on the design please see vcl/README.lifecycle |
53 | * |
54 | * @param reference_type must be a subclass of vcl::Window |
55 | */ |
56 | template <class reference_type> |
57 | class VclPtr |
58 | { |
59 | static_assert( |
60 | vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>( |
61 | nullptr), |
62 | "template argument type must be derived from VclReferenceBase"); |
63 | |
64 | ::rtl::Reference<reference_type> m_rInnerRef; |
65 | |
66 | public: |
67 | /** Constructor... |
68 | */ |
69 | VclPtr() |
70 | : m_rInnerRef() |
71 | {} |
72 | |
73 | /** Constructor... |
74 | */ |
75 | VclPtr (reference_type * pBody) |
76 | : m_rInnerRef(pBody) |
77 | {} |
78 | |
79 | /** Constructor... that doesn't take a ref. |
80 | */ |
81 | VclPtr (reference_type * pBody, __sal_NoAcquire) |
82 | : m_rInnerRef(pBody, SAL_NO_ACQUIRE) |
83 | {} |
84 | |
85 | /** Up-casting conversion constructor: Copies interface reference. |
86 | |
87 | Does not work for up-casts to ambiguous bases. For the special case of |
88 | up-casting to Reference< XInterface >, see the corresponding conversion |
89 | operator. |
90 | |
91 | @param rRef another reference |
92 | */ |
93 | template< class derived_type > |
94 | VclPtr( |
95 | const VclPtr< derived_type > & rRef, |
96 | typename std::enable_if< |
97 | std::is_base_of<reference_type, derived_type>::value, int>::type |
98 | = 0 ) |
99 | : m_rInnerRef( static_cast<reference_type*>(rRef) ) |
100 | { |
101 | } |
102 | |
103 | #if defined(DBG_UTIL) && !defined(_WIN32) |
104 | virtual ~VclPtr() |
105 | { |
106 | assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain ::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 106, __extension__ __PRETTY_FUNCTION__)); |
107 | // We can be one of the intermediate counts, but if we are the last |
108 | // VclPtr keeping this object alive, then something forgot to call dispose(). |
109 | assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef ->isDisposed() || m_rInnerRef->getRefCount() > 1) && "someone forgot to call dispose()") ? void (0) : __assert_fail ("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\"" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 110, __extension__ __PRETTY_FUNCTION__)) |
110 | && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef ->isDisposed() || m_rInnerRef->getRefCount() > 1) && "someone forgot to call dispose()") ? void (0) : __assert_fail ("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\"" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 110, __extension__ __PRETTY_FUNCTION__)); |
111 | } |
112 | VclPtr(VclPtr const &) = default; |
113 | VclPtr(VclPtr &&) = default; |
114 | VclPtr & operator =(VclPtr const &) = default; |
115 | VclPtr & operator =(VclPtr &&) = default; |
116 | #endif |
117 | |
118 | /** |
119 | * A construction helper for VclPtr. Since VclPtr types are created |
120 | * with a reference-count of one - to help fit into the existing |
121 | * code-flow; this helps us to construct them easily. |
122 | * |
123 | * For more details on the design please see vcl/README.lifecycle |
124 | * |
125 | * @tparam reference_type must be a subclass of vcl::Window |
126 | */ |
127 | template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg) |
128 | { |
129 | return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ); |
130 | } |
131 | |
132 | /** Probably most common used: handle->someBodyOp(). |
133 | */ |
134 | reference_type * operator->() const |
135 | { |
136 | return m_rInnerRef.get(); |
137 | } |
138 | |
139 | /** Get the body. Can be used instead of operator->(). |
140 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() |
141 | are the same. |
142 | */ |
143 | reference_type * get() const |
144 | { |
145 | return m_rInnerRef.get(); |
146 | } |
147 | |
148 | void set(reference_type *pBody) |
149 | { |
150 | m_rInnerRef.set(pBody); |
151 | } |
152 | |
153 | void reset(reference_type *pBody) |
154 | { |
155 | m_rInnerRef.set(pBody); |
156 | } |
157 | |
158 | /** Up-casting copy assignment operator. |
159 | |
160 | Does not work for up-casts to ambiguous bases. |
161 | |
162 | @param rRef another reference |
163 | */ |
164 | template<typename derived_type> |
165 | typename std::enable_if< |
166 | std::is_base_of<reference_type, derived_type>::value, |
167 | VclPtr &>::type |
168 | operator =(VclPtr<derived_type> const & rRef) |
169 | { |
170 | m_rInnerRef.set(rRef.get()); |
171 | return *this; |
172 | } |
173 | |
174 | VclPtr & operator =(reference_type * pBody) |
175 | { |
176 | m_rInnerRef.set(pBody); |
177 | return *this; |
178 | } |
179 | |
180 | operator reference_type * () const |
181 | { |
182 | return m_rInnerRef.get(); |
183 | } |
184 | |
185 | explicit operator bool () const |
186 | { |
187 | return m_rInnerRef.get() != nullptr; |
188 | } |
189 | |
190 | void clear() |
191 | { |
192 | m_rInnerRef.clear(); |
193 | } |
194 | |
195 | void reset() |
196 | { |
197 | m_rInnerRef.clear(); |
198 | } |
199 | |
200 | void disposeAndClear() |
201 | { |
202 | // hold it alive for the lifetime of this method |
203 | ::rtl::Reference<reference_type> aTmp(m_rInnerRef); |
204 | m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-) |
205 | if (aTmp.get()) { |
206 | aTmp->disposeOnce(); |
207 | } |
208 | } |
209 | |
210 | /** Needed to place VclPtr's into STL collection. |
211 | */ |
212 | bool operator< (const VclPtr<reference_type> & handle) const |
213 | { |
214 | return (m_rInnerRef < handle.m_rInnerRef); |
215 | } |
216 | }; // class VclPtr |
217 | |
218 | template<typename T1, typename T2> |
219 | inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
220 | return p1.get() == p2.get(); |
221 | } |
222 | |
223 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2) |
224 | { |
225 | return p1.get() == p2; |
226 | } |
227 | |
228 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) { |
229 | return p1.get() == p2; |
230 | } |
231 | |
232 | template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2) |
233 | { |
234 | return p1 == p2.get(); |
235 | } |
236 | |
237 | template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) { |
238 | return p1 == p2.get(); |
239 | } |
240 | |
241 | template<typename T1, typename T2> |
242 | inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
243 | return !(p1 == p2); |
244 | } |
245 | |
246 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2) |
247 | { |
248 | return !(p1 == p2); |
249 | } |
250 | |
251 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) { |
252 | return !(p1 == p2); |
253 | } |
254 | |
255 | template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2) |
256 | { |
257 | return !(p1 == p2); |
258 | } |
259 | |
260 | template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) { |
261 | return !(p1 == p2); |
262 | } |
263 | |
264 | /** |
265 | * A construction helper for a temporary VclPtr. Since VclPtr types |
266 | * are created with a reference-count of one - to help fit into |
267 | * the existing code-flow; this helps us to construct them easily. |
268 | * see also VclPtr::Create and ScopedVclPtr |
269 | * |
270 | * For more details on the design please see vcl/README.lifecycle |
271 | * |
272 | * @param reference_type must be a subclass of vcl::Window |
273 | */ |
274 | template <class reference_type> |
275 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type> |
276 | { |
277 | public: |
278 | template<typename... Arg> VclPtrInstance(Arg &&... arg) |
279 | : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ) |
280 | { |
281 | } |
282 | |
283 | /** |
284 | * Override and disallow this, to prevent people accidentally calling it and actually |
285 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
286 | */ |
287 | template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete; |
288 | }; |
289 | |
290 | template <class reference_type> |
291 | class ScopedVclPtr : public VclPtr<reference_type> |
292 | { |
293 | public: |
294 | /** Constructor... |
295 | */ |
296 | ScopedVclPtr() |
297 | : VclPtr<reference_type>() |
298 | {} |
299 | |
300 | /** Constructor |
301 | */ |
302 | ScopedVclPtr (reference_type * pBody) |
303 | : VclPtr<reference_type>(pBody) |
304 | {} |
305 | |
306 | /** Copy constructor... |
307 | */ |
308 | ScopedVclPtr (const VclPtr<reference_type> & handle) |
309 | : VclPtr<reference_type>(handle) |
310 | {} |
311 | |
312 | /** |
313 | Assignment that releases the last reference. |
314 | */ |
315 | void disposeAndReset(reference_type *pBody) |
316 | { |
317 | if (pBody != this->get()) { |
318 | VclPtr<reference_type>::disposeAndClear(); |
319 | VclPtr<reference_type>::set(pBody); |
320 | } |
321 | } |
322 | |
323 | /** |
324 | Assignment that releases the last reference. |
325 | */ |
326 | ScopedVclPtr<reference_type>& operator = (reference_type * pBody) |
327 | { |
328 | disposeAndReset(pBody); |
329 | return *this; |
330 | } |
331 | |
332 | /** Up-casting conversion constructor: Copies interface reference. |
333 | |
334 | Does not work for up-casts to ambiguous bases. For the special case of |
335 | up-casting to Reference< XInterface >, see the corresponding conversion |
336 | operator. |
337 | |
338 | @param rRef another reference |
339 | */ |
340 | template< class derived_type > |
341 | ScopedVclPtr( |
342 | const VclPtr< derived_type > & rRef, |
343 | typename std::enable_if< |
344 | std::is_base_of<reference_type, derived_type>::value, int>::type |
345 | = 0 ) |
346 | : VclPtr<reference_type>( rRef ) |
347 | { |
348 | } |
349 | |
350 | /** Up-casting assignment operator. |
351 | |
352 | Does not work for up-casts to ambiguous bases. |
353 | |
354 | @param rRef another VclPtr |
355 | */ |
356 | template<typename derived_type> |
357 | typename std::enable_if< |
358 | std::is_base_of<reference_type, derived_type>::value, |
359 | ScopedVclPtr &>::type |
360 | operator =(VclPtr<derived_type> const & rRef) |
361 | { |
362 | disposeAndReset(rRef.get()); |
363 | return *this; |
364 | } |
365 | |
366 | /** |
367 | * Override and disallow this, to prevent people accidentally calling it and actually |
368 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
369 | */ |
370 | template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete; |
371 | |
372 | ~ScopedVclPtr() |
373 | { |
374 | VclPtr<reference_type>::disposeAndClear(); |
375 | assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get( ) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 375, __extension__ __PRETTY_FUNCTION__)); // make sure there are no lingering references |
376 | } |
377 | |
378 | private: |
379 | // Most likely we don't want this default copy-constructor. |
380 | ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete; |
381 | // And certainly we don't want a default assignment operator. |
382 | ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete; |
383 | // And disallow reset as that doesn't call disposeAndClear on the original reference |
384 | void reset() = delete; |
385 | void reset(reference_type *pBody) = delete; |
386 | |
387 | protected: |
388 | ScopedVclPtr (reference_type * pBody, __sal_NoAcquire) |
389 | : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE) |
390 | {} |
391 | }; |
392 | |
393 | /** |
394 | * A construction helper for ScopedVclPtr. Since VclPtr types are created |
395 | * with a reference-count of one - to help fit into the existing |
396 | * code-flow; this helps us to construct them easily. |
397 | * |
398 | * For more details on the design please see vcl/README.lifecycle |
399 | * |
400 | * @param reference_type must be a subclass of vcl::Window |
401 | */ |
402 | #if defined _MSC_VER |
403 | #pragma warning(push) |
404 | #pragma warning(disable: 4521) // " multiple copy constructors specified" |
405 | #endif |
406 | template <class reference_type> |
407 | class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type> |
408 | { |
409 | public: |
410 | template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg) |
411 | : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ) |
412 | { |
413 | } |
414 | |
415 | /** |
416 | * Override and disallow this, to prevent people accidentally calling it and actually |
417 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
418 | */ |
419 | template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete; |
420 | |
421 | private: |
422 | // Prevent the above perfect forwarding ctor from hijacking (accidental) |
423 | // attempts at ScopedVclPtrInstance copy construction (where the hijacking |
424 | // would typically lead to somewhat obscure error messages); both non-const |
425 | // and const variants are needed here, as the ScopedVclPtr base class has a |
426 | // const--variant copy ctor, so the implicitly declared copy ctor for |
427 | // ScopedVclPtrInstance would also be the const variant, so non-const copy |
428 | // construction attempts would be hijacked by the perfect forwarding ctor; |
429 | // but if we only declared a non-const variant here, the const variant would |
430 | // no longer be implicitly declared (as there would already be an explicitly |
431 | // declared copy ctor), so const copy construction attempts would then be |
432 | // hijacked by the perfect forwarding ctor: |
433 | ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete; |
434 | ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete; |
435 | }; |
436 | #if defined _MSC_VER |
437 | #pragma warning(pop) |
438 | #endif |
439 | |
440 | #endif // INCLUDED_VCL_PTR_HXX |
441 | |
442 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_RTL_REF_HXX | ||||||||
21 | #define INCLUDED_RTL_REF_HXX | ||||||||
22 | |||||||||
23 | #include "sal/config.h" | ||||||||
24 | |||||||||
25 | #include <cassert> | ||||||||
26 | #include <cstddef> | ||||||||
27 | #include <functional> | ||||||||
28 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
29 | #include <type_traits> | ||||||||
30 | #endif | ||||||||
31 | |||||||||
32 | #include "sal/types.h" | ||||||||
33 | |||||||||
34 | namespace rtl | ||||||||
35 | { | ||||||||
36 | |||||||||
37 | /** Template reference class for reference type. | ||||||||
38 | */ | ||||||||
39 | template <class reference_type> | ||||||||
40 | class Reference | ||||||||
41 | { | ||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||
43 | */ | ||||||||
44 | reference_type * m_pBody; | ||||||||
45 | |||||||||
46 | |||||||||
47 | public: | ||||||||
48 | /** Constructor... | ||||||||
49 | */ | ||||||||
50 | Reference() | ||||||||
51 | : m_pBody (NULL__null) | ||||||||
52 | {} | ||||||||
53 | |||||||||
54 | |||||||||
55 | /** Constructor... | ||||||||
56 | */ | ||||||||
57 | Reference (reference_type * pBody, __sal_NoAcquire) | ||||||||
58 | : m_pBody (pBody) | ||||||||
59 | { | ||||||||
60 | } | ||||||||
61 | |||||||||
62 | /** Constructor... | ||||||||
63 | */ | ||||||||
64 | Reference (reference_type * pBody) | ||||||||
65 | : m_pBody (pBody) | ||||||||
66 | { | ||||||||
67 | if (m_pBody) | ||||||||
68 | m_pBody->acquire(); | ||||||||
69 | } | ||||||||
70 | |||||||||
71 | /** Copy constructor... | ||||||||
72 | */ | ||||||||
73 | Reference (const Reference<reference_type> & handle) | ||||||||
74 | : m_pBody (handle.m_pBody) | ||||||||
75 | { | ||||||||
76 | if (m_pBody) | ||||||||
77 | m_pBody->acquire(); | ||||||||
78 | } | ||||||||
79 | |||||||||
80 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
81 | /** Move constructor... | ||||||||
82 | */ | ||||||||
83 | Reference (Reference<reference_type> && handle) noexcept | ||||||||
84 | : m_pBody (handle.m_pBody) | ||||||||
85 | { | ||||||||
86 | handle.m_pBody = nullptr; | ||||||||
87 | } | ||||||||
88 | #endif | ||||||||
89 | |||||||||
90 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
91 | /** Up-casting conversion constructor: Copies interface reference. | ||||||||
92 | |||||||||
93 | Does not work for up-casts to ambiguous bases. | ||||||||
94 | |||||||||
95 | @param rRef another reference | ||||||||
96 | */ | ||||||||
97 | template< class derived_type > | ||||||||
98 | inline Reference( | ||||||||
99 | const Reference< derived_type > & rRef, | ||||||||
100 | std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 ) | ||||||||
101 | : m_pBody (rRef.get()) | ||||||||
102 | { | ||||||||
103 | if (m_pBody) | ||||||||
104 | m_pBody->acquire(); | ||||||||
105 | } | ||||||||
106 | #endif | ||||||||
107 | |||||||||
108 | /** Destructor... | ||||||||
109 | */ | ||||||||
110 | ~Reference() COVERITY_NOEXCEPT_FALSE | ||||||||
111 | { | ||||||||
112 | if (m_pBody
| ||||||||
113 | m_pBody->release(); | ||||||||
114 | } | ||||||||
115 | |||||||||
116 | /** Set... | ||||||||
117 | Similar to assignment. | ||||||||
118 | */ | ||||||||
119 | Reference<reference_type> & | ||||||||
120 | SAL_CALL set (reference_type * pBody) | ||||||||
121 | { | ||||||||
122 | if (pBody) | ||||||||
123 | pBody->acquire(); | ||||||||
124 | reference_type * const pOld = m_pBody; | ||||||||
125 | m_pBody = pBody; | ||||||||
126 | if (pOld) | ||||||||
127 | pOld->release(); | ||||||||
128 | return *this; | ||||||||
129 | } | ||||||||
130 | |||||||||
131 | /** Assignment. | ||||||||
132 | Unbinds this instance from its body (if bound) and | ||||||||
133 | bind it to the body represented by the handle. | ||||||||
134 | */ | ||||||||
135 | Reference<reference_type> & | ||||||||
136 | SAL_CALL operator= (const Reference<reference_type> & handle) | ||||||||
137 | { | ||||||||
138 | return set( handle.m_pBody ); | ||||||||
139 | } | ||||||||
140 | |||||||||
141 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
142 | /** Assignment. | ||||||||
143 | * Unbinds this instance from its body (if bound), | ||||||||
144 | * bind it to the body represented by the handle, and | ||||||||
145 | * set the body represented by the handle to nullptr. | ||||||||
146 | */ | ||||||||
147 | Reference<reference_type> & | ||||||||
148 | operator= (Reference<reference_type> && handle) | ||||||||
149 | { | ||||||||
150 | // self-movement guts ourself | ||||||||
151 | if (m_pBody) | ||||||||
152 | m_pBody->release(); | ||||||||
153 | m_pBody = handle.m_pBody; | ||||||||
154 | handle.m_pBody = nullptr; | ||||||||
155 | return *this; | ||||||||
156 | } | ||||||||
157 | #endif | ||||||||
158 | |||||||||
159 | /** Assignment... | ||||||||
160 | */ | ||||||||
161 | Reference<reference_type> & | ||||||||
162 | SAL_CALL operator= (reference_type * pBody) | ||||||||
163 | { | ||||||||
164 | return set( pBody ); | ||||||||
165 | } | ||||||||
166 | |||||||||
167 | /** Unbind the body from this handle. | ||||||||
168 | Note that for a handle representing a large body, | ||||||||
169 | "handle.clear().set(new body());" _might_ | ||||||||
170 | perform a little bit better than "handle.set(new body());", | ||||||||
171 | since in the second case two large objects exist in memory | ||||||||
172 | (the old body and the new body). | ||||||||
173 | */ | ||||||||
174 | Reference<reference_type> & SAL_CALL clear() | ||||||||
175 | { | ||||||||
176 | if (m_pBody) | ||||||||
177 | { | ||||||||
178 | reference_type * const pOld = m_pBody; | ||||||||
179 | m_pBody = NULL__null; | ||||||||
180 | pOld->release(); | ||||||||
181 | } | ||||||||
182 | return *this; | ||||||||
183 | } | ||||||||
184 | |||||||||
185 | |||||||||
186 | /** Get the body. Can be used instead of operator->(). | ||||||||
187 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() | ||||||||
188 | are the same. | ||||||||
189 | */ | ||||||||
190 | reference_type * SAL_CALL get() const | ||||||||
191 | { | ||||||||
192 | return m_pBody; | ||||||||
| |||||||||
193 | } | ||||||||
194 | |||||||||
195 | |||||||||
196 | /** Probably most common used: handle->someBodyOp(). | ||||||||
197 | */ | ||||||||
198 | reference_type * SAL_CALL operator->() const | ||||||||
199 | { | ||||||||
200 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 200, __extension__ __PRETTY_FUNCTION__)); | ||||||||
201 | return m_pBody; | ||||||||
202 | } | ||||||||
203 | |||||||||
204 | |||||||||
205 | /** Allows (*handle).someBodyOp(). | ||||||||
206 | */ | ||||||||
207 | reference_type & SAL_CALL operator*() const | ||||||||
208 | { | ||||||||
209 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 209, __extension__ __PRETTY_FUNCTION__)); | ||||||||
210 | return *m_pBody; | ||||||||
211 | } | ||||||||
212 | |||||||||
213 | |||||||||
214 | /** Returns True if the handle does point to a valid body. | ||||||||
215 | */ | ||||||||
216 | bool SAL_CALL is() const | ||||||||
217 | { | ||||||||
218 | return (m_pBody != NULL__null); | ||||||||
219 | } | ||||||||
220 | |||||||||
221 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
222 | /** Returns True if the handle does point to a valid body. | ||||||||
223 | */ | ||||||||
224 | explicit operator bool() const | ||||||||
225 | { | ||||||||
226 | return is(); | ||||||||
227 | } | ||||||||
228 | #endif | ||||||||
229 | |||||||||
230 | /** Returns True if this points to pBody. | ||||||||
231 | */ | ||||||||
232 | bool SAL_CALL operator== (const reference_type * pBody) const | ||||||||
233 | { | ||||||||
234 | return (m_pBody == pBody); | ||||||||
235 | } | ||||||||
236 | |||||||||
237 | |||||||||
238 | /** Returns True if handle points to the same body. | ||||||||
239 | */ | ||||||||
240 | bool | ||||||||
241 | SAL_CALL operator== (const Reference<reference_type> & handle) const | ||||||||
242 | { | ||||||||
243 | return (m_pBody == handle.m_pBody); | ||||||||
244 | } | ||||||||
245 | |||||||||
246 | |||||||||
247 | /** Needed to place References into STL collection. | ||||||||
248 | */ | ||||||||
249 | bool | ||||||||
250 | SAL_CALL operator!= (const Reference<reference_type> & handle) const | ||||||||
251 | { | ||||||||
252 | return (m_pBody != handle.m_pBody); | ||||||||
253 | } | ||||||||
254 | |||||||||
255 | |||||||||
256 | /** Needed to place References into STL collection. | ||||||||
257 | */ | ||||||||
258 | bool | ||||||||
259 | SAL_CALL operator< (const Reference<reference_type> & handle) const | ||||||||
260 | { | ||||||||
261 | return (m_pBody < handle.m_pBody); | ||||||||
262 | } | ||||||||
263 | |||||||||
264 | |||||||||
265 | /** Needed to place References into STL collection. | ||||||||
266 | */ | ||||||||
267 | bool | ||||||||
268 | SAL_CALL operator> (const Reference<reference_type> & handle) const | ||||||||
269 | { | ||||||||
270 | return (m_pBody > handle.m_pBody); | ||||||||
271 | } | ||||||||
272 | }; | ||||||||
273 | |||||||||
274 | } // namespace rtl | ||||||||
275 | |||||||||
276 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
277 | namespace std | ||||||||
278 | { | ||||||||
279 | |||||||||
280 | /// @cond INTERNAL | ||||||||
281 | /** | ||||||||
282 | Make rtl::Reference hashable by default for use in STL containers. | ||||||||
283 | |||||||||
284 | @since LibreOffice 6.3 | ||||||||
285 | */ | ||||||||
286 | template<typename T> | ||||||||
287 | struct hash<::rtl::Reference<T>> | ||||||||
288 | { | ||||||||
289 | std::size_t operator()(::rtl::Reference<T> const & s) const | ||||||||
290 | { return std::size_t(s.get()); } | ||||||||
291 | }; | ||||||||
292 | /// @endcond | ||||||||
293 | |||||||||
294 | } | ||||||||
295 | |||||||||
296 | #endif | ||||||||
297 | |||||||||
298 | #endif /* ! INCLUDED_RTL_REF_HXX */ | ||||||||
299 | |||||||||
300 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_VCL_Reference_HXX |
20 | #define INCLUDED_VCL_Reference_HXX |
21 | |
22 | #include <vcl/dllapi.h> |
23 | #include <osl/interlck.h> |
24 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
32 | void acquire() const |
33 | { |
34 | osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1); |
35 | } |
36 | |
37 | void release() const |
38 | { |
39 | if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |