File: | home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx |
Warning: | line 1524, column 17 Called C++ object pointer is null |
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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_RTL_USTRING_HXX |
21 | #define INCLUDED_RTL_USTRING_HXX |
22 | |
23 | #include "sal/config.h" |
24 | |
25 | #include <cassert> |
26 | #include <cstddef> |
27 | #include <cstdlib> |
28 | #include <limits> |
29 | #include <new> |
30 | #include <ostream> |
31 | #include <utility> |
32 | |
33 | #if defined LIBO_INTERNAL_ONLY1 |
34 | #include <string_view> |
35 | #include <type_traits> |
36 | #endif |
37 | |
38 | #include "rtl/ustring.h" |
39 | #include "rtl/string.hxx" |
40 | #include "rtl/stringutils.hxx" |
41 | #include "rtl/textenc.h" |
42 | |
43 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
44 | #include "config_global.h" |
45 | #include "rtl/stringconcat.hxx" |
46 | #endif |
47 | |
48 | #ifdef RTL_STRING_UNITTEST |
49 | extern bool rtl_string_unittest_invalid_conversion; |
50 | #endif |
51 | |
52 | // The unittest uses slightly different code to help check that the proper |
53 | // calls are made. The class is put into a different namespace to make |
54 | // sure the compiler generates a different (if generating also non-inline) |
55 | // copy of the function and does not merge them together. The class |
56 | // is "brought" into the proper rtl namespace by a typedef below. |
57 | #ifdef RTL_STRING_UNITTEST |
58 | #define rtl rtlunittest |
59 | #endif |
60 | |
61 | namespace rtl |
62 | { |
63 | |
64 | class OUStringBuffer; |
65 | |
66 | #ifdef RTL_STRING_UNITTEST |
67 | #undef rtl |
68 | #endif |
69 | |
70 | #if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
71 | /// @cond INTERNAL |
72 | |
73 | /** |
74 | A wrapper dressing a string literal as a static-refcount rtl_uString. |
75 | |
76 | This class is not part of public API and is meant to be used only in LibreOffice code. |
77 | @since LibreOffice 4.0 |
78 | */ |
79 | template<std::size_t N> class SAL_WARN_UNUSED__attribute__((warn_unused)) OUStringLiteral { |
80 | static_assert(N != 0); |
81 | static_assert(N - 1 <= std::numeric_limits<sal_Int32>::max(), "literal too long"); |
82 | |
83 | public: |
84 | #if HAVE_CPP_CONSTEVAL0 |
85 | consteval |
86 | #else |
87 | constexpr |
88 | #endif |
89 | OUStringLiteral(char16_t const (&literal)[N]) { |
90 | assertLayout(); |
91 | assert(literal[N - 1] == '\0')(static_cast <bool> (literal[N - 1] == '\0') ? void (0) : __assert_fail ("literal[N - 1] == '\\0'", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 91, __extension__ __PRETTY_FUNCTION__)); |
92 | //TODO: Use C++20 constexpr std::copy_n (P0202R3): |
93 | for (std::size_t i = 0; i != N; ++i) { |
94 | buffer[i] = literal[i]; |
95 | } |
96 | } |
97 | |
98 | constexpr sal_Int32 getLength() const { return length; } |
99 | |
100 | constexpr sal_Unicode const * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return buffer; } |
101 | |
102 | constexpr operator std::u16string_view() const { return {buffer, sal_uInt32(length)}; } |
103 | |
104 | private: |
105 | static constexpr void assertLayout() { |
106 | // These static_asserts verifying the layout compatibility with rtl_uString cannot be class |
107 | // member declarations, as offsetof requires a complete type, so defer them to here: |
108 | static_assert(offsetof(OUStringLiteral, refCount)__builtin_offsetof(OUStringLiteral, refCount) == offsetof(rtl_uString, refCount)__builtin_offsetof(rtl_uString, refCount)); |
109 | static_assert(std::is_same_v<decltype(refCount), decltype(rtl_uString::refCount)>); |
110 | static_assert(offsetof(OUStringLiteral, length)__builtin_offsetof(OUStringLiteral, length) == offsetof(rtl_uString, length)__builtin_offsetof(rtl_uString, length)); |
111 | static_assert(std::is_same_v<decltype(length), decltype(rtl_uString::length)>); |
112 | static_assert(offsetof(OUStringLiteral, buffer)__builtin_offsetof(OUStringLiteral, buffer) == offsetof(rtl_uString, buffer)__builtin_offsetof(rtl_uString, buffer)); |
113 | static_assert( |
114 | std::is_same_v< |
115 | std::remove_extent_t<decltype(buffer)>, |
116 | std::remove_extent_t<decltype(rtl_uString::buffer)>>); |
117 | } |
118 | |
119 | // Same layout as rtl_uString (include/rtl/ustring.h): |
120 | oslInterlockedCount refCount = 0x40000000; // SAL_STRING_STATIC_FLAG (sal/rtl/strimp.hxx) |
121 | sal_Int32 length = N - 1; |
122 | sal_Unicode buffer[N] = {}; //TODO: drop initialization for C++20 (P1331R2) |
123 | }; |
124 | |
125 | #if defined RTL_STRING_UNITTEST |
126 | namespace libreoffice_internal { |
127 | template<std::size_t N> struct ExceptConstCharArrayDetector<OUStringLiteral<N>> {}; |
128 | template<std::size_t N> struct ExceptCharArrayDetector<OUStringLiteral<N>> {}; |
129 | } |
130 | #endif |
131 | |
132 | /// @endcond |
133 | #endif |
134 | |
135 | /* ======================================================================= */ |
136 | |
137 | /** |
138 | This String class provides base functionality for C++ like Unicode |
139 | character array handling. The advantage of this class is that it |
140 | handles all the memory management for you - and it does it |
141 | more efficiently. If you assign a string to another string, the |
142 | data of both strings are shared (without any copy operation or |
143 | memory allocation) as long as you do not change the string. This class |
144 | also stores the length of the string, so that many operations are |
145 | faster than the C-str-functions. |
146 | |
147 | This class provides only readonly string handling. So you could create |
148 | a string and you could only query the content from this string. |
149 | It provides also functionality to change the string, but this results |
150 | in every case in a new string instance (in the most cases with a |
151 | memory allocation). You don't have functionality to change the |
152 | content of the string. If you want to change the string content, then |
153 | you should use the OStringBuffer class, which provides these |
154 | functionalities and avoids too much memory allocation. |
155 | |
156 | The design of this class is similar to the string classes in Java so |
157 | less people should have understanding problems when they use this class. |
158 | */ |
159 | |
160 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) OUString |
161 | { |
162 | public: |
163 | /// @cond INTERNAL |
164 | rtl_uString * pData; |
165 | /// @endcond |
166 | |
167 | /** |
168 | New string containing no characters. |
169 | */ |
170 | OUString() |
171 | { |
172 | pData = NULL__null; |
173 | rtl_uString_new( &pData ); |
174 | } |
175 | |
176 | /** |
177 | New string from OUString. |
178 | |
179 | @param str an OUString. |
180 | */ |
181 | OUString( const OUString & str ) |
182 | { |
183 | pData = str.pData; |
184 | rtl_uString_acquire( pData ); |
185 | } |
186 | |
187 | #if defined LIBO_INTERNAL_ONLY1 |
188 | /** |
189 | Move constructor. |
190 | |
191 | @param str an OUString. |
192 | @since LibreOffice 5.2 |
193 | */ |
194 | OUString( OUString && str ) noexcept |
195 | { |
196 | pData = str.pData; |
197 | str.pData = nullptr; |
198 | rtl_uString_new( &str.pData ); |
199 | } |
200 | #endif |
201 | |
202 | /** |
203 | New string from OUString data. |
204 | |
205 | @param str an OUString data. |
206 | */ |
207 | OUString( rtl_uString * str ) |
208 | { |
209 | pData = str; |
210 | rtl_uString_acquire( pData ); |
211 | } |
212 | |
213 | /** New OUString from OUString data without acquiring it. Takeover of ownership. |
214 | |
215 | The SAL_NO_ACQUIRE dummy parameter is only there to distinguish this |
216 | from other constructors. |
217 | |
218 | @param str |
219 | OUString data |
220 | */ |
221 | OUString( rtl_uString * str, __sal_NoAcquire ) |
222 | { pData = str; } |
223 | |
224 | /** |
225 | New string from a single Unicode character. |
226 | |
227 | @param value a Unicode character. |
228 | */ |
229 | explicit OUString( sal_Unicode value ) |
230 | : pData (NULL__null) |
231 | { |
232 | rtl_uString_newFromStr_WithLength( &pData, &value, 1 ); |
233 | } |
234 | |
235 | #if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST_CONCAT |
236 | /// @cond INTERNAL |
237 | // Catch inadvertent conversions to the above ctor (but still allow |
238 | // construction from char literals): |
239 | OUString(int) = delete; |
240 | explicit OUString(char c): |
241 | OUString(sal_Unicode(static_cast<unsigned char>(c))) |
242 | {} |
243 | /// @endcond |
244 | #endif |
245 | |
246 | #if defined LIBO_INTERNAL_ONLY1 |
247 | |
248 | template<typename T> explicit OUString( |
249 | T const & value, |
250 | typename libreoffice_internal::CharPtrDetector<T, libreoffice_internal::Dummy>::TypeUtf16 |
251 | = libreoffice_internal::Dummy()): |
252 | pData(nullptr) |
253 | { rtl_uString_newFromStr(&pData, value); } |
254 | |
255 | template<typename T> explicit OUString( |
256 | T & value, |
257 | typename |
258 | libreoffice_internal::NonConstCharArrayDetector<T, libreoffice_internal::Dummy>::TypeUtf16 |
259 | = libreoffice_internal::Dummy()): |
260 | pData(nullptr) |
261 | { rtl_uString_newFromStr(&pData, value); } |
262 | |
263 | #else |
264 | |
265 | /** |
266 | New string from a Unicode character buffer array. |
267 | |
268 | @param value a NULL-terminated Unicode character array. |
269 | */ |
270 | OUString( const sal_Unicode * value ) |
271 | { |
272 | pData = NULL__null; |
273 | rtl_uString_newFromStr( &pData, value ); |
274 | } |
275 | |
276 | #endif |
277 | |
278 | /** |
279 | New string from a Unicode character buffer array. |
280 | |
281 | @param value a Unicode character array. |
282 | @param length the number of character which should be copied. |
283 | The character array length must be greater than |
284 | or equal to this value. |
285 | */ |
286 | OUString( const sal_Unicode * value, sal_Int32 length ) |
287 | { |
288 | pData = NULL__null; |
289 | rtl_uString_newFromStr_WithLength( &pData, value, length ); |
290 | } |
291 | |
292 | /** |
293 | New string from an 8-Bit string literal that is expected to contain only |
294 | characters in the ASCII set (i.e. first 128 characters). This constructor |
295 | allows an efficient and convenient way to create OUString |
296 | instances from ASCII literals. When creating strings from data that |
297 | is not pure ASCII, it needs to be converted to OUString by explicitly |
298 | providing the encoding to use for the conversion. |
299 | |
300 | If there are any embedded \0's in the string literal, the result is undefined. |
301 | Use the overload that explicitly accepts length. |
302 | |
303 | @param literal the 8-bit ASCII string literal |
304 | |
305 | @since LibreOffice 3.6 |
306 | */ |
307 | template< typename T > |
308 | OUString( T& literal, typename libreoffice_internal::ConstCharArrayDetector< T, libreoffice_internal::Dummy >::Type = libreoffice_internal::Dummy() ) |
309 | { |
310 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 311, __extension__ __PRETTY_FUNCTION__)) |
311 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 311, __extension__ __PRETTY_FUNCTION__)); |
312 | pData = NULL__null; |
313 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { |
314 | rtl_uString_new(&pData); |
315 | } else { |
316 | rtl_uString_newFromLiteral( |
317 | &pData, |
318 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
319 | literal), |
320 | libreoffice_internal::ConstCharArrayDetector<T>::length, 0); |
321 | } |
322 | #ifdef RTL_STRING_UNITTEST |
323 | rtl_string_unittest_const_literal = true; |
324 | #endif |
325 | } |
326 | |
327 | #if defined LIBO_INTERNAL_ONLY1 |
328 | /** @overload @since LibreOffice 5.3 */ |
329 | template<typename T> OUString( |
330 | T & literal, |
331 | typename libreoffice_internal::ConstCharArrayDetector< |
332 | T, libreoffice_internal::Dummy>::TypeUtf16 |
333 | = libreoffice_internal::Dummy()): |
334 | pData(nullptr) |
335 | { |
336 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 337, __extension__ __PRETTY_FUNCTION__)) |
337 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 337, __extension__ __PRETTY_FUNCTION__)); |
338 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { |
339 | rtl_uString_new(&pData); |
340 | } else { |
341 | rtl_uString_newFromStr_WithLength( |
342 | &pData, |
343 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
344 | literal), |
345 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
346 | } |
347 | } |
348 | #endif |
349 | |
350 | #if defined LIBO_INTERNAL_ONLY1 && defined RTL_STRING_UNITTEST |
351 | /// @cond INTERNAL |
352 | /** |
353 | * Only used by unittests to detect incorrect conversions. |
354 | * @internal |
355 | */ |
356 | template< typename T > |
357 | OUString( T&, typename libreoffice_internal::ExceptConstCharArrayDetector< T >::Type = libreoffice_internal::Dummy() ) |
358 | { |
359 | pData = NULL__null; |
360 | rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage |
361 | rtl_string_unittest_invalid_conversion = true; |
362 | } |
363 | /** |
364 | * Only used by unittests to detect incorrect conversions. |
365 | * @internal |
366 | */ |
367 | template< typename T > |
368 | OUString( const T&, typename libreoffice_internal::ExceptCharArrayDetector< T >::Type = libreoffice_internal::Dummy() ) |
369 | { |
370 | pData = NULL__null; |
371 | rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage |
372 | rtl_string_unittest_invalid_conversion = true; |
373 | } |
374 | /// @endcond |
375 | #endif |
376 | |
377 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
378 | /// @cond INTERNAL |
379 | /** |
380 | New string from a string literal. |
381 | |
382 | @since LibreOffice 5.0 |
383 | */ |
384 | template<std::size_t N> OUString(OUStringLiteral<N> const & literal): |
385 | pData(const_cast<rtl_uString *>(reinterpret_cast<rtl_uString const *>(&literal))) {} |
386 | template<std::size_t N> OUString(OUStringLiteral<N> &&) = delete; |
387 | /// @endcond |
388 | #endif |
389 | |
390 | /** |
391 | New string from an 8-Bit character buffer array. |
392 | |
393 | @param value An 8-Bit character array. |
394 | @param length The number of character which should be converted. |
395 | The 8-Bit character array length must be |
396 | greater than or equal to this value. |
397 | @param encoding The text encoding from which the 8-Bit character |
398 | sequence should be converted. |
399 | @param convertFlags Flags which control the conversion. |
400 | see RTL_TEXTTOUNICODE_FLAGS_... |
401 | |
402 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs |
403 | */ |
404 | OUString( const char * value, sal_Int32 length, |
405 | rtl_TextEncoding encoding, |
406 | sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300 )) ) |
407 | { |
408 | pData = NULL__null; |
409 | rtl_string2UString( &pData, value, length, encoding, convertFlags ); |
410 | if (pData == NULL__null) { |
411 | throw std::bad_alloc(); |
412 | } |
413 | } |
414 | |
415 | /** Create a new string from an array of Unicode code points. |
416 | |
417 | @param codePoints |
418 | an array of at least codePointCount code points, which each must be in |
419 | the range from 0 to 0x10FFFF, inclusive. May be null if codePointCount |
420 | is zero. |
421 | |
422 | @param codePointCount |
423 | the non-negative number of code points. |
424 | |
425 | @exception std::bad_alloc |
426 | is thrown if either an out-of-memory condition occurs or the resulting |
427 | number of UTF-16 code units would have been larger than SAL_MAX_INT32. |
428 | |
429 | @since UDK 3.2.7 |
430 | */ |
431 | explicit OUString( |
432 | sal_uInt32 const * codePoints, sal_Int32 codePointCount): |
433 | pData(NULL__null) |
434 | { |
435 | rtl_uString_newFromCodePoints(&pData, codePoints, codePointCount); |
436 | if (pData == NULL__null) { |
437 | throw std::bad_alloc(); |
438 | } |
439 | } |
440 | |
441 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
442 | /** |
443 | @overload |
444 | @internal |
445 | */ |
446 | template< typename T1, typename T2 > |
447 | OUString( OUStringConcat< T1, T2 >&& c ) |
448 | { |
449 | const sal_Int32 l = c.length(); |
450 | pData = rtl_uString_alloc( l ); |
451 | if (l != 0) |
452 | { |
453 | sal_Unicode* end = c.addData( pData->buffer ); |
454 | pData->length = l; |
455 | *end = '\0'; |
456 | // TODO realloc in case pData->length is noticeably smaller than l? |
457 | } |
458 | } |
459 | |
460 | /** |
461 | @overload |
462 | @internal |
463 | */ |
464 | template< typename T > |
465 | OUString( OUStringNumber< T >&& n ) |
466 | : OUString( n.buf, n.length ) |
467 | {} |
468 | #endif |
469 | |
470 | #if defined LIBO_INTERNAL_ONLY1 |
471 | OUString(std::u16string_view sv) { |
472 | if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) { |
473 | throw std::bad_alloc(); |
474 | } |
475 | pData = nullptr; |
476 | rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size()); |
477 | } |
478 | #endif |
479 | |
480 | /** |
481 | Release the string data. |
482 | */ |
483 | ~OUString() |
484 | { |
485 | rtl_uString_release( pData ); |
486 | } |
487 | |
488 | /** Provides an OUString const & passing a storage pointer of an |
489 | rtl_uString * handle. |
490 | It is more convenient to use C++ OUString member functions when dealing |
491 | with rtl_uString * handles. Using this function avoids unnecessary |
492 | acquire()/release() calls for a temporary OUString object. |
493 | |
494 | @param ppHandle |
495 | pointer to storage |
496 | @return |
497 | OUString const & based on given storage |
498 | */ |
499 | static OUString const & unacquired( rtl_uString * const * ppHandle ) |
500 | { return * reinterpret_cast< OUString const * >( ppHandle ); } |
501 | |
502 | /** |
503 | Assign a new string. |
504 | |
505 | @param str an OUString. |
506 | */ |
507 | OUString & operator=( const OUString & str ) |
508 | { |
509 | rtl_uString_assign( &pData, str.pData ); |
510 | return *this; |
511 | } |
512 | |
513 | #if defined LIBO_INTERNAL_ONLY1 |
514 | /** |
515 | Move assign a new string. |
516 | |
517 | @param str an OUString. |
518 | @since LibreOffice 5.2 |
519 | */ |
520 | OUString & operator=( OUString && str ) noexcept |
521 | { |
522 | rtl_uString_release( pData ); |
523 | pData = str.pData; |
524 | str.pData = nullptr; |
525 | rtl_uString_new( &str.pData ); |
526 | return *this; |
527 | } |
528 | #endif |
529 | |
530 | /** |
531 | Assign a new string from an 8-Bit string literal that is expected to contain only |
532 | characters in the ASCII set (i.e. first 128 characters). This operator |
533 | allows an efficient and convenient way to assign OUString |
534 | instances from ASCII literals. When assigning strings from data that |
535 | is not pure ASCII, it needs to be converted to OUString by explicitly |
536 | providing the encoding to use for the conversion. |
537 | |
538 | @param literal the 8-bit ASCII string literal |
539 | |
540 | @since LibreOffice 3.6 |
541 | */ |
542 | template< typename T > |
543 | typename libreoffice_internal::ConstCharArrayDetector< T, OUString& >::Type operator=( T& literal ) |
544 | { |
545 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 546, __extension__ __PRETTY_FUNCTION__)) |
546 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 546, __extension__ __PRETTY_FUNCTION__)); |
547 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { |
548 | rtl_uString_new(&pData); |
549 | } else { |
550 | rtl_uString_newFromLiteral( |
551 | &pData, |
552 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
553 | literal), |
554 | libreoffice_internal::ConstCharArrayDetector<T>::length, 0); |
555 | } |
556 | return *this; |
557 | } |
558 | |
559 | #if defined LIBO_INTERNAL_ONLY1 |
560 | /** @overload @since LibreOffice 5.3 */ |
561 | template<typename T> |
562 | typename |
563 | libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16 |
564 | operator =(T & literal) { |
565 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { |
566 | rtl_uString_new(&pData); |
567 | } else { |
568 | rtl_uString_newFromStr_WithLength( |
569 | &pData, |
570 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
571 | literal), |
572 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
573 | } |
574 | return *this; |
575 | } |
576 | |
577 | /** @overload @since LibreOffice 5.4 */ |
578 | template<std::size_t N> OUString & operator =(OUStringLiteral<N> const & literal) { |
579 | if (literal.getLength() == 0) { |
580 | rtl_uString_new(&pData); |
581 | } else { |
582 | rtl_uString_newFromStr_WithLength(&pData, literal.getStr(), literal.getLength()); |
583 | } |
584 | return *this; |
585 | } |
586 | |
587 | template<typename T> |
588 | OUString & operator =(OUStringNumber<T> && n) { |
589 | // n.length should never be zero, so no need to add an optimization for that case |
590 | rtl_uString_newFromStr_WithLength(&pData, n.buf, n.length); |
591 | return *this; |
592 | } |
593 | |
594 | OUString & operator =(std::u16string_view sv) { |
595 | if (sv.empty()) { |
596 | rtl_uString_new(&pData); |
597 | } else { |
598 | rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size()); |
599 | } |
600 | return *this; |
601 | } |
602 | #endif |
603 | |
604 | #if defined LIBO_INTERNAL_ONLY1 |
605 | /** |
606 | Append the contents of an OUStringBuffer to this string. |
607 | |
608 | @param str an OUStringBuffer. |
609 | |
610 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs |
611 | @since LibreOffice 6.2 |
612 | */ |
613 | inline OUString & operator+=( const OUStringBuffer & str ) &; |
614 | #endif |
615 | |
616 | /** |
617 | Append a string to this string. |
618 | |
619 | @param str an OUString. |
620 | |
621 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs |
622 | */ |
623 | OUString & operator+=( const OUString & str ) |
624 | #if defined LIBO_INTERNAL_ONLY1 |
625 | & |
626 | #endif |
627 | { |
628 | return internalAppend(str.pData); |
629 | } |
630 | #if defined LIBO_INTERNAL_ONLY1 |
631 | void operator+=(OUString const &) && = delete; |
632 | #endif |
633 | |
634 | /** Append an ASCII string literal to this string. |
635 | |
636 | @param literal an 8-bit ASCII-only string literal |
637 | |
638 | @since LibreOffice 5.1 |
639 | */ |
640 | template<typename T> |
641 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type |
642 | operator +=(T & literal) |
643 | #if defined LIBO_INTERNAL_ONLY1 |
644 | & |
645 | #endif |
646 | { |
647 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 648, __extension__ __PRETTY_FUNCTION__)) |
648 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 648, __extension__ __PRETTY_FUNCTION__)); |
649 | rtl_uString_newConcatAsciiL( |
650 | &pData, pData, |
651 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
652 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
653 | return *this; |
654 | } |
655 | #if defined LIBO_INTERNAL_ONLY1 |
656 | template<typename T> |
657 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type |
658 | operator +=(T &) && = delete; |
659 | #endif |
660 | |
661 | #if defined LIBO_INTERNAL_ONLY1 |
662 | /** @overload @since LibreOffice 5.3 */ |
663 | template<typename T> |
664 | typename |
665 | libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16 |
666 | operator +=(T & literal) & { |
667 | rtl_uString_newConcatUtf16L( |
668 | &pData, pData, |
669 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
670 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
671 | return *this; |
672 | } |
673 | template<typename T> |
674 | typename |
675 | libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16 |
676 | operator +=(T &) && = delete; |
677 | |
678 | /** @overload @since LibreOffice 5.4 */ |
679 | template<std::size_t N> OUString & operator +=(OUStringLiteral<N> const & literal) & { |
680 | rtl_uString_newConcatUtf16L(&pData, pData, literal.getStr(), literal.getLength()); |
681 | return *this; |
682 | } |
683 | template<std::size_t N> void operator +=(OUStringLiteral<N> const &) && = delete; |
684 | |
685 | OUString & operator +=(std::u16string_view sv) & { |
686 | if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) { |
687 | throw std::bad_alloc(); |
688 | } |
689 | rtl_uString_newConcatUtf16L(&pData, pData, sv.data(), sv.size()); |
690 | return *this; |
691 | } |
692 | void operator +=(std::u16string_view) && = delete; |
693 | #endif |
694 | |
695 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
696 | /** |
697 | @overload |
698 | @internal |
699 | */ |
700 | template< typename T1, typename T2 > |
701 | OUString& operator+=( OUStringConcat< T1, T2 >&& c ) & { |
702 | sal_Int32 l = c.length(); |
703 | if( l == 0 ) |
704 | return *this; |
705 | l += pData->length; |
706 | rtl_uString_ensureCapacity( &pData, l ); |
707 | sal_Unicode* end = c.addData( pData->buffer + pData->length ); |
708 | *end = '\0'; |
709 | pData->length = l; |
710 | return *this; |
711 | } |
712 | template<typename T1, typename T2> void operator +=( |
713 | OUStringConcat<T1, T2> &&) && = delete; |
714 | |
715 | /** |
716 | @overload |
717 | @internal |
718 | */ |
719 | template< typename T > |
720 | OUString& operator+=( OUStringNumber< T >&& n ) & { |
721 | sal_Int32 l = n.length; |
722 | if( l == 0 ) |
723 | return *this; |
724 | l += pData->length; |
725 | rtl_uString_ensureCapacity( &pData, l ); |
726 | sal_Unicode* end = addDataHelper( pData->buffer + pData->length, n.buf, n.length ); |
727 | *end = '\0'; |
728 | pData->length = l; |
729 | return *this; |
730 | } |
731 | template<typename T> void operator +=( |
732 | OUStringNumber<T> &&) && = delete; |
733 | #endif |
734 | |
735 | /** |
736 | Clears the string, i.e, makes a zero-character string |
737 | @since LibreOffice 4.4 |
738 | */ |
739 | void clear() |
740 | { |
741 | rtl_uString_new( &pData ); |
742 | } |
743 | |
744 | /** |
745 | Returns the length of this string. |
746 | |
747 | The length is equal to the number of Unicode characters in this string. |
748 | |
749 | @return the length of the sequence of characters represented by this |
750 | object. |
751 | */ |
752 | sal_Int32 getLength() const { return pData->length; } |
753 | |
754 | /** |
755 | Checks if a string is empty. |
756 | |
757 | @return true if the string is empty; |
758 | false, otherwise. |
759 | |
760 | @since LibreOffice 3.4 |
761 | */ |
762 | bool isEmpty() const |
763 | { |
764 | return pData->length == 0; |
765 | } |
766 | |
767 | /** |
768 | Returns a pointer to the Unicode character buffer for this string. |
769 | |
770 | It isn't necessarily NULL terminated. |
771 | |
772 | @return a pointer to the Unicode characters buffer for this object. |
773 | */ |
774 | const sal_Unicode * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return pData->buffer; } |
775 | |
776 | /** |
777 | Access to individual characters. |
778 | |
779 | @param index must be non-negative and less than length. |
780 | |
781 | @return the character at the given index. |
782 | |
783 | @since LibreOffice 3.5 |
784 | */ |
785 | sal_Unicode operator [](sal_Int32 index) const { |
786 | // silence spurious -Werror=strict-overflow warnings from GCC 4.8.2 |
787 | assert(index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength()))(static_cast <bool> (index >= 0 && static_cast <sal_uInt32>(index) < static_cast<sal_uInt32>( getLength())) ? void (0) : __assert_fail ("index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength())" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 787, __extension__ __PRETTY_FUNCTION__)); |
788 | return getStr()[index]; |
789 | } |
790 | |
791 | /** |
792 | Compares two strings. |
793 | |
794 | The comparison is based on the numeric value of each character in |
795 | the strings and return a value indicating their relationship. |
796 | This function can't be used for language specific sorting. |
797 | |
798 | @param str the object to be compared. |
799 | @return 0 - if both strings are equal |
800 | < 0 - if this string is less than the string argument |
801 | > 0 - if this string is greater than the string argument |
802 | */ |
803 | sal_Int32 compareTo( const OUString & str ) const |
804 | { |
805 | return rtl_ustr_compare_WithLength( pData->buffer, pData->length, |
806 | str.pData->buffer, str.pData->length ); |
807 | } |
808 | |
809 | /** |
810 | Compares two strings with a maximum count of characters. |
811 | |
812 | The comparison is based on the numeric value of each character in |
813 | the strings and return a value indicating their relationship. |
814 | This function can't be used for language specific sorting. |
815 | |
816 | @param str the object to be compared. |
817 | @param maxLength the maximum count of characters to be compared. |
818 | @return 0 - if both strings are equal |
819 | < 0 - if this string is less than the string argument |
820 | > 0 - if this string is greater than the string argument |
821 | |
822 | @since UDK 3.2.7 |
823 | */ |
824 | sal_Int32 compareTo( const OUString & str, sal_Int32 maxLength ) const |
825 | { |
826 | return rtl_ustr_shortenedCompare_WithLength( pData->buffer, pData->length, |
827 | str.pData->buffer, str.pData->length, maxLength ); |
828 | } |
829 | |
830 | /** |
831 | Compares two strings in reverse order. |
832 | |
833 | The comparison is based on the numeric value of each character in |
834 | the strings and return a value indicating their relationship. |
835 | This function can't be used for language specific sorting. |
836 | |
837 | @param str the object to be compared. |
838 | @return 0 - if both strings are equal |
839 | < 0 - if this string is less than the string argument |
840 | > 0 - if this string is greater than the string argument |
841 | */ |
842 | #if defined LIBO_INTERNAL_ONLY1 |
843 | sal_Int32 reverseCompareTo(std::u16string_view sv) const { |
844 | return rtl_ustr_reverseCompare_WithLength( |
845 | pData->buffer, pData->length, sv.data(), sv.size()); |
846 | } |
847 | #else |
848 | sal_Int32 reverseCompareTo( const OUString & str ) const |
849 | { |
850 | return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length, |
851 | str.pData->buffer, str.pData->length ); |
852 | } |
853 | #endif |
854 | |
855 | /** |
856 | @overload |
857 | This function accepts an ASCII string literal as its argument. |
858 | @since LibreOffice 4.1 |
859 | */ |
860 | template< typename T > |
861 | typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type reverseCompareTo( T& literal ) const |
862 | { |
863 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 864, __extension__ __PRETTY_FUNCTION__)) |
864 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 864, __extension__ __PRETTY_FUNCTION__)); |
865 | return rtl_ustr_asciil_reverseCompare_WithLength( |
866 | pData->buffer, pData->length, |
867 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
868 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
869 | } |
870 | |
871 | /** |
872 | Perform a comparison of two strings. |
873 | |
874 | The result is true if and only if second string |
875 | represents the same sequence of characters as the first string. |
876 | This function can't be used for language specific comparison. |
877 | |
878 | @param str the object to be compared. |
879 | @return true if the strings are equal; |
880 | false, otherwise. |
881 | */ |
882 | bool equals( const OUString & str ) const |
883 | { |
884 | if ( pData->length != str.pData->length ) |
885 | return false; |
886 | if ( pData == str.pData ) |
887 | return true; |
888 | return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length, |
889 | str.pData->buffer, str.pData->length ) == 0; |
890 | } |
891 | |
892 | /** |
893 | Perform an ASCII lowercase comparison of two strings. |
894 | |
895 | The result is true if and only if second string |
896 | represents the same sequence of characters as the first string, |
897 | ignoring the case. |
898 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
899 | values between 97 and 122 (ASCII a-z). |
900 | This function can't be used for language specific comparison. |
901 | |
902 | @param str the object to be compared. |
903 | @return true if the strings are equal; |
904 | false, otherwise. |
905 | */ |
906 | #if defined LIBO_INTERNAL_ONLY1 |
907 | bool equalsIgnoreAsciiCase(std::u16string_view sv) const { |
908 | return |
909 | rtl_ustr_compareIgnoreAsciiCase_WithLength( |
910 | pData->buffer, pData->length, sv.data(), sv.size()) |
911 | == 0; |
912 | } |
913 | #else |
914 | bool equalsIgnoreAsciiCase( const OUString & str ) const |
915 | { |
916 | if ( pData->length != str.pData->length ) |
917 | return false; |
918 | if ( pData == str.pData ) |
919 | return true; |
920 | return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, |
921 | str.pData->buffer, str.pData->length ) == 0; |
922 | } |
923 | #endif |
924 | |
925 | /** |
926 | Perform an ASCII lowercase comparison of two strings. |
927 | |
928 | Compare the two strings with uppercase ASCII |
929 | character values between 65 and 90 (ASCII A-Z) interpreted as |
930 | values between 97 and 122 (ASCII a-z). |
931 | This function can't be used for language specific comparison. |
932 | |
933 | @param str the object to be compared. |
934 | @return 0 - if both strings are equal |
935 | < 0 - if this string is less than the string argument |
936 | > 0 - if this string is greater than the string argument |
937 | |
938 | @since LibreOffice 4.0 |
939 | */ |
940 | #if defined LIBO_INTERNAL_ONLY1 |
941 | sal_Int32 compareToIgnoreAsciiCase(std::u16string_view sv) const { |
942 | return rtl_ustr_compareIgnoreAsciiCase_WithLength( |
943 | pData->buffer, pData->length, sv.data(), sv.size()); |
944 | } |
945 | #else |
946 | sal_Int32 compareToIgnoreAsciiCase( const OUString & str ) const |
947 | { |
948 | return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, |
949 | str.pData->buffer, str.pData->length ); |
950 | } |
951 | #endif |
952 | |
953 | /** |
954 | @overload |
955 | This function accepts an ASCII string literal as its argument. |
956 | @since LibreOffice 3.6 |
957 | */ |
958 | template< typename T > |
959 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type equalsIgnoreAsciiCase( T& literal ) const |
960 | { |
961 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 962, __extension__ __PRETTY_FUNCTION__)) |
962 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 962, __extension__ __PRETTY_FUNCTION__)); |
963 | return |
964 | (pData->length |
965 | == libreoffice_internal::ConstCharArrayDetector<T>::length) |
966 | && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( |
967 | pData->buffer, pData->length, |
968 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
969 | literal)) |
970 | == 0); |
971 | } |
972 | |
973 | /** |
974 | Match against a substring appearing in this string. |
975 | |
976 | The result is true if and only if the second string appears as a substring |
977 | of this string, at the given position. |
978 | This function can't be used for language specific comparison. |
979 | |
980 | @param str the object (substring) to be compared. |
981 | @param fromIndex the index to start the comparison from. |
982 | The index must be greater than or equal to 0 |
983 | and less or equal as the string length. |
984 | @return true if str match with the characters in the string |
985 | at the given position; |
986 | false, otherwise. |
987 | */ |
988 | #if defined LIBO_INTERNAL_ONLY1 |
989 | bool match(std::u16string_view sv, sal_Int32 fromIndex = 0) const { |
990 | return |
991 | rtl_ustr_shortenedCompare_WithLength( |
992 | pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(), |
993 | sv.size()) |
994 | == 0; |
995 | } |
996 | #else |
997 | bool match( const OUString & str, sal_Int32 fromIndex = 0 ) const |
998 | { |
999 | return rtl_ustr_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, |
1000 | str.pData->buffer, str.pData->length, str.pData->length ) == 0; |
1001 | } |
1002 | #endif |
1003 | |
1004 | /** |
1005 | @overload |
1006 | This function accepts an ASCII string literal as its argument. |
1007 | @since LibreOffice 3.6 |
1008 | */ |
1009 | template< typename T > |
1010 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type match( T& literal, sal_Int32 fromIndex = 0 ) const |
1011 | { |
1012 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1013, __extension__ __PRETTY_FUNCTION__)) |
1013 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1013, __extension__ __PRETTY_FUNCTION__)); |
1014 | return |
1015 | rtl_ustr_ascii_shortenedCompare_WithLength( |
1016 | pData->buffer+fromIndex, pData->length-fromIndex, |
1017 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1018 | literal), |
1019 | libreoffice_internal::ConstCharArrayDetector<T>::length) |
1020 | == 0; |
1021 | } |
1022 | |
1023 | /** |
1024 | Match against a substring appearing in this string, ignoring the case of |
1025 | ASCII letters. |
1026 | |
1027 | The result is true if and only if the second string appears as a substring |
1028 | of this string, at the given position. |
1029 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
1030 | values between 97 and 122 (ASCII a-z). |
1031 | This function can't be used for language specific comparison. |
1032 | |
1033 | @param str the object (substring) to be compared. |
1034 | @param fromIndex the index to start the comparison from. |
1035 | The index must be greater than or equal to 0 |
1036 | and less than or equal to the string length. |
1037 | @return true if str match with the characters in the string |
1038 | at the given position; |
1039 | false, otherwise. |
1040 | */ |
1041 | #if defined LIBO_INTERNAL_ONLY1 |
1042 | bool matchIgnoreAsciiCase(std::u16string_view sv, sal_Int32 fromIndex = 0) const { |
1043 | return |
1044 | rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( |
1045 | pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(), |
1046 | sv.size()) |
1047 | == 0; |
1048 | } |
1049 | #else |
1050 | bool matchIgnoreAsciiCase( const OUString & str, sal_Int32 fromIndex = 0 ) const |
1051 | { |
1052 | return rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, |
1053 | str.pData->buffer, str.pData->length, |
1054 | str.pData->length ) == 0; |
1055 | } |
1056 | #endif |
1057 | |
1058 | /** |
1059 | @overload |
1060 | This function accepts an ASCII string literal as its argument. |
1061 | @since LibreOffice 3.6 |
1062 | */ |
1063 | template< typename T > |
1064 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type matchIgnoreAsciiCase( T& literal, sal_Int32 fromIndex = 0 ) const |
1065 | { |
1066 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1067, __extension__ __PRETTY_FUNCTION__)) |
1067 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1067, __extension__ __PRETTY_FUNCTION__)); |
1068 | return |
1069 | rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( |
1070 | pData->buffer+fromIndex, pData->length-fromIndex, |
1071 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1072 | literal), |
1073 | libreoffice_internal::ConstCharArrayDetector<T>::length) |
1074 | == 0; |
1075 | } |
1076 | |
1077 | /** |
1078 | Compares two strings. |
1079 | |
1080 | The comparison is based on the numeric value of each character in |
1081 | the strings and return a value indicating their relationship. |
1082 | Since this method is optimized for performance, the ASCII character |
1083 | values are not converted in any way. The caller has to make sure that |
1084 | all ASCII characters are in the allowed range between 0 and 127. |
1085 | The ASCII string must be NULL-terminated. |
1086 | This function can't be used for language specific sorting. |
1087 | |
1088 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1089 | @return 0 - if both strings are equal |
1090 | < 0 - if this string is less than the string argument |
1091 | > 0 - if this string is greater than the string argument |
1092 | */ |
1093 | sal_Int32 compareToAscii( const char* asciiStr ) const |
1094 | { |
1095 | return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length, asciiStr ); |
1096 | } |
1097 | |
1098 | /** |
1099 | Compares two strings with a maximum count of characters. |
1100 | |
1101 | The comparison is based on the numeric value of each character in |
1102 | the strings and return a value indicating their relationship. |
1103 | Since this method is optimized for performance, the ASCII character |
1104 | values are not converted in any way. The caller has to make sure that |
1105 | all ASCII characters are in the allowed range between 0 and 127. |
1106 | The ASCII string must be NULL-terminated. |
1107 | This function can't be used for language specific sorting. |
1108 | |
1109 | @deprecated This is a confusing overload with unexpectedly different |
1110 | semantics from the one-parameter form, so it is marked as deprecated. |
1111 | Practically all uses compare the return value against zero and can thus |
1112 | be replaced with uses of startsWith. |
1113 | |
1114 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1115 | @param maxLength the maximum count of characters to be compared. |
1116 | @return 0 - if both strings are equal |
1117 | < 0 - if this string is less than the string argument |
1118 | > 0 - if this string is greater than the string argument |
1119 | */ |
1120 | SAL_DEPRECATED(__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)" ))) |
1121 | "replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)")__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)" ))) |
1122 | sal_Int32 compareToAscii( const char * asciiStr, sal_Int32 maxLength ) const |
1123 | { |
1124 | return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer, pData->length, |
1125 | asciiStr, maxLength ); |
1126 | } |
1127 | |
1128 | /** |
1129 | Compares two strings in reverse order. |
1130 | |
1131 | This could be useful, if normally both strings start with the same |
1132 | content. The comparison is based on the numeric value of each character |
1133 | in the strings and return a value indicating their relationship. |
1134 | Since this method is optimized for performance, the ASCII character |
1135 | values are not converted in any way. The caller has to make sure that |
1136 | all ASCII characters are in the allowed range between 0 and 127. |
1137 | The ASCII string must be NULL-terminated and must be greater than |
1138 | or equal to asciiStrLength. |
1139 | This function can't be used for language specific sorting. |
1140 | |
1141 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1142 | @param asciiStrLength the length of the ascii string |
1143 | @return 0 - if both strings are equal |
1144 | < 0 - if this string is less than the string argument |
1145 | > 0 - if this string is greater than the string argument |
1146 | */ |
1147 | sal_Int32 reverseCompareToAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const |
1148 | { |
1149 | return rtl_ustr_asciil_reverseCompare_WithLength( pData->buffer, pData->length, |
1150 | asciiStr, asciiStrLength ); |
1151 | } |
1152 | |
1153 | /** |
1154 | Perform a comparison of two strings. |
1155 | |
1156 | The result is true if and only if second string |
1157 | represents the same sequence of characters as the first string. |
1158 | Since this method is optimized for performance, the ASCII character |
1159 | values are not converted in any way. The caller has to make sure that |
1160 | all ASCII characters are in the allowed range between 0 and 127. |
1161 | The ASCII string must be NULL-terminated. |
1162 | This function can't be used for language specific comparison. |
1163 | |
1164 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1165 | @return true if the strings are equal; |
1166 | false, otherwise. |
1167 | */ |
1168 | bool equalsAscii( const char* asciiStr ) const |
1169 | { |
1170 | return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length, |
1171 | asciiStr ) == 0; |
1172 | } |
1173 | |
1174 | /** |
1175 | Perform a comparison of two strings. |
1176 | |
1177 | The result is true if and only if second string |
1178 | represents the same sequence of characters as the first string. |
1179 | Since this method is optimized for performance, the ASCII character |
1180 | values are not converted in any way. The caller has to make sure that |
1181 | all ASCII characters are in the allowed range between 0 and 127. |
1182 | The ASCII string must be NULL-terminated and must be greater than |
1183 | or equal to asciiStrLength. |
1184 | This function can't be used for language specific comparison. |
1185 | |
1186 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1187 | @param asciiStrLength the length of the ascii string |
1188 | @return true if the strings are equal; |
1189 | false, otherwise. |
1190 | */ |
1191 | bool equalsAsciiL( const char* asciiStr, sal_Int32 asciiStrLength ) const |
1192 | { |
1193 | if ( pData->length != asciiStrLength ) |
1194 | return false; |
1195 | |
1196 | return rtl_ustr_asciil_reverseEquals_WithLength( |
1197 | pData->buffer, asciiStr, asciiStrLength ); |
1198 | } |
1199 | |
1200 | /** |
1201 | Perform an ASCII lowercase comparison of two strings. |
1202 | |
1203 | The result is true if and only if second string |
1204 | represents the same sequence of characters as the first string, |
1205 | ignoring the case. |
1206 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
1207 | values between 97 and 122 (ASCII a-z). |
1208 | Since this method is optimized for performance, the ASCII character |
1209 | values are not converted in any way. The caller has to make sure that |
1210 | all ASCII characters are in the allowed range between 0 and 127. |
1211 | The ASCII string must be NULL-terminated. |
1212 | This function can't be used for language specific comparison. |
1213 | |
1214 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1215 | @return true if the strings are equal; |
1216 | false, otherwise. |
1217 | */ |
1218 | bool equalsIgnoreAsciiCaseAscii( const char * asciiStr ) const |
1219 | { |
1220 | return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0; |
1221 | } |
1222 | |
1223 | /** |
1224 | Compares two ASCII strings ignoring case |
1225 | |
1226 | The comparison is based on the numeric value of each character in |
1227 | the strings and return a value indicating their relationship. |
1228 | Since this method is optimized for performance, the ASCII character |
1229 | values are not converted in any way. The caller has to make sure that |
1230 | all ASCII characters are in the allowed range between 0 and 127. |
1231 | The ASCII string must be NULL-terminated. |
1232 | This function can't be used for language specific sorting. |
1233 | |
1234 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1235 | @return 0 - if both strings are equal |
1236 | < 0 - if this string is less than the string argument |
1237 | > 0 - if this string is greater than the string argument |
1238 | |
1239 | @since LibreOffice 3.5 |
1240 | */ |
1241 | sal_Int32 compareToIgnoreAsciiCaseAscii( const char * asciiStr ) const |
1242 | { |
1243 | return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ); |
1244 | } |
1245 | |
1246 | /** |
1247 | Perform an ASCII lowercase comparison of two strings. |
1248 | |
1249 | The result is true if and only if second string |
1250 | represents the same sequence of characters as the first string, |
1251 | ignoring the case. |
1252 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
1253 | values between 97 and 122 (ASCII a-z). |
1254 | Since this method is optimized for performance, the ASCII character |
1255 | values are not converted in any way. The caller has to make sure that |
1256 | all ASCII characters are in the allowed range between 0 and 127. |
1257 | The ASCII string must be NULL-terminated and must be greater than |
1258 | or equal to asciiStrLength. |
1259 | This function can't be used for language specific comparison. |
1260 | |
1261 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1262 | @param asciiStrLength the length of the ascii string |
1263 | @return true if the strings are equal; |
1264 | false, otherwise. |
1265 | */ |
1266 | bool equalsIgnoreAsciiCaseAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const |
1267 | { |
1268 | if ( pData->length != asciiStrLength ) |
1269 | return false; |
1270 | |
1271 | return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0; |
1272 | } |
1273 | |
1274 | /** |
1275 | Match against a substring appearing in this string. |
1276 | |
1277 | The result is true if and only if the second string appears as a substring |
1278 | of this string, at the given position. |
1279 | Since this method is optimized for performance, the ASCII character |
1280 | values are not converted in any way. The caller has to make sure that |
1281 | all ASCII characters are in the allowed range between 0 and 127. |
1282 | The ASCII string must be NULL-terminated and must be greater than or |
1283 | equal to asciiStrLength. |
1284 | This function can't be used for language specific comparison. |
1285 | |
1286 | @param asciiStr the object (substring) to be compared. |
1287 | @param asciiStrLength the length of asciiStr. |
1288 | @param fromIndex the index to start the comparison from. |
1289 | The index must be greater than or equal to 0 |
1290 | and less than or equal to the string length. |
1291 | @return true if str match with the characters in the string |
1292 | at the given position; |
1293 | false, otherwise. |
1294 | */ |
1295 | bool matchAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const |
1296 | { |
1297 | return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, |
1298 | asciiStr, asciiStrLength ) == 0; |
1299 | } |
1300 | |
1301 | // This overload is left undefined, to detect calls of matchAsciiL that |
1302 | // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of |
1303 | // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit |
1304 | // platforms): |
1305 | #if SAL_TYPES_SIZEOFLONG8 == 8 |
1306 | void matchAsciiL(char const *, sal_Int32, rtl_TextEncoding) const; |
1307 | #endif |
1308 | |
1309 | /** |
1310 | Match against a substring appearing in this string, ignoring the case of |
1311 | ASCII letters. |
1312 | |
1313 | The result is true if and only if the second string appears as a substring |
1314 | of this string, at the given position. |
1315 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
1316 | values between 97 and 122 (ASCII a-z). |
1317 | Since this method is optimized for performance, the ASCII character |
1318 | values are not converted in any way. The caller has to make sure that |
1319 | all ASCII characters are in the allowed range between 0 and 127. |
1320 | The ASCII string must be NULL-terminated and must be greater than or |
1321 | equal to asciiStrLength. |
1322 | This function can't be used for language specific comparison. |
1323 | |
1324 | @param asciiStr the 8-Bit ASCII character string to be compared. |
1325 | @param asciiStrLength the length of the ascii string |
1326 | @param fromIndex the index to start the comparison from. |
1327 | The index must be greater than or equal to 0 |
1328 | and less than or equal to the string length. |
1329 | @return true if str match with the characters in the string |
1330 | at the given position; |
1331 | false, otherwise. |
1332 | */ |
1333 | bool matchIgnoreAsciiCaseAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const |
1334 | { |
1335 | return rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, |
1336 | asciiStr, asciiStrLength ) == 0; |
1337 | } |
1338 | |
1339 | // This overload is left undefined, to detect calls of |
1340 | // matchIgnoreAsciiCaseAsciiL that erroneously use |
1341 | // RTL_CONSTASCII_USTRINGPARAM instead of RTL_CONSTASCII_STRINGPARAM (but |
1342 | // would lead to ambiguities on 32 bit platforms): |
1343 | #if SAL_TYPES_SIZEOFLONG8 == 8 |
1344 | void matchIgnoreAsciiCaseAsciiL(char const *, sal_Int32, rtl_TextEncoding) |
1345 | const; |
1346 | #endif |
1347 | |
1348 | /** |
1349 | Check whether this string starts with a given substring. |
1350 | |
1351 | @param str the substring to be compared |
1352 | |
1353 | @param rest if non-null, and this function returns true, then assign a |
1354 | copy of the remainder of this string to *rest. Available since |
1355 | LibreOffice 4.2 |
1356 | |
1357 | @return true if and only if the given str appears as a substring at the |
1358 | start of this string |
1359 | |
1360 | @since LibreOffice 4.0 |
1361 | */ |
1362 | #if defined LIBO_INTERNAL_ONLY1 |
1363 | bool startsWith(std::u16string_view sv, OUString * rest = nullptr) const { |
1364 | auto const b = match(sv); |
1365 | if (b && rest != nullptr) { |
1366 | *rest = copy(sv.size()); |
1367 | } |
1368 | return b; |
1369 | } |
1370 | #else |
1371 | bool startsWith(OUString const & str, OUString * rest = NULL__null) const { |
1372 | bool b = match(str); |
1373 | if (b && rest != NULL__null) { |
1374 | *rest = copy(str.getLength()); |
1375 | } |
1376 | return b; |
1377 | } |
1378 | #endif |
1379 | |
1380 | /** |
1381 | @overload |
1382 | This function accepts an ASCII string literal as its argument. |
1383 | @since LibreOffice 4.0 |
1384 | */ |
1385 | template< typename T > |
1386 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type startsWith( |
1387 | T & literal, OUString * rest = NULL__null) const |
1388 | { |
1389 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1390, __extension__ __PRETTY_FUNCTION__)) |
1390 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1390, __extension__ __PRETTY_FUNCTION__)); |
1391 | bool b |
1392 | = (libreoffice_internal::ConstCharArrayDetector<T>::length |
1393 | <= sal_uInt32(pData->length)) |
1394 | && rtl_ustr_asciil_reverseEquals_WithLength( |
1395 | pData->buffer, |
1396 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1397 | literal), |
1398 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1399 | if (b && rest != NULL__null) { |
1400 | *rest = copy( |
1401 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1402 | } |
1403 | return b; |
1404 | } |
1405 | |
1406 | /** |
1407 | Check whether this string starts with a given string, ignoring the case of |
1408 | ASCII letters. |
1409 | |
1410 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
1411 | values between 97 and 122 (ASCII a-z). |
1412 | This function can't be used for language specific comparison. |
1413 | |
1414 | @param str the substring to be compared |
1415 | |
1416 | @param rest if non-null, and this function returns true, then assign a |
1417 | copy of the remainder of this string to *rest. Available since |
1418 | LibreOffice 4.2 |
1419 | |
1420 | @return true if and only if the given str appears as a substring at the |
1421 | start of this string, ignoring the case of ASCII letters ("A"--"Z" and |
1422 | "a"--"z") |
1423 | |
1424 | @since LibreOffice 4.0 |
1425 | */ |
1426 | #if defined LIBO_INTERNAL_ONLY1 |
1427 | bool startsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const { |
1428 | auto const b = matchIgnoreAsciiCase(sv); |
1429 | if (b && rest != nullptr) { |
1430 | *rest = copy(sv.size()); |
1431 | } |
1432 | return b; |
1433 | } |
1434 | #else |
1435 | bool startsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null) |
1436 | const |
1437 | { |
1438 | bool b = matchIgnoreAsciiCase(str); |
1439 | if (b && rest != NULL__null) { |
1440 | *rest = copy(str.getLength()); |
1441 | } |
1442 | return b; |
1443 | } |
1444 | #endif |
1445 | |
1446 | /** |
1447 | @overload |
1448 | This function accepts an ASCII string literal as its argument. |
1449 | @since LibreOffice 4.0 |
1450 | */ |
1451 | template< typename T > |
1452 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type |
1453 | startsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const |
1454 | { |
1455 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1456, __extension__ __PRETTY_FUNCTION__)) |
1456 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1456, __extension__ __PRETTY_FUNCTION__)); |
1457 | bool b |
1458 | = (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( |
1459 | pData->buffer, |
1460 | libreoffice_internal::ConstCharArrayDetector<T>::length, |
1461 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1462 | literal), |
1463 | libreoffice_internal::ConstCharArrayDetector<T>::length) |
1464 | == 0); |
1465 | if (b && rest != NULL__null) { |
1466 | *rest = copy( |
1467 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1468 | } |
1469 | return b; |
1470 | } |
1471 | |
1472 | /** |
1473 | Check whether this string ends with a given substring. |
1474 | |
1475 | @param str the substring to be compared |
1476 | |
1477 | @param rest if non-null, and this function returns true, then assign a |
1478 | copy of the remainder of this string to *rest. Available since |
1479 | LibreOffice 4.2 |
1480 | |
1481 | @return true if and only if the given str appears as a substring at the |
1482 | end of this string |
1483 | |
1484 | @since LibreOffice 3.6 |
1485 | */ |
1486 | #if defined LIBO_INTERNAL_ONLY1 |
1487 | bool endsWith(std::u16string_view sv, OUString * rest = nullptr) const { |
1488 | auto const b = sv.size() <= sal_uInt32(pData->length) |
1489 | && match(sv, pData->length - sv.size()); |
1490 | if (b && rest != nullptr) { |
1491 | *rest = copy(0, (pData->length - sv.size())); |
1492 | } |
1493 | return b; |
1494 | } |
1495 | #else |
1496 | bool endsWith(OUString const & str, OUString * rest = NULL__null) const { |
1497 | bool b = str.getLength() <= getLength() |
1498 | && match(str, getLength() - str.getLength()); |
1499 | if (b && rest != NULL__null) { |
1500 | *rest = copy(0, getLength() - str.getLength()); |
1501 | } |
1502 | return b; |
1503 | } |
1504 | #endif |
1505 | |
1506 | /** |
1507 | @overload |
1508 | This function accepts an ASCII string literal as its argument. |
1509 | @since LibreOffice 3.6 |
1510 | */ |
1511 | template< typename T > |
1512 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type |
1513 | endsWith(T & literal, OUString * rest = NULL__null) const |
1514 | { |
1515 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1516, __extension__ __PRETTY_FUNCTION__)) |
1516 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1516, __extension__ __PRETTY_FUNCTION__)); |
1517 | bool b |
1518 | = (libreoffice_internal::ConstCharArrayDetector<T>::length |
1519 | <= sal_uInt32(pData->length)) |
1520 | && rtl_ustr_asciil_reverseEquals_WithLength( |
1521 | (pData->buffer + pData->length |
1522 | - libreoffice_internal::ConstCharArrayDetector<T>::length), |
1523 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1524 | literal), |
1525 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1526 | if (b && rest != NULL__null) { |
1527 | *rest = copy( |
1528 | 0, |
1529 | (getLength() |
1530 | - libreoffice_internal::ConstCharArrayDetector<T>::length)); |
1531 | } |
1532 | return b; |
1533 | } |
1534 | |
1535 | /** |
1536 | Check whether this string ends with a given ASCII string. |
1537 | |
1538 | @param asciiStr a sequence of at least asciiStrLength ASCII characters |
1539 | (bytes in the range 0x00--0x7F) |
1540 | @param asciiStrLength the length of asciiStr; must be non-negative |
1541 | @return true if this string ends with asciiStr; otherwise, false is |
1542 | returned |
1543 | |
1544 | @since UDK 3.2.7 |
1545 | */ |
1546 | bool endsWithAsciiL(char const * asciiStr, sal_Int32 asciiStrLength) |
1547 | const |
1548 | { |
1549 | return asciiStrLength <= pData->length |
1550 | && rtl_ustr_asciil_reverseEquals_WithLength( |
1551 | pData->buffer + pData->length - asciiStrLength, asciiStr, |
1552 | asciiStrLength); |
1553 | } |
1554 | |
1555 | /** |
1556 | Check whether this string ends with a given string, ignoring the case of |
1557 | ASCII letters. |
1558 | |
1559 | Character values between 65 and 90 (ASCII A-Z) are interpreted as |
1560 | values between 97 and 122 (ASCII a-z). |
1561 | This function can't be used for language specific comparison. |
1562 | |
1563 | @param str the substring to be compared |
1564 | |
1565 | @param rest if non-null, and this function returns true, then assign a |
1566 | copy of the remainder of this string to *rest. Available since |
1567 | LibreOffice 4.2 |
1568 | |
1569 | @return true if and only if the given str appears as a substring at the |
1570 | end of this string, ignoring the case of ASCII letters ("A"--"Z" and |
1571 | "a"--"z") |
1572 | |
1573 | @since LibreOffice 3.6 |
1574 | */ |
1575 | #if defined LIBO_INTERNAL_ONLY1 |
1576 | bool endsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const { |
1577 | auto const b = sv.size() <= sal_uInt32(pData->length) |
1578 | && matchIgnoreAsciiCase(sv, pData->length - sv.size()); |
1579 | if (b && rest != nullptr) { |
1580 | *rest = copy(0, pData->length - sv.size()); |
1581 | } |
1582 | return b; |
1583 | } |
1584 | #else |
1585 | bool endsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null) const |
1586 | { |
1587 | bool b = str.getLength() <= getLength() |
1588 | && matchIgnoreAsciiCase(str, getLength() - str.getLength()); |
1589 | if (b && rest != NULL__null) { |
1590 | *rest = copy(0, getLength() - str.getLength()); |
1591 | } |
1592 | return b; |
1593 | } |
1594 | #endif |
1595 | |
1596 | /** |
1597 | @overload |
1598 | This function accepts an ASCII string literal as its argument. |
1599 | @since LibreOffice 3.6 |
1600 | */ |
1601 | template< typename T > |
1602 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type |
1603 | endsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const |
1604 | { |
1605 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1606, __extension__ __PRETTY_FUNCTION__)) |
1606 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1606, __extension__ __PRETTY_FUNCTION__)); |
1607 | bool b |
1608 | = (libreoffice_internal::ConstCharArrayDetector<T>::length |
1609 | <= sal_uInt32(pData->length)) |
1610 | && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( |
1611 | (pData->buffer + pData->length |
1612 | - libreoffice_internal::ConstCharArrayDetector<T>::length), |
1613 | libreoffice_internal::ConstCharArrayDetector<T>::length, |
1614 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1615 | literal), |
1616 | libreoffice_internal::ConstCharArrayDetector<T>::length) |
1617 | == 0); |
1618 | if (b && rest != NULL__null) { |
1619 | *rest = copy( |
1620 | 0, |
1621 | (getLength() |
1622 | - libreoffice_internal::ConstCharArrayDetector<T>::length)); |
1623 | } |
1624 | return b; |
1625 | } |
1626 | |
1627 | /** |
1628 | Check whether this string ends with a given ASCII string, ignoring the |
1629 | case of ASCII letters. |
1630 | |
1631 | @param asciiStr a sequence of at least asciiStrLength ASCII characters |
1632 | (bytes in the range 0x00--0x7F) |
1633 | @param asciiStrLength the length of asciiStr; must be non-negative |
1634 | @return true if this string ends with asciiStr, ignoring the case of ASCII |
1635 | letters ("A"--"Z" and "a"--"z"); otherwise, false is returned |
1636 | */ |
1637 | bool endsWithIgnoreAsciiCaseAsciiL( |
1638 | char const * asciiStr, sal_Int32 asciiStrLength) const |
1639 | { |
1640 | return asciiStrLength <= pData->length |
1641 | && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( |
1642 | pData->buffer + pData->length - asciiStrLength, |
1643 | asciiStrLength, asciiStr, asciiStrLength) |
1644 | == 0); |
1645 | } |
1646 | |
1647 | friend bool operator == ( const OUString& rStr1, const OUString& rStr2 ) |
1648 | { return rStr1.equals(rStr2); } |
1649 | |
1650 | friend bool operator != ( const OUString& rStr1, const OUString& rStr2 ) |
1651 | { return !(operator == ( rStr1, rStr2 )); } |
1652 | |
1653 | friend bool operator < ( const OUString& rStr1, const OUString& rStr2 ) |
1654 | { return rStr1.compareTo( rStr2 ) < 0; } |
1655 | friend bool operator > ( const OUString& rStr1, const OUString& rStr2 ) |
1656 | { return rStr1.compareTo( rStr2 ) > 0; } |
1657 | friend bool operator <= ( const OUString& rStr1, const OUString& rStr2 ) |
1658 | { return rStr1.compareTo( rStr2 ) <= 0; } |
1659 | friend bool operator >= ( const OUString& rStr1, const OUString& rStr2 ) |
1660 | { return rStr1.compareTo( rStr2 ) >= 0; } |
1661 | |
1662 | #if defined LIBO_INTERNAL_ONLY1 |
1663 | |
1664 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 |
1665 | operator ==(OUString const & s1, T const & s2) { |
1666 | return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2)) |
1667 | == 0; |
1668 | } |
1669 | |
1670 | template<typename T> |
1671 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 |
1672 | operator ==(OUString const & s1, T & s2) { |
1673 | return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2)) |
1674 | == 0; |
1675 | } |
1676 | |
1677 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 |
1678 | operator ==(T const & s1, OUString const & s2) { |
1679 | return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength()) |
1680 | == 0; |
1681 | } |
1682 | |
1683 | template<typename T> |
1684 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 |
1685 | operator ==(T & s1, OUString const & s2) { |
1686 | return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength()) |
1687 | == 0; |
1688 | } |
1689 | |
1690 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 |
1691 | operator !=(OUString const & s1, T const & s2) { return !(s1 == s2); } |
1692 | |
1693 | template<typename T> |
1694 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 |
1695 | operator !=(OUString const & s1, T & s2) { return !(s1 == s2); } |
1696 | |
1697 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 |
1698 | operator !=(T const & s1, OUString const & s2) { return !(s1 == s2); } |
1699 | |
1700 | template<typename T> |
1701 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 |
1702 | operator !=(T & s1, OUString const & s2) { return !(s1 == s2); } |
1703 | |
1704 | #else |
1705 | |
1706 | friend bool operator == ( const OUString& rStr1, const sal_Unicode * pStr2 ) |
1707 | { return rStr1.compareTo( pStr2 ) == 0; } |
1708 | friend bool operator == ( const sal_Unicode * pStr1, const OUString& rStr2 ) |
1709 | { return OUString( pStr1 ).compareTo( rStr2 ) == 0; } |
1710 | |
1711 | friend bool operator != ( const OUString& rStr1, const sal_Unicode * pStr2 ) |
1712 | { return !(operator == ( rStr1, pStr2 )); } |
1713 | friend bool operator != ( const sal_Unicode * pStr1, const OUString& rStr2 ) |
1714 | { return !(operator == ( pStr1, rStr2 )); } |
1715 | |
1716 | #endif |
1717 | |
1718 | /** |
1719 | * Compare string to an ASCII string literal. |
1720 | * |
1721 | * This operator is equal to calling equalsAsciiL(). |
1722 | * |
1723 | * @since LibreOffice 3.6 |
1724 | */ |
1725 | template< typename T > |
1726 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( const OUString& rString, T& literal ) |
1727 | { |
1728 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1729, __extension__ __PRETTY_FUNCTION__)) |
1729 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1729, __extension__ __PRETTY_FUNCTION__)); |
1730 | return rString.equalsAsciiL( |
1731 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
1732 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1733 | } |
1734 | /** |
1735 | * Compare string to an ASCII string literal. |
1736 | * |
1737 | * This operator is equal to calling equalsAsciiL(). |
1738 | * |
1739 | * @since LibreOffice 3.6 |
1740 | */ |
1741 | template< typename T > |
1742 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( T& literal, const OUString& rString ) |
1743 | { |
1744 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1745, __extension__ __PRETTY_FUNCTION__)) |
1745 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1745, __extension__ __PRETTY_FUNCTION__)); |
1746 | return rString.equalsAsciiL( |
1747 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
1748 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1749 | } |
1750 | /** |
1751 | * Compare string to an ASCII string literal. |
1752 | * |
1753 | * This operator is equal to calling !equalsAsciiL(). |
1754 | * |
1755 | * @since LibreOffice 3.6 |
1756 | */ |
1757 | template< typename T > |
1758 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( const OUString& rString, T& literal ) |
1759 | { |
1760 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1761, __extension__ __PRETTY_FUNCTION__)) |
1761 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1761, __extension__ __PRETTY_FUNCTION__)); |
1762 | return !rString.equalsAsciiL( |
1763 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
1764 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1765 | } |
1766 | /** |
1767 | * Compare string to an ASCII string literal. |
1768 | * |
1769 | * This operator is equal to calling !equalsAsciiL(). |
1770 | * |
1771 | * @since LibreOffice 3.6 |
1772 | */ |
1773 | template< typename T > |
1774 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( T& literal, const OUString& rString ) |
1775 | { |
1776 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1777, __extension__ __PRETTY_FUNCTION__)) |
1777 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1777, __extension__ __PRETTY_FUNCTION__)); |
1778 | return !rString.equalsAsciiL( |
1779 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
1780 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
1781 | } |
1782 | |
1783 | #if defined LIBO_INTERNAL_ONLY1 |
1784 | /** @overload @since LibreOffice 5.3 */ |
1785 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 |
1786 | operator ==(OUString const & string, T & literal) { |
1787 | return |
1788 | rtl_ustr_reverseCompare_WithLength( |
1789 | string.pData->buffer, string.pData->length, |
1790 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1791 | literal), |
1792 | libreoffice_internal::ConstCharArrayDetector<T>::length) |
1793 | == 0; |
1794 | } |
1795 | /** @overload @since LibreOffice 5.3 */ |
1796 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 |
1797 | operator ==(T & literal, OUString const & string) { |
1798 | return |
1799 | rtl_ustr_reverseCompare_WithLength( |
1800 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1801 | literal), |
1802 | libreoffice_internal::ConstCharArrayDetector<T>::length, |
1803 | string.pData->buffer, string.pData->length) |
1804 | == 0; |
1805 | } |
1806 | /** @overload @since LibreOffice 5.3 */ |
1807 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 |
1808 | operator !=(OUString const & string, T & literal) { |
1809 | return |
1810 | rtl_ustr_reverseCompare_WithLength( |
1811 | string.pData->buffer, string.pData->length, |
1812 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1813 | literal), |
1814 | libreoffice_internal::ConstCharArrayDetector<T>::length) |
1815 | != 0; |
1816 | } |
1817 | /** @overload @since LibreOffice 5.3 */ |
1818 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 |
1819 | operator !=(T & literal, OUString const & string) { |
1820 | return |
1821 | rtl_ustr_reverseCompare_WithLength( |
1822 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( |
1823 | literal), |
1824 | libreoffice_internal::ConstCharArrayDetector<T>::length, |
1825 | string.pData->buffer, string.pData->length) |
1826 | != 0; |
1827 | } |
1828 | #endif |
1829 | |
1830 | #if defined LIBO_INTERNAL_ONLY1 |
1831 | /// @cond INTERNAL |
1832 | |
1833 | /* Comparison between OUString and OUStringLiteral. |
1834 | |
1835 | @since LibreOffice 5.0 |
1836 | */ |
1837 | |
1838 | template<std::size_t N> |
1839 | friend bool operator ==(OUString const & lhs, OUStringLiteral<N> const & rhs) { |
1840 | return |
1841 | rtl_ustr_reverseCompare_WithLength( |
1842 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()) |
1843 | == 0; |
1844 | } |
1845 | |
1846 | template<std::size_t N> |
1847 | friend bool operator !=(OUString const & lhs, OUStringLiteral<N> const & rhs) { |
1848 | return |
1849 | rtl_ustr_reverseCompare_WithLength( |
1850 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()) |
1851 | != 0; |
1852 | } |
1853 | |
1854 | template<std::size_t N> |
1855 | friend bool operator <(OUString const & lhs, OUStringLiteral<N> const & rhs) { |
1856 | return |
1857 | (rtl_ustr_compare_WithLength( |
1858 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) |
1859 | < 0; |
1860 | } |
1861 | |
1862 | template<std::size_t N> |
1863 | friend bool operator <=(OUString const & lhs, OUStringLiteral<N> const & rhs) { |
1864 | return |
1865 | (rtl_ustr_compare_WithLength( |
1866 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) |
1867 | <= 0; |
1868 | } |
1869 | |
1870 | template<std::size_t N> |
1871 | friend bool operator >(OUString const & lhs, OUStringLiteral<N> const & rhs) { |
1872 | return |
1873 | (rtl_ustr_compare_WithLength( |
1874 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) |
1875 | > 0; |
1876 | } |
1877 | |
1878 | template<std::size_t N> |
1879 | friend bool operator >=(OUString const & lhs, OUStringLiteral<N> const & rhs) { |
1880 | return |
1881 | (rtl_ustr_compare_WithLength( |
1882 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) |
1883 | >= 0; |
1884 | } |
1885 | |
1886 | template<std::size_t N> |
1887 | friend bool operator ==(OUStringLiteral<N> const & lhs, OUString const & rhs) { |
1888 | return |
1889 | rtl_ustr_reverseCompare_WithLength( |
1890 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length) |
1891 | == 0; |
1892 | } |
1893 | |
1894 | template<std::size_t N> |
1895 | friend bool operator !=(OUStringLiteral<N> const & lhs, OUString const & rhs) { |
1896 | return |
1897 | rtl_ustr_reverseCompare_WithLength( |
1898 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length) |
1899 | != 0; |
1900 | } |
1901 | |
1902 | template<std::size_t N> |
1903 | friend bool operator <(OUStringLiteral<N> const & lhs, OUString const & rhs) { |
1904 | return |
1905 | (rtl_ustr_compare_WithLength( |
1906 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) |
1907 | < 0; |
1908 | } |
1909 | |
1910 | template<std::size_t N> |
1911 | friend bool operator <=(OUStringLiteral<N> const & lhs, OUString const & rhs) { |
1912 | return |
1913 | (rtl_ustr_compare_WithLength( |
1914 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) |
1915 | <= 0; |
1916 | } |
1917 | |
1918 | template<std::size_t N> |
1919 | friend bool operator >(OUStringLiteral<N> const & lhs, OUString const & rhs) { |
1920 | return |
1921 | (rtl_ustr_compare_WithLength( |
1922 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) |
1923 | > 0; |
1924 | } |
1925 | |
1926 | template<std::size_t N> |
1927 | friend bool operator >=(OUStringLiteral<N> const & lhs, OUString const & rhs) { |
1928 | return |
1929 | (rtl_ustr_compare_WithLength( |
1930 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) |
1931 | >= 0; |
1932 | } |
1933 | |
1934 | /// @endcond |
1935 | #endif |
1936 | |
1937 | #if defined LIBO_INTERNAL_ONLY1 |
1938 | friend bool operator ==(OUString const & lhs, std::u16string_view rhs) { |
1939 | return |
1940 | rtl_ustr_reverseCompare_WithLength( |
1941 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()) |
1942 | == 0; |
1943 | } |
1944 | |
1945 | friend bool operator !=(OUString const & lhs, std::u16string_view rhs) { |
1946 | return |
1947 | rtl_ustr_reverseCompare_WithLength( |
1948 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()) |
1949 | != 0; |
1950 | } |
1951 | |
1952 | friend bool operator <(OUString const & lhs, std::u16string_view rhs) { |
1953 | return |
1954 | (rtl_ustr_compare_WithLength( |
1955 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) |
1956 | < 0; |
1957 | } |
1958 | |
1959 | friend bool operator <=(OUString const & lhs, std::u16string_view rhs) { |
1960 | return |
1961 | (rtl_ustr_compare_WithLength( |
1962 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) |
1963 | <= 0; |
1964 | } |
1965 | |
1966 | friend bool operator >(OUString const & lhs, std::u16string_view rhs) { |
1967 | return |
1968 | (rtl_ustr_compare_WithLength( |
1969 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) |
1970 | > 0; |
1971 | } |
1972 | |
1973 | friend bool operator >=(OUString const & lhs, std::u16string_view rhs) { |
1974 | return |
1975 | (rtl_ustr_compare_WithLength( |
1976 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) |
1977 | >= 0; |
1978 | } |
1979 | |
1980 | friend bool operator ==(std::u16string_view lhs, OUString const & rhs) { |
1981 | return |
1982 | rtl_ustr_reverseCompare_WithLength( |
1983 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length) |
1984 | == 0; |
1985 | } |
1986 | |
1987 | friend bool operator !=(std::u16string_view lhs, OUString const & rhs) { |
1988 | return |
1989 | rtl_ustr_reverseCompare_WithLength( |
1990 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length) |
1991 | != 0; |
1992 | } |
1993 | |
1994 | friend bool operator <(std::u16string_view lhs, OUString const & rhs) { |
1995 | return |
1996 | (rtl_ustr_compare_WithLength( |
1997 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) |
1998 | < 0; |
1999 | } |
2000 | |
2001 | friend bool operator <=(std::u16string_view lhs, OUString const & rhs) { |
2002 | return |
2003 | (rtl_ustr_compare_WithLength( |
2004 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) |
2005 | <= 0; |
2006 | } |
2007 | |
2008 | friend bool operator >(std::u16string_view lhs, OUString const & rhs) { |
2009 | return |
2010 | (rtl_ustr_compare_WithLength( |
2011 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) |
2012 | > 0; |
2013 | } |
2014 | |
2015 | friend bool operator >=(std::u16string_view lhs, OUString const & rhs) { |
2016 | return |
2017 | (rtl_ustr_compare_WithLength( |
2018 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) |
2019 | >= 0; |
2020 | } |
2021 | #endif |
2022 | |
2023 | /** |
2024 | Returns a hashcode for this string. |
2025 | |
2026 | @return a hash code value for this object. |
2027 | |
2028 | @see rtl::OUStringHash for convenient use of std::unordered_map |
2029 | */ |
2030 | sal_Int32 hashCode() const |
2031 | { |
2032 | return rtl_ustr_hashCode_WithLength( pData->buffer, pData->length ); |
2033 | } |
2034 | |
2035 | /** |
2036 | Returns the index within this string of the first occurrence of the |
2037 | specified character, starting the search at the specified index. |
2038 | |
2039 | @param ch character to be located. |
2040 | @param fromIndex the index to start the search from. |
2041 | The index must be greater than or equal to 0 |
2042 | and less than or equal to the string length. |
2043 | @return the index of the first occurrence of the character in the |
2044 | character sequence represented by this string that is |
2045 | greater than or equal to fromIndex, or |
2046 | -1 if the character does not occur. |
2047 | */ |
2048 | sal_Int32 indexOf( sal_Unicode ch, sal_Int32 fromIndex = 0 ) const |
2049 | { |
2050 | sal_Int32 ret = rtl_ustr_indexOfChar_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, ch ); |
2051 | return (ret < 0 ? ret : ret+fromIndex); |
2052 | } |
2053 | |
2054 | /** |
2055 | Returns the index within this string of the last occurrence of the |
2056 | specified character, searching backward starting at the end. |
2057 | |
2058 | @param ch character to be located. |
2059 | @return the index of the last occurrence of the character in the |
2060 | character sequence represented by this string, or |
2061 | -1 if the character does not occur. |
2062 | */ |
2063 | sal_Int32 lastIndexOf( sal_Unicode ch ) const |
2064 | { |
2065 | return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, pData->length, ch ); |
2066 | } |
2067 | |
2068 | /** |
2069 | Returns the index within this string of the last occurrence of the |
2070 | specified character, searching backward starting before the specified |
2071 | index. |
2072 | |
2073 | @param ch character to be located. |
2074 | @param fromIndex the index before which to start the search. |
2075 | @return the index of the last occurrence of the character in the |
2076 | character sequence represented by this string that |
2077 | is less than fromIndex, or -1 |
2078 | if the character does not occur before that point. |
2079 | */ |
2080 | sal_Int32 lastIndexOf( sal_Unicode ch, sal_Int32 fromIndex ) const |
2081 | { |
2082 | return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, fromIndex, ch ); |
2083 | } |
2084 | |
2085 | /** |
2086 | Returns the index within this string of the first occurrence of the |
2087 | specified substring, starting at the specified index. |
2088 | |
2089 | If str doesn't include any character, always -1 is |
2090 | returned. This is also the case, if both strings are empty. |
2091 | |
2092 | @param str the substring to search for. |
2093 | @param fromIndex the index to start the search from. |
2094 | @return If the string argument occurs one or more times as a substring |
2095 | within this string at the starting index, then the index |
2096 | of the first character of the first such substring is |
2097 | returned. If it does not occur as a substring starting |
2098 | at fromIndex or beyond, -1 is returned. |
2099 | */ |
2100 | #if defined LIBO_INTERNAL_ONLY1 |
2101 | sal_Int32 indexOf(std::u16string_view sv, sal_Int32 fromIndex = 0) const { |
2102 | auto const n = rtl_ustr_indexOfStr_WithLength( |
2103 | pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size()); |
2104 | return n < 0 ? n : n + fromIndex; |
2105 | } |
2106 | #else |
2107 | sal_Int32 indexOf( const OUString & str, sal_Int32 fromIndex = 0 ) const |
2108 | { |
2109 | sal_Int32 ret = rtl_ustr_indexOfStr_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, |
2110 | str.pData->buffer, str.pData->length ); |
2111 | return (ret < 0 ? ret : ret+fromIndex); |
2112 | } |
2113 | #endif |
2114 | |
2115 | /** |
2116 | @overload |
2117 | This function accepts an ASCII string literal as its argument. |
2118 | @since LibreOffice 3.6 |
2119 | */ |
2120 | template< typename T > |
2121 | typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type indexOf( T& literal, sal_Int32 fromIndex = 0 ) const |
2122 | { |
2123 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2124, __extension__ __PRETTY_FUNCTION__)) |
2124 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2124, __extension__ __PRETTY_FUNCTION__)); |
2125 | sal_Int32 n = rtl_ustr_indexOfAscii_WithLength( |
2126 | pData->buffer + fromIndex, pData->length - fromIndex, |
2127 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
2128 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
2129 | return n < 0 ? n : n + fromIndex; |
2130 | } |
2131 | |
2132 | /** |
2133 | Returns the index within this string of the first occurrence of the |
2134 | specified ASCII substring, starting at the specified index. |
2135 | |
2136 | @param str |
2137 | the substring to be searched for. Need not be null-terminated, but must |
2138 | be at least as long as the specified len. Must only contain characters |
2139 | in the ASCII range 0x00--7F. |
2140 | |
2141 | @param len |
2142 | the length of the substring; must be non-negative. |
2143 | |
2144 | @param fromIndex |
2145 | the index to start the search from. Must be in the range from zero to |
2146 | the length of this string, inclusive. |
2147 | |
2148 | @return |
2149 | the index (starting at 0) of the first character of the first occurrence |
2150 | of the substring within this string starting at the given fromIndex, or |
2151 | -1 if the substring does not occur. If len is zero, -1 is returned. |
2152 | |
2153 | @since UDK 3.2.7 |
2154 | */ |
2155 | sal_Int32 indexOfAsciiL( |
2156 | char const * str, sal_Int32 len, sal_Int32 fromIndex = 0) const |
2157 | { |
2158 | sal_Int32 ret = rtl_ustr_indexOfAscii_WithLength( |
2159 | pData->buffer + fromIndex, pData->length - fromIndex, str, len); |
2160 | return ret < 0 ? ret : ret + fromIndex; |
2161 | } |
2162 | |
2163 | // This overload is left undefined, to detect calls of indexOfAsciiL that |
2164 | // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of |
2165 | // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit |
2166 | // platforms): |
2167 | #if SAL_TYPES_SIZEOFLONG8 == 8 |
2168 | void indexOfAsciiL(char const *, sal_Int32 len, rtl_TextEncoding) const; |
2169 | #endif |
2170 | |
2171 | /** |
2172 | Returns the index within this string of the last occurrence of |
2173 | the specified substring, searching backward starting at the end. |
2174 | |
2175 | The returned index indicates the starting index of the substring |
2176 | in this string. |
2177 | If str doesn't include any character, always -1 is |
2178 | returned. This is also the case, if both strings are empty. |
2179 | |
2180 | @param str the substring to search for. |
2181 | @return If the string argument occurs one or more times as a substring |
2182 | within this string, then the index of the first character of |
2183 | the last such substring is returned. If it does not occur as |
2184 | a substring, -1 is returned. |
2185 | */ |
2186 | #if defined LIBO_INTERNAL_ONLY1 |
2187 | sal_Int32 lastIndexOf(std::u16string_view sv) const { |
2188 | return rtl_ustr_lastIndexOfStr_WithLength( |
2189 | pData->buffer, pData->length, sv.data(), sv.size()); |
2190 | } |
2191 | #else |
2192 | sal_Int32 lastIndexOf( const OUString & str ) const |
2193 | { |
2194 | return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, pData->length, |
2195 | str.pData->buffer, str.pData->length ); |
2196 | } |
2197 | #endif |
2198 | |
2199 | /** |
2200 | Returns the index within this string of the last occurrence of |
2201 | the specified substring, searching backward starting before the specified |
2202 | index. |
2203 | |
2204 | The returned index indicates the starting index of the substring |
2205 | in this string. |
2206 | If str doesn't include any character, always -1 is |
2207 | returned. This is also the case, if both strings are empty. |
2208 | |
2209 | @param str the substring to search for. |
2210 | @param fromIndex the index before which to start the search. |
2211 | @return If the string argument occurs one or more times as a substring |
2212 | within this string before the starting index, then the index |
2213 | of the first character of the last such substring is |
2214 | returned. Otherwise, -1 is returned. |
2215 | */ |
2216 | #if defined LIBO_INTERNAL_ONLY1 |
2217 | sal_Int32 lastIndexOf(std::u16string_view sv, sal_Int32 fromIndex) const { |
2218 | return rtl_ustr_lastIndexOfStr_WithLength(pData->buffer, fromIndex, sv.data(), sv.size()); |
2219 | } |
2220 | #else |
2221 | sal_Int32 lastIndexOf( const OUString & str, sal_Int32 fromIndex ) const |
2222 | { |
2223 | return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, fromIndex, |
2224 | str.pData->buffer, str.pData->length ); |
2225 | } |
2226 | #endif |
2227 | |
2228 | /** |
2229 | @overload |
2230 | This function accepts an ASCII string literal as its argument. |
2231 | @since LibreOffice 3.6 |
2232 | */ |
2233 | template< typename T > |
2234 | typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type lastIndexOf( T& literal ) const |
2235 | { |
2236 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2237, __extension__ __PRETTY_FUNCTION__)) |
2237 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2237, __extension__ __PRETTY_FUNCTION__)); |
2238 | return rtl_ustr_lastIndexOfAscii_WithLength( |
2239 | pData->buffer, pData->length, |
2240 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), |
2241 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
2242 | } |
2243 | |
2244 | /** |
2245 | Returns the index within this string of the last occurrence of the |
2246 | specified ASCII substring. |
2247 | |
2248 | @param str |
2249 | the substring to be searched for. Need not be null-terminated, but must |
2250 | be at least as long as the specified len. Must only contain characters |
2251 | in the ASCII range 0x00--7F. |
2252 | |
2253 | @param len |
2254 | the length of the substring; must be non-negative. |
2255 | |
2256 | @return |
2257 | the index (starting at 0) of the first character of the last occurrence |
2258 | of the substring within this string, or -1 if the substring does not |
2259 | occur. If len is zero, -1 is returned. |
2260 | |
2261 | @since UDK 3.2.7 |
2262 | */ |
2263 | sal_Int32 lastIndexOfAsciiL(char const * str, sal_Int32 len) const |
2264 | { |
2265 | return rtl_ustr_lastIndexOfAscii_WithLength( |
2266 | pData->buffer, pData->length, str, len); |
2267 | } |
2268 | |
2269 | /** |
2270 | Returns a new string that is a substring of this string. |
2271 | |
2272 | The substring begins at the specified beginIndex. If |
2273 | beginIndex is negative or be greater than the length of |
2274 | this string, behaviour is undefined. |
2275 | |
2276 | @param beginIndex the beginning index, inclusive. |
2277 | @return the specified substring. |
2278 | */ |
2279 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex ) const |
2280 | { |
2281 | return copy(beginIndex, getLength() - beginIndex); |
2282 | } |
2283 | |
2284 | /** |
2285 | Returns a new string that is a substring of this string. |
2286 | |
2287 | The substring begins at the specified beginIndex and contains count |
2288 | characters. If either beginIndex or count are negative, |
2289 | or beginIndex + count are greater than the length of this string |
2290 | then behaviour is undefined. |
2291 | |
2292 | @param beginIndex the beginning index, inclusive. |
2293 | @param count the number of characters. |
2294 | @return the specified substring. |
2295 | */ |
2296 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex, sal_Int32 count ) const |
2297 | { |
2298 | rtl_uString *pNew = NULL__null; |
2299 | rtl_uString_newFromSubString( &pNew, pData, beginIndex, count ); |
2300 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2301 | } |
2302 | |
2303 | /** |
2304 | Concatenates the specified string to the end of this string. |
2305 | |
2306 | @param str the string that is concatenated to the end |
2307 | of this string. |
2308 | @return a string that represents the concatenation of this string |
2309 | followed by the string argument. |
2310 | */ |
2311 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString concat( const OUString & str ) const |
2312 | { |
2313 | rtl_uString* pNew = NULL__null; |
2314 | rtl_uString_newConcat( &pNew, pData, str.pData ); |
2315 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2316 | } |
2317 | |
2318 | #ifndef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
2319 | friend OUString operator+( const OUString& rStr1, const OUString& rStr2 ) |
2320 | { |
2321 | return rStr1.concat( rStr2 ); |
2322 | } |
2323 | #endif |
2324 | |
2325 | /** |
2326 | Returns a new string resulting from replacing n = count characters |
2327 | from position index in this string with newStr. |
2328 | |
2329 | @param index the replacing index in str. |
2330 | The index must be greater than or equal to 0 and |
2331 | less than or equal to the length of the string. |
2332 | @param count the count of characters that will be replaced |
2333 | The count must be greater than or equal to 0 and |
2334 | less than or equal to the length of the string minus index. |
2335 | @param newStr the new substring. |
2336 | @return the new string. |
2337 | */ |
2338 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const |
2339 | { |
2340 | rtl_uString* pNew = NULL__null; |
2341 | rtl_uString_newReplaceStrAt( &pNew, pData, index, count, newStr.pData ); |
2342 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2343 | } |
2344 | |
2345 | /** |
2346 | Returns a new string resulting from replacing all occurrences of |
2347 | oldChar in this string with newChar. |
2348 | |
2349 | If the character oldChar does not occur in the character sequence |
2350 | represented by this object, then the string is assigned with |
2351 | str. |
2352 | |
2353 | @param oldChar the old character. |
2354 | @param newChar the new character. |
2355 | @return a string derived from this string by replacing every |
2356 | occurrence of oldChar with newChar. |
2357 | */ |
2358 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replace( sal_Unicode oldChar, sal_Unicode newChar ) const |
2359 | { |
2360 | rtl_uString* pNew = NULL__null; |
2361 | rtl_uString_newReplace( &pNew, pData, oldChar, newChar ); |
2362 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2363 | } |
2364 | |
2365 | /** |
2366 | Returns a new string resulting from replacing the first occurrence of a |
2367 | given substring with another substring. |
2368 | |
2369 | @param from the substring to be replaced |
2370 | |
2371 | @param to the replacing substring |
2372 | |
2373 | @param[in,out] index pointer to a start index; if the pointer is |
2374 | non-null: upon entry to the function, its value is the index into this |
2375 | string at which to start searching for the \p from substring, the value |
2376 | must be non-negative and not greater than this string's length; upon exiting |
2377 | the function its value is the index into this string at which the |
2378 | replacement took place or -1 if no replacement took place; if the pointer |
2379 | is null, searching always starts at index 0 |
2380 | |
2381 | @since LibreOffice 3.6 |
2382 | */ |
2383 | #if defined LIBO_INTERNAL_ONLY1 |
2384 | [[nodiscard]] OUString replaceFirst( |
2385 | std::u16string_view from, std::u16string_view to, sal_Int32 * index = nullptr) const |
2386 | { |
2387 | rtl_uString * s = nullptr; |
2388 | sal_Int32 i = 0; |
2389 | rtl_uString_newReplaceFirstUtf16LUtf16L( |
2390 | &s, pData, from.data(), from.size(), to.data(), to.size(), |
2391 | index == nullptr ? &i : index); |
2392 | return OUString(s, SAL_NO_ACQUIRE); |
2393 | } |
2394 | #else |
2395 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceFirst( |
2396 | OUString const & from, OUString const & to, sal_Int32 * index = NULL__null) const |
2397 | { |
2398 | rtl_uString * s = NULL__null; |
2399 | sal_Int32 i = 0; |
2400 | rtl_uString_newReplaceFirst( |
2401 | &s, pData, from.pData, to.pData, index == NULL__null ? &i : index); |
2402 | return OUString(s, SAL_NO_ACQUIRE); |
2403 | } |
2404 | #endif |
2405 | |
2406 | /** |
2407 | Returns a new string resulting from replacing the first occurrence of a |
2408 | given substring with another substring. |
2409 | |
2410 | @param from ASCII string literal, the substring to be replaced |
2411 | |
2412 | @param to the replacing substring |
2413 | |
2414 | @param[in,out] index pointer to a start index; if the pointer is |
2415 | non-null: upon entry to the function, its value is the index into the this |
2416 | string at which to start searching for the \p from substring, the value |
2417 | must be non-negative and not greater than this string's length; upon exiting |
2418 | the function its value is the index into this string at which the |
2419 | replacement took place or -1 if no replacement took place; if the pointer |
2420 | is null, searching always starts at index 0 |
2421 | |
2422 | @since LibreOffice 3.6 |
2423 | */ |
2424 | #if defined LIBO_INTERNAL_ONLY1 |
2425 | template<typename T> [[nodiscard]] |
2426 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst( |
2427 | T & from, std::u16string_view to, sal_Int32 * index = nullptr) const |
2428 | { |
2429 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2429, __extension__ __PRETTY_FUNCTION__)); |
2430 | rtl_uString * s = nullptr; |
2431 | sal_Int32 i = 0; |
2432 | rtl_uString_newReplaceFirstAsciiLUtf16L( |
2433 | &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), |
2434 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size(), |
2435 | index == nullptr ? &i : index); |
2436 | return OUString(s, SAL_NO_ACQUIRE); |
2437 | } |
2438 | #else |
2439 | template< typename T > |
2440 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( T& from, OUString const & to, |
2441 | sal_Int32 * index = NULL__null) const |
2442 | { |
2443 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2443, __extension__ __PRETTY_FUNCTION__)); |
2444 | rtl_uString * s = NULL__null; |
2445 | sal_Int32 i = 0; |
2446 | rtl_uString_newReplaceFirstAsciiL( |
2447 | &s, pData, |
2448 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), |
2449 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData, |
2450 | index == NULL__null ? &i : index); |
2451 | return OUString(s, SAL_NO_ACQUIRE); |
2452 | } |
2453 | #endif |
2454 | |
2455 | /** |
2456 | Returns a new string resulting from replacing the first occurrence of a |
2457 | given substring with another substring. |
2458 | |
2459 | @param from the substring to be replaced |
2460 | |
2461 | @param to ASCII string literal, the replacing substring |
2462 | |
2463 | @param[in,out] index pointer to a start index; if the pointer is |
2464 | non-null: upon entry to the function, its value is the index into the this |
2465 | string at which to start searching for the \p from substring, the value |
2466 | must be non-negative and not greater than this string's length; upon exiting |
2467 | the function its value is the index into this string at which the |
2468 | replacement took place or -1 if no replacement took place; if the pointer |
2469 | is null, searching always starts at index 0 |
2470 | |
2471 | @since LibreOffice 5.1 |
2472 | */ |
2473 | #if defined LIBO_INTERNAL_ONLY1 |
2474 | template<typename T> [[nodiscard]] |
2475 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst( |
2476 | std::u16string_view from, T & to, sal_Int32 * index = nullptr) const |
2477 | { |
2478 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2478, __extension__ __PRETTY_FUNCTION__)); |
2479 | rtl_uString * s = nullptr; |
2480 | sal_Int32 i = 0; |
2481 | rtl_uString_newReplaceFirstUtf16LAsciiL( |
2482 | &s, pData, from.data(), from.size(), |
2483 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), |
2484 | libreoffice_internal::ConstCharArrayDetector<T>::length, index == nullptr ? &i : index); |
2485 | return OUString(s, SAL_NO_ACQUIRE); |
2486 | } |
2487 | #else |
2488 | template< typename T > |
2489 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( OUString const & from, T& to, |
2490 | sal_Int32 * index = NULL__null) const |
2491 | { |
2492 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2492, __extension__ __PRETTY_FUNCTION__)); |
2493 | rtl_uString * s = NULL__null; |
2494 | sal_Int32 i = 0; |
2495 | rtl_uString_newReplaceFirstToAsciiL( |
2496 | &s, pData, from.pData, |
2497 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), |
2498 | libreoffice_internal::ConstCharArrayDetector<T>::length, |
2499 | index == NULL__null ? &i : index); |
2500 | return OUString(s, SAL_NO_ACQUIRE); |
2501 | } |
2502 | #endif |
2503 | |
2504 | /** |
2505 | Returns a new string resulting from replacing the first occurrence of a |
2506 | given substring with another substring. |
2507 | |
2508 | @param from ASCII string literal, the substring to be replaced |
2509 | |
2510 | @param to ASCII string literal, the substring to be replaced |
2511 | |
2512 | @param[in,out] index pointer to a start index; if the pointer is |
2513 | non-null: upon entry to the function, its value is the index into the this |
2514 | string at which to start searching for the \p from substring, the value |
2515 | must be non-negative and not greater than this string's length; upon exiting |
2516 | the function its value is the index into this string at which the |
2517 | replacement took place or -1 if no replacement took place; if the pointer |
2518 | is null, searching always starts at index 0 |
2519 | |
2520 | @since LibreOffice 3.6 |
2521 | */ |
2522 | template< typename T1, typename T2 > |
2523 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type |
2524 | replaceFirst( T1& from, T2& to, sal_Int32 * index = NULL__null) const |
2525 | { |
2526 | assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2526, __extension__ __PRETTY_FUNCTION__)); |
2527 | assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2527, __extension__ __PRETTY_FUNCTION__)); |
2528 | rtl_uString * s = NULL__null; |
2529 | sal_Int32 i = 0; |
2530 | rtl_uString_newReplaceFirstAsciiLAsciiL( |
2531 | &s, pData, |
2532 | libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from), |
2533 | libreoffice_internal::ConstCharArrayDetector<T1>::length, |
2534 | libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to), |
2535 | libreoffice_internal::ConstCharArrayDetector<T2>::length, |
2536 | index == NULL__null ? &i : index); |
2537 | return OUString(s, SAL_NO_ACQUIRE); |
2538 | } |
2539 | |
2540 | /** |
2541 | Returns a new string resulting from replacing all occurrences of a given |
2542 | substring with another substring. |
2543 | |
2544 | Replacing subsequent occurrences picks up only after a given replacement. |
2545 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". |
2546 | |
2547 | @param from the substring to be replaced |
2548 | |
2549 | @param to the replacing substring |
2550 | |
2551 | @param fromIndex the position in the string where we will begin searching |
2552 | |
2553 | @since LibreOffice 4.0 |
2554 | */ |
2555 | #if defined LIBO_INTERNAL_ONLY1 |
2556 | [[nodiscard]] OUString replaceAll( |
2557 | std::u16string_view from, std::u16string_view to, sal_Int32 fromIndex = 0) const |
2558 | { |
2559 | rtl_uString * s = nullptr; |
2560 | rtl_uString_newReplaceAllFromIndexUtf16LUtf16L( |
2561 | &s, pData, from.data(), from.size(), to.data(), to.size(), fromIndex); |
2562 | return OUString(s, SAL_NO_ACQUIRE); |
2563 | } |
2564 | #else |
2565 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAll( |
2566 | OUString const & from, OUString const & to, sal_Int32 fromIndex = 0) const |
2567 | { |
2568 | rtl_uString * s = NULL__null; |
2569 | rtl_uString_newReplaceAllFromIndex(&s, pData, from.pData, to.pData, fromIndex); |
2570 | return OUString(s, SAL_NO_ACQUIRE); |
2571 | } |
2572 | #endif |
2573 | |
2574 | /** |
2575 | Returns a new string resulting from replacing all occurrences of a given |
2576 | substring with another substring. |
2577 | |
2578 | Replacing subsequent occurrences picks up only after a given replacement. |
2579 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". |
2580 | |
2581 | @param from ASCII string literal, the substring to be replaced |
2582 | |
2583 | @param to the replacing substring |
2584 | |
2585 | @since LibreOffice 3.6 |
2586 | */ |
2587 | #if defined LIBO_INTERNAL_ONLY1 |
2588 | template<typename T> [[nodiscard]] |
2589 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll( |
2590 | T & from, std::u16string_view to) const |
2591 | { |
2592 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2592, __extension__ __PRETTY_FUNCTION__)); |
2593 | rtl_uString * s = nullptr; |
2594 | rtl_uString_newReplaceAllAsciiLUtf16L( |
2595 | &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), |
2596 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size()); |
2597 | return OUString(s, SAL_NO_ACQUIRE); |
2598 | } |
2599 | #else |
2600 | template< typename T > |
2601 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( T& from, OUString const & to) const |
2602 | { |
2603 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2603, __extension__ __PRETTY_FUNCTION__)); |
2604 | rtl_uString * s = NULL__null; |
2605 | rtl_uString_newReplaceAllAsciiL( |
2606 | &s, pData, |
2607 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), |
2608 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData); |
2609 | return OUString(s, SAL_NO_ACQUIRE); |
2610 | } |
2611 | #endif |
2612 | |
2613 | /** |
2614 | Returns a new string resulting from replacing all occurrences of a given |
2615 | substring with another substring. |
2616 | |
2617 | Replacing subsequent occurrences picks up only after a given replacement. |
2618 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". |
2619 | |
2620 | @param from the substring to be replaced |
2621 | |
2622 | @param to ASCII string literal, the replacing substring |
2623 | |
2624 | @since LibreOffice 5.1 |
2625 | */ |
2626 | #if defined LIBO_INTERNAL_ONLY1 |
2627 | template<typename T> [[nodiscard]] |
2628 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll( |
2629 | std::u16string_view from, T & to) const |
2630 | { |
2631 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2631, __extension__ __PRETTY_FUNCTION__)); |
2632 | rtl_uString * s = nullptr; |
2633 | rtl_uString_newReplaceAllUtf16LAsciiL( |
2634 | &s, pData, from.data(), from.size(), |
2635 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), |
2636 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
2637 | return OUString(s, SAL_NO_ACQUIRE); |
2638 | } |
2639 | #else |
2640 | template< typename T > |
2641 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( OUString const & from, T& to) const |
2642 | { |
2643 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2643, __extension__ __PRETTY_FUNCTION__)); |
2644 | rtl_uString * s = NULL__null; |
2645 | rtl_uString_newReplaceAllToAsciiL( |
2646 | &s, pData, from.pData, |
2647 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), |
2648 | libreoffice_internal::ConstCharArrayDetector<T>::length); |
2649 | return OUString(s, SAL_NO_ACQUIRE); |
2650 | } |
2651 | #endif |
2652 | |
2653 | /** |
2654 | Returns a new string resulting from replacing all occurrences of a given |
2655 | substring with another substring. |
2656 | |
2657 | Replacing subsequent occurrences picks up only after a given replacement. |
2658 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". |
2659 | |
2660 | @param from ASCII string literal, the substring to be replaced |
2661 | |
2662 | @param to ASCII string literal, the substring to be replaced |
2663 | |
2664 | @since LibreOffice 3.6 |
2665 | */ |
2666 | template< typename T1, typename T2 > |
2667 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type |
2668 | replaceAll( T1& from, T2& to ) const |
2669 | { |
2670 | assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2670, __extension__ __PRETTY_FUNCTION__)); |
2671 | assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2671, __extension__ __PRETTY_FUNCTION__)); |
2672 | rtl_uString * s = NULL__null; |
2673 | rtl_uString_newReplaceAllAsciiLAsciiL( |
2674 | &s, pData, |
2675 | libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from), |
2676 | libreoffice_internal::ConstCharArrayDetector<T1>::length, |
2677 | libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to), |
2678 | libreoffice_internal::ConstCharArrayDetector<T2>::length); |
2679 | return OUString(s, SAL_NO_ACQUIRE); |
2680 | } |
2681 | |
2682 | /** |
2683 | Converts from this string all ASCII uppercase characters (65-90) |
2684 | to ASCII lowercase characters (97-122). |
2685 | |
2686 | This function can't be used for language specific conversion. |
2687 | If the string doesn't contain characters which must be converted, |
2688 | then the new string is assigned with str. |
2689 | |
2690 | @return the string, converted to ASCII lowercase. |
2691 | */ |
2692 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiLowerCase() const |
2693 | { |
2694 | rtl_uString* pNew = NULL__null; |
2695 | rtl_uString_newToAsciiLowerCase( &pNew, pData ); |
2696 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2697 | } |
2698 | |
2699 | /** |
2700 | Converts from this string all ASCII lowercase characters (97-122) |
2701 | to ASCII uppercase characters (65-90). |
2702 | |
2703 | This function can't be used for language specific conversion. |
2704 | If the string doesn't contain characters which must be converted, |
2705 | then the new string is assigned with str. |
2706 | |
2707 | @return the string, converted to ASCII uppercase. |
2708 | */ |
2709 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiUpperCase() const |
2710 | { |
2711 | rtl_uString* pNew = NULL__null; |
2712 | rtl_uString_newToAsciiUpperCase( &pNew, pData ); |
2713 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2714 | } |
2715 | |
2716 | /** |
2717 | Returns a new string resulting from removing white space from both ends |
2718 | of the string. |
2719 | |
2720 | All characters that have codes less than or equal to |
2721 | 32 (the space character), and Unicode General Punctuation area Space |
2722 | and some Control characters are considered to be white space (see |
2723 | rtl_ImplIsWhitespace). |
2724 | If the string doesn't contain white spaces at both ends, |
2725 | then the new string is assigned with str. |
2726 | |
2727 | @return the string, with white space removed from the front and end. |
2728 | */ |
2729 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString trim() const |
2730 | { |
2731 | rtl_uString* pNew = NULL__null; |
2732 | rtl_uString_newTrim( &pNew, pData ); |
2733 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2734 | } |
2735 | |
2736 | /** |
2737 | Returns a token in the string. |
2738 | |
2739 | Example: |
2740 | sal_Int32 nIndex = 0; |
2741 | do |
2742 | { |
2743 | ... |
2744 | OUString aToken = aStr.getToken( 0, ';', nIndex ); |
2745 | ... |
2746 | } |
2747 | while ( nIndex >= 0 ); |
2748 | |
2749 | @param token the number of the token to return |
2750 | @param cTok the character which separate the tokens. |
2751 | @param index the position at which the token is searched in the |
2752 | string. |
2753 | The index must not be greater than the length of the |
2754 | string. |
2755 | This param is set to the position of the |
2756 | next token or to -1, if it is the last token. |
2757 | @return the token; if either token or index is negative, an empty token |
2758 | is returned (and index is set to -1) |
2759 | */ |
2760 | OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const |
2761 | { |
2762 | rtl_uString * pNew = NULL__null; |
2763 | index = rtl_uString_getToken( &pNew, pData, token, cTok, index ); |
2764 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2765 | } |
2766 | |
2767 | /** |
2768 | Returns a token from the string. |
2769 | |
2770 | The same as getToken(sal_Int32, sal_Unicode, sal_Int32 &), but always |
2771 | passing in 0 as the start index in the third argument. |
2772 | |
2773 | @param count the number of the token to return, starting with 0 |
2774 | @param separator the character which separates the tokens |
2775 | |
2776 | @return the given token, or an empty string |
2777 | |
2778 | @since LibreOffice 3.6 |
2779 | */ |
2780 | OUString getToken(sal_Int32 count, sal_Unicode separator) const { |
2781 | sal_Int32 n = 0; |
2782 | return getToken(count, separator, n); |
2783 | } |
2784 | |
2785 | /** |
2786 | Returns the Boolean value from this string. |
2787 | |
2788 | This function can't be used for language specific conversion. |
2789 | |
2790 | @return true, if the string is 1 or "True" in any ASCII case. |
2791 | false in any other case. |
2792 | */ |
2793 | bool toBoolean() const |
2794 | { |
2795 | return rtl_ustr_toBoolean( pData->buffer ); |
2796 | } |
2797 | |
2798 | /** |
2799 | Returns the first character from this string. |
2800 | |
2801 | @return the first character from this string or 0, if this string |
2802 | is empty. |
2803 | */ |
2804 | sal_Unicode toChar() const |
2805 | { |
2806 | return pData->buffer[0]; |
2807 | } |
2808 | |
2809 | /** |
2810 | Returns the int32 value from this string. |
2811 | |
2812 | This function can't be used for language specific conversion. |
2813 | |
2814 | @param radix the radix (between 2 and 36) |
2815 | @return the int32 represented from this string. |
2816 | 0 if this string represents no number or one of too large |
2817 | magnitude. |
2818 | */ |
2819 | sal_Int32 toInt32( sal_Int16 radix = 10 ) const |
2820 | { |
2821 | return rtl_ustr_toInt32( pData->buffer, radix ); |
2822 | } |
2823 | |
2824 | /** |
2825 | Returns the uint32 value from this string. |
2826 | |
2827 | This function can't be used for language specific conversion. |
2828 | |
2829 | @param radix the radix (between 2 and 36) |
2830 | @return the uint32 represented from this string. |
2831 | 0 if this string represents no number or one of too large |
2832 | magnitude. |
2833 | |
2834 | @since LibreOffice 4.2 |
2835 | */ |
2836 | sal_uInt32 toUInt32( sal_Int16 radix = 10 ) const |
2837 | { |
2838 | return rtl_ustr_toUInt32( pData->buffer, radix ); |
2839 | } |
2840 | |
2841 | /** |
2842 | Returns the int64 value from this string. |
2843 | |
2844 | This function can't be used for language specific conversion. |
2845 | |
2846 | @param radix the radix (between 2 and 36) |
2847 | @return the int64 represented from this string. |
2848 | 0 if this string represents no number or one of too large |
2849 | magnitude. |
2850 | */ |
2851 | sal_Int64 toInt64( sal_Int16 radix = 10 ) const |
2852 | { |
2853 | return rtl_ustr_toInt64( pData->buffer, radix ); |
2854 | } |
2855 | |
2856 | /** |
2857 | Returns the uint64 value from this string. |
2858 | |
2859 | This function can't be used for language specific conversion. |
2860 | |
2861 | @param radix the radix (between 2 and 36) |
2862 | @return the uint64 represented from this string. |
2863 | 0 if this string represents no number or one of too large |
2864 | magnitude. |
2865 | |
2866 | @since LibreOffice 4.1 |
2867 | */ |
2868 | sal_uInt64 toUInt64( sal_Int16 radix = 10 ) const |
2869 | { |
2870 | return rtl_ustr_toUInt64( pData->buffer, radix ); |
2871 | } |
2872 | |
2873 | /** |
2874 | Returns the float value from this string. |
2875 | |
2876 | This function can't be used for language specific conversion. |
2877 | |
2878 | @return the float represented from this string. |
2879 | 0.0 if this string represents no number. |
2880 | */ |
2881 | float toFloat() const |
2882 | { |
2883 | return rtl_ustr_toFloat( pData->buffer ); |
2884 | } |
2885 | |
2886 | /** |
2887 | Returns the double value from this string. |
2888 | |
2889 | This function can't be used for language specific conversion. |
2890 | |
2891 | @return the double represented from this string. |
2892 | 0.0 if this string represents no number. |
2893 | */ |
2894 | double toDouble() const |
2895 | { |
2896 | return rtl_ustr_toDouble( pData->buffer ); |
2897 | } |
2898 | |
2899 | |
2900 | /** |
2901 | Return a canonical representation for a string. |
2902 | |
2903 | A pool of strings, initially empty is maintained privately |
2904 | by the string class. On invocation, if present in the pool |
2905 | the original string will be returned. Otherwise this string, |
2906 | or a copy thereof will be added to the pool and returned. |
2907 | |
2908 | @return |
2909 | a version of the string from the pool. |
2910 | |
2911 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs |
2912 | |
2913 | @since UDK 3.2.7 |
2914 | */ |
2915 | OUString intern() const |
2916 | { |
2917 | rtl_uString * pNew = NULL__null; |
2918 | rtl_uString_intern( &pNew, pData ); |
2919 | if (pNew == NULL__null) { |
2920 | throw std::bad_alloc(); |
2921 | } |
2922 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2923 | } |
2924 | |
2925 | /** |
2926 | Return a canonical representation for a converted string. |
2927 | |
2928 | A pool of strings, initially empty is maintained privately |
2929 | by the string class. On invocation, if present in the pool |
2930 | the original string will be returned. Otherwise this string, |
2931 | or a copy thereof will be added to the pool and returned. |
2932 | |
2933 | @param value a 8-Bit character array. |
2934 | @param length the number of character which should be converted. |
2935 | The 8-Bit character array length must be |
2936 | greater than or equal to this value. |
2937 | @param encoding the text encoding from which the 8-Bit character |
2938 | sequence should be converted. |
2939 | @param convertFlags flags which controls the conversion. |
2940 | see RTL_TEXTTOUNICODE_FLAGS_... |
2941 | @param pInfo pointer to return conversion status or NULL. |
2942 | |
2943 | @return |
2944 | a version of the converted string from the pool. |
2945 | |
2946 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs |
2947 | |
2948 | @since UDK 3.2.7 |
2949 | */ |
2950 | static OUString intern( const char * value, sal_Int32 length, |
2951 | rtl_TextEncoding encoding, |
2952 | sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300 )), |
2953 | sal_uInt32 *pInfo = NULL__null ) |
2954 | { |
2955 | rtl_uString * pNew = NULL__null; |
2956 | rtl_uString_internConvert( &pNew, value, length, encoding, |
2957 | convertFlags, pInfo ); |
2958 | if (pNew == NULL__null) { |
2959 | throw std::bad_alloc(); |
2960 | } |
2961 | return OUString( pNew, SAL_NO_ACQUIRE ); |
2962 | } |
2963 | |
2964 | /** |
2965 | Converts to an OString, signalling failure. |
2966 | |
2967 | @param pTarget |
2968 | An out parameter receiving the converted OString. Must not be null; the |
2969 | contents are not modified if conversion fails (convertToOString returns |
2970 | false). |
2971 | |
2972 | @param nEncoding |
2973 | The text encoding to convert into. Must be an octet encoding (i.e., |
2974 | rtl_isOctetTextEncoding(nEncoding) must return true). |
2975 | |
2976 | @param nFlags |
2977 | A combination of RTL_UNICODETOTEXT_FLAGS that detail how to do the |
2978 | conversion (see rtl_convertUnicodeToText). RTL_UNICODETOTEXT_FLAGS_FLUSH |
2979 | need not be included, it is implicitly assumed. Typical uses are either |
2980 | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | |
2981 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR (fail if a Unicode character cannot |
2982 | be converted to the target nEncoding) or OUSTRING_TO_OSTRING_CVTFLAGS |
2983 | (make a best efforts conversion). |
2984 | |
2985 | @return |
2986 | True if the conversion succeeded, false otherwise. |
2987 | */ |
2988 | bool convertToString(OString * pTarget, rtl_TextEncoding nEncoding, |
2989 | sal_uInt32 nFlags) const |
2990 | { |
2991 | return rtl_convertUStringToString(&pTarget->pData, pData->buffer, |
2992 | pData->length, nEncoding, nFlags); |
2993 | } |
2994 | |
2995 | /** Iterate through this string based on code points instead of UTF-16 code |
2996 | units. |
2997 | |
2998 | See Chapter 3 of The Unicode Standard 5.0 (Addison--Wesley, 2006) for |
2999 | definitions of the various terms used in this description. |
3000 | |
3001 | This string is interpreted as a sequence of zero or more UTF-16 code |
3002 | units. For each index into this sequence (from zero to one less than |
3003 | the length of the sequence, inclusive), a code point represented |
3004 | starting at the given index is computed as follows: |
3005 | |
3006 | - If the UTF-16 code unit addressed by the index constitutes a |
3007 | well-formed UTF-16 code unit sequence, the computed code point is the |
3008 | scalar value encoded by that UTF-16 code unit sequence. |
3009 | |
3010 | - Otherwise, if the index is at least two UTF-16 code units away from |
3011 | the end of the sequence, and the sequence of two UTF-16 code units |
3012 | addressed by the index constitutes a well-formed UTF-16 code unit |
3013 | sequence, the computed code point is the scalar value encoded by that |
3014 | UTF-16 code unit sequence. |
3015 | |
3016 | - Otherwise, the computed code point is the UTF-16 code unit addressed |
3017 | by the index. (This last case catches unmatched surrogates as well as |
3018 | indices pointing into the middle of surrogate pairs.) |
3019 | |
3020 | @param indexUtf16 |
3021 | pointer to a UTF-16 based index into this string; must not be null. On |
3022 | entry, the index must be in the range from zero to the length of this |
3023 | string (in UTF-16 code units), inclusive. Upon successful return, the |
3024 | index will be updated to address the UTF-16 code unit that is the given |
3025 | incrementCodePoints away from the initial index. |
3026 | |
3027 | @param incrementCodePoints |
3028 | the number of code points to move the given *indexUtf16. If |
3029 | non-negative, moving is done after determining the code point at the |
3030 | index. If negative, moving is done before determining the code point |
3031 | at the (then updated) index. The value must be such that the resulting |
3032 | UTF-16 based index is in the range from zero to the length of this |
3033 | string (in UTF-16 code units), inclusive. |
3034 | |
3035 | @return |
3036 | the code point (an integer in the range from 0 to 0x10FFFF, inclusive) |
3037 | that is represented within this string starting at the index computed as |
3038 | follows: If incrementCodePoints is non-negative, the index is the |
3039 | initial value of *indexUtf16; if incrementCodePoints is negative, the |
3040 | index is the updated value of *indexUtf16. In either case, the computed |
3041 | index must be in the range from zero to one less than the length of this |
3042 | string (in UTF-16 code units), inclusive. |
3043 | |
3044 | @since UDK 3.2.7 |
3045 | */ |
3046 | sal_uInt32 iterateCodePoints( |
3047 | sal_Int32 * indexUtf16, sal_Int32 incrementCodePoints = 1) const |
3048 | { |
3049 | return rtl_uString_iterateCodePoints( |
3050 | pData, indexUtf16, incrementCodePoints); |
3051 | } |
3052 | |
3053 | /** |
3054 | * Convert an OString to an OUString, assuming that the OString is |
3055 | * UTF-8-encoded. |
3056 | * |
3057 | * @param rSource |
3058 | * an OString to convert |
3059 | * |
3060 | * @since LibreOffice 4.4 |
3061 | */ |
3062 | static OUString fromUtf8(const OString& rSource) |
3063 | { |
3064 | OUString aTarget; |
3065 | bool bSuccess = rtl_convertStringToUString(&aTarget.pData, |
3066 | rSource.getStr(), |
3067 | rSource.getLength(), |
3068 | RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)), |
3069 | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR((sal_uInt32)0x0010)|RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR((sal_uInt32)0x0100)); |
3070 | (void) bSuccess; |
3071 | assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail ("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 3071, __extension__ __PRETTY_FUNCTION__)); |
3072 | return aTarget; |
3073 | } |
3074 | |
3075 | /** |
3076 | * Convert this string to an OString, assuming that the string can be |
3077 | * UTF-8-encoded successfully. |
3078 | * |
3079 | * In other words, you must not use this method on a random sequence of |
3080 | * UTF-16 code units, but only at places where it is assumed that the |
3081 | * content is a proper string. |
3082 | * |
3083 | * @since LibreOffice 4.4 |
3084 | */ |
3085 | OString toUtf8() const |
3086 | { |
3087 | OString aTarget; |
3088 | bool bSuccess = rtl_convertUStringToString(&aTarget.pData, |
3089 | getStr(), |
3090 | getLength(), |
3091 | RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)), |
3092 | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR((sal_uInt32)0x0010)); |
3093 | (void) bSuccess; |
3094 | assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail ("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 3094, __extension__ __PRETTY_FUNCTION__)); |
3095 | return aTarget; |
3096 | } |
3097 | |
3098 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
3099 | |
3100 | static OUStringNumber< int > number( int i, sal_Int16 radix = 10 ) |
3101 | { |
3102 | return OUStringNumber< int >( i, radix ); |
3103 | } |
3104 | static OUStringNumber< long long > number( long long ll, sal_Int16 radix = 10 ) |
3105 | { |
3106 | return OUStringNumber< long long >( ll, radix ); |
3107 | } |
3108 | static OUStringNumber< unsigned long long > number( unsigned long long ll, sal_Int16 radix = 10 ) |
3109 | { |
3110 | return OUStringNumber< unsigned long long >( ll, radix ); |
3111 | } |
3112 | static OUStringNumber< unsigned long long > number( unsigned int i, sal_Int16 radix = 10 ) |
3113 | { |
3114 | return number( static_cast< unsigned long long >( i ), radix ); |
3115 | } |
3116 | static OUStringNumber< long long > number( long i, sal_Int16 radix = 10) |
3117 | { |
3118 | return number( static_cast< long long >( i ), radix ); |
3119 | } |
3120 | static OUStringNumber< unsigned long long > number( unsigned long i, sal_Int16 radix = 10 ) |
3121 | { |
3122 | return number( static_cast< unsigned long long >( i ), radix ); |
3123 | } |
3124 | static OUStringNumber< float > number( float f ) |
3125 | { |
3126 | return OUStringNumber< float >( f ); |
3127 | } |
3128 | static OUStringNumber< double > number( double d ) |
3129 | { |
3130 | return OUStringNumber< double >( d ); |
3131 | } |
3132 | #else |
3133 | /** |
3134 | Returns the string representation of the integer argument. |
3135 | |
3136 | This function can't be used for language specific conversion. |
3137 | |
3138 | @param i an integer value |
3139 | @param radix the radix (between 2 and 36) |
3140 | @return a string with the string representation of the argument. |
3141 | @since LibreOffice 4.1 |
3142 | */ |
3143 | static OUString number( int i, sal_Int16 radix = 10 ) |
3144 | { |
3145 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT3233]; |
3146 | return OUString(aBuf, rtl_ustr_valueOfInt32(aBuf, i, radix)); |
3147 | } |
3148 | /// @overload |
3149 | /// @since LibreOffice 4.1 |
3150 | static OUString number( unsigned int i, sal_Int16 radix = 10 ) |
3151 | { |
3152 | return number( static_cast< unsigned long long >( i ), radix ); |
3153 | } |
3154 | /// @overload |
3155 | /// @since LibreOffice 4.1 |
3156 | static OUString number( long i, sal_Int16 radix = 10) |
3157 | { |
3158 | return number( static_cast< long long >( i ), radix ); |
3159 | } |
3160 | /// @overload |
3161 | /// @since LibreOffice 4.1 |
3162 | static OUString number( unsigned long i, sal_Int16 radix = 10 ) |
3163 | { |
3164 | return number( static_cast< unsigned long long >( i ), radix ); |
3165 | } |
3166 | /// @overload |
3167 | /// @since LibreOffice 4.1 |
3168 | static OUString number( long long ll, sal_Int16 radix = 10 ) |
3169 | { |
3170 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT6465]; |
3171 | return OUString(aBuf, rtl_ustr_valueOfInt64(aBuf, ll, radix)); |
3172 | } |
3173 | /// @overload |
3174 | /// @since LibreOffice 4.1 |
3175 | static OUString number( unsigned long long ll, sal_Int16 radix = 10 ) |
3176 | { |
3177 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFUINT6465]; |
3178 | return OUString(aBuf, rtl_ustr_valueOfUInt64(aBuf, ll, radix)); |
3179 | } |
3180 | |
3181 | /** |
3182 | Returns the string representation of the float argument. |
3183 | |
3184 | This function can't be used for language specific conversion. |
3185 | |
3186 | @param f a float. |
3187 | @return a string with the decimal representation of the argument. |
3188 | @since LibreOffice 4.1 |
3189 | */ |
3190 | static OUString number( float f ) |
3191 | { |
3192 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT15]; |
3193 | return OUString(aBuf, rtl_ustr_valueOfFloat(aBuf, f)); |
3194 | } |
3195 | |
3196 | /** |
3197 | Returns the string representation of the double argument. |
3198 | |
3199 | This function can't be used for language specific conversion. |
3200 | |
3201 | @param d a double. |
3202 | @return a string with the decimal representation of the argument. |
3203 | @since LibreOffice 4.1 |
3204 | */ |
3205 | static OUString number( double d ) |
3206 | { |
3207 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE25]; |
3208 | return OUString(aBuf, rtl_ustr_valueOfDouble(aBuf, d)); |
3209 | } |
3210 | #endif |
3211 | |
3212 | /** |
3213 | Returns the string representation of the sal_Bool argument. |
3214 | |
3215 | If the sal_Bool is true, the string "true" is returned. |
3216 | If the sal_Bool is false, the string "false" is returned. |
3217 | This function can't be used for language specific conversion. |
3218 | |
3219 | @param b a sal_Bool. |
3220 | @return a string with the string representation of the argument. |
3221 | @deprecated use boolean() |
3222 | */ |
3223 | SAL_DEPRECATED("use boolean()")__attribute__((deprecated("use boolean()"))) static OUString valueOf( sal_Bool b ) |
3224 | { |
3225 | return boolean(b); |
3226 | } |
3227 | |
3228 | /** |
3229 | Returns the string representation of the boolean argument. |
3230 | |
3231 | If the argument is true, the string "true" is returned. |
3232 | If the argument is false, the string "false" is returned. |
3233 | This function can't be used for language specific conversion. |
3234 | |
3235 | @param b a bool. |
3236 | @return a string with the string representation of the argument. |
3237 | @since LibreOffice 4.1 |
3238 | */ |
3239 | static OUString boolean( bool b ) |
3240 | { |
3241 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFBOOLEAN6]; |
3242 | return OUString(aBuf, rtl_ustr_valueOfBoolean(aBuf, b)); |
3243 | } |
3244 | |
3245 | /** |
3246 | Returns the string representation of the char argument. |
3247 | |
3248 | @param c a character. |
3249 | @return a string with the string representation of the argument. |
3250 | @deprecated use operator, function or constructor taking char or sal_Unicode argument |
3251 | */ |
3252 | SAL_DEPRECATED("convert to OUString or use directly")__attribute__((deprecated("convert to OUString or use directly" ))) static OUString valueOf( sal_Unicode c ) |
3253 | { |
3254 | return OUString( &c, 1 ); |
3255 | } |
3256 | |
3257 | /** |
3258 | Returns the string representation of the int argument. |
3259 | |
3260 | This function can't be used for language specific conversion. |
3261 | |
3262 | @param i a int32. |
3263 | @param radix the radix (between 2 and 36) |
3264 | @return a string with the string representation of the argument. |
3265 | @deprecated use number() |
3266 | */ |
3267 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int32 i, sal_Int16 radix = 10 ) |
3268 | { |
3269 | return number( i, radix ); |
3270 | } |
3271 | |
3272 | /** |
3273 | Returns the string representation of the long argument. |
3274 | |
3275 | This function can't be used for language specific conversion. |
3276 | |
3277 | @param ll a int64. |
3278 | @param radix the radix (between 2 and 36) |
3279 | @return a string with the string representation of the argument. |
3280 | @deprecated use number() |
3281 | */ |
3282 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int64 ll, sal_Int16 radix = 10 ) |
3283 | { |
3284 | return number( ll, radix ); |
3285 | } |
3286 | |
3287 | /** |
3288 | Returns the string representation of the float argument. |
3289 | |
3290 | This function can't be used for language specific conversion. |
3291 | |
3292 | @param f a float. |
3293 | @return a string with the string representation of the argument. |
3294 | @deprecated use number() |
3295 | */ |
3296 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( float f ) |
3297 | { |
3298 | return number(f); |
3299 | } |
3300 | |
3301 | /** |
3302 | Returns the string representation of the double argument. |
3303 | |
3304 | This function can't be used for language specific conversion. |
3305 | |
3306 | @param d a double. |
3307 | @return a string with the string representation of the argument. |
3308 | @deprecated use number() |
3309 | */ |
3310 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( double d ) |
3311 | { |
3312 | return number(d); |
3313 | } |
3314 | |
3315 | /** |
3316 | Returns an OUString copied without conversion from an ASCII |
3317 | character string. |
3318 | |
3319 | Since this method is optimized for performance, the ASCII character |
3320 | values are not converted in any way. The caller has to make sure that |
3321 | all ASCII characters are in the allowed range between 0 and 127. |
3322 | The ASCII string must be NULL-terminated. |
3323 | |
3324 | Note that for string literals it is simpler and more efficient |
3325 | to directly use the OUString constructor. |
3326 | |
3327 | @param value the 8-Bit ASCII character string |
3328 | @return a string with the string representation of the argument. |
3329 | */ |
3330 | static OUString createFromAscii( const char * value ) |
3331 | { |
3332 | rtl_uString* pNew = NULL__null; |
3333 | rtl_uString_newFromAscii( &pNew, value ); |
3334 | return OUString( pNew, SAL_NO_ACQUIRE ); |
3335 | } |
3336 | |
3337 | #if defined LIBO_INTERNAL_ONLY1 |
3338 | static OUString createFromAscii(std::string_view value) { |
3339 | rtl_uString * p = nullptr; |
3340 | rtl_uString_newFromLiteral(&p, value.data(), value.size(), 0); //TODO: check for overflow |
3341 | return OUString(p, SAL_NO_ACQUIRE); |
3342 | } |
3343 | #endif |
3344 | |
3345 | #if defined LIBO_INTERNAL_ONLY1 |
3346 | operator std::u16string_view() const { return {getStr(), sal_uInt32(getLength())}; } |
3347 | #endif |
3348 | |
3349 | #if defined LIBO_INTERNAL_ONLY1 |
3350 | // A wrapper for the first expression in an |
3351 | // |
3352 | // OUString::Concat(e1) + e2 + ... |
3353 | // |
3354 | // concatenation chain, when neither of the first two e1, e2 is one of our rtl string-related |
3355 | // classes (so something like |
3356 | // |
3357 | // OUString s = "a" + (b ? std::u16string_view(u"c") : std::u16string_view(u"dd")); |
3358 | // |
3359 | // would not compile): |
3360 | template<typename T> [[nodiscard]] static |
3361 | typename std::enable_if_t< |
3362 | ToStringHelper<T>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T>> |
3363 | Concat(T const & value) { return OUStringConcat<OUStringConcatMarker, T>({}, value); } |
3364 | |
3365 | // This overload is needed so that an argument of type 'char const[N]' ends up as |
3366 | // 'OUStringConcat<rtl::OUStringConcatMarker, char const[N]>' rather than as |
3367 | // 'OUStringConcat<rtl::OUStringConcatMarker, char[N]>': |
3368 | template<typename T, std::size_t N> [[nodiscard]] static |
3369 | typename std::enable_if_t< |
3370 | ToStringHelper<T[N]>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T[N]>> |
3371 | Concat(T (& value)[N]) { return OUStringConcat<OUStringConcatMarker, T[N]>({}, value); } |
3372 | #endif |
3373 | |
3374 | private: |
3375 | OUString & internalAppend( rtl_uString* pOtherData ) |
3376 | { |
3377 | rtl_uString* pNewData = NULL__null; |
3378 | rtl_uString_newConcat( &pNewData, pData, pOtherData ); |
3379 | if (pNewData == NULL__null) { |
3380 | throw std::bad_alloc(); |
3381 | } |
3382 | rtl_uString_assign(&pData, pNewData); |
3383 | rtl_uString_release(pNewData); |
3384 | return *this; |
3385 | } |
3386 | |
3387 | }; |
3388 | |
3389 | #if defined LIBO_INTERNAL_ONLY1 |
3390 | // Prevent the operator ==/!= overloads with 'sal_Unicode const *' parameter from |
3391 | // being selected for nonsensical code like |
3392 | // |
3393 | // if (ouIdAttr == nullptr) |
3394 | // |
3395 | void operator ==(OUString const &, std::nullptr_t) = delete; |
3396 | void operator ==(std::nullptr_t, OUString const &) = delete; |
3397 | void operator !=(OUString const &, std::nullptr_t) = delete; |
3398 | void operator !=(std::nullptr_t, OUString const &) = delete; |
3399 | #endif |
3400 | |
3401 | #if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" |
3402 | /// @cond INTERNAL |
3403 | |
3404 | /** |
3405 | @internal |
3406 | */ |
3407 | template<> |
3408 | struct ToStringHelper< OUString > |
3409 | { |
3410 | static std::size_t length( const OUString& s ) { return s.getLength(); } |
3411 | static sal_Unicode* addData( sal_Unicode* buffer, const OUString& s ) { return addDataHelper( buffer, s.getStr(), s.getLength()); } |
3412 | static const bool allowOStringConcat = false; |
3413 | static const bool allowOUStringConcat = true; |
3414 | }; |
3415 | |
3416 | /** |
3417 | @internal |
3418 | */ |
3419 | template<std::size_t N> |
3420 | struct ToStringHelper< OUStringLiteral<N> > |
3421 | { |
3422 | static std::size_t length( const OUStringLiteral<N>& str ) { return str.getLength(); } |
3423 | static sal_Unicode* addData( sal_Unicode* buffer, const OUStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), str.getLength() ); } |
3424 | static const bool allowOStringConcat = false; |
3425 | static const bool allowOUStringConcat = true; |
3426 | }; |
3427 | |
3428 | /** |
3429 | @internal |
3430 | */ |
3431 | template< typename charT, typename traits, typename T1, typename T2 > |
3432 | inline std::basic_ostream<charT, traits> & operator <<( |
3433 | std::basic_ostream<charT, traits> & stream, OUStringConcat< T1, T2 >&& concat) |
3434 | { |
3435 | return stream << OUString( std::move(concat) ); |
3436 | } |
3437 | |
3438 | /// @endcond |
3439 | #endif |
3440 | |
3441 | /** A helper to use OUStrings with hash maps. |
3442 | |
3443 | Instances of this class are unary function objects that can be used as |
3444 | hash function arguments to std::unordered_map and similar constructs. |
3445 | */ |
3446 | struct OUStringHash |
3447 | { |
3448 | /** Compute a hash code for a string. |
3449 | |
3450 | @param rString |
3451 | a string. |
3452 | |
3453 | @return |
3454 | a hash code for the string. This hash code should not be stored |
3455 | persistently, as its computation may change in later revisions. |
3456 | */ |
3457 | size_t operator()(const OUString& rString) const |
3458 | { return static_cast<size_t>(rString.hashCode()); } |
3459 | }; |
3460 | |
3461 | /* ======================================================================= */ |
3462 | |
3463 | /** Convert an OString to an OUString, using a specific text encoding. |
3464 | |
3465 | The lengths of the two strings may differ (e.g., for double-byte |
3466 | encodings, UTF-7, UTF-8). |
3467 | |
3468 | @param rStr |
3469 | an OString to convert. |
3470 | |
3471 | @param encoding |
3472 | the text encoding to use for conversion. |
3473 | |
3474 | @param convertFlags |
3475 | flags which control the conversion. Either use |
3476 | OSTRING_TO_OUSTRING_CVTFLAGS, or see |
3477 | <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more |
3478 | details. |
3479 | */ |
3480 | inline OUString OStringToOUString( const OString & rStr, |
3481 | rtl_TextEncoding encoding, |
3482 | sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300 )) ) |
3483 | { |
3484 | return OUString( rStr.getStr(), rStr.getLength(), encoding, convertFlags ); |
3485 | } |
3486 | |
3487 | /** Convert an OUString to an OString, using a specific text encoding. |
3488 | |
3489 | The lengths of the two strings may differ (e.g., for double-byte |
3490 | encodings, UTF-7, UTF-8). |
3491 | |
3492 | @param rUnicode |
3493 | an OUString to convert. |
3494 | |
3495 | @param encoding |
3496 | the text encoding to use for conversion. |
3497 | |
3498 | @param convertFlags |
3499 | flags which control the conversion. Either use |
3500 | OUSTRING_TO_OSTRING_CVTFLAGS, or see |
3501 | <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more |
3502 | details. |
3503 | */ |
3504 | inline OString OUStringToOString( const OUString & rUnicode, |
3505 | rtl_TextEncoding encoding, |
3506 | sal_uInt32 convertFlags = OUSTRING_TO_OSTRING_CVTFLAGS(((sal_uInt32)0x0006) | ((sal_uInt32)0x0060) | ((sal_uInt32)0x0100 ) | ((sal_uInt32)0x0400)) ) |
3507 | { |
3508 | return OString( rUnicode.getStr(), rUnicode.getLength(), encoding, convertFlags ); |
3509 | } |
3510 | |
3511 | /* ======================================================================= */ |
3512 | |
3513 | /** |
3514 | Support for rtl::OUString in std::ostream (and thus in |
3515 | CPPUNIT_ASSERT or SAL_INFO macros, for example). |
3516 | |
3517 | The rtl::OUString is converted to UTF-8. |
3518 | |
3519 | @since LibreOffice 3.5. |
3520 | */ |
3521 | template< typename charT, typename traits > |
3522 | inline std::basic_ostream<charT, traits> & operator <<( |
3523 | std::basic_ostream<charT, traits> & stream, OUString const & rString) |
3524 | { |
3525 | return stream << |
3526 | OUStringToOString(rString, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))); |
3527 | // best effort; potentially loses data due to conversion failures |
3528 | // (stray surrogate halves) and embedded null characters |
3529 | } |
3530 | |
3531 | } // namespace |
3532 | |
3533 | #ifdef RTL_STRING_UNITTEST |
3534 | namespace rtl |
3535 | { |
3536 | typedef rtlunittest::OUString OUString; |
3537 | } |
3538 | #endif |
3539 | |
3540 | // In internal code, allow to use classes like OUString without having to |
3541 | // explicitly refer to the rtl namespace, which is kind of superfluous given |
3542 | // that OUString itself is namespaced by its OU prefix: |
3543 | #if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST |
3544 | using ::rtl::OUString; |
3545 | using ::rtl::OUStringHash; |
3546 | using ::rtl::OStringToOUString; |
3547 | using ::rtl::OUStringToOString; |
3548 | using ::rtl::OUStringLiteral; |
3549 | using ::rtl::OUStringChar; |
3550 | #endif |
3551 | |
3552 | /// @cond INTERNAL |
3553 | /** |
3554 | Make OUString hashable by default for use in STL containers. |
3555 | |
3556 | @since LibreOffice 6.0 |
3557 | */ |
3558 | #if defined LIBO_INTERNAL_ONLY1 |
3559 | namespace std { |
3560 | |
3561 | template<> |
3562 | struct hash<::rtl::OUString> |
3563 | { |
3564 | std::size_t operator()(::rtl::OUString const & s) const |
3565 | { return std::size_t(s.hashCode()); } |
3566 | }; |
3567 | |
3568 | } |
3569 | |
3570 | #endif |
3571 | /// @endcond |
3572 | |
3573 | #endif /* _RTL_USTRING_HXX */ |
3574 | |
3575 | /* 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_SW_INC_DBMGR_HXX |
20 | #define INCLUDED_SW_INC_DBMGR_HXX |
21 | |
22 | #include <rtl/ustring.hxx> |
23 | #include <tools/solar.h> |
24 | #include <i18nlangtag/lang.h> |
25 | #include <com/sun/star/util/Date.hpp> |
26 | #include "swdllapi.h" |
27 | #include "swdbdata.hxx" |
28 | #include <com/sun/star/uno/Reference.h> |
29 | #include <com/sun/star/uno/Sequence.hxx> |
30 | #include <com/sun/star/lang/Locale.hpp> |
31 | #include <com/sun/star/beans/PropertyValue.hpp> |
32 | |
33 | #include <memory> |
34 | #include <vector> |
35 | |
36 | namespace com::sun::star{ |
37 | namespace sdbc{ |
38 | class XConnection; |
39 | class XStatement; |
40 | class XDataSource; |
41 | class XResultSet; |
42 | } |
43 | namespace beans{ |
44 | |
45 | class XPropertySet; |
46 | } |
47 | namespace sdbcx{ |
48 | class XColumnsSupplier; |
49 | } |
50 | namespace util{ |
51 | class XNumberFormatter; |
52 | } |
53 | namespace mail{ |
54 | class XSmtpService; |
55 | } |
56 | namespace embed { class XStorage; } |
57 | namespace frame { class XStorable; } |
58 | } |
59 | namespace svx { |
60 | class ODataAccessDescriptor; |
61 | } |
62 | |
63 | struct SwDBFormatData |
64 | { |
65 | css::util::Date aNullDate; |
66 | css::uno::Reference< css::util::XNumberFormatter> xFormatter; |
67 | css::lang::Locale aLocale; |
68 | }; |
69 | |
70 | namespace weld { |
71 | class ComboBox; |
72 | class Window; |
73 | } |
74 | |
75 | class SwView; |
76 | class SwWrtShell; |
77 | class ListBox; |
78 | class SvNumberFormatter; |
79 | class SwXMailMerge; |
80 | class SwMailMergeConfigItem; |
81 | class SwCalc; |
82 | class INetURLObject; |
83 | class SwDocShell; |
84 | |
85 | enum DBManagerOptions |
86 | { |
87 | DBMGR_MERGE, ///< Data records in fields. |
88 | DBMGR_MERGE_PRINTER, ///< Print mail merge. |
89 | DBMGR_MERGE_EMAIL, ///< Send mail merge as email. |
90 | DBMGR_MERGE_FILE, ///< Save mail merge as files. |
91 | DBMGR_MERGE_SHELL ///< Create merge doc and keep the doc shell. |
92 | }; |
93 | |
94 | // Administration of (new) logical databases. |
95 | enum class SwDBSelect |
96 | { |
97 | UNKNOWN, TABLE, QUERY |
98 | }; |
99 | |
100 | struct SwDSParam : public SwDBData |
101 | { |
102 | css::util::Date aNullDate; |
103 | |
104 | css::uno::Reference<css::util::XNumberFormatter> xFormatter; |
105 | css::uno::Reference< css::sdbc::XConnection> xConnection; |
106 | css::uno::Reference< css::sdbc::XStatement> xStatement; |
107 | css::uno::Reference< css::sdbc::XResultSet> xResultSet; |
108 | css::uno::Sequence< css::uno::Any > aSelection; |
109 | bool bScrollable; |
110 | bool bEndOfDB; |
111 | long nSelectionIndex; |
112 | |
113 | SwDSParam(const SwDBData& rData) : |
114 | SwDBData(rData), |
115 | bScrollable(false), |
116 | bEndOfDB(false), |
117 | nSelectionIndex(0) |
118 | {} |
119 | |
120 | SwDSParam(const SwDBData& rData, |
121 | const css::uno::Reference< css::sdbc::XResultSet>& xResSet, |
122 | const css::uno::Sequence< css::uno::Any >& rSelection) : |
123 | SwDBData(rData), |
124 | xResultSet(xResSet), |
125 | aSelection(rSelection), |
126 | bScrollable(true), |
127 | bEndOfDB(false), |
128 | nSelectionIndex(0) |
129 | {} |
130 | |
131 | bool HasValidRecord() const |
132 | { return( !bEndOfDB && xResultSet.is() ); } |
133 | }; |
134 | |
135 | typedef std::vector<std::unique_ptr<SwDSParam>> SwDSParams_t; |
136 | |
137 | struct SwMergeDescriptor |
138 | { |
139 | const DBManagerOptions nMergeType; |
140 | SwWrtShell& rSh; |
141 | const svx::ODataAccessDescriptor& rDescriptor; |
142 | |
143 | /** |
144 | * Create a single or multiple results |
145 | * |
146 | * This currently just affects FILE, as EMAIL is always |
147 | * multiple and SHELL and PRINTER are always single. |
148 | */ |
149 | bool bCreateSingleFile; |
150 | |
151 | /** |
152 | * @defgroup save Export filter settings |
153 | * @addtogroup save |
154 | * @{ */ |
155 | OUString sSaveToFilter; |
156 | OUString sSaveToFilterOptions; |
157 | css::uno::Sequence< css::beans::PropertyValue > aSaveToFilterData; |
158 | /** @} */ |
159 | |
160 | /** |
161 | * @defgroup file Mail merge as File settings |
162 | * @addtogroup file |
163 | * @{ */ |
164 | |
165 | /** |
166 | * Basename incl. the path for the generated files. |
167 | * |
168 | * The final filename will be created by concatenating a number to prevent |
169 | * overwriting an existing file and the extension based on the filter |
170 | * settings. |
171 | */ |
172 | OUString sPrefix; |
173 | /** |
174 | * Use the sPrefix as the target filename also overwriting an existing |
175 | * target file. |
176 | * |
177 | * Just used for the internal mail merge dialogs as mail merge never |
178 | * overwrites existing files (see SwDBManager::ExecuteFormLetter). |
179 | */ |
180 | bool bPrefixIsFilename; |
181 | /** @} */ |
182 | |
183 | /** |
184 | * @defgroup email Mail merge as eMail settings |
185 | * @addtogroup email |
186 | * @{ */ |
187 | OUString sSubject; |
188 | OUString sMailBody; |
189 | OUString sAttachmentName; |
190 | css::uno::Sequence< OUString > aCopiesTo; |
191 | css::uno::Sequence< OUString > aBlindCopiesTo; |
192 | css::uno::Reference< css::mail::XSmtpService > xSmtpServer; |
193 | bool bSendAsHTML; |
194 | bool bSendAsAttachment; |
195 | /** @} */ |
196 | |
197 | /** |
198 | * @addtogroup file email |
199 | * @{ */ |
200 | |
201 | /** DB column to fetch EMail of Filename from |
202 | */ |
203 | OUString sDBcolumn; |
204 | |
205 | /** DB column to fetch password |
206 | */ |
207 | OUString sDBPasswordColumn; |
208 | |
209 | /** @} */ |
210 | |
211 | /** |
212 | * @defgroup print Mail merge to Printer |
213 | * @addtogroup print |
214 | * @{ */ |
215 | css::uno::Sequence< css::beans::PropertyValue > aPrintOptions; |
216 | /** @} */ |
217 | |
218 | SwMailMergeConfigItem* pMailMergeConfigItem; |
219 | |
220 | SwMergeDescriptor( const DBManagerOptions nType, |
221 | SwWrtShell& rShell, |
222 | const svx::ODataAccessDescriptor& rDesc ) : |
223 | nMergeType(nType), |
224 | rSh(rShell), |
225 | rDescriptor(rDesc), |
226 | bCreateSingleFile( false ), |
227 | bPrefixIsFilename( false ), |
228 | bSendAsHTML( true ), |
229 | bSendAsAttachment( false ), |
230 | pMailMergeConfigItem( nullptr ) |
231 | { |
232 | if( nType == DBMGR_MERGE_SHELL || nType == DBMGR_MERGE_PRINTER ) |
233 | bCreateSingleFile = true; |
234 | } |
235 | }; |
236 | |
237 | class SwDoc; |
238 | |
239 | class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwDBManager |
240 | { |
241 | struct SwDBManager_Impl; |
242 | class SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) ConnectionDisposedListener_Impl; |
243 | class MailDispatcherListener_Impl; |
244 | |
245 | enum class MergeStatus |
246 | { |
247 | Ok = 0, Cancel, Error |
248 | }; |
249 | |
250 | MergeStatus m_aMergeStatus; ///< current / last merge status |
251 | bool m_bInitDBFields : 1; |
252 | bool m_bInMerge : 1; ///< merge process active |
253 | bool m_bMergeSilent : 1; ///< suppress display of dialogs/boxes (used when called over API) |
254 | SwDSParams_t m_DataSourceParams; |
255 | std::unique_ptr<SwDBManager_Impl> m_pImpl; |
256 | const SwXMailMerge* m_pMergeEvtSrc; ///< != 0 if mail merge events are to be send |
257 | /// Name of the embedded database that's included in the current document. |
258 | OUString m_sEmbeddedName; |
259 | |
260 | /// Store last registrations to revoke or commit |
261 | static std::vector<std::pair<SwDocShell*, OUString>> m_aUncommittedRegistrations; |
262 | |
263 | /// Not used connections. |
264 | std::vector<OUString> m_aNotUsedConnections; |
265 | |
266 | /// Set connection as used. |
267 | void SetAsUsed(const OUString& rName); |
268 | |
269 | /// The document that owns this manager. |
270 | SwDoc* m_pDoc; |
271 | |
272 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwDSParam* FindDSData(const SwDBData& rData, bool bCreate); |
273 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwDSParam* FindDSConnection(const OUString& rSource, bool bCreate); |
274 | |
275 | /// Insert data record as text into document. |
276 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImportFromConnection( SwWrtShell* pSh); |
277 | |
278 | /// Insert a single data record as text into document. |
279 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void ImportDBEntry(SwWrtShell* pSh); |
280 | |
281 | /// Run the mail merge for defined modes, except DBMGR_MERGE |
282 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool MergeMailFiles( SwWrtShell* pSh, |
283 | const SwMergeDescriptor& rMergeDescriptor ); |
284 | |
285 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool ToNextMergeRecord(); |
286 | SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) bool IsValidMergeRecord() const; |
287 | |
288 | SwDBManager(SwDBManager const&) = delete; |
289 | SwDBManager& operator=(SwDBManager const&) = delete; |
290 | |
291 | public: |
292 | SwDBManager(SwDoc* pDoc); |
293 | ~SwDBManager() COVERITY_NOEXCEPT_FALSE; |
294 | |
295 | /// MailMergeEvent source |
296 | const SwXMailMerge * GetMailMergeEvtSrc() const { return m_pMergeEvtSrc; } |
297 | void SetMailMergeEvtSrc( const SwXMailMerge *pSrc ) { m_pMergeEvtSrc = pSrc; } |
298 | |
299 | bool IsMergeSilent() const { return m_bMergeSilent; } |
300 | void SetMergeSilent( bool bVal ) { m_bMergeSilent = bVal; } |
301 | |
302 | /// Merging of data records into fields. |
303 | bool Merge( const SwMergeDescriptor& rMergeDesc ); |
304 | void MergeCancel(); |
305 | |
306 | bool IsMergeOk() const { return MergeStatus::Ok == m_aMergeStatus; } |
307 | bool IsMergeError() const { return MergeStatus::Error <= m_aMergeStatus; } |
308 | |
309 | static std::shared_ptr<SwMailMergeConfigItem> PerformMailMerge(SwView const * pView); |
310 | |
311 | /// Initialize data fields that lack name of database. |
312 | bool IsInitDBFields() const { return m_bInitDBFields; } |
313 | void SetInitDBFields(bool b) { m_bInitDBFields = b; } |
314 | |
315 | /// Fill listbox with all table names of a database. |
316 | bool GetTableNames(weld::ComboBox& rBox, const OUString& rDBName); |
317 | |
318 | /// Fill listbox with all column names of a database table. |
319 | void GetColumnNames(weld::ComboBox& rBox, |
320 | const OUString& rDBName, const OUString& rTableName); |
321 | static void GetColumnNames(weld::ComboBox& rBox, |
322 | css::uno::Reference< css::sdbc::XConnection> const & xConnection, |
323 | const OUString& rTableName); |
324 | |
325 | static sal_uLong GetColumnFormat( css::uno::Reference< css::sdbc::XDataSource> const & xSource, |
326 | css::uno::Reference< css::sdbc::XConnection> const & xConnection, |
327 | css::uno::Reference< css::beans::XPropertySet> const & xColumn, |
328 | SvNumberFormatter* pNFormatr, |
329 | LanguageType nLanguage ); |
330 | |
331 | sal_uLong GetColumnFormat( const OUString& rDBName, |
332 | const OUString& rTableName, |
333 | const OUString& rColNm, |
334 | SvNumberFormatter* pNFormatr, |
335 | LanguageType nLanguage ); |
336 | sal_Int32 GetColumnType( const OUString& rDBName, |
337 | const OUString& rTableName, |
338 | const OUString& rColNm ); |
339 | |
340 | bool IsInMerge() const { return m_bInMerge; } |
341 | |
342 | void ExecuteFormLetter(SwWrtShell& rSh, |
343 | const css::uno::Sequence< css::beans::PropertyValue>& rProperties); |
344 | |
345 | static void InsertText(SwWrtShell& rSh, |
346 | const css::uno::Sequence< css::beans::PropertyValue>& rProperties); |
347 | |
348 | /// check if a data source is open |
349 | bool IsDataSourceOpen(const OUString& rDataSource, |
350 | const OUString& rTableOrQuery, bool bMergeShell); |
351 | |
352 | /// open the source while fields are updated - for the calculator only! |
353 | bool OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery); |
354 | sal_uInt32 GetSelectedRecordId(const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType = -1); |
355 | bool GetColumnCnt(const OUString& rSourceName, const OUString& rTableName, |
356 | const OUString& rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage, |
357 | OUString& rResult, double* pNumber); |
358 | /** create and store or find an already stored connection to a data source for use |
359 | in SwFieldMgr and SwDBTreeList */ |
360 | css::uno::Reference< css::sdbc::XConnection> const & |
361 | RegisterConnection(OUString const& rSource); |
362 | |
363 | void CreateDSData(const SwDBData& rData) |
364 | { FindDSData(rData, true); } |
365 | const SwDSParams_t& GetDSParamArray() const { return m_DataSourceParams; } |
366 | |
367 | /// close all data sources - after fields were updated |
368 | void CloseAll(bool bIncludingMerge = true); |
369 | |
370 | bool GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage, |
371 | OUString &rResult, double *pNumber); |
372 | bool FillCalcWithMergeData(SvNumberFormatter *pDocFormatter, |
373 | LanguageType nLanguage, SwCalc &aCalc); |
374 | void ToNextRecord(const OUString& rDataSource, const OUString& rTableOrQuery); |
375 | |
376 | sal_uInt32 GetSelectedRecordId(); |
377 | bool ToRecordId(sal_Int32 nSet); |
378 | |
379 | static const SwDBData& GetAddressDBName(); |
380 | |
381 | static OUString GetDBField( |
382 | css::uno::Reference< css::beans::XPropertySet > const & xColumnProp, |
383 | const SwDBFormatData& rDBFormatData, |
384 | double *pNumber = nullptr); |
385 | |
386 | static css::uno::Reference< css::sdbc::XConnection> |
387 | GetConnection(const OUString& rDataSource, |
388 | css::uno::Reference< css::sdbc::XDataSource>& rxSource, |
389 | const SwView* pView); |
390 | |
391 | static css::uno::Reference< css::sdbcx::XColumnsSupplier> |
392 | GetColumnSupplier(css::uno::Reference< css::sdbc::XConnection> const & xConnection, |
393 | const OUString& rTableOrQuery, |
394 | SwDBSelect eTableOrQuery = SwDBSelect::UNKNOWN); |
395 | |
396 | static css::uno::Sequence<OUString> GetExistingDatabaseNames(); |
397 | |
398 | /** |
399 | Loads a data source from file and registers it. |
400 | |
401 | This function requires GUI interaction, as it loads the data source from |
402 | the filename returned by a file picker and additional settings dialog. |
403 | In case of success it returns the registered name, otherwise an empty string. |
404 | */ |
405 | static OUString LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell = nullptr); |
406 | |
407 | /** |
408 | Loads a data source from file and registers it. |
409 | |
410 | Convenience function, which calls GetDBunoURI and has just one mandatory parameter. |
411 | In case of success it returns the registered name, otherwise an empty string. |
412 | */ |
413 | static OUString LoadAndRegisterDataSource(const OUString& rURI, const OUString *pDestDir); |
414 | |
415 | /// Load the embedded data source of the document and also register it. |
416 | void LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell); |
417 | |
418 | /// Unregister a data source. |
419 | static void RevokeDataSource(const OUString& rName); |
420 | |
421 | /** try to get the data source from the given connection through the XChild interface. |
422 | If this is not possible, the data source will be created through its name. |
423 | @param _xConnection |
424 | The connection which should support the XChild interface. (not a must) |
425 | @param _sDataSourceName |
426 | The data source name will be used to create the data source when the connection can not be used for it. |
427 | @return |
428 | The data source. |
429 | */ |
430 | static css::uno::Reference< css::sdbc::XDataSource> |
431 | getDataSourceAsParent(const css::uno::Reference< css::sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName); |
432 | |
433 | /** creates a RowSet, which must be disposed after use. |
434 | @param _sDataSourceName |
435 | The data source name |
436 | @param _sCommand |
437 | The command. |
438 | @param _nCommandType |
439 | The type of the command. |
440 | @param _xConnection |
441 | The active connection which may be <NULL/>. |
442 | @return |
443 | The new created RowSet. |
444 | |
445 | */ |
446 | static css::uno::Reference< css::sdbc::XResultSet> |
447 | createCursor(const OUString& _sDataSourceName, |
448 | const OUString& _sCommand, |
449 | sal_Int32 _nCommandType, |
450 | const css::uno::Reference< css::sdbc::XConnection>& _xConnection, |
451 | const SwView* pView); |
452 | |
453 | void setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell); |
454 | const OUString& getEmbeddedName() const; |
455 | |
456 | // rOwnURL should be taken using INetURLObject::GetMainURL(INetURLObject::DecodeMechanism::NONE) |
457 | static void StoreEmbeddedDataSource(const css::uno::Reference<css::frame::XStorable>& xStorable, |
458 | const css::uno::Reference<css::embed::XStorage>& xStorage, |
459 | const OUString& rStreamRelPath, |
460 | const OUString& rOwnURL, bool bCopyTo = false); |
461 | |
462 | SwDoc* getDoc() const; |
463 | /// Stop reacting to removed database registrations. |
464 | void releaseRevokeListener(); |
465 | |
466 | /// Revoke not committed registrations in case of mail merge cancel |
467 | void RevokeLastRegistrations(); |
468 | |
469 | /// Accept not committed registrations |
470 | void CommitLastRegistrations(); |
471 | |
472 | /// Remove not used connections. |
473 | void RevokeNotUsedConnections(); |
474 | }; |
475 | |
476 | namespace sw |
477 | { |
478 | enum class DBConnURIType |
479 | { |
480 | UNKNOWN = 0, |
481 | ODB, |
482 | CALC, |
483 | DBASE, |
484 | FLAT, |
485 | MSJET, |
486 | MSACE, |
487 | WRITER |
488 | }; |
489 | |
490 | DBConnURIType SW_DLLPUBLIC__attribute__ ((visibility("default"))) GetDBunoType(const INetURLObject &rURL); |
491 | } |
492 | |
493 | #endif |
494 | |
495 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |