Line data Source code
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 <cstdarg>
21 :
22 : #include <unotxdoc.hxx>
23 : #include <com/sun/star/text/NotePrintMode.hpp>
24 : #include <sfx2/app.hxx>
25 : #include <sfx2/printer.hxx>
26 : #include <com/sun/star/sdb/CommandType.hpp>
27 : #include <com/sun/star/sdb/XDocumentDataSource.hpp>
28 : #include <com/sun/star/frame/XComponentLoader.hpp>
29 : #include <com/sun/star/lang/DisposedException.hpp>
30 : #include <com/sun/star/lang/XEventListener.hpp>
31 : #include <com/sun/star/util/NumberFormatter.hpp>
32 : #include <com/sun/star/sdb/DatabaseContext.hpp>
33 : #include <com/sun/star/sdb/TextConnectionSettings.hpp>
34 : #include <com/sun/star/sdb/XCompletedConnection.hpp>
35 : #include <com/sun/star/sdb/XCompletedExecution.hpp>
36 : #include <com/sun/star/container/XChild.hpp>
37 : #include <com/sun/star/text/MailMergeEvent.hpp>
38 : #include <com/sun/star/frame/XStorable.hpp>
39 : #include <com/sun/star/task/InteractionHandler.hpp>
40 : #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
41 : #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
42 : #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
43 : #include <com/sun/star/uno/XNamingService.hpp>
44 : #include <com/sun/star/util/XCloseable.hpp>
45 : #include <com/sun/star/beans/XPropertySet.hpp>
46 : #include <sfx2/fcontnr.hxx>
47 : #include <sfx2/filedlghelper.hxx>
48 : #include <sfx2/viewfrm.hxx>
49 : #include <dbconfig.hxx>
50 : #include <pagedesc.hxx>
51 : #include <vcl/lstbox.hxx>
52 : #include <unotools/tempfile.hxx>
53 : #include <unotools/pathoptions.hxx>
54 : #include <svl/urihelper.hxx>
55 : #include <svl/zforlist.hxx>
56 : #include <svl/zformat.hxx>
57 : #include <svl/stritem.hxx>
58 : #include <svl/eitem.hxx>
59 : #include <vcl/oldprintadaptor.hxx>
60 : #include <sfx2/docfile.hxx>
61 : #include <sfx2/progress.hxx>
62 : #include <sfx2/dispatch.hxx>
63 : #include <svl/mailenum.hxx>
64 : #include <cmdid.h>
65 : #include <swmodule.hxx>
66 : #include <view.hxx>
67 : #include <docsh.hxx>
68 : #include <edtwin.hxx>
69 : #include <wrtsh.hxx>
70 : #include <fldbas.hxx>
71 : #include <initui.hxx>
72 : #include <swundo.hxx>
73 : #include <flddat.hxx>
74 : #include <modcfg.hxx>
75 : #include <shellio.hxx>
76 : #include <dbui.hxx>
77 : #include <dbmgr.hxx>
78 : #include <doc.hxx>
79 : #include <IDocumentSettingAccess.hxx>
80 : #include <IDocumentLinksAdministration.hxx>
81 : #include <IDocumentContentOperations.hxx>
82 : #include <IDocumentFieldsAccess.hxx>
83 : #include <swwait.hxx>
84 : #include <swunohelper.hxx>
85 : #include <dbui.hrc>
86 : #include <globals.hrc>
87 : #include <statstr.hrc>
88 : #include <mmconfigitem.hxx>
89 : #include <sfx2/request.hxx>
90 : #include <hintids.hxx>
91 : #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
92 : #include <com/sun/star/sdbc/XRowSet.hpp>
93 : #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
94 : #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
95 : #include <com/sun/star/sdb/XQueriesSupplier.hpp>
96 : #include <com/sun/star/sdb/XColumn.hpp>
97 : #include <com/sun/star/sdbc/DataType.hpp>
98 : #include <com/sun/star/sdbc/ResultSetType.hpp>
99 : #include <com/sun/star/mail/MailAttachment.hpp>
100 : #include <comphelper/processfactory.hxx>
101 : #include <comphelper/property.hxx>
102 : #include <comphelper/string.hxx>
103 : #include <comphelper/types.hxx>
104 : #include <mailmergehelper.hxx>
105 : #include <maildispatcher.hxx>
106 : #include <svtools/htmlcfg.hxx>
107 : #include <i18nlangtag/languagetag.hxx>
108 : #include <com/sun/star/util/XNumberFormatTypes.hpp>
109 : #include <editeng/langitem.hxx>
110 : #include <svl/numuno.hxx>
111 : #include <connectivity/dbtools.hxx>
112 : #include <connectivity/dbconversion.hxx>
113 :
114 : #include <unomailmerge.hxx>
115 : #include <sfx2/event.hxx>
116 : #include <vcl/msgbox.hxx>
117 : #include <svx/dataaccessdescriptor.hxx>
118 : #include <osl/mutex.hxx>
119 : #include <rtl/textenc.h>
120 : #include <cppuhelper/implbase.hxx>
121 : #include <ndindex.hxx>
122 : #include <pam.hxx>
123 : #include <swcrsr.hxx>
124 : #include <swevent.hxx>
125 : #include <osl/file.hxx>
126 : #include <sal/log.hxx>
127 : #include <swabstdlg.hxx>
128 : #include <fmthdft.hxx>
129 : #include <envelp.hrc>
130 : #include <vector>
131 : #include <unomid.h>
132 : #include <section.hxx>
133 : #include <rootfrm.hxx>
134 : #include <fmtpdsc.hxx>
135 : #include <ndtxt.hxx>
136 : #include <calc.hxx>
137 : #include <dbfld.hxx>
138 :
139 : #include <boost/scoped_ptr.hpp>
140 : #include <config_cups.h>
141 : #if ENABLE_CUPS && !defined(MACOSX)
142 : #include <vcl/printerinfomanager.hxx>
143 : #endif
144 : #include <comphelper/propertysequence.hxx>
145 : #include <officecfg/Office/Common.hxx>
146 :
147 : using namespace ::com::sun::star;
148 :
149 : #define DB_SEP_SPACE 0
150 : #define DB_SEP_TAB 1
151 : #define DB_SEP_RETURN 2
152 : #define DB_SEP_NEWLINE 3
153 :
154 : const sal_Char cCursor[] = "Cursor";
155 : const sal_Char cCommand[] = "Command";
156 : const sal_Char cCommandType[] = "CommandType";
157 : const sal_Char cDataSourceName[] = "DataSourceName";
158 : const sal_Char cSelection[] = "Selection";
159 : const sal_Char cActiveConnection[] = "ActiveConnection";
160 :
161 : namespace
162 : {
163 :
164 0 : bool lcl_getCountFromResultSet( sal_Int32& rCount, const uno::Reference<sdbc::XResultSet>& xResultSet )
165 : {
166 0 : uno::Reference<beans::XPropertySet> xPrSet(xResultSet, uno::UNO_QUERY);
167 0 : if(xPrSet.is())
168 : {
169 : try
170 : {
171 0 : bool bFinal = false;
172 0 : uno::Any aFinal = xPrSet->getPropertyValue("IsRowCountFinal");
173 0 : aFinal >>= bFinal;
174 0 : if(!bFinal)
175 : {
176 0 : xResultSet->last();
177 0 : xResultSet->first();
178 : }
179 0 : uno::Any aCount = xPrSet->getPropertyValue("RowCount");
180 0 : if( aCount >>= rCount )
181 0 : return true;
182 : }
183 0 : catch(const uno::Exception&)
184 : {
185 : }
186 : }
187 0 : return false;
188 : }
189 : }
190 :
191 : class SwConnectionDisposedListener_Impl : public cppu::WeakImplHelper
192 : < lang::XEventListener >
193 : {
194 : private:
195 : SwDBManager * m_pDBManager;
196 :
197 : virtual void SAL_CALL disposing( const lang::EventObject& Source ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
198 :
199 : public:
200 : explicit SwConnectionDisposedListener_Impl(SwDBManager& rMgr);
201 : virtual ~SwConnectionDisposedListener_Impl();
202 :
203 2949 : void Dispose() { m_pDBManager = 0; }
204 :
205 : };
206 :
207 : /// Listens to removed data sources, and if it's one that's embedded into this document, triggers embedding removal.
208 : class SwDataSourceRemovedListener : public cppu::WeakImplHelper<sdb::XDatabaseRegistrationsListener>
209 : {
210 : uno::Reference<sdb::XDatabaseContext> m_xDatabaseContext;
211 : SwDBManager* m_pDBManager;
212 :
213 : public:
214 : SwDataSourceRemovedListener(SwDBManager& rDBManager);
215 : virtual ~SwDataSourceRemovedListener();
216 : virtual void SAL_CALL registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
217 : virtual void SAL_CALL revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
218 : virtual void SAL_CALL changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
219 : virtual void SAL_CALL disposing(const lang::EventObject& rObject) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
220 : void Dispose();
221 : };
222 :
223 2 : SwDataSourceRemovedListener::SwDataSourceRemovedListener(SwDBManager& rDBManager)
224 2 : : m_pDBManager(&rDBManager)
225 : {
226 2 : uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
227 2 : m_xDatabaseContext = sdb::DatabaseContext::create(xComponentContext);
228 2 : m_xDatabaseContext->addDatabaseRegistrationsListener(this);
229 2 : }
230 :
231 0 : SwDataSourceRemovedListener::~SwDataSourceRemovedListener()
232 : {
233 0 : if (m_xDatabaseContext.is())
234 0 : m_xDatabaseContext->removeDatabaseRegistrationsListener(this);
235 0 : }
236 :
237 1 : void SAL_CALL SwDataSourceRemovedListener::registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& /*rEvent*/) throw (uno::RuntimeException, std::exception)
238 : {
239 1 : }
240 :
241 3 : void SAL_CALL SwDataSourceRemovedListener::revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) throw (uno::RuntimeException, std::exception)
242 : {
243 3 : if (!m_pDBManager || m_pDBManager->getEmbeddedName().isEmpty())
244 6 : return;
245 :
246 0 : SwDoc* pDoc = m_pDBManager->getDoc();
247 0 : if (!pDoc)
248 0 : return;
249 :
250 0 : SwDocShell* pDocShell = pDoc->GetDocShell();
251 0 : if (!pDocShell)
252 0 : return;
253 :
254 0 : OUString aOwnURL = pDocShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_WITH_CHARSET);
255 0 : OUString sTmpName = "vnd.sun.star.pkg://";
256 0 : sTmpName += INetURLObject::encode(aOwnURL, INetURLObject::PART_AUTHORITY, INetURLObject::ENCODE_ALL);
257 0 : sTmpName += "/" + m_pDBManager->getEmbeddedName();
258 :
259 0 : if (sTmpName != rEvent.OldLocation)
260 0 : return;
261 :
262 : // The revoked database location is inside this document, then remove the
263 : // embedding, as otherwise it would be back on the next reload of the
264 : // document.
265 0 : pDocShell->GetStorage()->removeElement(m_pDBManager->getEmbeddedName());
266 0 : m_pDBManager->setEmbeddedName(OUString(), *pDocShell);
267 : }
268 :
269 0 : void SAL_CALL SwDataSourceRemovedListener::changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) throw (uno::RuntimeException, std::exception)
270 : {
271 0 : if (rEvent.OldLocation != rEvent.NewLocation)
272 0 : revokedDatabaseLocation(rEvent);
273 0 : }
274 :
275 0 : void SwDataSourceRemovedListener::disposing(const lang::EventObject& /*rObject*/) throw (uno::RuntimeException, std::exception)
276 : {
277 0 : m_xDatabaseContext.clear();
278 0 : }
279 :
280 2 : void SwDataSourceRemovedListener::Dispose()
281 : {
282 2 : m_pDBManager = 0;
283 2 : }
284 :
285 : struct SwDBManager_Impl
286 : {
287 : SwDSParam* pMergeData;
288 : AbstractMailMergeDlg* pMergeDialog;
289 : ::rtl::Reference<SwConnectionDisposedListener_Impl> m_xDisposeListener;
290 : rtl::Reference<SwDataSourceRemovedListener> m_xDataSourceRemovedListener;
291 :
292 2958 : explicit SwDBManager_Impl(SwDBManager& rDBManager)
293 : :pMergeData(0)
294 : ,pMergeDialog(0)
295 2958 : , m_xDisposeListener(new SwConnectionDisposedListener_Impl(rDBManager))
296 2958 : {}
297 :
298 2949 : ~SwDBManager_Impl()
299 2949 : {
300 2949 : m_xDisposeListener->Dispose();
301 2949 : if (m_xDataSourceRemovedListener.is())
302 0 : m_xDataSourceRemovedListener->Dispose();
303 2949 : }
304 : };
305 :
306 8 : static void lcl_InitNumberFormatter(SwDSParam& rParam, uno::Reference<sdbc::XDataSource> xSource)
307 : {
308 8 : uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
309 8 : rParam.xFormatter = uno::Reference<util::XNumberFormatter>(util::NumberFormatter::create(xContext), uno::UNO_QUERY);
310 8 : if(!xSource.is())
311 0 : xSource = SwDBManager::getDataSourceAsParent(rParam.xConnection, rParam.sDataSource);
312 :
313 16 : uno::Reference<beans::XPropertySet> xSourceProps(xSource, uno::UNO_QUERY);
314 8 : if(xSourceProps.is())
315 : {
316 8 : uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
317 8 : if(aFormats.hasValue())
318 : {
319 8 : uno::Reference<util::XNumberFormatsSupplier> xSuppl;
320 8 : aFormats >>= xSuppl;
321 8 : if(xSuppl.is())
322 : {
323 8 : uno::Reference< beans::XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
324 16 : uno::Any aNull = xSettings->getPropertyValue("NullDate");
325 8 : aNull >>= rParam.aNullDate;
326 8 : if(rParam.xFormatter.is())
327 16 : rParam.xFormatter->attachNumberFormatsSupplier(xSuppl);
328 8 : }
329 8 : }
330 8 : }
331 8 : }
332 :
333 0 : static bool lcl_MoveAbsolute(SwDSParam* pParam, long nAbsPos)
334 : {
335 0 : bool bRet = false;
336 : try
337 : {
338 0 : if(pParam->bScrollable)
339 : {
340 0 : bRet = pParam->xResultSet->absolute( nAbsPos );
341 : }
342 : else
343 : {
344 : OSL_FAIL("no absolute positioning available");
345 : }
346 : }
347 0 : catch(const uno::Exception&)
348 : {
349 : }
350 0 : return bRet;
351 : }
352 :
353 620 : static void lcl_GetColumnCnt(SwDSParam *pParam,
354 : const uno::Reference< beans::XPropertySet > &rColumnProps,
355 : long nLanguage, OUString &rResult, double* pNumber)
356 : {
357 620 : SwDBFormatData aFormatData;
358 620 : if(!pParam->xFormatter.is())
359 : {
360 : uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(
361 0 : pParam->xConnection,pParam->sDataSource);
362 0 : lcl_InitNumberFormatter(*pParam, xSource );
363 : }
364 620 : aFormatData.aNullDate = pParam->aNullDate;
365 620 : aFormatData.xFormatter = pParam->xFormatter;
366 :
367 620 : aFormatData.aLocale = LanguageTag( (LanguageType)nLanguage ).getLocale();
368 :
369 620 : rResult = SwDBManager::GetDBField( rColumnProps, aFormatData, pNumber);
370 620 : }
371 :
372 60 : static bool lcl_GetColumnCnt(SwDSParam* pParam, const OUString& rColumnName,
373 : long nLanguage, OUString& rResult, double* pNumber)
374 : {
375 60 : uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pParam->xResultSet, uno::UNO_QUERY );
376 120 : uno::Reference<container::XNameAccess> xCols;
377 : try
378 : {
379 60 : xCols = xColsSupp->getColumns();
380 : }
381 0 : catch(const lang::DisposedException&)
382 : {
383 : }
384 60 : if(!xCols.is() || !xCols->hasByName(rColumnName))
385 0 : return false;
386 120 : uno::Any aCol = xCols->getByName(rColumnName);
387 120 : uno::Reference< beans::XPropertySet > xColumnProps;
388 60 : aCol >>= xColumnProps;
389 60 : lcl_GetColumnCnt( pParam, xColumnProps, nLanguage, rResult, pNumber );
390 120 : return true;
391 : };
392 :
393 : // import data
394 8 : bool SwDBManager::MergeNew( const SwMergeDescriptor& rMergeDesc, vcl::Window* pParent )
395 : {
396 : OSL_ENSURE(!bInMerge && !pImpl->pMergeData, "merge already activated!");
397 :
398 8 : SwDBData aData;
399 8 : aData.nCommandType = sdb::CommandType::TABLE;
400 16 : uno::Reference<sdbc::XResultSet> xResSet;
401 16 : uno::Sequence<uno::Any> aSelection;
402 16 : uno::Reference< sdbc::XConnection> xConnection;
403 :
404 8 : aData.sDataSource = rMergeDesc.rDescriptor.getDataSource();
405 8 : rMergeDesc.rDescriptor[svx::daCommand] >>= aData.sCommand;
406 8 : rMergeDesc.rDescriptor[svx::daCommandType] >>= aData.nCommandType;
407 :
408 8 : if ( rMergeDesc.rDescriptor.has(svx::daCursor) )
409 8 : rMergeDesc.rDescriptor[svx::daCursor] >>= xResSet;
410 8 : if ( rMergeDesc.rDescriptor.has(svx::daSelection) )
411 8 : rMergeDesc.rDescriptor[svx::daSelection] >>= aSelection;
412 8 : if ( rMergeDesc.rDescriptor.has(svx::daConnection) )
413 8 : rMergeDesc.rDescriptor[svx::daConnection] >>= xConnection;
414 :
415 8 : if(aData.sDataSource.isEmpty() || aData.sCommand.isEmpty() || !xResSet.is())
416 : {
417 0 : return false;
418 : }
419 :
420 8 : pImpl->pMergeData = new SwDSParam(aData, xResSet, aSelection);
421 8 : SwDSParam* pTemp = FindDSData(aData, false);
422 8 : if(pTemp)
423 8 : *pTemp = *pImpl->pMergeData;
424 : else
425 : {
426 : // calls from the calculator may have added a connection with an invalid commandtype
427 : //"real" data base connections added here have to re-use the already available
428 : //DSData and set the correct CommandType
429 0 : SwDBData aTempData(aData);
430 0 : aData.nCommandType = -1;
431 0 : pTemp = FindDSData(aData, false);
432 0 : if(pTemp)
433 0 : *pTemp = *pImpl->pMergeData;
434 : else
435 : {
436 0 : SwDSParam* pInsert = new SwDSParam(*pImpl->pMergeData);
437 0 : aDataSourceParams.push_back(pInsert);
438 : try
439 : {
440 0 : uno::Reference<lang::XComponent> xComponent(pInsert->xConnection, uno::UNO_QUERY);
441 0 : if(xComponent.is())
442 0 : xComponent->addEventListener(pImpl->m_xDisposeListener.get());
443 : }
444 0 : catch(const uno::Exception&)
445 : {
446 : }
447 0 : }
448 : }
449 8 : if(!pImpl->pMergeData->xConnection.is())
450 8 : pImpl->pMergeData->xConnection = xConnection;
451 : // add an XEventListener
452 :
453 : try{
454 : //set to start position
455 8 : if(pImpl->pMergeData->aSelection.getLength())
456 : {
457 0 : sal_Int32 nPos = 0;
458 0 : pImpl->pMergeData->aSelection.getConstArray()[ pImpl->pMergeData->nSelectionIndex++ ] >>= nPos;
459 0 : pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->absolute( nPos );
460 0 : pImpl->pMergeData->CheckEndOfDB();
461 0 : if(pImpl->pMergeData->nSelectionIndex >= pImpl->pMergeData->aSelection.getLength())
462 0 : pImpl->pMergeData->bEndOfDB = true;
463 : }
464 : else
465 : {
466 8 : pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->first();
467 8 : pImpl->pMergeData->CheckEndOfDB();
468 : }
469 : }
470 0 : catch (const uno::Exception& e)
471 : {
472 0 : pImpl->pMergeData->bEndOfDB = true;
473 0 : pImpl->pMergeData->CheckEndOfDB();
474 : SAL_WARN("sw.mailmerge", "exception in MergeNew(): " << e.Message);
475 : }
476 :
477 16 : uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection,aData.sDataSource);
478 :
479 8 : lcl_InitNumberFormatter(*pImpl->pMergeData, xSource);
480 :
481 8 : rMergeDesc.rSh.ChgDBData(aData);
482 8 : bInMerge = true;
483 :
484 8 : if (IsInitDBFields())
485 : {
486 : // with database fields without DB-Name, use DB-Name from Doc
487 0 : std::vector<OUString> aDBNames;
488 0 : aDBNames.push_back(OUString());
489 0 : SwDBData aInsertData = rMergeDesc.rSh.GetDBData();
490 0 : OUString sDBName = aInsertData.sDataSource;
491 0 : sDBName += OUString(DB_DELIM);
492 0 : sDBName += aInsertData.sCommand;
493 0 : sDBName += OUString(DB_DELIM);
494 0 : sDBName += OUString::number(aInsertData.nCommandType);
495 0 : rMergeDesc.rSh.ChangeDBFields( aDBNames, sDBName);
496 0 : SetInitDBFields(false);
497 : }
498 :
499 8 : bool bRet = true;
500 8 : switch(rMergeDesc.nMergeType)
501 : {
502 : case DBMGR_MERGE:
503 0 : bRet = Merge(&rMergeDesc.rSh);
504 0 : break;
505 :
506 : case DBMGR_MERGE_PRINTER:
507 : case DBMGR_MERGE_EMAIL:
508 : case DBMGR_MERGE_FILE:
509 : case DBMGR_MERGE_SHELL:
510 : // save files and send them as e-Mail if required
511 : bRet = MergeMailFiles(&rMergeDesc.rSh,
512 8 : rMergeDesc, pParent);
513 8 : break;
514 :
515 : default:
516 : // insert selected entries
517 : // (was: InsertRecord)
518 0 : ImportFromConnection(&rMergeDesc.rSh);
519 0 : break;
520 : }
521 :
522 8 : DELETEZ( pImpl->pMergeData );
523 :
524 8 : bInMerge = false;
525 :
526 16 : return bRet;
527 : }
528 :
529 : // import data
530 0 : bool SwDBManager::Merge(SwWrtShell* pSh)
531 : {
532 0 : pSh->StartAllAction();
533 :
534 0 : pSh->SwViewShell::UpdateFields(true);
535 0 : pSh->SetModified();
536 :
537 0 : pSh->EndAllAction();
538 :
539 0 : return true;
540 : }
541 :
542 0 : void SwDBManager::ImportFromConnection( SwWrtShell* pSh )
543 : {
544 0 : if(pImpl->pMergeData && !pImpl->pMergeData->bEndOfDB)
545 : {
546 : {
547 0 : pSh->StartAllAction();
548 0 : pSh->StartUndo(UNDO_EMPTY);
549 0 : bool bGroupUndo(pSh->DoesGroupUndo());
550 0 : pSh->DoGroupUndo(false);
551 :
552 0 : if( pSh->HasSelection() )
553 0 : pSh->DelRight();
554 :
555 0 : boost::scoped_ptr<SwWait> pWait;
556 :
557 : {
558 0 : sal_uLong i = 0;
559 0 : do {
560 :
561 0 : ImportDBEntry(pSh);
562 0 : if( 10 == ++i )
563 0 : pWait.reset(new SwWait( *pSh->GetView().GetDocShell(), true));
564 :
565 : } while(ToNextMergeRecord());
566 : }
567 :
568 0 : pSh->DoGroupUndo(bGroupUndo);
569 0 : pSh->EndUndo(UNDO_EMPTY);
570 0 : pSh->EndAllAction();
571 : }
572 : }
573 0 : }
574 :
575 0 : static OUString lcl_FindColumn(const OUString& sFormatStr,sal_uInt16 &nUsedPos, sal_uInt8 &nSeparator)
576 : {
577 0 : OUString sReturn;
578 0 : sal_uInt16 nLen = sFormatStr.getLength();
579 0 : nSeparator = 0xff;
580 0 : while(nUsedPos < nLen && nSeparator == 0xff)
581 : {
582 0 : sal_Unicode cAkt = sFormatStr[nUsedPos];
583 0 : switch(cAkt)
584 : {
585 : case ',':
586 0 : nSeparator = DB_SEP_SPACE;
587 0 : break;
588 : case ';':
589 0 : nSeparator = DB_SEP_RETURN;
590 0 : break;
591 : case ':':
592 0 : nSeparator = DB_SEP_TAB;
593 0 : break;
594 : case '#':
595 0 : nSeparator = DB_SEP_NEWLINE;
596 0 : break;
597 : default:
598 0 : sReturn += OUString(cAkt);
599 : }
600 0 : nUsedPos++;
601 :
602 : }
603 0 : return sReturn;
604 : }
605 :
606 0 : void SwDBManager::ImportDBEntry(SwWrtShell* pSh)
607 : {
608 0 : if(pImpl->pMergeData && !pImpl->pMergeData->bEndOfDB)
609 : {
610 0 : uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
611 0 : uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
612 0 : OUString sFormatStr;
613 0 : sal_uInt16 nFormatLen = sFormatStr.getLength();
614 0 : if( nFormatLen )
615 : {
616 0 : const char cSpace = ' ';
617 0 : const char cTab = '\t';
618 0 : sal_uInt16 nUsedPos = 0;
619 : sal_uInt8 nSeparator;
620 0 : OUString sColumn = lcl_FindColumn(sFormatStr, nUsedPos, nSeparator);
621 0 : while( !sColumn.isEmpty() )
622 : {
623 0 : if(!xCols->hasByName(sColumn))
624 0 : return;
625 0 : uno::Any aCol = xCols->getByName(sColumn);
626 0 : uno::Reference< beans::XPropertySet > xColumnProp;
627 0 : aCol >>= xColumnProp;
628 0 : if(xColumnProp.is())
629 : {
630 0 : SwDBFormatData aDBFormat;
631 0 : OUString sInsert = GetDBField( xColumnProp, aDBFormat);
632 0 : if( DB_SEP_SPACE == nSeparator )
633 0 : sInsert += OUString(cSpace);
634 0 : else if( DB_SEP_TAB == nSeparator)
635 0 : sInsert += OUString(cTab);
636 0 : pSh->Insert(sInsert);
637 0 : if( DB_SEP_RETURN == nSeparator)
638 0 : pSh->SplitNode();
639 0 : else if(DB_SEP_NEWLINE == nSeparator)
640 0 : pSh->InsertLineBreak();
641 : }
642 : else
643 : {
644 : // column not found -> show error
645 0 : OUStringBuffer sInsert;
646 0 : sInsert.append('?').append(sColumn).append('?');
647 0 : pSh->Insert(sInsert.makeStringAndClear());
648 : }
649 0 : sColumn = lcl_FindColumn(sFormatStr, nUsedPos, nSeparator);
650 0 : }
651 0 : pSh->SplitNode();
652 : }
653 : else
654 : {
655 0 : OUString sStr;
656 0 : uno::Sequence<OUString> aColNames = xCols->getElementNames();
657 0 : const OUString* pColNames = aColNames.getConstArray();
658 0 : long nLength = aColNames.getLength();
659 0 : for(long i = 0; i < nLength; i++)
660 : {
661 0 : uno::Any aCol = xCols->getByName(pColNames[i]);
662 0 : uno::Reference< beans::XPropertySet > xColumnProp;
663 0 : aCol >>= xColumnProp;
664 0 : SwDBFormatData aDBFormat;
665 0 : sStr += GetDBField( xColumnProp, aDBFormat);
666 0 : if (i < nLength - 1)
667 0 : sStr += "\t";
668 0 : }
669 0 : pSh->SwEditShell::Insert2(sStr);
670 0 : pSh->SwFEShell::SplitNode(); // line feed
671 0 : }
672 : }
673 : }
674 :
675 : // fill Listbox with tablelist
676 0 : bool SwDBManager::GetTableNames(ListBox* pListBox, const OUString& rDBName)
677 : {
678 0 : bool bRet = false;
679 0 : OUString sOldTableName(pListBox->GetSelectEntry());
680 0 : pListBox->Clear();
681 0 : SwDSParam* pParam = FindDSConnection(rDBName, false);
682 0 : uno::Reference< sdbc::XConnection> xConnection;
683 0 : if(pParam && pParam->xConnection.is())
684 0 : xConnection = pParam->xConnection;
685 : else
686 : {
687 0 : OUString sDBName(rDBName);
688 0 : if ( !sDBName.isEmpty() )
689 0 : xConnection = RegisterConnection( sDBName );
690 : }
691 0 : if(xConnection.is())
692 : {
693 0 : uno::Reference<sdbcx::XTablesSupplier> xTSupplier = uno::Reference<sdbcx::XTablesSupplier>(xConnection, uno::UNO_QUERY);
694 0 : if(xTSupplier.is())
695 : {
696 0 : uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
697 0 : uno::Sequence<OUString> aTables = xTables->getElementNames();
698 0 : const OUString* pTables = aTables.getConstArray();
699 0 : for(long i = 0; i < aTables.getLength(); i++)
700 : {
701 0 : sal_uInt16 nEntry = pListBox->InsertEntry(pTables[i]);
702 0 : pListBox->SetEntryData(nEntry, nullptr);
703 0 : }
704 : }
705 0 : uno::Reference<sdb::XQueriesSupplier> xQSupplier = uno::Reference<sdb::XQueriesSupplier>(xConnection, uno::UNO_QUERY);
706 0 : if(xQSupplier.is())
707 : {
708 0 : uno::Reference<container::XNameAccess> xQueries = xQSupplier->getQueries();
709 0 : uno::Sequence<OUString> aQueries = xQueries->getElementNames();
710 0 : const OUString* pQueries = aQueries.getConstArray();
711 0 : for(long i = 0; i < aQueries.getLength(); i++)
712 : {
713 0 : sal_uInt16 nEntry = pListBox->InsertEntry(pQueries[i]);
714 0 : pListBox->SetEntryData(nEntry, reinterpret_cast<void*>(1));
715 0 : }
716 : }
717 0 : if (!sOldTableName.isEmpty())
718 0 : pListBox->SelectEntry(sOldTableName);
719 0 : bRet = true;
720 : }
721 0 : return bRet;
722 : }
723 :
724 : // fill Listbox with column names of a database
725 0 : void SwDBManager::GetColumnNames(ListBox* pListBox,
726 : const OUString& rDBName, const OUString& rTableName, bool bAppend)
727 : {
728 0 : if (!bAppend)
729 0 : pListBox->Clear();
730 0 : SwDBData aData;
731 0 : aData.sDataSource = rDBName;
732 0 : aData.sCommand = rTableName;
733 0 : aData.nCommandType = -1;
734 0 : SwDSParam* pParam = FindDSData(aData, false);
735 0 : uno::Reference< sdbc::XConnection> xConnection;
736 0 : if(pParam && pParam->xConnection.is())
737 0 : xConnection = pParam->xConnection;
738 : else
739 : {
740 0 : OUString sDBName(rDBName);
741 0 : xConnection = RegisterConnection( sDBName );
742 : }
743 0 : uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
744 0 : if(xColsSupp.is())
745 : {
746 0 : uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
747 0 : const uno::Sequence<OUString> aColNames = xCols->getElementNames();
748 0 : const OUString* pColNames = aColNames.getConstArray();
749 0 : for(int nCol = 0; nCol < aColNames.getLength(); nCol++)
750 : {
751 0 : pListBox->InsertEntry(pColNames[nCol]);
752 : }
753 0 : ::comphelper::disposeComponent( xColsSupp );
754 0 : }
755 0 : }
756 :
757 0 : void SwDBManager::GetColumnNames(ListBox* pListBox,
758 : uno::Reference< sdbc::XConnection> xConnection,
759 : const OUString& rTableName, bool bAppend)
760 : {
761 0 : if (!bAppend)
762 0 : pListBox->Clear();
763 0 : uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
764 0 : if(xColsSupp.is())
765 : {
766 0 : uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
767 0 : const uno::Sequence<OUString> aColNames = xCols->getElementNames();
768 0 : const OUString* pColNames = aColNames.getConstArray();
769 0 : for(int nCol = 0; nCol < aColNames.getLength(); nCol++)
770 : {
771 0 : pListBox->InsertEntry(pColNames[nCol]);
772 : }
773 0 : ::comphelper::disposeComponent( xColsSupp );
774 0 : }
775 0 : }
776 :
777 2958 : SwDBManager::SwDBManager(SwDoc* pDoc)
778 : : bCancel(false)
779 : , bInitDBFields(false)
780 : , bSingleJobs(false)
781 : , bInMerge(false)
782 : , bMergeSilent(false)
783 : , bMergeLock(false)
784 2958 : , pImpl(new SwDBManager_Impl(*this))
785 : , pMergeEvtSrc(NULL)
786 5916 : , m_pDoc(pDoc)
787 : {
788 2958 : }
789 :
790 5898 : SwDBManager::~SwDBManager()
791 : {
792 2949 : for(size_t nPos = 0; nPos < aDataSourceParams.size(); nPos++)
793 : {
794 0 : SwDSParam* pParam = &aDataSourceParams[nPos];
795 0 : if(pParam->xConnection.is())
796 : {
797 : try
798 : {
799 0 : uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY);
800 0 : if(xComp.is())
801 0 : xComp->dispose();
802 : }
803 0 : catch(const uno::RuntimeException&)
804 : {
805 : //may be disposed already since multiple entries may have used the same connection
806 : }
807 : }
808 : }
809 2949 : delete pImpl;
810 2949 : }
811 :
812 : // save bulk letters as single documents
813 0 : static OUString lcl_FindUniqueName(SwWrtShell* pTargetShell, const OUString& rStartingPageDesc, sal_uLong nDocNo )
814 : {
815 : do
816 : {
817 0 : OUString sTest = rStartingPageDesc;
818 0 : sTest += OUString::number( nDocNo );
819 0 : if( !pTargetShell->FindPageDescByName( sTest ) )
820 0 : return sTest;
821 0 : ++nDocNo;
822 0 : }while(true);
823 : }
824 :
825 0 : static void lcl_CopyFollowPageDesc(
826 : SwWrtShell& rTargetShell,
827 : const SwPageDesc& rSourcePageDesc,
828 : const SwPageDesc& rTargetPageDesc,
829 : const sal_uLong nDocNo )
830 : {
831 : //now copy the follow page desc, too
832 0 : const SwPageDesc* pFollowPageDesc = rSourcePageDesc.GetFollow();
833 0 : OUString sFollowPageDesc = pFollowPageDesc->GetName();
834 0 : if( sFollowPageDesc != rSourcePageDesc.GetName() )
835 : {
836 0 : SwDoc* pTargetDoc = rTargetShell.GetDoc();
837 0 : OUString sNewFollowPageDesc = lcl_FindUniqueName(&rTargetShell, sFollowPageDesc, nDocNo );
838 0 : SwPageDesc* pTargetFollowPageDesc = pTargetDoc->MakePageDesc(sNewFollowPageDesc);
839 :
840 0 : pTargetDoc->CopyPageDesc(*pFollowPageDesc, *pTargetFollowPageDesc, false);
841 0 : SwPageDesc aDesc(rTargetPageDesc);
842 0 : aDesc.SetFollow(pTargetFollowPageDesc);
843 0 : pTargetDoc->ChgPageDesc(rTargetPageDesc.GetName(), aDesc);
844 0 : }
845 0 : }
846 :
847 0 : static void lcl_RemoveSectionLinks( SwWrtShell& rWorkShell )
848 : {
849 : //reset all links of the sections of synchronized labels
850 0 : size_t nSections = rWorkShell.GetSectionFormatCount();
851 0 : for (size_t nSection = 0; nSection < nSections; ++nSection)
852 : {
853 0 : SwSectionData aSectionData( *rWorkShell.GetSectionFormat( nSection ).GetSection() );
854 0 : if( aSectionData.GetType() == FILE_LINK_SECTION )
855 : {
856 0 : aSectionData.SetType( CONTENT_SECTION );
857 0 : aSectionData.SetLinkFileName( OUString() );
858 0 : rWorkShell.UpdateSection( nSection, aSectionData );
859 : }
860 0 : }
861 0 : rWorkShell.SetLabelDoc( false );
862 0 : }
863 :
864 0 : static void lcl_SaveDoc( SfxObjectShell *xTargetDocShell,
865 : const char *name, int no = 0 )
866 : {
867 0 : OUString sExt( ".odt" );
868 0 : OUString basename = OUString::createFromAscii( name );
869 0 : if (no > 0)
870 0 : basename += OUString::number(no) + "-";
871 : // aTempFile is not deleted, but that seems to be intentional
872 0 : utl::TempFile aTempFile(basename, true, &sExt);
873 0 : INetURLObject aTempFileURL( aTempFile.GetURL() );
874 : SfxMedium* pDstMed = new SfxMedium(
875 : aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),
876 0 : STREAM_STD_READWRITE );
877 0 : if( !xTargetDocShell->DoSaveAs( *pDstMed ) )
878 : SAL_WARN( "sw.mailmerge", "Error saving: " << aTempFile.GetURL() );
879 : else
880 : SAL_INFO( "sw.mailmerge", "Saved doc as: " << aTempFile.GetURL() );
881 0 : delete pDstMed;
882 0 : }
883 :
884 8 : bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
885 : const SwMergeDescriptor& rMergeDescriptor,
886 : vcl::Window* pParent)
887 : {
888 : //check if the doc is synchronized and contains at least one linked section
889 8 : bool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFormatCount() > 1;
890 8 : bool bNoError = true;
891 8 : const bool bEMail = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL;
892 8 : const bool bMergeShell = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL;
893 8 : bool bCreateSingleFile = rMergeDescriptor.bCreateSingleFile;
894 :
895 8 : if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
896 : {
897 : // It is possible to do MM printing in both modes for the same result, but the singlefile mode
898 : // is slower because of all the temporary document copies and merging them together
899 : // into the single file, while the other mode simply updates fields and prints for every record.
900 : // However, this would cause one print job for every record, and e.g. CUPS refuses new jobs
901 : // if it has many jobs enqueued (500 by default), and with the current printing framework
902 : // (which uses a pull model) it's rather complicated to create a single print job
903 : // in steps.
904 : // To handle this, CUPS backend has been changed to cache all the documents to print
905 : // and send them to CUPS only as one job at the very end. Therefore, with CUPS, it's ok
906 : // to use the faster mode. As I have no idea about other platforms, keep them using
907 : // the slower singlefile mode (or feel free to check them, or rewrite the printing code).
908 : #if ENABLE_CUPS && !defined(MACOSX)
909 0 : bCreateSingleFile = !psp::PrinterInfoManager::get().supportsBatchPrint();
910 : #else
911 : bCreateSingleFile = true;
912 : #endif
913 : }
914 :
915 8 : ::rtl::Reference< MailDispatcher > xMailDispatcher;
916 16 : OUString sBodyMimeType;
917 8 : rtl_TextEncoding eEncoding = ::osl_getThreadTextEncoding();
918 :
919 : static const char *sMaxDumpDocs = 0;
920 : static sal_Int32 nMaxDumpDocs = 0;
921 8 : if (!sMaxDumpDocs)
922 : {
923 1 : sMaxDumpDocs = getenv("SW_DEBUG_MAILMERGE_DOCS");
924 1 : if (!sMaxDumpDocs)
925 1 : sMaxDumpDocs = "";
926 : else
927 0 : nMaxDumpDocs = rtl_ustr_toInt32(reinterpret_cast<const sal_Unicode*>( sMaxDumpDocs ), 10);
928 : }
929 :
930 8 : if(bEMail)
931 : {
932 0 : xMailDispatcher.set( new MailDispatcher(rMergeDescriptor.xSmtpServer));
933 0 : if(!rMergeDescriptor.bSendAsAttachment && rMergeDescriptor.bSendAsHTML)
934 : {
935 0 : sBodyMimeType = "text/html; charset=";
936 0 : sBodyMimeType += OUString::createFromAscii(
937 0 : rtl_getBestMimeCharsetFromTextEncoding( eEncoding ));
938 0 : SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
939 0 : eEncoding = rHtmlOptions.GetTextEncoding();
940 : }
941 : else
942 0 : sBodyMimeType = "text/plain; charset=UTF-8; format=flowed";
943 : }
944 :
945 16 : uno::Reference< beans::XPropertySet > xColumnProp;
946 : {
947 8 : bool bColumnName = !sEMailAddrField.isEmpty();
948 :
949 8 : if (bColumnName)
950 : {
951 0 : uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
952 0 : uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
953 0 : if(!xCols->hasByName(sEMailAddrField))
954 0 : return false;
955 0 : uno::Any aCol = xCols->getByName(sEMailAddrField);
956 0 : aCol >>= xColumnProp;
957 : }
958 :
959 : // Try saving the source document
960 8 : SfxDispatcher* pSfxDispatcher = pSourceShell->GetView().GetViewFrame()->GetDispatcher();
961 8 : SwDocShell* pSourceDocSh = pSourceShell->GetView().GetDocShell();
962 :
963 8 : uno::Reference<document::XDocumentProperties> xSourceDocProps;
964 : {
965 : uno::Reference<document::XDocumentPropertiesSupplier>
966 8 : xDPS(pSourceDocSh->GetModel(), uno::UNO_QUERY);
967 8 : xSourceDocProps.set(xDPS->getDocumentProperties());
968 8 : OSL_ENSURE(xSourceDocProps.is(), "DocumentProperties is null");
969 : }
970 :
971 8 : if( !bMergeShell && pSourceDocSh->IsModified() )
972 1 : pSfxDispatcher->Execute( pSourceDocSh->HasName() ? SID_SAVEDOC : SID_SAVEASDOC, SfxCallMode::SYNCHRON|SfxCallMode::RECORD);
973 8 : if( bMergeShell || !pSourceDocSh->IsModified() )
974 : {
975 : const SfxFilter* pStoreToFilter = SwIoSystem::GetFileFilter(
976 8 : pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::NO_DECODE));
977 8 : SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer();
978 8 : const OUString* pStoreToFilterOptions = 0;
979 :
980 : // if a save_to filter is set then use it - otherwise use the default
981 8 : if( bEMail && !rMergeDescriptor.bSendAsAttachment )
982 : {
983 0 : OUString sExtension = rMergeDescriptor.bSendAsHTML ? OUString("html") : OUString("txt");
984 0 : pStoreToFilter = pFilterContainer->GetFilter4Extension(sExtension, SfxFilterFlags::EXPORT);
985 : }
986 8 : else if( !rMergeDescriptor.sSaveToFilter.isEmpty())
987 : {
988 : const SfxFilter* pFilter =
989 0 : pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter );
990 0 : if(pFilter)
991 : {
992 0 : pStoreToFilter = pFilter;
993 0 : if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty())
994 0 : pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions;
995 : }
996 : }
997 8 : bCancel = false;
998 :
999 : // in case of creating a single resulting file this has to be created here
1000 8 : SwWrtShell* pTargetShell = 0;
1001 8 : SwDoc* pTargetDoc = 0;
1002 :
1003 8 : SfxObjectShellRef xTargetDocShell;
1004 :
1005 8 : SwView* pTargetView = 0;
1006 16 : boost::scoped_ptr< utl::TempFile > aTempFile;
1007 8 : bool createTempFile = ( rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL || rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE );
1008 16 : OUString sModifiedStartingPageDesc;
1009 16 : OUString sStartingPageDesc;
1010 8 : sal_uInt16 nStartingPageNo = 0;
1011 8 : bool bPageStylesWithHeaderFooter = false;
1012 :
1013 8 : vcl::Window *pSourceWindow = 0;
1014 16 : VclPtr<CancelableDialog> pProgressDlg;
1015 :
1016 8 : if (!IsMergeSilent()) {
1017 0 : pSourceWindow = &pSourceShell->GetView().GetEditWin();
1018 0 : if( ! pParent )
1019 0 : pParent = pSourceWindow;
1020 0 : if( bMergeShell )
1021 0 : pProgressDlg = VclPtr<CreateMonitor>::Create( pParent, pParent != pSourceWindow );
1022 : else {
1023 0 : pProgressDlg = VclPtr<PrintMonitor>::Create( pParent, pParent != pSourceWindow, PrintMonitor::MONITOR_TYPE_PRINT );
1024 0 : static_cast<PrintMonitor*>( pProgressDlg.get() )->SetText(pSourceShell->GetView().GetDocShell()->GetTitle(22));
1025 : }
1026 0 : pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) );
1027 0 : pProgressDlg->Show();
1028 :
1029 0 : for( sal_uInt16 i = 0; i < 25; i++)
1030 0 : Application::Reschedule();
1031 : }
1032 :
1033 8 : if(bCreateSingleFile)
1034 : {
1035 : // create a target docshell to put the merged document into
1036 5 : xTargetDocShell = new SwDocShell( SfxObjectCreateMode::STANDARD );
1037 5 : xTargetDocShell->DoInitNew( 0 );
1038 5 : if (nMaxDumpDocs)
1039 0 : lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
1040 5 : SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 );
1041 5 : if (bMergeShell && pSourceWindow) {
1042 : //the created window has to be located at the same position as the source window
1043 0 : vcl::Window& rTargetWindow = pTargetFrame->GetFrame().GetWindow();
1044 0 : rTargetWindow.SetPosPixel(pSourceWindow->GetPosPixel());
1045 : }
1046 :
1047 5 : pTargetView = static_cast<SwView*>( pTargetFrame->GetViewShell() );
1048 :
1049 : //initiate SelectShell() to create sub shells
1050 5 : pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() );
1051 5 : pTargetShell = pTargetView->GetWrtShellPtr();
1052 5 : pTargetDoc = pTargetShell->GetDoc();
1053 5 : pTargetDoc->SetInMailMerge(true);
1054 :
1055 : //copy the styles from the source to the target document
1056 5 : pTargetView->GetDocShell()->_LoadStyles( *pSourceDocSh, true );
1057 :
1058 : //determine the page style and number used at the start of the source document
1059 5 : pSourceShell->SttEndDoc(true);
1060 5 : nStartingPageNo = pSourceShell->GetVirtPageNum();
1061 10 : sStartingPageDesc = sModifiedStartingPageDesc = pSourceShell->GetPageDesc(
1062 10 : pSourceShell->GetCurPageDesc()).GetName();
1063 :
1064 : // #i72517#
1065 5 : const SwPageDesc* pSourcePageDesc = pSourceShell->FindPageDescByName( sStartingPageDesc );
1066 5 : const SwFrameFormat& rMaster = pSourcePageDesc->GetMaster();
1067 10 : bPageStylesWithHeaderFooter = rMaster.GetHeader().IsActive() ||
1068 10 : rMaster.GetFooter().IsActive();
1069 :
1070 : // copy compatibility options
1071 5 : pTargetShell->GetDoc()->ReplaceCompatibilityOptions( *pSourceShell->GetDoc());
1072 : // #72821# copy dynamic defaults
1073 5 : pTargetShell->GetDoc()->ReplaceDefaults( *pSourceShell->GetDoc());
1074 :
1075 5 : pTargetShell->GetDoc()->ReplaceDocumentProperties( *pSourceShell->GetDoc());
1076 : }
1077 :
1078 : // Progress, to prohibit KeyInputs
1079 16 : SfxProgress aProgress(pSourceDocSh, ::aEmptyOUStr, 1);
1080 :
1081 : // lock all dispatchers
1082 8 : SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst(pSourceDocSh);
1083 16 : while (pViewFrm)
1084 : {
1085 0 : pViewFrm->GetDispatcher()->Lock(true);
1086 0 : pViewFrm = SfxViewFrame::GetNext(*pViewFrm, pSourceDocSh);
1087 : }
1088 :
1089 8 : sal_Int32 nDocNo = 1;
1090 8 : sal_Int32 nDocCount = 0;
1091 : // For single file mode, the number of pages in the target document so far, which is used
1092 : // by AppendDoc() to adjust position of page-bound objects. Getting this information directly
1093 : // from the target doc would require repeated layouts of the doc, which is expensive, but
1094 : // it can be manually computed from the source documents (for which we do layouts, so the page
1095 : // count is known, and there is a blank page between each of them in the target document).
1096 8 : int targetDocPageCount = 0;
1097 8 : if( !IsMergeSilent() && bMergeShell &&
1098 0 : lcl_getCountFromResultSet( nDocCount, pImpl->pMergeData->xResultSet ) )
1099 0 : static_cast<CreateMonitor*>( pProgressDlg.get() )->SetTotalCount( nDocCount );
1100 :
1101 : long nStartRow, nEndRow;
1102 8 : bool bFreezedLayouts = false;
1103 : // collect temporary files
1104 16 : ::std::vector< OUString> aFilesToRemove;
1105 :
1106 : // The SfxObjectShell will be closed explicitly later but it is more safe to use SfxObjectShellLock here
1107 16 : SfxObjectShellLock xWorkDocSh;
1108 : // a view frame for the document
1109 8 : SwView* pWorkView = NULL;
1110 8 : SwDoc* pWorkDoc = NULL;
1111 8 : SwDBManager* pOldDBManager = NULL;
1112 :
1113 65 : do
1114 : {
1115 65 : nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
1116 : {
1117 65 : OUString sPath(sSubject);
1118 :
1119 130 : OUString sAddress;
1120 65 : if( !bEMail && bColumnName )
1121 : {
1122 0 : SwDBFormatData aDBFormat;
1123 0 : aDBFormat.xFormatter = pImpl->pMergeData->xFormatter;
1124 0 : aDBFormat.aNullDate = pImpl->pMergeData->aNullDate;
1125 0 : sAddress = GetDBField( xColumnProp, aDBFormat);
1126 0 : if (sAddress.isEmpty())
1127 0 : sAddress = "_";
1128 0 : sPath += sAddress;
1129 : }
1130 :
1131 : // create a new temporary file name - only done once in case of bCreateSingleFile
1132 65 : if( createTempFile && ( 1 == nDocNo || !bCreateSingleFile ))
1133 : {
1134 21 : INetURLObject aEntry(sPath);
1135 42 : OUString sLeading;
1136 : //#i97667# if the name is from a database field then it will be used _as is_
1137 21 : if( !sAddress.isEmpty() )
1138 0 : sLeading = sAddress;
1139 : else
1140 21 : sLeading = aEntry.GetBase();
1141 21 : aEntry.removeSegment();
1142 21 : sPath = aEntry.GetMainURL( INetURLObject::NO_DECODE );
1143 42 : OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
1144 : aTempFile.reset(
1145 21 : new utl::TempFile(sLeading, true, &sExt, &sPath));
1146 21 : if( rMergeDescriptor.bSubjectIsFilename )
1147 0 : aTempFile->EnableKillingFile();
1148 21 : if( !aTempFile->IsValid() )
1149 : {
1150 0 : ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED );
1151 0 : bNoError = false;
1152 0 : bCancel = true;
1153 21 : }
1154 : }
1155 :
1156 65 : if( !bCancel )
1157 : {
1158 65 : boost::scoped_ptr< INetURLObject > aTempFileURL;
1159 65 : if( createTempFile )
1160 21 : aTempFileURL.reset( new INetURLObject(aTempFile->GetURL()));
1161 65 : if (!IsMergeSilent()) {
1162 0 : if( bMergeShell )
1163 0 : static_cast<CreateMonitor*>( pProgressDlg.get() )->SetCurrentPosition( nDocNo );
1164 : else {
1165 0 : PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>( pProgressDlg.get() );
1166 0 : pPrintMonDlg->m_pPrinter->SetText( createTempFile ? aTempFileURL->GetBase() : OUString( pSourceDocSh->GetTitle( 22 )));
1167 0 : OUString sStat(SW_RES(STR_STATSTR_LETTER)); // Brief
1168 0 : sStat += " ";
1169 0 : sStat += OUString::number( nDocNo );
1170 0 : pPrintMonDlg->m_pPrintInfo->SetText( sStat );
1171 : }
1172 0 : pProgressDlg->Update();
1173 : }
1174 :
1175 : // Computation time for the GUI
1176 1690 : for( sal_uInt16 i = 0; i < 25; i++ )
1177 1625 : Application::Reschedule();
1178 :
1179 : // Create a copy of the source document and work with that one instead of the source.
1180 : // If we're not in the single file mode (which requires modifying the document for the merging),
1181 : // it is enough to do this just once.
1182 65 : if( 1 == nDocNo || bCreateSingleFile )
1183 : {
1184 : assert( !xWorkDocSh.Is());
1185 : // copy the source document
1186 47 : xWorkDocSh = pSourceDocSh->GetDoc()->CreateCopy( true );
1187 :
1188 : //create a view frame for the document
1189 47 : pWorkView = static_cast< SwView* >( SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 )->GetViewShell() );
1190 : //request the layout calculation
1191 47 : SwWrtShell& rWorkShell = pWorkView->GetWrtShell();
1192 47 : pWorkView->AttrChangedNotify( &rWorkShell );// in order for SelectShell to be called
1193 :
1194 47 : pWorkDoc = rWorkShell.GetDoc();
1195 47 : pWorkDoc->ReplaceDocumentProperties( *pSourceDocSh->GetDoc());
1196 47 : if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1197 0 : lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo );
1198 47 : pOldDBManager = pWorkDoc->GetDBManager();
1199 47 : pWorkDoc->SetDBManager( this );
1200 47 : pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks();
1201 :
1202 : // #i69458# lock fields to prevent access to the result set while calculating layout
1203 47 : rWorkShell.LockExpFields();
1204 47 : rWorkShell.CalcLayout();
1205 47 : rWorkShell.UnlockExpFields();
1206 : }
1207 :
1208 65 : SwWrtShell& rWorkShell = pWorkView->GetWrtShell();
1209 65 : SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), xWorkDocSh));
1210 65 : rWorkShell.SwViewShell::UpdateFields();
1211 65 : SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh));
1212 :
1213 : // launch MailMergeEvent if required
1214 65 : const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
1215 65 : if(pEvtSrc)
1216 : {
1217 65 : uno::Reference< uno::XInterface > xRef( const_cast<text::XMailMergeBroadcaster *>(static_cast<text::XMailMergeBroadcaster const *>(pEvtSrc)) );
1218 130 : text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() );
1219 130 : pEvtSrc->LaunchMailMergeEvent( aEvt );
1220 : }
1221 :
1222 65 : if(bCreateSingleFile)
1223 : {
1224 44 : pWorkDoc->RemoveInvisibleContent();
1225 :
1226 : OSL_ENSURE( pTargetShell, "no target shell available!" );
1227 : // copy created file into the target document
1228 44 : rWorkShell.ConvertFieldsToText();
1229 44 : rWorkShell.SetNumberingRestart();
1230 44 : if( bSynchronizedDoc )
1231 : {
1232 0 : lcl_RemoveSectionLinks( rWorkShell );
1233 : }
1234 :
1235 : // insert the document into the target document
1236 :
1237 : //#i72517# put the styles to the target document
1238 : //if the source uses headers or footers each new copy need to copy a new page styles
1239 44 : SwPageDesc* pTargetPageDesc(NULL);
1240 44 : if(bPageStylesWithHeaderFooter)
1241 : {
1242 : //create a new pagestyle
1243 : //copy the pagedesc from the current document to the new document and change the name of the to-be-applied style
1244 0 : OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo );
1245 0 : pTargetPageDesc = pTargetDoc->MakePageDesc( sNewPageDescName );
1246 0 : const SwPageDesc* pWorkPageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc );
1247 :
1248 0 : if(pWorkPageDesc && pTargetPageDesc)
1249 : {
1250 0 : pTargetDoc->CopyPageDesc( *pWorkPageDesc, *pTargetPageDesc, false );
1251 0 : sModifiedStartingPageDesc = sNewPageDescName;
1252 0 : lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo );
1253 0 : }
1254 : }
1255 44 : else if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
1256 : {
1257 : assert(!bCreateSingleFile);
1258 0 : if( 1 == nDocNo ) // set up printing only once at the beginning
1259 : {
1260 : // printing should be done synchronously otherwise the document
1261 : // might already become invalid during the process
1262 0 : uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
1263 :
1264 0 : aOptions.realloc( 2 );
1265 0 : aOptions[ 0 ].Name = "Wait";
1266 0 : aOptions[ 0 ].Value <<= sal_True;
1267 0 : aOptions[ 1 ].Name = "MonitorVisible";
1268 0 : aOptions[ 1 ].Value <<= sal_False;
1269 : // move print options
1270 0 : const beans::PropertyValue* pPrintOptions = rMergeDescriptor.aPrintOptions.getConstArray();
1271 0 : for( sal_Int32 nOption = 0, nIndex = 1 ; nOption < rMergeDescriptor.aPrintOptions.getLength(); ++nOption)
1272 : {
1273 0 : if( pPrintOptions[nOption].Name == "CopyCount" || pPrintOptions[nOption].Name == "FileName"
1274 0 : || pPrintOptions[nOption].Name == "Collate" || pPrintOptions[nOption].Name == "Pages"
1275 0 : || pPrintOptions[nOption].Name == "Wait" || pPrintOptions[nOption].Name == "PrinterName" )
1276 : {
1277 : // add an option
1278 0 : aOptions.realloc( nIndex + 1 );
1279 0 : aOptions[ nIndex ].Name = pPrintOptions[nOption].Name;
1280 0 : aOptions[ nIndex++ ].Value = pPrintOptions[nOption].Value ;
1281 : }
1282 : }
1283 0 : pWorkView->StartPrint( aOptions, IsMergeSilent(), rMergeDescriptor.bPrintAsync );
1284 0 : SfxPrinter* pDocPrt = pWorkView->GetPrinter(false);
1285 0 : JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : SfxViewShell::GetJobSetup();
1286 0 : Printer::PreparePrintJob( pWorkView->GetPrinterController(), aJobSetup );
1287 : #if ENABLE_CUPS && !defined(MACOSX)
1288 0 : psp::PrinterInfoManager::get().startBatchPrint();
1289 : #endif
1290 : }
1291 0 : if( !Printer::ExecutePrintJob( pWorkView->GetPrinterController()))
1292 0 : bCancel = true;
1293 : }
1294 : else
1295 44 : pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc );
1296 :
1297 44 : if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1298 0 : lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo );
1299 44 : if( targetDocPageCount % 2 == 1 )
1300 27 : ++targetDocPageCount; // Docs always start on odd pages (so offset must be even).
1301 44 : SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc(*rWorkShell.GetDoc(),
1302 88 : nStartingPageNo, pTargetPageDesc, nDocNo == 1, targetDocPageCount);
1303 44 : targetDocPageCount += rWorkShell.GetPageCnt();
1304 44 : if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1305 0 : lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
1306 44 : if (bMergeShell)
1307 : {
1308 : SwDocMergeInfo aMergeInfo;
1309 : // Name of the mark is actually irrelevant, UNO bookmarks have internals names.
1310 44 : aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark( appendedDocStart, "",
1311 44 : IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
1312 44 : aMergeInfo.nDBRow = nStartRow;
1313 44 : rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo );
1314 44 : }
1315 : }
1316 : else
1317 : {
1318 : assert( createTempFile );
1319 21 : OUString sFileURL = aTempFileURL->GetMainURL( INetURLObject::NO_DECODE );
1320 : SfxMedium* pDstMed = new SfxMedium(
1321 : sFileURL,
1322 21 : STREAM_STD_READWRITE );
1323 21 : pDstMed->SetFilter( pStoreToFilter );
1324 21 : if(pDstMed->GetItemSet())
1325 : {
1326 21 : if(pStoreToFilterOptions )
1327 0 : pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions));
1328 21 : if(rMergeDescriptor.aSaveToFilterData.getLength())
1329 0 : pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, uno::makeAny(rMergeDescriptor.aSaveToFilterData)));
1330 : }
1331 :
1332 : //convert fields to text if we are exporting to PDF
1333 : //this prevents a second merge while updating the fields in SwXTextDocument::getRendererCount()
1334 21 : if( pStoreToFilter && pStoreToFilter->GetFilterName() == "writer_pdf_Export")
1335 0 : rWorkShell.ConvertFieldsToText();
1336 21 : xWorkDocSh->DoSaveAs(*pDstMed);
1337 21 : xWorkDocSh->DoSaveCompleted(pDstMed);
1338 21 : if( xWorkDocSh->GetError() )
1339 : {
1340 : // error message ??
1341 0 : ErrorHandler::HandleError( xWorkDocSh->GetError() );
1342 0 : bCancel = true;
1343 0 : bNoError = false;
1344 : }
1345 21 : if( bEMail )
1346 : {
1347 0 : SwDBFormatData aDBFormat;
1348 0 : aDBFormat.xFormatter = pImpl->pMergeData->xFormatter;
1349 0 : aDBFormat.aNullDate = pImpl->pMergeData->aNullDate;
1350 0 : OUString sMailAddress = GetDBField( xColumnProp, aDBFormat);
1351 0 : if(!SwMailMergeHelper::CheckMailAddress( sMailAddress ))
1352 : {
1353 : OSL_FAIL("invalid e-Mail address in database column");
1354 : }
1355 : else
1356 : {
1357 0 : SwMailMessage* pMessage = new SwMailMessage;
1358 0 : uno::Reference< mail::XMailMessage > xMessage = pMessage;
1359 0 : if(rMergeDescriptor.pMailMergeConfigItem->IsMailReplyTo())
1360 0 : pMessage->setReplyToAddress(rMergeDescriptor.pMailMergeConfigItem->GetMailReplyTo());
1361 0 : pMessage->addRecipient( sMailAddress );
1362 0 : pMessage->SetSenderAddress( rMergeDescriptor.pMailMergeConfigItem->GetMailAddress() );
1363 0 : OUString sBody;
1364 0 : if(rMergeDescriptor.bSendAsAttachment)
1365 : {
1366 0 : sBody = rMergeDescriptor.sMailBody;
1367 0 : mail::MailAttachment aAttach;
1368 0 : aAttach.Data = new SwMailTransferable(
1369 : sFileURL,
1370 : rMergeDescriptor.sAttachmentName,
1371 0 : pStoreToFilter->GetMimeType());
1372 0 : aAttach.ReadableName = rMergeDescriptor.sAttachmentName;
1373 0 : pMessage->addAttachment( aAttach );
1374 : }
1375 : else
1376 : {
1377 : {
1378 : //read in the temporary file and use it as mail body
1379 0 : SfxMedium aMedium( sFileURL, StreamMode::READ);
1380 0 : SvStream* pInStream = aMedium.GetInStream();
1381 : OSL_ENSURE(pInStream, "no output file created?");
1382 0 : if(pInStream)
1383 : {
1384 0 : pInStream->SetStreamCharSet( eEncoding );
1385 0 : OString sLine;
1386 0 : bool bDone = pInStream->ReadLine( sLine );
1387 0 : while ( bDone )
1388 : {
1389 0 : sBody += OStringToOUString(sLine, eEncoding);
1390 0 : sBody += "\n";
1391 0 : bDone = pInStream->ReadLine( sLine );
1392 0 : }
1393 0 : }
1394 : }
1395 : }
1396 0 : pMessage->setSubject( rMergeDescriptor.sSubject );
1397 : uno::Reference< datatransfer::XTransferable> xBody =
1398 : new SwMailTransferable(
1399 : sBody,
1400 0 : sBodyMimeType);
1401 0 : pMessage->setBody( xBody );
1402 :
1403 0 : if(rMergeDescriptor.aCopiesTo.getLength())
1404 : {
1405 0 : const OUString* pCopies = rMergeDescriptor.aCopiesTo.getConstArray();
1406 0 : for( sal_Int32 nToken = 0; nToken < rMergeDescriptor.aCopiesTo.getLength(); ++nToken)
1407 0 : pMessage->addCcRecipient( pCopies[nToken] );
1408 : }
1409 0 : if(rMergeDescriptor.aBlindCopiesTo.getLength())
1410 : {
1411 0 : const OUString* pCopies = rMergeDescriptor.aBlindCopiesTo.getConstArray();
1412 0 : for( sal_Int32 nToken = 0; nToken < rMergeDescriptor.aBlindCopiesTo.getLength(); ++nToken)
1413 0 : pMessage->addBccRecipient( pCopies[nToken] );
1414 : }
1415 0 : xMailDispatcher->enqueueMailMessage( xMessage );
1416 0 : if(!xMailDispatcher->isStarted())
1417 0 : xMailDispatcher->start();
1418 : //schedule for removal
1419 0 : aFilesToRemove.push_back(sFileURL);
1420 0 : }
1421 21 : }
1422 : }
1423 65 : if( bCreateSingleFile )
1424 : {
1425 44 : pWorkDoc->SetDBManager( pOldDBManager );
1426 44 : xWorkDocSh->DoClose();
1427 44 : xWorkDocSh = NULL;
1428 65 : }
1429 65 : }
1430 : }
1431 65 : nDocNo++;
1432 65 : nEndRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
1433 :
1434 : // Freeze the layouts of the target document after the first inserted
1435 : // sub-document, to get the correct PageDesc.
1436 65 : if(!bFreezedLayouts && bCreateSingleFile)
1437 : {
1438 5 : std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
1439 : std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
1440 5 : ::std::bind2nd(::std::mem_fun(&SwRootFrm::FreezeLayout), true));
1441 5 : bFreezedLayouts = true;
1442 : }
1443 130 : } while( !bCancel &&
1444 65 : (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord()));
1445 :
1446 8 : if( !bCreateSingleFile )
1447 : {
1448 3 : if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
1449 : {
1450 0 : Printer::FinishPrintJob( pWorkView->GetPrinterController());
1451 : #if ENABLE_CUPS && !defined(MACOSX)
1452 0 : psp::PrinterInfoManager::get().flushBatchPrint();
1453 : #endif
1454 : }
1455 3 : pWorkDoc->SetDBManager( pOldDBManager );
1456 3 : xWorkDocSh->DoClose();
1457 : }
1458 :
1459 8 : if (bCreateSingleFile)
1460 : {
1461 : // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate
1462 : // unique fly names, do it here once.
1463 5 : pTargetDoc->SetInMailMerge(false);
1464 5 : pTargetDoc->SetAllUniqueFlyNames();
1465 : }
1466 :
1467 208 : for( sal_uInt16 i = 0; i < 25; i++)
1468 200 : Application::Reschedule();
1469 :
1470 : // Unfreeze target document layouts and correct all PageDescs.
1471 8 : if(bCreateSingleFile)
1472 : {
1473 5 : pTargetShell->CalcLayout();
1474 5 : std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
1475 : std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
1476 5 : ::std::bind2nd(::std::mem_fun(&SwRootFrm::FreezeLayout), false));
1477 5 : std::for_each( aAllLayouts.begin(), aAllLayouts.end(),std::mem_fun(&SwRootFrm::AllCheckPageDescs));
1478 : }
1479 :
1480 8 : pProgressDlg.disposeAndClear();
1481 :
1482 : // save the single output document
1483 8 : if (bMergeShell)
1484 : {
1485 5 : rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView );
1486 : }
1487 3 : else if(bCreateSingleFile)
1488 : {
1489 0 : if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER )
1490 : {
1491 0 : if( !bCancel )
1492 : {
1493 : assert( aTempFile.get());
1494 0 : INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : aTempFile->GetURL());
1495 : SfxMedium* pDstMed = new SfxMedium(
1496 : aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),
1497 0 : STREAM_STD_READWRITE );
1498 0 : pDstMed->SetFilter( pStoreToFilter );
1499 0 : if(pDstMed->GetItemSet())
1500 : {
1501 0 : if(pStoreToFilterOptions )
1502 0 : pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions));
1503 0 : if(rMergeDescriptor.aSaveToFilterData.getLength())
1504 0 : pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, uno::makeAny(rMergeDescriptor.aSaveToFilterData)));
1505 : }
1506 :
1507 0 : xTargetDocShell->DoSaveAs(*pDstMed);
1508 0 : xTargetDocShell->DoSaveCompleted(pDstMed);
1509 0 : if( xTargetDocShell->GetError() )
1510 : {
1511 : // error message ??
1512 0 : ErrorHandler::HandleError( xTargetDocShell->GetError() );
1513 0 : bNoError = false;
1514 0 : }
1515 : }
1516 : }
1517 0 : else if( pTargetView ) // must be available!
1518 : {
1519 : //print the target document
1520 : // printing should be done synchronously otherwise the document
1521 : // might already become invalid during the process
1522 0 : uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
1523 :
1524 0 : aOptions.realloc( 1 );
1525 0 : aOptions[ 0 ].Name = "Wait";
1526 0 : aOptions[ 0 ].Value <<= sal_True ;
1527 : // move print options
1528 0 : const beans::PropertyValue* pPrintOptions = rMergeDescriptor.aPrintOptions.getConstArray();
1529 0 : for( sal_Int32 nOption = 0, nIndex = 1 ; nOption < rMergeDescriptor.aPrintOptions.getLength(); ++nOption)
1530 : {
1531 0 : if( pPrintOptions[nOption].Name == "CopyCount" || pPrintOptions[nOption].Name == "FileName"
1532 0 : || pPrintOptions[nOption].Name == "Collate" || pPrintOptions[nOption].Name == "Pages"
1533 0 : || pPrintOptions[nOption].Name == "Wait" || pPrintOptions[nOption].Name == "PrinterName" )
1534 : {
1535 : // add an option
1536 0 : aOptions.realloc( nIndex + 1 );
1537 0 : aOptions[ nIndex ].Name = pPrintOptions[nOption].Name;
1538 0 : aOptions[ nIndex++ ].Value = pPrintOptions[nOption].Value ;
1539 : }
1540 : }
1541 :
1542 0 : pTargetView->ExecPrint( aOptions, IsMergeSilent(), rMergeDescriptor.bPrintAsync );
1543 : }
1544 :
1545 : // Leave docshell available for caller (e.g. MM wizard)
1546 0 : if (!bMergeShell)
1547 0 : xTargetDocShell->DoClose();
1548 : }
1549 :
1550 : //remove the temporary files
1551 8 : ::std::vector<OUString>::iterator aFileIter;
1552 24 : for(aFileIter = aFilesToRemove.begin();
1553 16 : aFileIter != aFilesToRemove.end(); ++aFileIter)
1554 0 : SWUnoHelper::UCB_DeleteFile( *aFileIter );
1555 :
1556 : // unlock all dispatchers
1557 8 : pViewFrm = SfxViewFrame::GetFirst(pSourceDocSh);
1558 16 : while (pViewFrm)
1559 : {
1560 0 : pViewFrm->GetDispatcher()->Lock(false);
1561 0 : pViewFrm = SfxViewFrame::GetNext(*pViewFrm, pSourceDocSh);
1562 : }
1563 :
1564 16 : SW_MOD()->SetView(&pSourceShell->GetView());
1565 8 : }
1566 : }
1567 :
1568 8 : if(bEMail)
1569 : {
1570 0 : xMailDispatcher->stop();
1571 0 : xMailDispatcher->shutdown();
1572 : }
1573 :
1574 16 : return bNoError;
1575 : }
1576 :
1577 0 : void SwDBManager::MergeCancel()
1578 : {
1579 0 : bCancel = true;
1580 0 : }
1581 :
1582 0 : IMPL_LINK( SwDBManager, PrtCancelHdl, Button *, pButton )
1583 : {
1584 0 : pButton->GetParent()->Hide();
1585 0 : MergeCancel();
1586 0 : return 0;
1587 : }
1588 :
1589 : // determine the column's Numberformat and transfer to the forwarded Formatter,
1590 : // if applicable.
1591 620 : sal_uLong SwDBManager::GetColumnFormat( const OUString& rDBName,
1592 : const OUString& rTableName,
1593 : const OUString& rColNm,
1594 : SvNumberFormatter* pNFormatr,
1595 : long nLanguage )
1596 : {
1597 620 : sal_uLong nRet = 0;
1598 620 : if(pNFormatr)
1599 : {
1600 620 : uno::Reference< sdbc::XDataSource> xSource;
1601 1240 : uno::Reference< sdbc::XConnection> xConnection;
1602 620 : bool bUseMergeData = false;
1603 1240 : uno::Reference< sdbcx::XColumnsSupplier> xColsSupp;
1604 620 : bool bDisposeConnection = false;
1605 1240 : if(pImpl->pMergeData &&
1606 1240 : pImpl->pMergeData->sDataSource.equals(rDBName) && pImpl->pMergeData->sCommand.equals(rTableName))
1607 : {
1608 620 : xConnection = pImpl->pMergeData->xConnection;
1609 620 : xSource = SwDBManager::getDataSourceAsParent(xConnection,rDBName);
1610 620 : bUseMergeData = true;
1611 620 : xColsSupp.set(pImpl->pMergeData->xResultSet, css::uno::UNO_QUERY);
1612 : }
1613 620 : if(!xConnection.is())
1614 : {
1615 0 : SwDBData aData;
1616 0 : aData.sDataSource = rDBName;
1617 0 : aData.sCommand = rTableName;
1618 0 : aData.nCommandType = -1;
1619 0 : SwDSParam* pParam = FindDSData(aData, false);
1620 0 : if(pParam && pParam->xConnection.is())
1621 : {
1622 0 : xConnection = pParam->xConnection;
1623 0 : xColsSupp.set(pParam->xResultSet, css::uno::UNO_QUERY);
1624 : }
1625 : else
1626 : {
1627 0 : OUString sDBName(rDBName);
1628 0 : xConnection = RegisterConnection( sDBName );
1629 0 : bDisposeConnection = true;
1630 : }
1631 0 : if(bUseMergeData)
1632 0 : pImpl->pMergeData->xConnection = xConnection;
1633 : }
1634 620 : bool bDispose = !xColsSupp.is();
1635 620 : if(bDispose)
1636 : {
1637 0 : xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1638 : }
1639 620 : if(xColsSupp.is())
1640 : {
1641 620 : uno::Reference<container::XNameAccess> xCols;
1642 : try
1643 : {
1644 620 : xCols = xColsSupp->getColumns();
1645 : }
1646 0 : catch (const uno::Exception& e)
1647 : {
1648 : SAL_WARN("sw.mailmerge", "Exception in getColumns(): " << e.Message);
1649 : }
1650 620 : if(!xCols.is() || !xCols->hasByName(rColNm))
1651 0 : return nRet;
1652 1240 : uno::Any aCol = xCols->getByName(rColNm);
1653 1240 : uno::Reference< beans::XPropertySet > xColumn;
1654 620 : aCol >>= xColumn;
1655 620 : nRet = GetColumnFormat(xSource, xConnection, xColumn, pNFormatr, nLanguage);
1656 620 : if(bDispose)
1657 : {
1658 0 : ::comphelper::disposeComponent( xColsSupp );
1659 : }
1660 620 : if(bDisposeConnection)
1661 : {
1662 0 : ::comphelper::disposeComponent( xConnection );
1663 620 : }
1664 : }
1665 : else
1666 620 : nRet = pNFormatr->GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_SYSTEM );
1667 : }
1668 620 : return nRet;
1669 : }
1670 :
1671 620 : sal_uLong SwDBManager::GetColumnFormat( uno::Reference< sdbc::XDataSource> xSource,
1672 : uno::Reference< sdbc::XConnection> xConnection,
1673 : uno::Reference< beans::XPropertySet> xColumn,
1674 : SvNumberFormatter* pNFormatr,
1675 : long nLanguage )
1676 : {
1677 : // set the NumberFormat in the doc if applicable
1678 620 : sal_uLong nRet = 0;
1679 :
1680 620 : if(!xSource.is())
1681 : {
1682 0 : uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
1683 0 : if ( xChild.is() )
1684 0 : xSource = uno::Reference<sdbc::XDataSource>(xChild->getParent(), uno::UNO_QUERY);
1685 : }
1686 620 : if(xSource.is() && xConnection.is() && xColumn.is() && pNFormatr)
1687 : {
1688 620 : SvNumberFormatsSupplierObj* pNumFormat = new SvNumberFormatsSupplierObj( pNFormatr );
1689 620 : uno::Reference< util::XNumberFormatsSupplier > xDocNumFormatsSupplier = pNumFormat;
1690 1240 : uno::Reference< util::XNumberFormats > xDocNumberFormats = xDocNumFormatsSupplier->getNumberFormats();
1691 1240 : uno::Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, uno::UNO_QUERY);
1692 :
1693 1240 : com::sun::star::lang::Locale aLocale( LanguageTag( (LanguageType)nLanguage ).getLocale());
1694 :
1695 : //get the number formatter of the data source
1696 1240 : uno::Reference<beans::XPropertySet> xSourceProps(xSource, uno::UNO_QUERY);
1697 1240 : uno::Reference< util::XNumberFormats > xNumberFormats;
1698 620 : if(xSourceProps.is())
1699 : {
1700 620 : uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
1701 620 : if(aFormats.hasValue())
1702 : {
1703 620 : uno::Reference<util::XNumberFormatsSupplier> xSuppl;
1704 620 : aFormats >>= xSuppl;
1705 620 : if(xSuppl.is())
1706 : {
1707 620 : xNumberFormats = xSuppl->getNumberFormats();
1708 620 : }
1709 620 : }
1710 : }
1711 620 : bool bUseDefault = true;
1712 : try
1713 : {
1714 620 : uno::Any aFormatKey = xColumn->getPropertyValue("FormatKey");
1715 620 : if(aFormatKey.hasValue())
1716 : {
1717 620 : sal_Int32 nFormat = 0;
1718 620 : aFormatKey >>= nFormat;
1719 620 : if(xNumberFormats.is())
1720 : {
1721 : try
1722 : {
1723 620 : uno::Reference<beans::XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat );
1724 1240 : uno::Any aFormatString = xNumProps->getPropertyValue("FormatString");
1725 1240 : uno::Any aLocaleVal = xNumProps->getPropertyValue("Locale");
1726 1240 : OUString sFormat;
1727 620 : aFormatString >>= sFormat;
1728 1240 : lang::Locale aLoc;
1729 620 : aLocaleVal >>= aLoc;
1730 620 : nFormat = xDocNumberFormats->queryKey( sFormat, aLoc, sal_False );
1731 620 : if(NUMBERFORMAT_ENTRY_NOT_FOUND == sal::static_int_cast< sal_uInt32, sal_Int32>(nFormat))
1732 0 : nFormat = xDocNumberFormats->addNew( sFormat, aLoc );
1733 620 : nRet = nFormat;
1734 1240 : bUseDefault = false;
1735 : }
1736 0 : catch (const uno::Exception& e)
1737 : {
1738 : SAL_WARN("sw.mailmerge", "illegal number format key: " << e.Message);
1739 : }
1740 : }
1741 620 : }
1742 : }
1743 0 : catch(const uno::Exception&)
1744 : {
1745 : SAL_WARN("sw.mailmerge", "no FormatKey property found");
1746 : }
1747 620 : if(bUseDefault)
1748 620 : nRet = dbtools::getDefaultNumberFormat(xColumn, xDocNumberFormatTypes, aLocale);
1749 : }
1750 620 : return nRet;
1751 : }
1752 :
1753 0 : sal_Int32 SwDBManager::GetColumnType( const OUString& rDBName,
1754 : const OUString& rTableName,
1755 : const OUString& rColNm )
1756 : {
1757 0 : sal_Int32 nRet = sdbc::DataType::SQLNULL;
1758 0 : SwDBData aData;
1759 0 : aData.sDataSource = rDBName;
1760 0 : aData.sCommand = rTableName;
1761 0 : aData.nCommandType = -1;
1762 0 : SwDSParam* pParam = FindDSData(aData, false);
1763 0 : uno::Reference< sdbc::XConnection> xConnection;
1764 0 : uno::Reference< sdbcx::XColumnsSupplier > xColsSupp;
1765 0 : bool bDispose = false;
1766 0 : if(pParam && pParam->xConnection.is())
1767 : {
1768 0 : xConnection = pParam->xConnection;
1769 0 : xColsSupp = uno::Reference< sdbcx::XColumnsSupplier >( pParam->xResultSet, uno::UNO_QUERY );
1770 : }
1771 : else
1772 : {
1773 0 : OUString sDBName(rDBName);
1774 0 : xConnection = RegisterConnection( sDBName );
1775 : }
1776 0 : if( !xColsSupp.is() )
1777 : {
1778 0 : xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1779 0 : bDispose = true;
1780 : }
1781 0 : if(xColsSupp.is())
1782 : {
1783 0 : uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1784 0 : if(xCols->hasByName(rColNm))
1785 : {
1786 0 : uno::Any aCol = xCols->getByName(rColNm);
1787 0 : uno::Reference<beans::XPropertySet> xCol;
1788 0 : aCol >>= xCol;
1789 0 : uno::Any aType = xCol->getPropertyValue("Type");
1790 0 : aType >>= nRet;
1791 : }
1792 0 : if(bDispose)
1793 0 : ::comphelper::disposeComponent( xColsSupp );
1794 : }
1795 0 : return nRet;
1796 : }
1797 :
1798 0 : uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rDataSource,
1799 : uno::Reference<sdbc::XDataSource>& rxSource)
1800 : {
1801 0 : uno::Reference< sdbc::XConnection> xConnection;
1802 0 : uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1803 : try
1804 : {
1805 0 : uno::Reference<sdb::XCompletedConnection> xComplConnection(dbtools::getDataSource(rDataSource, xContext), uno::UNO_QUERY);
1806 0 : if ( xComplConnection.is() )
1807 : {
1808 0 : rxSource.set(xComplConnection, uno::UNO_QUERY);
1809 0 : uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(xContext, 0), uno::UNO_QUERY_THROW );
1810 0 : xConnection = xComplConnection->connectWithCompletion( xHandler );
1811 0 : }
1812 : }
1813 0 : catch(const uno::Exception&)
1814 : {
1815 : }
1816 :
1817 0 : return xConnection;
1818 : }
1819 :
1820 0 : uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference<sdbc::XConnection> xConnection,
1821 : const OUString& rTableOrQuery,
1822 : SwDBSelect eTableOrQuery)
1823 : {
1824 0 : uno::Reference< sdbcx::XColumnsSupplier> xRet;
1825 : try
1826 : {
1827 0 : if(eTableOrQuery == SwDBSelect::UNKNOWN)
1828 : {
1829 : //search for a table with the given command name
1830 0 : uno::Reference<sdbcx::XTablesSupplier> xTSupplier = uno::Reference<sdbcx::XTablesSupplier>(xConnection, uno::UNO_QUERY);
1831 0 : if(xTSupplier.is())
1832 : {
1833 0 : uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
1834 0 : eTableOrQuery = xTables->hasByName(rTableOrQuery) ?
1835 0 : SwDBSelect::TABLE : SwDBSelect::QUERY;
1836 0 : }
1837 : }
1838 : sal_Int32 nCommandType = SwDBSelect::TABLE == eTableOrQuery ?
1839 0 : sdb::CommandType::TABLE : sdb::CommandType::QUERY;
1840 0 : uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
1841 0 : uno::Reference<sdbc::XRowSet> xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), uno::UNO_QUERY);
1842 :
1843 0 : OUString sDataSource;
1844 0 : uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection, sDataSource);
1845 0 : uno::Reference<beans::XPropertySet> xSourceProperties(xSource, uno::UNO_QUERY);
1846 0 : if(xSourceProperties.is())
1847 : {
1848 0 : xSourceProperties->getPropertyValue("Name") >>= sDataSource;
1849 : }
1850 :
1851 0 : uno::Reference<beans::XPropertySet> xRowProperties(xRowSet, uno::UNO_QUERY);
1852 0 : xRowProperties->setPropertyValue("DataSourceName", uno::makeAny(sDataSource));
1853 0 : xRowProperties->setPropertyValue("Command", uno::makeAny(OUString(rTableOrQuery)));
1854 0 : xRowProperties->setPropertyValue("CommandType", uno::makeAny(nCommandType));
1855 0 : xRowProperties->setPropertyValue("FetchSize", uno::makeAny((sal_Int32)10));
1856 0 : xRowProperties->setPropertyValue("ActiveConnection", uno::makeAny(xConnection));
1857 0 : xRowSet->execute();
1858 0 : xRet = uno::Reference<sdbcx::XColumnsSupplier>( xRowSet, uno::UNO_QUERY );
1859 : }
1860 0 : catch (const uno::Exception& e)
1861 : {
1862 : SAL_WARN("sw.mailmerge", "Exception in SwDBManager::GetColumnSupplier: " << e.Message);
1863 : }
1864 :
1865 0 : return xRet;
1866 : }
1867 :
1868 620 : OUString SwDBManager::GetDBField(uno::Reference<beans::XPropertySet> xColumnProps,
1869 : const SwDBFormatData& rDBFormatData,
1870 : double* pNumber)
1871 : {
1872 620 : uno::Reference< sdb::XColumn > xColumn(xColumnProps, uno::UNO_QUERY);
1873 620 : OUString sRet;
1874 : OSL_ENSURE(xColumn.is(), "SwDBManager::::ImportDBField: illegal arguments");
1875 620 : if(!xColumn.is())
1876 0 : return sRet;
1877 :
1878 1240 : uno::Any aType = xColumnProps->getPropertyValue("Type");
1879 620 : sal_Int32 eDataType = sdbc::DataType::SQLNULL;
1880 620 : aType >>= eDataType;
1881 620 : switch(eDataType)
1882 : {
1883 : case sdbc::DataType::CHAR:
1884 : case sdbc::DataType::VARCHAR:
1885 : case sdbc::DataType::LONGVARCHAR:
1886 : try
1887 : {
1888 620 : sRet = xColumn->getString();
1889 620 : sRet = sRet.replace( '\xb', '\n' ); // MSWord uses \xb as a newline
1890 : }
1891 0 : catch(const sdbc::SQLException&)
1892 : {
1893 : }
1894 620 : break;
1895 : case sdbc::DataType::BIT:
1896 : case sdbc::DataType::BOOLEAN:
1897 : case sdbc::DataType::TINYINT:
1898 : case sdbc::DataType::SMALLINT:
1899 : case sdbc::DataType::INTEGER:
1900 : case sdbc::DataType::BIGINT:
1901 : case sdbc::DataType::FLOAT:
1902 : case sdbc::DataType::REAL:
1903 : case sdbc::DataType::DOUBLE:
1904 : case sdbc::DataType::NUMERIC:
1905 : case sdbc::DataType::DECIMAL:
1906 : case sdbc::DataType::DATE:
1907 : case sdbc::DataType::TIME:
1908 : case sdbc::DataType::TIMESTAMP:
1909 : {
1910 :
1911 : try
1912 : {
1913 0 : sRet = dbtools::DBTypeConversion::getFormattedValue(
1914 : xColumnProps,
1915 : rDBFormatData.xFormatter,
1916 : rDBFormatData.aLocale,
1917 0 : rDBFormatData.aNullDate);
1918 0 : if (pNumber)
1919 : {
1920 0 : double fVal = xColumn->getDouble();
1921 0 : if(!xColumn->wasNull())
1922 : {
1923 0 : *pNumber = fVal;
1924 : }
1925 : }
1926 : }
1927 0 : catch (const uno::Exception& e)
1928 : {
1929 : SAL_WARN("sw.mailmerge", "exception caught: " << e.Message);
1930 : }
1931 :
1932 : }
1933 0 : break;
1934 : }
1935 :
1936 1240 : return sRet;
1937 : }
1938 :
1939 : // checks if a desired data source table or query is open
1940 236 : bool SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
1941 : const OUString& rTableOrQuery, bool bMergeShell)
1942 : {
1943 236 : if(pImpl->pMergeData)
1944 : {
1945 272 : return !bMergeLock &&
1946 256 : ((rDataSource == pImpl->pMergeData->sDataSource &&
1947 120 : rTableOrQuery == pImpl->pMergeData->sCommand)
1948 16 : ||(rDataSource.isEmpty() && rTableOrQuery.isEmpty()))
1949 256 : &&
1950 256 : pImpl->pMergeData->xResultSet.is();
1951 : }
1952 100 : else if(!bMergeShell)
1953 : {
1954 50 : SwDBData aData;
1955 50 : aData.sDataSource = rDataSource;
1956 50 : aData.sCommand = rTableOrQuery;
1957 50 : aData.nCommandType = -1;
1958 50 : SwDSParam* pFound = FindDSData(aData, false);
1959 50 : return (pFound && pFound->xResultSet.is());
1960 : }
1961 50 : return false;
1962 : }
1963 :
1964 : // read column data at a specified position
1965 0 : bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
1966 : const OUString& rColumnName, sal_uInt32 nAbsRecordId,
1967 : long nLanguage,
1968 : OUString& rResult, double* pNumber)
1969 : {
1970 0 : bool bRet = false;
1971 0 : SwDSParam* pFound = 0;
1972 : //check if it's the merge data source
1973 0 : if(pImpl->pMergeData &&
1974 0 : rSourceName == pImpl->pMergeData->sDataSource &&
1975 0 : rTableName == pImpl->pMergeData->sCommand)
1976 : {
1977 0 : pFound = pImpl->pMergeData;
1978 : }
1979 : else
1980 : {
1981 0 : SwDBData aData;
1982 0 : aData.sDataSource = rSourceName;
1983 0 : aData.sCommand = rTableName;
1984 0 : aData.nCommandType = -1;
1985 0 : pFound = FindDSData(aData, false);
1986 : }
1987 0 : if (!pFound)
1988 0 : return false;
1989 : //check validity of supplied record Id
1990 0 : if(pFound->aSelection.getLength())
1991 : {
1992 : //the destination has to be an element of the selection
1993 0 : const uno::Any* pSelection = pFound->aSelection.getConstArray();
1994 0 : bool bFound = false;
1995 0 : for(sal_Int32 nPos = 0; !bFound && nPos < pFound->aSelection.getLength(); nPos++)
1996 : {
1997 0 : sal_Int32 nSelection = 0;
1998 0 : pSelection[nPos] >>= nSelection;
1999 0 : if(nSelection == static_cast<sal_Int32>(nAbsRecordId))
2000 0 : bFound = true;
2001 : }
2002 0 : if(!bFound)
2003 0 : return false;
2004 : }
2005 0 : if(pFound->xResultSet.is() && !pFound->bAfterSelection)
2006 : {
2007 0 : sal_Int32 nOldRow = 0;
2008 : try
2009 : {
2010 0 : nOldRow = pFound->xResultSet->getRow();
2011 : }
2012 0 : catch(const uno::Exception&)
2013 : {
2014 0 : return false;
2015 : }
2016 : //position to the desired index
2017 0 : bool bMove = true;
2018 0 : if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2019 0 : bMove = lcl_MoveAbsolute(pFound, nAbsRecordId);
2020 0 : if(bMove)
2021 : {
2022 0 : bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber);
2023 : }
2024 0 : if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2025 0 : bMove = lcl_MoveAbsolute(pFound, nOldRow);
2026 : }
2027 0 : return bRet;
2028 : }
2029 :
2030 : // reads the column data at the current position
2031 60 : bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, sal_uInt16 nLanguage,
2032 : OUString &rResult, double *pNumber)
2033 : {
2034 60 : if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is() || pImpl->pMergeData->bAfterSelection )
2035 : {
2036 0 : rResult.clear();
2037 0 : return false;
2038 : }
2039 :
2040 60 : bool bRet = lcl_GetColumnCnt(pImpl->pMergeData, rColumnName, nLanguage, rResult, pNumber);
2041 60 : return bRet;
2042 : }
2043 :
2044 65 : bool SwDBManager::ToNextMergeRecord()
2045 : {
2046 : OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge");
2047 65 : return ToNextRecord(pImpl->pMergeData);
2048 : }
2049 :
2050 73 : bool SwDBManager::FillCalcWithMergeData( SvNumberFormatter *pDocFormatter,
2051 : sal_uInt16 nLanguage, bool asString, SwCalc &rCalc )
2052 : {
2053 73 : if (!(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is()))
2054 32 : return false;
2055 :
2056 41 : uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
2057 41 : if(xColsSupp.is())
2058 : {
2059 41 : uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
2060 82 : const uno::Sequence<OUString> aColNames = xCols->getElementNames();
2061 41 : const OUString* pColNames = aColNames.getConstArray();
2062 82 : OUString aString;
2063 :
2064 41 : const bool bExistsNextRecord = ExistsNextRecord();
2065 :
2066 615 : for( int nCol = 0; nCol < aColNames.getLength(); nCol++ )
2067 : {
2068 574 : const OUString &rColName = pColNames[nCol];
2069 :
2070 : // empty variables, if no more records;
2071 574 : if( !bExistsNextRecord )
2072 : {
2073 14 : rCalc.VarChange( rColName, 0 );
2074 14 : continue;
2075 : }
2076 :
2077 : // get the column type
2078 560 : sal_Int32 nColumnType = sdbc::DataType::SQLNULL;
2079 560 : uno::Any aCol = xCols->getByName( pColNames[nCol] );
2080 1120 : uno::Reference<beans::XPropertySet> xColumnProps;
2081 560 : aCol >>= xColumnProps;
2082 1120 : uno::Any aType = xColumnProps->getPropertyValue( "Type" );
2083 560 : aType >>= nColumnType;
2084 560 : double aNumber = DBL_MAX;
2085 :
2086 560 : lcl_GetColumnCnt( pImpl->pMergeData, xColumnProps, nLanguage, aString, &aNumber );
2087 :
2088 : sal_uInt32 nFormat = GetColumnFormat( pImpl->pMergeData->sDataSource,
2089 : pImpl->pMergeData->sCommand,
2090 560 : pColNames[nCol], pDocFormatter, nLanguage );
2091 : // aNumber is overwritten by SwDBField::FormatValue, so store initial status
2092 560 : bool colIsNumber = aNumber != DBL_MAX;
2093 : bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFormat,
2094 560 : aNumber, nColumnType, NULL );
2095 560 : if( colIsNumber )
2096 : {
2097 0 : if( bValidValue )
2098 : {
2099 0 : SwSbxValue aValue;
2100 0 : if( !asString )
2101 0 : aValue.PutDouble( aNumber );
2102 : else
2103 0 : aValue.PutString( aString );
2104 : SAL_INFO( "sw.dbmgr", "'" << pColNames[nCol] << "': " << aNumber << " / " << aString );
2105 0 : rCalc.VarChange( pColNames[nCol], aValue );
2106 : }
2107 : }
2108 : else
2109 : {
2110 560 : SwSbxValue aValue;
2111 560 : aValue.PutString( aString );
2112 : SAL_INFO( "sw.dbmgr", "'" << pColNames[nCol] << "': " << aString );
2113 560 : rCalc.VarChange( pColNames[nCol], aValue );
2114 : }
2115 560 : }
2116 82 : return bExistsNextRecord;
2117 : }
2118 0 : return false;
2119 : }
2120 :
2121 0 : bool SwDBManager::ToNextRecord(
2122 : const OUString& rDataSource, const OUString& rCommand, sal_Int32 /*nCommandType*/)
2123 : {
2124 0 : SwDSParam* pFound = 0;
2125 0 : if(pImpl->pMergeData &&
2126 0 : rDataSource == pImpl->pMergeData->sDataSource &&
2127 0 : rCommand == pImpl->pMergeData->sCommand)
2128 0 : pFound = pImpl->pMergeData;
2129 : else
2130 : {
2131 0 : SwDBData aData;
2132 0 : aData.sDataSource = rDataSource;
2133 0 : aData.sCommand = rCommand;
2134 0 : aData.nCommandType = -1;
2135 0 : pFound = FindDSData(aData, false);
2136 : }
2137 0 : return ToNextRecord(pFound);
2138 : }
2139 :
2140 65 : bool SwDBManager::ToNextRecord(SwDSParam* pParam)
2141 : {
2142 65 : bool bRet = true;
2143 130 : if(!pParam || !pParam->xResultSet.is() || pParam->bEndOfDB ||
2144 64 : (pParam->aSelection.getLength() && pParam->aSelection.getLength() <= pParam->nSelectionIndex))
2145 : {
2146 1 : if(pParam)
2147 1 : pParam->CheckEndOfDB();
2148 1 : return false;
2149 : }
2150 : try
2151 : {
2152 64 : if(pParam->aSelection.getLength())
2153 : {
2154 0 : sal_Int32 nPos = 0;
2155 0 : pParam->aSelection.getConstArray()[ pParam->nSelectionIndex++ ] >>= nPos;
2156 0 : pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
2157 0 : pParam->CheckEndOfDB();
2158 0 : bRet = !pParam->bEndOfDB;
2159 0 : if(pParam->nSelectionIndex >= pParam->aSelection.getLength())
2160 0 : pParam->bEndOfDB = true;
2161 : }
2162 : else
2163 : {
2164 64 : sal_Int32 nBefore = pParam->xResultSet->getRow();
2165 64 : pParam->bEndOfDB = !pParam->xResultSet->next();
2166 64 : if( !pParam->bEndOfDB && nBefore == pParam->xResultSet->getRow())
2167 : {
2168 : //next returned true but it didn't move
2169 0 : pParam->bEndOfDB = true;
2170 : }
2171 :
2172 64 : pParam->CheckEndOfDB();
2173 64 : bRet = !pParam->bEndOfDB;
2174 64 : ++pParam->nSelectionIndex;
2175 : }
2176 : }
2177 0 : catch(const uno::Exception&)
2178 : {
2179 : }
2180 64 : return bRet;
2181 : }
2182 :
2183 : // synchronized labels contain a next record field at their end
2184 : // to assure that the next page can be created in mail merge
2185 : // the cursor position must be validated
2186 41 : bool SwDBManager::ExistsNextRecord() const
2187 : {
2188 41 : return pImpl->pMergeData && !pImpl->pMergeData->bEndOfDB;
2189 : }
2190 :
2191 60 : sal_uInt32 SwDBManager::GetSelectedRecordId()
2192 : {
2193 60 : sal_uInt32 nRet = 0;
2194 : OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge");
2195 60 : if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is())
2196 0 : return 0;
2197 : try
2198 : {
2199 60 : nRet = pImpl->pMergeData->xResultSet->getRow();
2200 : }
2201 0 : catch(const uno::Exception&)
2202 : {
2203 : }
2204 60 : return nRet;
2205 : }
2206 :
2207 0 : bool SwDBManager::ToRecordId(sal_Int32 nSet)
2208 : {
2209 : OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge");
2210 0 : if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is()|| nSet < 0)
2211 0 : return false;
2212 0 : bool bRet = false;
2213 0 : sal_Int32 nAbsPos = nSet;
2214 :
2215 0 : if(nAbsPos >= 0)
2216 : {
2217 0 : bRet = lcl_MoveAbsolute(pImpl->pMergeData, nAbsPos);
2218 0 : pImpl->pMergeData->bEndOfDB = !bRet;
2219 0 : pImpl->pMergeData->CheckEndOfDB();
2220 : }
2221 0 : return bRet;
2222 : }
2223 :
2224 0 : bool SwDBManager::OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery,
2225 : sal_Int32 nCommandType, bool bCreate)
2226 : {
2227 0 : SwDBData aData;
2228 0 : aData.sDataSource = rDataSource;
2229 0 : aData.sCommand = rTableOrQuery;
2230 0 : aData.nCommandType = nCommandType;
2231 :
2232 0 : SwDSParam* pFound = FindDSData(aData, true);
2233 0 : uno::Reference< sdbc::XDataSource> xSource;
2234 0 : if(pFound->xResultSet.is())
2235 0 : return true;
2236 0 : SwDSParam* pParam = FindDSConnection(rDataSource, false);
2237 0 : uno::Reference< sdbc::XConnection> xConnection;
2238 0 : if(pParam && pParam->xConnection.is())
2239 0 : pFound->xConnection = pParam->xConnection;
2240 0 : else if(bCreate)
2241 : {
2242 0 : OUString sDataSource(rDataSource);
2243 0 : pFound->xConnection = RegisterConnection( sDataSource );
2244 : }
2245 0 : if(pFound->xConnection.is())
2246 : {
2247 : try
2248 : {
2249 0 : uno::Reference< sdbc::XDatabaseMetaData > xMetaData = pFound->xConnection->getMetaData();
2250 : try
2251 : {
2252 : pFound->bScrollable = xMetaData
2253 0 : ->supportsResultSetType((sal_Int32)sdbc::ResultSetType::SCROLL_INSENSITIVE);
2254 : }
2255 0 : catch(const uno::Exception&)
2256 : {
2257 : // DB driver may not be ODBC 3.0 compliant
2258 0 : pFound->bScrollable = true;
2259 : }
2260 0 : pFound->xStatement = pFound->xConnection->createStatement();
2261 0 : OUString aQuoteChar = xMetaData->getIdentifierQuoteString();
2262 0 : OUString sStatement("SELECT * FROM ");
2263 0 : sStatement = "SELECT * FROM ";
2264 0 : sStatement += aQuoteChar;
2265 0 : sStatement += rTableOrQuery;
2266 0 : sStatement += aQuoteChar;
2267 0 : pFound->xResultSet = pFound->xStatement->executeQuery( sStatement );
2268 :
2269 : //after executeQuery the cursor must be positioned
2270 0 : pFound->bEndOfDB = !pFound->xResultSet->next();
2271 0 : pFound->bAfterSelection = false;
2272 0 : pFound->CheckEndOfDB();
2273 0 : ++pFound->nSelectionIndex;
2274 : }
2275 0 : catch (const uno::Exception&)
2276 : {
2277 0 : pFound->xResultSet = 0;
2278 0 : pFound->xStatement = 0;
2279 0 : pFound->xConnection = 0;
2280 : }
2281 : }
2282 0 : return pFound->xResultSet.is();
2283 : }
2284 :
2285 0 : uno::Reference< sdbc::XConnection> SwDBManager::RegisterConnection(OUString& rDataSource)
2286 : {
2287 0 : SwDSParam* pFound = SwDBManager::FindDSConnection(rDataSource, true);
2288 0 : uno::Reference< sdbc::XDataSource> xSource;
2289 0 : if(!pFound->xConnection.is())
2290 : {
2291 0 : pFound->xConnection = SwDBManager::GetConnection(rDataSource, xSource );
2292 : try
2293 : {
2294 0 : uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2295 0 : if(xComponent.is())
2296 0 : xComponent->addEventListener(pImpl->m_xDisposeListener.get());
2297 : }
2298 0 : catch(const uno::Exception&)
2299 : {
2300 : }
2301 : }
2302 0 : return pFound->xConnection;
2303 : }
2304 :
2305 60 : sal_uInt32 SwDBManager::GetSelectedRecordId(
2306 : const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType)
2307 : {
2308 60 : sal_uInt32 nRet = 0xffffffff;
2309 : //check for merge data source first
2310 180 : if(pImpl->pMergeData && rDataSource == pImpl->pMergeData->sDataSource &&
2311 120 : rTableOrQuery == pImpl->pMergeData->sCommand &&
2312 180 : (nCommandType == -1 || nCommandType == pImpl->pMergeData->nCommandType) &&
2313 60 : pImpl->pMergeData->xResultSet.is())
2314 60 : nRet = GetSelectedRecordId();
2315 : else
2316 : {
2317 0 : SwDBData aData;
2318 0 : aData.sDataSource = rDataSource;
2319 0 : aData.sCommand = rTableOrQuery;
2320 0 : aData.nCommandType = nCommandType;
2321 0 : SwDSParam* pFound = FindDSData(aData, false);
2322 0 : if(pFound && pFound->xResultSet.is())
2323 : {
2324 : try
2325 : { //if a selection array is set the current row at the result set may not be set yet
2326 0 : if(pFound->aSelection.getLength())
2327 : {
2328 0 : sal_Int32 nSelIndex = pFound->nSelectionIndex;
2329 0 : if(nSelIndex >= pFound->aSelection.getLength())
2330 0 : nSelIndex = pFound->aSelection.getLength() -1;
2331 0 : pFound->aSelection.getConstArray()[nSelIndex] >>= nRet;
2332 :
2333 : }
2334 : else
2335 0 : nRet = pFound->xResultSet->getRow();
2336 : }
2337 0 : catch(const uno::Exception&)
2338 : {
2339 : }
2340 0 : }
2341 : }
2342 60 : return nRet;
2343 : }
2344 :
2345 : // close all data sources - after fields were updated
2346 149 : void SwDBManager::CloseAll(bool bIncludingMerge)
2347 : {
2348 : //the only thing done here is to reset the selection index
2349 : //all connections stay open
2350 149 : for(size_t nPos = 0; nPos < aDataSourceParams.size(); nPos++)
2351 : {
2352 0 : SwDSParam* pParam = &aDataSourceParams[nPos];
2353 0 : if(bIncludingMerge || pParam != pImpl->pMergeData)
2354 : {
2355 0 : pParam->nSelectionIndex = 0;
2356 0 : pParam->bAfterSelection = false;
2357 0 : pParam->bEndOfDB = false;
2358 : try
2359 : {
2360 0 : if(!bInMerge && pParam->xResultSet.is())
2361 0 : pParam->xResultSet->first();
2362 : }
2363 0 : catch(const uno::Exception&)
2364 : {}
2365 : }
2366 : }
2367 149 : }
2368 :
2369 58 : SwDSParam* SwDBManager::FindDSData(const SwDBData& rData, bool bCreate)
2370 : {
2371 : //prefer merge data if available
2372 74 : if(pImpl->pMergeData && rData.sDataSource == pImpl->pMergeData->sDataSource &&
2373 82 : rData.sCommand == pImpl->pMergeData->sCommand &&
2374 16 : (rData.nCommandType == -1 || rData.nCommandType == pImpl->pMergeData->nCommandType ||
2375 0 : (bCreate && pImpl->pMergeData->nCommandType == -1)))
2376 : {
2377 8 : return pImpl->pMergeData;
2378 : }
2379 :
2380 50 : SwDSParam* pFound = 0;
2381 50 : for(sal_uInt16 nPos = aDataSourceParams.size(); nPos; nPos--)
2382 : {
2383 0 : SwDSParam* pParam = &aDataSourceParams[nPos - 1];
2384 0 : if(rData.sDataSource == pParam->sDataSource &&
2385 0 : rData.sCommand == pParam->sCommand &&
2386 0 : (rData.nCommandType == -1 || rData.nCommandType == pParam->nCommandType ||
2387 0 : (bCreate && pParam->nCommandType == -1)))
2388 : {
2389 : // calls from the calculator may add a connection with an invalid commandtype
2390 : //later added "real" data base connections have to re-use the already available
2391 : //DSData and set the correct CommandType
2392 0 : if(bCreate && pParam->nCommandType == -1)
2393 0 : pParam->nCommandType = rData.nCommandType;
2394 0 : pFound = pParam;
2395 0 : break;
2396 : }
2397 : }
2398 50 : if(bCreate)
2399 : {
2400 0 : if(!pFound)
2401 : {
2402 0 : pFound = new SwDSParam(rData);
2403 0 : aDataSourceParams.push_back(pFound);
2404 : try
2405 : {
2406 0 : uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2407 0 : if(xComponent.is())
2408 0 : xComponent->addEventListener(pImpl->m_xDisposeListener.get());
2409 : }
2410 0 : catch(const uno::Exception&)
2411 : {
2412 : }
2413 : }
2414 : }
2415 50 : return pFound;
2416 : }
2417 :
2418 0 : SwDSParam* SwDBManager::FindDSConnection(const OUString& rDataSource, bool bCreate)
2419 : {
2420 : //prefer merge data if available
2421 0 : if(pImpl->pMergeData && rDataSource == pImpl->pMergeData->sDataSource )
2422 : {
2423 0 : return pImpl->pMergeData;
2424 : }
2425 0 : SwDSParam* pFound = 0;
2426 0 : for(size_t nPos = 0; nPos < aDataSourceParams.size(); nPos++)
2427 : {
2428 0 : SwDSParam* pParam = &aDataSourceParams[nPos];
2429 0 : if(rDataSource == pParam->sDataSource)
2430 : {
2431 0 : pFound = pParam;
2432 0 : break;
2433 : }
2434 : }
2435 0 : if(bCreate && !pFound)
2436 : {
2437 0 : SwDBData aData;
2438 0 : aData.sDataSource = rDataSource;
2439 0 : pFound = new SwDSParam(aData);
2440 0 : aDataSourceParams.push_back(pFound);
2441 : try
2442 : {
2443 0 : uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2444 0 : if(xComponent.is())
2445 0 : xComponent->addEventListener(pImpl->m_xDisposeListener.get());
2446 : }
2447 0 : catch(const uno::Exception&)
2448 : {
2449 0 : }
2450 : }
2451 0 : return pFound;
2452 : }
2453 :
2454 827 : const SwDBData& SwDBManager::GetAddressDBName()
2455 : {
2456 827 : return SW_MOD()->GetDBConfig()->GetAddressSource();
2457 : }
2458 :
2459 0 : uno::Sequence<OUString> SwDBManager::GetExistingDatabaseNames()
2460 : {
2461 0 : uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2462 0 : uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2463 0 : return xDBContext->getElementNames();
2464 : }
2465 :
2466 0 : OUString SwDBManager::LoadAndRegisterDataSource(SwDocShell* pDocShell)
2467 : {
2468 0 : sfx2::FileDialogHelper aDlgHelper( ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, 0 );
2469 0 : uno::Reference < ui::dialogs::XFilePicker > xFP = aDlgHelper.GetFilePicker();
2470 :
2471 0 : OUString sHomePath(SvtPathOptions().GetWorkPath());
2472 0 : aDlgHelper.SetDisplayDirectory( sHomePath );
2473 :
2474 0 : uno::Reference<ui::dialogs::XFilterManager> xFltMgr(xFP, uno::UNO_QUERY);
2475 :
2476 0 : OUString sFilterAll(SW_RES(STR_FILTER_ALL));
2477 0 : OUString sFilterAllData(SW_RES(STR_FILTER_ALL_DATA));
2478 0 : OUString sFilterSXB(SW_RES(STR_FILTER_SXB));
2479 0 : OUString sFilterSXC(SW_RES(STR_FILTER_SXC));
2480 0 : OUString sFilterDBF(SW_RES(STR_FILTER_DBF));
2481 0 : OUString sFilterXLS(SW_RES(STR_FILTER_XLS));
2482 0 : OUString sFilterTXT(SW_RES(STR_FILTER_TXT));
2483 0 : OUString sFilterCSV(SW_RES(STR_FILTER_CSV));
2484 : #ifdef WNT
2485 : OUString sFilterMDB(SW_RES(STR_FILTER_MDB));
2486 : OUString sFilterACCDB(SW_RES(STR_FILTER_ACCDB));
2487 : #endif
2488 0 : xFltMgr->appendFilter( sFilterAll, "*" );
2489 0 : xFltMgr->appendFilter( sFilterAllData, "*.ods;*.sxc;*.dbf;*.xls;*.txt;*.csv");
2490 :
2491 0 : xFltMgr->appendFilter( sFilterSXB, "*.odb" );
2492 0 : xFltMgr->appendFilter( sFilterSXC, "*.ods;*.sxc" );
2493 0 : xFltMgr->appendFilter( sFilterDBF, "*.dbf" );
2494 0 : xFltMgr->appendFilter( sFilterXLS, "*.xls" );
2495 0 : xFltMgr->appendFilter( sFilterTXT, "*.txt" );
2496 0 : xFltMgr->appendFilter( sFilterCSV, "*.csv" );
2497 : #ifdef WNT
2498 : xFltMgr->appendFilter( sFilterMDB, "*.mdb" );
2499 : xFltMgr->appendFilter( sFilterACCDB, "*.accdb" );
2500 : #endif
2501 :
2502 0 : xFltMgr->setCurrentFilter( sFilterAll ) ;
2503 0 : OUString sFind;
2504 0 : if( ERRCODE_NONE == aDlgHelper.Execute() )
2505 : {
2506 0 : uno::Any aURLAny;
2507 0 : uno::Reference< beans::XPropertySet > aSettings;
2508 0 : const OUString aURI( xFP->getFiles().getConstArray()[0] );
2509 0 : const DBConnURITypes type = GetDBunoURI( aURI, aURLAny );
2510 :
2511 0 : if( DBCONN_FLAT == type )
2512 : {
2513 0 : uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2514 0 : uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
2515 0 : if( xSettingsDlg->execute() )
2516 0 : aSettings.set( uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ) );
2517 : }
2518 0 : sFind = LoadAndRegisterDataSource( type, aURLAny, DBCONN_FLAT == type ? &aSettings : 0, aURI, 0, 0, pDocShell );
2519 : }
2520 0 : return sFind;
2521 : }
2522 :
2523 3 : SwDBManager::DBConnURITypes SwDBManager::GetDBunoURI(const OUString &rURI, uno::Any &aURLAny)
2524 : {
2525 3 : INetURLObject aURL( rURI );
2526 6 : OUString sExt( aURL.GetExtension() );
2527 3 : DBConnURITypes type = DBCONN_UNKNOWN;
2528 :
2529 3 : if(sExt == "odb")
2530 : {
2531 0 : type = DBCONN_ODB;
2532 : }
2533 6 : else if(sExt.equalsIgnoreAsciiCase("sxc")
2534 3 : || sExt.equalsIgnoreAsciiCase("ods")
2535 3 : || sExt.equalsIgnoreAsciiCase("xls"))
2536 : {
2537 3 : OUString sDBURL("sdbc:calc:");
2538 3 : sDBURL += aURL.GetMainURL(INetURLObject::NO_DECODE);
2539 3 : aURLAny <<= sDBURL;
2540 3 : type = DBCONN_CALC;
2541 : }
2542 0 : else if(sExt.equalsIgnoreAsciiCase("dbf"))
2543 : {
2544 0 : aURL.removeSegment();
2545 0 : aURL.removeFinalSlash();
2546 0 : OUString sDBURL("sdbc:dbase:");
2547 0 : sDBURL += aURL.GetMainURL(INetURLObject::NO_DECODE);
2548 0 : aURLAny <<= sDBURL;
2549 0 : type = DBCONN_DBASE;
2550 : }
2551 0 : else if(sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
2552 : {
2553 0 : aURL.removeSegment();
2554 0 : aURL.removeFinalSlash();
2555 0 : OUString sDBURL("sdbc:flat:");
2556 : //only the 'path' has to be added
2557 0 : sDBURL += aURL.GetMainURL(INetURLObject::NO_DECODE);
2558 0 : aURLAny <<= sDBURL;
2559 0 : type = DBCONN_FLAT;
2560 : }
2561 : #ifdef WNT
2562 : else if(sExt.equalsIgnoreAsciiCase("mdb"))
2563 : {
2564 : OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=");
2565 : sDBURL += aURL.PathToFileName();
2566 : aURLAny <<= sDBURL;
2567 : type = DBCONN_MSJET;
2568 : }
2569 : else if(sExt.equalsIgnoreAsciiCase("accdb"))
2570 : {
2571 : OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=");
2572 : sDBURL += aURL.PathToFileName();
2573 : aURLAny <<= sDBURL;
2574 : type = DBCONN_MSACE;
2575 : }
2576 : #endif
2577 6 : return type;
2578 : }
2579 :
2580 : /// Returns the URL of this SwDoc.
2581 3 : OUString lcl_getOwnURL(SwDocShell* pDocShell)
2582 : {
2583 3 : OUString aRet;
2584 :
2585 3 : if (!pDocShell)
2586 3 : return aRet;
2587 :
2588 0 : const INetURLObject& rURLObject = pDocShell->GetMedium()->GetURLObject();
2589 0 : aRet = rURLObject.GetMainURL(INetURLObject::DECODE_WITH_CHARSET);
2590 0 : return aRet;
2591 : }
2592 :
2593 3 : OUString SwDBManager::LoadAndRegisterDataSource(const DBConnURITypes type, const uno::Any &aURLAny, const uno::Reference< beans::XPropertySet > *pSettings,
2594 : const OUString &rURI, const OUString *pPrefix, const OUString *pDestDir, SwDocShell* pDocShell)
2595 : {
2596 3 : INetURLObject aURL( rURI );
2597 6 : OUString sExt( aURL.GetExtension() );
2598 6 : uno::Any aTableFilterAny;
2599 6 : uno::Any aSuppressVersionsAny;
2600 6 : uno::Any aInfoAny;
2601 3 : bool bStore = true;
2602 3 : OUString sFind;
2603 6 : uno::Sequence<OUString> aFilters(1);
2604 :
2605 3 : switch (type) {
2606 : case DBCONN_UNKNOWN:
2607 : case DBCONN_CALC:
2608 3 : break;
2609 : case DBCONN_ODB:
2610 0 : bStore = false;
2611 0 : break;
2612 : case DBCONN_FLAT:
2613 : case DBCONN_DBASE:
2614 : //set the filter to the file name without extension
2615 0 : aFilters[0] = aURL.getBase();
2616 0 : aTableFilterAny <<= aFilters;
2617 0 : break;
2618 : case DBCONN_MSJET:
2619 : case DBCONN_MSACE:
2620 0 : aSuppressVersionsAny <<= uno::makeAny(true);
2621 0 : break;
2622 : }
2623 :
2624 : try
2625 : {
2626 3 : uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2627 6 : uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2628 :
2629 : OUString sNewName = INetURLObject::decode( aURL.getName(),
2630 : INetURLObject::DECODE_UNAMBIGUOUS,
2631 6 : RTL_TEXTENCODING_UTF8 );
2632 3 : sal_Int32 nExtLen = aURL.GetExtension().getLength();
2633 3 : sNewName = sNewName.replaceAt( sNewName.getLength() - nExtLen - 1, nExtLen + 1, "" );
2634 3 : if (pPrefix)
2635 0 : sNewName = *pPrefix + sNewName;
2636 :
2637 : //find a unique name if sNewName already exists
2638 3 : sFind = sNewName;
2639 3 : sal_Int32 nIndex = 0;
2640 6 : while(xDBContext->hasByName(sFind))
2641 : {
2642 0 : sFind = sNewName;
2643 0 : sFind += OUString::number(++nIndex);
2644 : }
2645 :
2646 6 : uno::Reference<uno::XInterface> xNewInstance;
2647 3 : if(!bStore)
2648 : {
2649 : //odb-file
2650 0 : uno::Any aDataSource = xDBContext->getByName(aURL.GetMainURL(INetURLObject::NO_DECODE));
2651 0 : aDataSource >>= xNewInstance;
2652 : }
2653 : else
2654 : {
2655 3 : xNewInstance = xDBContext->createInstance();
2656 3 : uno::Reference<beans::XPropertySet> xDataProperties(xNewInstance, uno::UNO_QUERY);
2657 :
2658 3 : if(aURLAny.hasValue())
2659 3 : xDataProperties->setPropertyValue("URL", aURLAny);
2660 3 : if(aTableFilterAny.hasValue())
2661 0 : xDataProperties->setPropertyValue("TableFilter", aTableFilterAny);
2662 3 : if(aSuppressVersionsAny.hasValue())
2663 0 : xDataProperties->setPropertyValue("SuppressVersionColumns", aSuppressVersionsAny);
2664 3 : if(aInfoAny.hasValue())
2665 0 : xDataProperties->setPropertyValue("Info", aInfoAny);
2666 :
2667 3 : if( DBCONN_FLAT == type && pSettings )
2668 : {
2669 0 : uno::Any aSettings = xDataProperties->getPropertyValue( "Settings" );
2670 0 : uno::Reference < beans::XPropertySet > xDSSettings;
2671 0 : aSettings >>= xDSSettings;
2672 0 : ::comphelper::copyProperties( *pSettings, xDSSettings );
2673 0 : xDSSettings->setPropertyValue( "Extension", uno::makeAny( sExt ));
2674 : }
2675 :
2676 6 : uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, uno::UNO_QUERY_THROW);
2677 6 : uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), uno::UNO_QUERY_THROW);
2678 6 : OUString sOutputExt = ".odb";
2679 6 : OUString aOwnURL = lcl_getOwnURL(pDocShell);
2680 3 : if (aOwnURL.isEmpty())
2681 : {
2682 : // Cannot embed, as embedded data source would need the URL of the parent document.
2683 3 : OUString sHomePath(SvtPathOptions().GetWorkPath());
2684 6 : utl::TempFile aTempFile(sNewName, true, &sOutputExt, pDestDir ? pDestDir : &sHomePath);
2685 3 : aTempFile.EnableKillingFile(true);
2686 6 : OUString sTmpName = aTempFile.GetURL();
2687 6 : xStore->storeAsURL(sTmpName, uno::Sequence<beans::PropertyValue>());
2688 : }
2689 : else
2690 : {
2691 : // Embed.
2692 0 : OUString aStreamRelPath = "EmbeddedDatabase";
2693 0 : uno::Reference<embed::XStorage> xStorage = pDocShell->GetStorage();
2694 :
2695 0 : SwDBManager::StoreEmbeddedDataSource(xStore, xStorage, aStreamRelPath, aOwnURL);
2696 :
2697 : // Refer to the sub-storage name in the document settings, so
2698 : // we can load it again next time the file is imported.
2699 0 : uno::Reference<lang::XMultiServiceFactory> xFactory(pDocShell->GetModel(), uno::UNO_QUERY);
2700 0 : uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
2701 0 : xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::makeAny(aStreamRelPath));
2702 3 : }
2703 : }
2704 6 : xDBContext->registerObject( sFind, xNewInstance );
2705 : }
2706 0 : catch(const uno::Exception&)
2707 : {
2708 0 : sFind.clear();
2709 : }
2710 6 : return sFind;
2711 : }
2712 :
2713 1 : void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>& xStorable,
2714 : const uno::Reference<embed::XStorage>& xStorage,
2715 : const OUString& rStreamRelPath,
2716 : const OUString& rOwnURL)
2717 : {
2718 : // Construct vnd.sun.star.pkg:// URL for later loading, and TargetStorage/StreamRelPath for storing.
2719 1 : OUString sTmpName = "vnd.sun.star.pkg://";
2720 1 : sTmpName += INetURLObject::encode(rOwnURL, INetURLObject::PART_AUTHORITY, INetURLObject::ENCODE_ALL);
2721 1 : sTmpName += "/" + rStreamRelPath;
2722 :
2723 : uno::Sequence<beans::PropertyValue> aSequence = comphelper::InitPropertySequence(
2724 : {
2725 : {"TargetStorage", uno::makeAny(xStorage)},
2726 : {"StreamRelPath", uno::makeAny(rStreamRelPath)},
2727 : {"BaseURI", uno::makeAny(rOwnURL)}
2728 2 : });
2729 2 : xStorable->storeAsURL(sTmpName, aSequence);
2730 1 : }
2731 :
2732 3 : OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pPrefix, const OUString *pDestDir,
2733 : const uno::Reference< beans::XPropertySet > *pSettings)
2734 : {
2735 3 : uno::Any aURLAny;
2736 3 : DBConnURITypes type = GetDBunoURI( rURI, aURLAny );
2737 3 : return LoadAndRegisterDataSource( type, aURLAny, pSettings, rURI, pPrefix, pDestDir );
2738 : }
2739 :
2740 4 : void SwDBManager::RevokeDataSource(const OUString& rName)
2741 : {
2742 4 : uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2743 4 : if (xDatabaseContext->hasByName(rName))
2744 2 : xDatabaseContext->revokeObject(rName);
2745 4 : }
2746 :
2747 2 : void SwDBManager::LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell)
2748 : {
2749 2 : uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2750 :
2751 4 : OUString sDataSource = rData.sDataSource;
2752 :
2753 : // Fallback, just in case the document would contain an embedded data source, but no DB fields.
2754 2 : if (sDataSource.isEmpty())
2755 0 : sDataSource = "EmbeddedDatabase";
2756 :
2757 2 : SwDBManager::RevokeDataSource(rData.sDataSource);
2758 :
2759 : // Encode the stream name and the real path into a single URL.
2760 2 : const INetURLObject& rURLObject = rDocShell.GetMedium()->GetURLObject();
2761 4 : OUString aURL = "vnd.sun.star.pkg://";
2762 2 : aURL += INetURLObject::encode(rURLObject.GetMainURL(INetURLObject::DECODE_WITH_CHARSET), INetURLObject::PART_AUTHORITY, INetURLObject::ENCODE_ALL);
2763 2 : aURL += "/" + INetURLObject::encode(m_sEmbeddedName, INetURLObject::PART_FPATH, INetURLObject::ENCODE_ALL);
2764 :
2765 4 : uno::Reference<uno::XInterface> xDataSource(xDatabaseContext->getByName(aURL), uno::UNO_QUERY);
2766 4 : xDatabaseContext->registerObject(rData.sDataSource, xDataSource);
2767 2 : }
2768 :
2769 0 : void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
2770 : const uno::Sequence<beans::PropertyValue>& rProperties,
2771 : bool bWithDataSourceBrowser)
2772 : {
2773 : //prevent second call
2774 0 : if(pImpl->pMergeDialog)
2775 0 : return ;
2776 0 : OUString sDataSource, sDataTableOrQuery;
2777 0 : uno::Sequence<uno::Any> aSelection;
2778 :
2779 0 : sal_Int32 nCmdType = sdb::CommandType::TABLE;
2780 0 : uno::Reference< sdbc::XConnection> xConnection;
2781 :
2782 0 : svx::ODataAccessDescriptor aDescriptor(rProperties);
2783 0 : sDataSource = aDescriptor.getDataSource();
2784 0 : OSL_VERIFY(aDescriptor[svx::daCommand] >>= sDataTableOrQuery);
2785 0 : OSL_VERIFY(aDescriptor[svx::daCommandType] >>= nCmdType);
2786 :
2787 0 : if ( aDescriptor.has(svx::daSelection) )
2788 0 : aDescriptor[svx::daSelection] >>= aSelection;
2789 0 : if ( aDescriptor.has(svx::daConnection) )
2790 0 : aDescriptor[svx::daConnection] >>= xConnection;
2791 :
2792 0 : if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty())
2793 : {
2794 : OSL_FAIL("PropertyValues missing or unset");
2795 0 : return;
2796 : }
2797 :
2798 : //always create a connection for the dialog and dispose it after the dialog has been closed
2799 0 : SwDSParam* pFound = 0;
2800 0 : if(!xConnection.is())
2801 : {
2802 0 : xConnection = SwDBManager::RegisterConnection(sDataSource);
2803 0 : pFound = FindDSConnection(sDataSource, true);
2804 : }
2805 0 : SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
2806 : OSL_ENSURE(pFact, "Dialog creation failed!");
2807 : pImpl->pMergeDialog = pFact->CreateMailMergeDlg( DLG_MAILMERGE,
2808 0 : &rSh.GetView().GetViewFrame()->GetWindow(), rSh,
2809 : sDataSource,
2810 : sDataTableOrQuery,
2811 : nCmdType,
2812 : xConnection,
2813 0 : bWithDataSourceBrowser ? 0 : &aSelection);
2814 : OSL_ENSURE(pImpl->pMergeDialog, "Dialog creation failed!");
2815 0 : if(pImpl->pMergeDialog->Execute() == RET_OK)
2816 : {
2817 0 : aDescriptor[svx::daSelection] <<= pImpl->pMergeDialog->GetSelection();
2818 :
2819 0 : uno::Reference<sdbc::XResultSet> xResSet = pImpl->pMergeDialog->GetResultSet();
2820 0 : if(xResSet.is())
2821 0 : aDescriptor[svx::daCursor] <<= xResSet;
2822 :
2823 : // SfxObjectShellRef is ok, since there should be no control over the document lifetime here
2824 0 : SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame()->GetObjectShell();
2825 0 : SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE), xDocShell));
2826 : {
2827 : //copy rSh to aTempFile
2828 0 : OUString sTempURL;
2829 : const SfxFilter *pSfxFlt = SwIoSystem::GetFilterOfFormat(
2830 : OUString(FILTER_XML),
2831 0 : SwDocShell::Factory().GetFilterContainer() );
2832 : try
2833 : {
2834 :
2835 0 : uno::Sequence< beans::PropertyValue > aValues(1);
2836 0 : beans::PropertyValue* pValues = aValues.getArray();
2837 0 : pValues[0].Name = "FilterName";
2838 0 : pValues[0].Value <<= OUString(pSfxFlt->GetFilterName());
2839 0 : uno::Reference< frame::XStorable > xStore( xDocShell->GetModel(), uno::UNO_QUERY);
2840 0 : sTempURL = URIHelper::SmartRel2Abs( INetURLObject(), utl::TempFile::CreateTempName() );
2841 0 : xStore->storeToURL( sTempURL, aValues );
2842 : }
2843 0 : catch(const uno::Exception&)
2844 : {
2845 : }
2846 0 : if( xDocShell->GetError() )
2847 : {
2848 : // error message ??
2849 0 : ErrorHandler::HandleError( xDocShell->GetError() );
2850 : }
2851 : else
2852 : {
2853 : // the shell will be explicitly closed, but it is more safe to use SfxObjectShellLock here
2854 : // especially for the case that the loading has failed
2855 0 : SfxObjectShellLock xWorkDocSh( new SwDocShell( SfxObjectCreateMode::INTERNAL ));
2856 0 : SfxMedium* pWorkMed = new SfxMedium( sTempURL, STREAM_STD_READ );
2857 0 : pWorkMed->SetFilter( pSfxFlt );
2858 0 : if( xWorkDocSh->DoLoad(pWorkMed) )
2859 : {
2860 0 : SfxViewFrame *pFrame = SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 );
2861 0 : SwView *pView = static_cast<SwView*>( pFrame->GetViewShell() );
2862 0 : pView->AttrChangedNotify( &pView->GetWrtShell() );// in order for SelectShell to be called
2863 : //set the current DBManager
2864 0 : SwDoc* pWorkDoc = pView->GetWrtShell().GetDoc();
2865 0 : SwDBManager* pWorkDBManager = pWorkDoc->GetDBManager();
2866 0 : pWorkDoc->SetDBManager( this );
2867 :
2868 0 : SwMergeDescriptor aMergeDesc( pImpl->pMergeDialog->GetMergeType(), pView->GetWrtShell(), aDescriptor );
2869 0 : aMergeDesc.sSaveToFilter = pImpl->pMergeDialog->GetSaveFilter();
2870 0 : aMergeDesc.bCreateSingleFile = pImpl->pMergeDialog->IsSaveSingleDoc() && pImpl->pMergeDialog->GetMergeType() != DBMGR_MERGE_PRINTER;
2871 0 : aMergeDesc.bSubjectIsFilename = aMergeDesc.bCreateSingleFile;
2872 0 : if( !aMergeDesc.bCreateSingleFile && pImpl->pMergeDialog->IsGenerateFromDataBase() )
2873 : {
2874 0 : aMergeDesc.sAddressFromColumn = pImpl->pMergeDialog->GetColumnName();
2875 0 : aMergeDesc.sSubject = pImpl->pMergeDialog->GetPath();
2876 : }
2877 :
2878 0 : MergeNew(aMergeDesc);
2879 :
2880 0 : pWorkDoc->SetDBManager( pWorkDBManager );
2881 : //close the temporary file
2882 0 : uno::Reference< util::XCloseable > xClose( xWorkDocSh->GetModel(), uno::UNO_QUERY );
2883 0 : if (xClose.is())
2884 : {
2885 : try
2886 : {
2887 : //! 'sal_True' -> transfer ownership to vetoing object if vetoed!
2888 : //! I.e. now that object is responsible for closing the model and doc shell.
2889 0 : xClose->close( sal_True );
2890 : }
2891 0 : catch (const uno::Exception&)
2892 : {
2893 : }
2894 0 : }
2895 0 : }
2896 : }
2897 : //remove the temporary file
2898 0 : SWUnoHelper::UCB_DeleteFile( sTempURL );
2899 : }
2900 0 : SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE_END, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END), rSh.GetView().GetViewFrame()->GetObjectShell()));
2901 :
2902 : // reset the cursor inside
2903 0 : xResSet = NULL;
2904 0 : aDescriptor[svx::daCursor] <<= xResSet;
2905 : }
2906 0 : if(pFound)
2907 : {
2908 0 : for(size_t nPos = 0; nPos < aDataSourceParams.size(); nPos++)
2909 : {
2910 0 : SwDSParam* pParam = &aDataSourceParams[nPos];
2911 0 : if(pParam == pFound)
2912 : {
2913 : try
2914 : {
2915 0 : uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY);
2916 0 : if(xComp.is())
2917 0 : xComp->dispose();
2918 : }
2919 0 : catch(const uno::RuntimeException&)
2920 : {
2921 : //may be disposed already since multiple entries may have used the same connection
2922 : }
2923 0 : break;
2924 : }
2925 : //pFound doesn't need to be removed/deleted -
2926 : //this has been done by the SwConnectionDisposedListener_Impl already
2927 : }
2928 : }
2929 0 : DELETEZ(pImpl->pMergeDialog);
2930 : }
2931 :
2932 0 : void SwDBManager::InsertText(SwWrtShell& rSh,
2933 : const uno::Sequence< beans::PropertyValue>& rProperties)
2934 : {
2935 0 : OUString sDataSource, sDataTableOrQuery;
2936 0 : uno::Reference<sdbc::XResultSet> xResSet;
2937 0 : uno::Sequence<uno::Any> aSelection;
2938 0 : sal_Int16 nCmdType = sdb::CommandType::TABLE;
2939 0 : const beans::PropertyValue* pValues = rProperties.getConstArray();
2940 0 : uno::Reference< sdbc::XConnection> xConnection;
2941 0 : for(sal_Int32 nPos = 0; nPos < rProperties.getLength(); nPos++)
2942 : {
2943 0 : if ( pValues[nPos].Name == cDataSourceName )
2944 0 : pValues[nPos].Value >>= sDataSource;
2945 0 : else if ( pValues[nPos].Name == cCommand )
2946 0 : pValues[nPos].Value >>= sDataTableOrQuery;
2947 0 : else if ( pValues[nPos].Name == cCursor )
2948 0 : pValues[nPos].Value >>= xResSet;
2949 0 : else if ( pValues[nPos].Name == cSelection )
2950 0 : pValues[nPos].Value >>= aSelection;
2951 0 : else if ( pValues[nPos].Name == cCommandType )
2952 0 : pValues[nPos].Value >>= nCmdType;
2953 0 : else if ( pValues[nPos].Name == cActiveConnection )
2954 0 : pValues[nPos].Value >>= xConnection;
2955 : }
2956 0 : if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty() || !xResSet.is())
2957 : {
2958 : OSL_FAIL("PropertyValues missing or unset");
2959 0 : return;
2960 : }
2961 0 : uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2962 0 : uno::Reference<sdbc::XDataSource> xSource;
2963 0 : uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
2964 0 : if(xChild.is())
2965 0 : xSource = uno::Reference<sdbc::XDataSource>(xChild->getParent(), uno::UNO_QUERY);
2966 0 : if(!xSource.is())
2967 0 : xSource = dbtools::getDataSource(sDataSource, xContext);
2968 0 : uno::Reference< sdbcx::XColumnsSupplier > xColSupp( xResSet, uno::UNO_QUERY );
2969 0 : SwDBData aDBData;
2970 0 : aDBData.sDataSource = sDataSource;
2971 0 : aDBData.sCommand = sDataTableOrQuery;
2972 0 : aDBData.nCommandType = nCmdType;
2973 :
2974 0 : SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
2975 : OSL_ENSURE(pFact, "SwAbstractDialogFactory fail!");
2976 :
2977 0 : boost::scoped_ptr<AbstractSwInsertDBColAutoPilot> pDlg(pFact->CreateSwInsertDBColAutoPilot( rSh.GetView(),
2978 : xSource,
2979 : xColSupp,
2980 0 : aDBData ));
2981 : OSL_ENSURE(pDlg, "Dialog creation failed!");
2982 0 : if( RET_OK == pDlg->Execute() )
2983 : {
2984 0 : OUString sDummy;
2985 0 : if(!xConnection.is())
2986 0 : xConnection = xSource->getConnection(sDummy, sDummy);
2987 : try
2988 : {
2989 0 : pDlg->DataToDoc( aSelection , xSource, xConnection, xResSet);
2990 : }
2991 0 : catch (const uno::Exception& e)
2992 : {
2993 : SAL_WARN("sw.mailmerge", "exception caught: " << e.Message);
2994 0 : }
2995 0 : }
2996 : }
2997 :
2998 628 : uno::Reference<sdbc::XDataSource> SwDBManager::getDataSourceAsParent(const uno::Reference< sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName)
2999 : {
3000 628 : uno::Reference<sdbc::XDataSource> xSource;
3001 : try
3002 : {
3003 628 : uno::Reference<container::XChild> xChild(_xConnection, uno::UNO_QUERY);
3004 628 : if ( xChild.is() )
3005 628 : xSource = uno::Reference<sdbc::XDataSource>(xChild->getParent(), uno::UNO_QUERY);
3006 628 : if ( !xSource.is() )
3007 0 : xSource = dbtools::getDataSource(_sDataSourceName, ::comphelper::getProcessComponentContext());
3008 : }
3009 0 : catch (const uno::Exception& e)
3010 : {
3011 : SAL_WARN("sw.mailmerge", "exception caught in getDataSourceAsParent(): " << e.Message);
3012 : }
3013 628 : return xSource;
3014 : }
3015 :
3016 0 : uno::Reference<sdbc::XResultSet> SwDBManager::createCursor(const OUString& _sDataSourceName,
3017 : const OUString& _sCommand,
3018 : sal_Int32 _nCommandType,
3019 : const uno::Reference<sdbc::XConnection>& _xConnection
3020 : )
3021 : {
3022 0 : uno::Reference<sdbc::XResultSet> xResultSet;
3023 : try
3024 : {
3025 0 : uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
3026 0 : if( xMgr.is() )
3027 : {
3028 0 : uno::Reference<uno::XInterface> xInstance = xMgr->createInstance("com.sun.star.sdb.RowSet");
3029 0 : uno::Reference<beans::XPropertySet> xRowSetPropSet(xInstance, uno::UNO_QUERY);
3030 0 : if(xRowSetPropSet.is())
3031 : {
3032 0 : xRowSetPropSet->setPropertyValue("DataSourceName", uno::makeAny(_sDataSourceName));
3033 0 : xRowSetPropSet->setPropertyValue("ActiveConnection", uno::makeAny(_xConnection));
3034 0 : xRowSetPropSet->setPropertyValue("Command", uno::makeAny(_sCommand));
3035 0 : xRowSetPropSet->setPropertyValue("CommandType", uno::makeAny(_nCommandType));
3036 :
3037 0 : uno::Reference< sdb::XCompletedExecution > xRowSet(xInstance, uno::UNO_QUERY);
3038 :
3039 0 : if ( xRowSet.is() )
3040 : {
3041 0 : uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(comphelper::getComponentContext(xMgr), 0), uno::UNO_QUERY_THROW );
3042 0 : xRowSet->executeWithCompletion(xHandler);
3043 : }
3044 0 : xResultSet = uno::Reference<sdbc::XResultSet>(xRowSet, uno::UNO_QUERY);
3045 0 : }
3046 0 : }
3047 : }
3048 0 : catch (const uno::Exception& e)
3049 : {
3050 : SAL_WARN("sw.mailmerge", "Caught exception while creating a new RowSet: " << e.Message);
3051 : }
3052 0 : return xResultSet;
3053 : }
3054 :
3055 67 : void SwDBManager::setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell)
3056 : {
3057 67 : bool bLoad = m_sEmbeddedName != rEmbeddedName && !rEmbeddedName.isEmpty();
3058 67 : bool bRegisterListener = m_sEmbeddedName.isEmpty() && !rEmbeddedName.isEmpty();
3059 :
3060 67 : m_sEmbeddedName = rEmbeddedName;
3061 :
3062 67 : if (bLoad)
3063 : {
3064 2 : uno::Reference<embed::XStorage> xStorage = rDocShell.GetStorage();
3065 : // It's OK that we don't have the named sub-storage yet, in case
3066 : // we're in the process of creating it.
3067 2 : if (xStorage->hasByName(rEmbeddedName))
3068 2 : LoadAndRegisterEmbeddedDataSource(rDocShell.GetDoc()->GetDBData(), rDocShell);
3069 : }
3070 :
3071 67 : if (bRegisterListener)
3072 : // Register a remove listener, so we know when the embedded data source is removed.
3073 2 : pImpl->m_xDataSourceRemovedListener = new SwDataSourceRemovedListener(*this);
3074 67 : }
3075 :
3076 3093 : OUString SwDBManager::getEmbeddedName() const
3077 : {
3078 3093 : return m_sEmbeddedName;
3079 : }
3080 :
3081 0 : SwDoc* SwDBManager::getDoc() const
3082 : {
3083 0 : return m_pDoc;
3084 : }
3085 :
3086 2 : void SwDBManager::releaseRevokeListener()
3087 : {
3088 2 : pImpl->m_xDataSourceRemovedListener->Dispose();
3089 2 : pImpl->m_xDataSourceRemovedListener.clear();
3090 2 : }
3091 :
3092 2958 : SwConnectionDisposedListener_Impl::SwConnectionDisposedListener_Impl(SwDBManager& rManager)
3093 2958 : : m_pDBManager(&rManager)
3094 : {
3095 2958 : }
3096 :
3097 5898 : SwConnectionDisposedListener_Impl::~SwConnectionDisposedListener_Impl()
3098 : {
3099 5898 : }
3100 :
3101 0 : void SwConnectionDisposedListener_Impl::disposing( const lang::EventObject& rSource )
3102 : throw (uno::RuntimeException, std::exception)
3103 : {
3104 0 : ::SolarMutexGuard aGuard;
3105 :
3106 0 : if (!m_pDBManager) return; // we're disposed too!
3107 :
3108 0 : uno::Reference<sdbc::XConnection> xSource(rSource.Source, uno::UNO_QUERY);
3109 0 : for (size_t nPos = m_pDBManager->aDataSourceParams.size(); nPos; nPos--)
3110 : {
3111 0 : SwDSParam* pParam = &m_pDBManager->aDataSourceParams[nPos - 1];
3112 0 : if(pParam->xConnection.is() &&
3113 0 : (xSource == pParam->xConnection))
3114 : {
3115 : m_pDBManager->aDataSourceParams.erase(
3116 0 : m_pDBManager->aDataSourceParams.begin() + nPos - 1);
3117 : }
3118 0 : }
3119 177 : }
3120 :
3121 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|