summaryrefslogtreecommitdiff
path: root/sw/source/uibase/dbui/dbmgr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/dbui/dbmgr.cxx')
-rw-r--r--sw/source/uibase/dbui/dbmgr.cxx2943
1 files changed, 2943 insertions, 0 deletions
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
new file mode 100644
index 000000000000..638e2dade2cf
--- /dev/null
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -0,0 +1,2943 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cstdarg>
+
+#include <stdio.h>
+#include <unotxdoc.hxx>
+#include <com/sun/star/text/NotePrintMode.hpp>
+#include <sfx2/app.hxx>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/TextConnectionSettings.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XCompletedExecution.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/text/MailMergeEvent.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker.hpp>
+#include <com/sun/star/ui/dialogs/XFilterManager.hpp>
+#include <com/sun/star/uno/XNamingService.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <dbconfig.hxx>
+#include <swdbtoolsclient.hxx>
+#include <pagedesc.hxx>
+#include <vcl/lstbox.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svl/urihelper.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <vcl/oldprintadaptor.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/progress.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/mailenum.hxx>
+#include <cmdid.h>
+#include <swmodule.hxx>
+#include <view.hxx>
+#include <docsh.hxx>
+#include <edtwin.hxx>
+#include <wrtsh.hxx>
+#include <fldbas.hxx>
+#include <initui.hxx>
+#include <swundo.hxx>
+#include <flddat.hxx>
+#include <modcfg.hxx>
+#include <shellio.hxx>
+#include <dbui.hxx>
+#include <dbmgr.hxx>
+#include <doc.hxx>
+#include <swwait.hxx>
+#include <swunohelper.hxx>
+#include <dbui.hrc>
+#include <globals.hrc>
+#include <statstr.hrc>
+#include <mmconfigitem.hxx>
+#include <sfx2/request.hxx>
+#include <hintids.hxx>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/mail/MailAttachment.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <mailmergehelper.hxx>
+#include <maildispatcher.hxx>
+#include <svtools/htmlcfg.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <editeng/langitem.hxx>
+#include <svl/numuno.hxx>
+
+#include <unomailmerge.hxx>
+#include <sfx2/event.hxx>
+#include <vcl/msgbox.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/textenc.h>
+#include <ndindex.hxx>
+#include <pam.hxx>
+#include <swcrsr.hxx>
+#include <swevent.hxx>
+#include <osl/file.hxx>
+#include <swabstdlg.hxx>
+#include <fmthdft.hxx>
+#include <envelp.hrc>
+#include <vector>
+#include <unomid.h>
+#include <section.hxx>
+#include <rootfrm.hxx>
+
+#include <boost/scoped_ptr.hpp>
+
+using namespace ::osl;
+using namespace ::svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::ui::dialogs;
+
+#define DB_SEP_SPACE 0
+#define DB_SEP_TAB 1
+#define DB_SEP_RETURN 2
+#define DB_SEP_NEWLINE 3
+
+const sal_Char cCursor[] = "Cursor";
+const sal_Char cCommand[] = "Command";
+const sal_Char cCommandType[] = "CommandType";
+const sal_Char cDataSourceName[] = "DataSourceName";
+const sal_Char cSelection[] = "Selection";
+const sal_Char cActiveConnection[] = "ActiveConnection";
+
+// Use nameless namespace to avoid to rubbish the global namespace
+
+namespace
+{
+
+bool lcl_getCountFromResultSet( sal_Int32& rCount, const uno::Reference<XResultSet>& xResultSet )
+{
+ uno::Reference<XPropertySet> xPrSet(xResultSet, UNO_QUERY);
+ if(xPrSet.is())
+ {
+ try
+ {
+ bool bFinal = false;
+ Any aFinal = xPrSet->getPropertyValue("IsRowCountFinal");
+ aFinal >>= bFinal;
+ if(!bFinal)
+ {
+ xResultSet->last();
+ xResultSet->first();
+ }
+ Any aCount = xPrSet->getPropertyValue("RowCount");
+ if( aCount >>= rCount )
+ return true;
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return false;
+}
+// copy compatibility options
+void lcl_CopyCompatibilityOptions( SwWrtShell& rSourceShell, SwWrtShell& rTargetShell)
+{
+ IDocumentSettingAccess* pIDsa = rSourceShell.getIDocumentSettingAccess();
+
+ rTargetShell.SetParaSpaceMax( pIDsa->get(IDocumentSettingAccess::PARA_SPACE_MAX));
+ rTargetShell.SetParaSpaceMaxAtPages(pIDsa->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES));
+ rTargetShell.SetTabCompat( pIDsa->get(IDocumentSettingAccess::TAB_COMPAT));
+ rTargetShell.SetAddExtLeading( pIDsa->get(IDocumentSettingAccess::ADD_EXT_LEADING));
+ rTargetShell.SetUseVirDev( pIDsa->get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE));
+ rTargetShell.SetAddParaSpacingToTableCells( pIDsa->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS));
+ rTargetShell.SetUseFormerLineSpacing( pIDsa->get(IDocumentSettingAccess::OLD_LINE_SPACING));
+ rTargetShell.SetUseFormerObjectPositioning( pIDsa->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS));
+ rTargetShell.SetConsiderWrapOnObjPos( pIDsa->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION));
+ rTargetShell.SetUseFormerTextWrapping( pIDsa->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING));
+}
+}
+
+class SwConnectionDisposedListener_Impl : public cppu::WeakImplHelper1
+< lang::XEventListener >
+{
+ SwDBManager& rDBManager;
+
+ virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
+public:
+ SwConnectionDisposedListener_Impl(SwDBManager& rMgr);
+ virtual ~SwConnectionDisposedListener_Impl();
+
+};
+
+struct SwDBManager_Impl
+{
+ SwDSParam* pMergeData;
+ AbstractMailMergeDlg* pMergeDialog;
+ uno::Reference<lang::XEventListener> xDisposeListener;
+
+ SwDBManager_Impl(SwDBManager& rDBManager)
+ :pMergeData(0)
+ ,pMergeDialog(0)
+ ,xDisposeListener(new SwConnectionDisposedListener_Impl(rDBManager))
+ {}
+};
+
+static void lcl_InitNumberFormatter(SwDSParam& rParam, uno::Reference<XDataSource> xSource)
+{
+ uno::Reference<XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ rParam.xFormatter = uno::Reference<util::XNumberFormatter>(util::NumberFormatter::create(xContext), UNO_QUERY);
+ if(!xSource.is())
+ xSource = SwDBManager::getDataSourceAsParent(rParam.xConnection, rParam.sDataSource);
+
+ uno::Reference<XPropertySet> xSourceProps(xSource, UNO_QUERY);
+ if(xSourceProps.is())
+ {
+ Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
+ if(aFormats.hasValue())
+ {
+ uno::Reference<XNumberFormatsSupplier> xSuppl;
+ aFormats >>= xSuppl;
+ if(xSuppl.is())
+ {
+ uno::Reference< XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
+ Any aNull = xSettings->getPropertyValue("NullDate");
+ aNull >>= rParam.aNullDate;
+ if(rParam.xFormatter.is())
+ rParam.xFormatter->attachNumberFormatsSupplier(xSuppl);
+ }
+ }
+ }
+}
+
+static bool lcl_MoveAbsolute(SwDSParam* pParam, long nAbsPos)
+{
+ bool bRet = false;
+ try
+ {
+ if(pParam->bScrollable)
+ {
+ bRet = pParam->xResultSet->absolute( nAbsPos );
+ }
+ else
+ {
+ OSL_FAIL("no absolute positioning available");
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ return bRet;
+}
+
+static bool lcl_GetColumnCnt(SwDSParam* pParam,
+ const OUString& rColumnName, long nLanguage, OUString& rResult, double* pNumber)
+{
+ uno::Reference< XColumnsSupplier > xColsSupp( pParam->xResultSet, UNO_QUERY );
+ uno::Reference<XNameAccess> xCols;
+ try
+ {
+ xCols = xColsSupp->getColumns();
+ }
+ catch(const lang::DisposedException&)
+ {
+ }
+ if(!xCols.is() || !xCols->hasByName(rColumnName))
+ return false;
+ Any aCol = xCols->getByName(rColumnName);
+ uno::Reference< XPropertySet > xColumnProps;
+ aCol >>= xColumnProps;
+
+ SwDBFormatData aFormatData;
+ if(!pParam->xFormatter.is())
+ {
+ uno::Reference<XDataSource> xSource = SwDBManager::getDataSourceAsParent(
+ pParam->xConnection,pParam->sDataSource);
+ lcl_InitNumberFormatter(*pParam, xSource );
+ }
+ aFormatData.aNullDate = pParam->aNullDate;
+ aFormatData.xFormatter = pParam->xFormatter;
+
+ aFormatData.aLocale = LanguageTag( (LanguageType)nLanguage ).getLocale();
+
+ rResult = SwDBManager::GetDBField( xColumnProps, aFormatData, pNumber);
+ return true;
+};
+
+// import data
+bool SwDBManager::MergeNew(const SwMergeDescriptor& rMergeDesc )
+{
+ OSL_ENSURE(!bInMerge && !pImpl->pMergeData, "merge already activated!");
+
+ SwDBData aData;
+ aData.nCommandType = CommandType::TABLE;
+ uno::Reference<XResultSet> xResSet;
+ Sequence<Any> aSelection;
+ uno::Reference< XConnection> xConnection;
+
+ aData.sDataSource = rMergeDesc.rDescriptor.getDataSource();
+ rMergeDesc.rDescriptor[daCommand] >>= aData.sCommand;
+ rMergeDesc.rDescriptor[daCommandType] >>= aData.nCommandType;
+
+ if ( rMergeDesc.rDescriptor.has(daCursor) )
+ rMergeDesc.rDescriptor[daCursor] >>= xResSet;
+ if ( rMergeDesc.rDescriptor.has(daSelection) )
+ rMergeDesc.rDescriptor[daSelection] >>= aSelection;
+ if ( rMergeDesc.rDescriptor.has(daConnection) )
+ rMergeDesc.rDescriptor[daConnection] >>= xConnection;
+
+ if(aData.sDataSource.isEmpty() || aData.sCommand.isEmpty() || !xResSet.is())
+ {
+ return false;
+ }
+
+ pImpl->pMergeData = new SwDSParam(aData, xResSet, aSelection);
+ SwDSParam* pTemp = FindDSData(aData, false);
+ if(pTemp)
+ *pTemp = *pImpl->pMergeData;
+ else
+ {
+ // calls from the calculator may have added a connection with an invalid commandtype
+ //"real" data base connections added here have to re-use the already available
+ //DSData and set the correct CommandType
+ SwDBData aTempData(aData);
+ aData.nCommandType = -1;
+ pTemp = FindDSData(aData, false);
+ if(pTemp)
+ *pTemp = *pImpl->pMergeData;
+ else
+ {
+ SwDSParam* pInsert = new SwDSParam(*pImpl->pMergeData);
+ aDataSourceParams.push_back(pInsert);
+ try
+ {
+ uno::Reference<XComponent> xComponent(pInsert->xConnection, UNO_QUERY);
+ if(xComponent.is())
+ xComponent->addEventListener(pImpl->xDisposeListener);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ }
+ if(!pImpl->pMergeData->xConnection.is())
+ pImpl->pMergeData->xConnection = xConnection;
+ // add an XEventListener
+
+ try{
+ //set to start position
+ if(pImpl->pMergeData->aSelection.getLength())
+ {
+ sal_Int32 nPos = 0;
+ pImpl->pMergeData->aSelection.getConstArray()[ pImpl->pMergeData->nSelectionIndex++ ] >>= nPos;
+ pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->absolute( nPos );
+ pImpl->pMergeData->CheckEndOfDB();
+ if(pImpl->pMergeData->nSelectionIndex >= pImpl->pMergeData->aSelection.getLength())
+ pImpl->pMergeData->bEndOfDB = true;
+ }
+ else
+ {
+ pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->first();
+ pImpl->pMergeData->CheckEndOfDB();
+ }
+ }
+ catch(const Exception&)
+ {
+ pImpl->pMergeData->bEndOfDB = true;
+ pImpl->pMergeData->CheckEndOfDB();
+ OSL_FAIL("exception in MergeNew()");
+ }
+
+ uno::Reference<XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection,aData.sDataSource);
+
+ lcl_InitNumberFormatter(*pImpl->pMergeData, xSource);
+
+ rMergeDesc.rSh.ChgDBData(aData);
+ bInMerge = true;
+
+ if (IsInitDBFields())
+ {
+ // with database fields without DB-Name, use DB-Name from Doc
+ std::vector<OUString> aDBNames;
+ aDBNames.push_back(OUString());
+ SwDBData aInsertData = rMergeDesc.rSh.GetDBData();
+ OUString sDBName = aInsertData.sDataSource;
+ sDBName += OUString(DB_DELIM);
+ sDBName += aInsertData.sCommand;
+ sDBName += OUString(DB_DELIM);
+ sDBName += OUString::number(aInsertData.nCommandType);
+ rMergeDesc.rSh.ChangeDBFields( aDBNames, sDBName);
+ SetInitDBFields(false);
+ }
+
+ bool bRet = true;
+ switch(rMergeDesc.nMergeType)
+ {
+ case DBMGR_MERGE:
+ bRet = Merge(&rMergeDesc.rSh);
+ break;
+
+ case DBMGR_MERGE_MAILMERGE: // printing merge from 'old' merge dialog or from UNO-component
+ case DBMGR_MERGE_MAILING:
+ case DBMGR_MERGE_MAILFILES:
+ case DBMGR_MERGE_SINGLE_FILE:
+ // save files and send them as e-Mail if required
+ bRet = MergeMailFiles(&rMergeDesc.rSh,
+ rMergeDesc);
+ break;
+
+ default:
+ // insert selected entries
+ // (was: InsertRecord)
+ ImportFromConnection(&rMergeDesc.rSh);
+ break;
+ }
+
+ EndMerge();
+ return bRet;
+}
+
+// import data
+bool SwDBManager::Merge(SwWrtShell* pSh)
+{
+ pSh->StartAllAction();
+
+ pSh->SwViewShell::UpdateFlds(true);
+ pSh->SetModified();
+
+ pSh->EndAllAction();
+
+ return true;
+}
+
+void SwDBManager::ImportFromConnection( SwWrtShell* pSh )
+{
+ if(pImpl->pMergeData && !pImpl->pMergeData->bEndOfDB)
+ {
+ {
+ pSh->StartAllAction();
+ pSh->StartUndo(UNDO_EMPTY);
+ bool bGroupUndo(pSh->DoesGroupUndo());
+ pSh->DoGroupUndo(false);
+
+ if( pSh->HasSelection() )
+ pSh->DelRight();
+
+ boost::scoped_ptr<SwWait> pWait;
+
+ {
+ sal_uLong i = 0;
+ do {
+
+ ImportDBEntry(pSh);
+ if( 10 == ++i )
+ pWait.reset(new SwWait( *pSh->GetView().GetDocShell(), true));
+
+ } while(ToNextMergeRecord());
+ }
+
+ pSh->DoGroupUndo(bGroupUndo);
+ pSh->EndUndo(UNDO_EMPTY);
+ pSh->EndAllAction();
+ }
+ }
+}
+
+static OUString lcl_FindColumn(const OUString& sFormatStr,sal_uInt16 &nUsedPos, sal_uInt8 &nSeparator)
+{
+ OUString sReturn;
+ sal_uInt16 nLen = sFormatStr.getLength();
+ nSeparator = 0xff;
+ while(nUsedPos < nLen && nSeparator == 0xff)
+ {
+ sal_Unicode cAkt = sFormatStr[nUsedPos];
+ switch(cAkt)
+ {
+ case ',':
+ nSeparator = DB_SEP_SPACE;
+ break;
+ case ';':
+ nSeparator = DB_SEP_RETURN;
+ break;
+ case ':':
+ nSeparator = DB_SEP_TAB;
+ break;
+ case '#':
+ nSeparator = DB_SEP_NEWLINE;
+ break;
+ default:
+ sReturn += OUString(cAkt);
+ }
+ nUsedPos++;
+
+ }
+ return sReturn;
+}
+
+void SwDBManager::ImportDBEntry(SwWrtShell* pSh)
+{
+ if(pImpl->pMergeData && !pImpl->pMergeData->bEndOfDB)
+ {
+ uno::Reference< XColumnsSupplier > xColsSupp( pImpl->pMergeData->xResultSet, UNO_QUERY );
+ uno::Reference<XNameAccess> xCols = xColsSupp->getColumns();
+ OUString sFormatStr;
+ sal_uInt16 nFmtLen = sFormatStr.getLength();
+ if( nFmtLen )
+ {
+ const char cSpace = ' ';
+ const char cTab = '\t';
+ sal_uInt16 nUsedPos = 0;
+ sal_uInt8 nSeparator;
+ OUString sColumn = lcl_FindColumn(sFormatStr, nUsedPos, nSeparator);
+ while( !sColumn.isEmpty() )
+ {
+ if(!xCols->hasByName(sColumn))
+ return;
+ Any aCol = xCols->getByName(sColumn);
+ uno::Reference< XPropertySet > xColumnProp;
+ aCol >>= xColumnProp;
+ if(xColumnProp.is())
+ {
+ SwDBFormatData aDBFormat;
+ OUString sInsert = GetDBField( xColumnProp, aDBFormat);
+ if( DB_SEP_SPACE == nSeparator )
+ sInsert += OUString(cSpace);
+ else if( DB_SEP_TAB == nSeparator)
+ sInsert += OUString(cTab);
+ pSh->Insert(sInsert);
+ if( DB_SEP_RETURN == nSeparator)
+ pSh->SplitNode();
+ else if(DB_SEP_NEWLINE == nSeparator)
+ pSh->InsertLineBreak();
+ }
+ else
+ {
+ // column not found -> show error
+ OUStringBuffer sInsert;
+ sInsert.append('?').append(sColumn).append('?');
+ pSh->Insert(sInsert.makeStringAndClear());
+ }
+ sColumn = lcl_FindColumn(sFormatStr, nUsedPos, nSeparator);
+ }
+ pSh->SplitNode();
+ }
+ else
+ {
+ OUString sStr;
+ Sequence<OUString> aColNames = xCols->getElementNames();
+ const OUString* pColNames = aColNames.getConstArray();
+ long nLength = aColNames.getLength();
+ for(long i = 0; i < nLength; i++)
+ {
+ Any aCol = xCols->getByName(pColNames[i]);
+ uno::Reference< XPropertySet > xColumnProp;
+ aCol >>= xColumnProp;
+ SwDBFormatData aDBFormat;
+ sStr += GetDBField( xColumnProp, aDBFormat);
+ if (i < nLength - 1)
+ sStr += "\t";
+ }
+ pSh->SwEditShell::Insert2(sStr);
+ pSh->SwFEShell::SplitNode(); // line feed
+ }
+ }
+}
+
+// fill Listbox with tablelist
+bool SwDBManager::GetTableNames(ListBox* pListBox, const OUString& rDBName)
+{
+ bool bRet = false;
+ OUString sOldTableName(pListBox->GetSelectEntry());
+ pListBox->Clear();
+ SwDSParam* pParam = FindDSConnection(rDBName, false);
+ uno::Reference< XConnection> xConnection;
+ if(pParam && pParam->xConnection.is())
+ xConnection = pParam->xConnection;
+ else
+ {
+ OUString sDBName(rDBName);
+ if ( !sDBName.isEmpty() )
+ xConnection = RegisterConnection( sDBName );
+ }
+ if(xConnection.is())
+ {
+ uno::Reference<XTablesSupplier> xTSupplier = uno::Reference<XTablesSupplier>(xConnection, UNO_QUERY);
+ if(xTSupplier.is())
+ {
+ uno::Reference<XNameAccess> xTbls = xTSupplier->getTables();
+ Sequence<OUString> aTbls = xTbls->getElementNames();
+ const OUString* pTbls = aTbls.getConstArray();
+ for(long i = 0; i < aTbls.getLength(); i++)
+ {
+ sal_uInt16 nEntry = pListBox->InsertEntry(pTbls[i]);
+ pListBox->SetEntryData(nEntry, (void*)0);
+ }
+ }
+ uno::Reference<XQueriesSupplier> xQSupplier = uno::Reference<XQueriesSupplier>(xConnection, UNO_QUERY);
+ if(xQSupplier.is())
+ {
+ uno::Reference<XNameAccess> xQueries = xQSupplier->getQueries();
+ Sequence<OUString> aQueries = xQueries->getElementNames();
+ const OUString* pQueries = aQueries.getConstArray();
+ for(long i = 0; i < aQueries.getLength(); i++)
+ {
+ sal_uInt16 nEntry = pListBox->InsertEntry(pQueries[i]);
+ pListBox->SetEntryData(nEntry, (void*)1);
+ }
+ }
+ if (!sOldTableName.isEmpty())
+ pListBox->SelectEntry(sOldTableName);
+ bRet = true;
+ }
+ return bRet;
+}
+
+// fill Listbox with column names of a database
+void SwDBManager::GetColumnNames(ListBox* pListBox,
+ const OUString& rDBName, const OUString& rTableName, bool bAppend)
+{
+ if (!bAppend)
+ pListBox->Clear();
+ SwDBData aData;
+ aData.sDataSource = rDBName;
+ aData.sCommand = rTableName;
+ aData.nCommandType = -1;
+ SwDSParam* pParam = FindDSData(aData, false);
+ uno::Reference< XConnection> xConnection;
+ if(pParam && pParam->xConnection.is())
+ xConnection = pParam->xConnection;
+ else
+ {
+ OUString sDBName(rDBName);
+ xConnection = RegisterConnection( sDBName );
+ }
+ uno::Reference< XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
+ if(xColsSupp.is())
+ {
+ uno::Reference<XNameAccess> xCols = xColsSupp->getColumns();
+ const Sequence<OUString> aColNames = xCols->getElementNames();
+ const OUString* pColNames = aColNames.getConstArray();
+ for(int nCol = 0; nCol < aColNames.getLength(); nCol++)
+ {
+ pListBox->InsertEntry(pColNames[nCol]);
+ }
+ ::comphelper::disposeComponent( xColsSupp );
+ }
+}
+
+void SwDBManager::GetColumnNames(ListBox* pListBox,
+ uno::Reference< XConnection> xConnection,
+ const OUString& rTableName, bool bAppend)
+{
+ if (!bAppend)
+ pListBox->Clear();
+ uno::Reference< XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
+ if(xColsSupp.is())
+ {
+ uno::Reference<XNameAccess> xCols = xColsSupp->getColumns();
+ const Sequence<OUString> aColNames = xCols->getElementNames();
+ const OUString* pColNames = aColNames.getConstArray();
+ for(int nCol = 0; nCol < aColNames.getLength(); nCol++)
+ {
+ pListBox->InsertEntry(pColNames[nCol]);
+ }
+ ::comphelper::disposeComponent( xColsSupp );
+ }
+}
+
+SwDBManager::SwDBManager()
+ : bCancel(false)
+ , bInitDBFields(false)
+ , bSingleJobs(false)
+ , bInMerge(false)
+ , bMergeSilent(false)
+ , bMergeLock(false)
+ , pImpl(new SwDBManager_Impl(*this))
+ , pMergeEvtSrc(NULL)
+{
+}
+
+SwDBManager::~SwDBManager()
+{
+ for(sal_uInt16 nPos = 0; nPos < aDataSourceParams.size(); nPos++)
+ {
+ SwDSParam* pParam = &aDataSourceParams[nPos];
+ if(pParam->xConnection.is())
+ {
+ try
+ {
+ uno::Reference<XComponent> xComp(pParam->xConnection, UNO_QUERY);
+ if(xComp.is())
+ xComp->dispose();
+ }
+ catch(const RuntimeException&)
+ {
+ //may be disposed already since multiple entries may have used the same connection
+ }
+ }
+ }
+ delete pImpl;
+}
+
+// save bulk letters as single documents
+static OUString lcl_FindUniqueName(SwWrtShell* pTargetShell, const OUString& rStartingPageDesc, sal_uLong nDocNo )
+{
+ do
+ {
+ OUString sTest = rStartingPageDesc;
+ sTest += OUString::number( nDocNo );
+ if( !pTargetShell->FindPageDescByName( sTest ) )
+ return sTest;
+ ++nDocNo;
+ }while(true);
+}
+
+static void lcl_CopyDynamicDefaults( const SwDoc& rSource, SwDoc& rTarget )
+{
+ sal_uInt16 aRangeOfDefaults[] = {
+ RES_FRMATR_BEGIN, RES_FRMATR_END-1,
+ RES_CHRATR_BEGIN, RES_CHRATR_END-1,
+ RES_PARATR_BEGIN, RES_PARATR_END-1,
+ RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
+ RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
+ 0
+ };
+
+ SfxItemSet aNewDefaults( rTarget.GetAttrPool(), aRangeOfDefaults );
+
+ sal_uInt16 nWhich;
+ sal_uInt16 nRange = 0;
+ while( aRangeOfDefaults[nRange] != 0)
+ {
+ for( nWhich = aRangeOfDefaults[nRange]; nWhich < aRangeOfDefaults[nRange + 1]; ++nWhich )
+ {
+ const SfxPoolItem& rSourceAttr = rSource.GetDefault( nWhich );
+ if( rSourceAttr != rTarget.GetDefault( nWhich ) )
+ aNewDefaults.Put( rSourceAttr );
+ }
+ nRange += 2;
+ }
+ if( aNewDefaults.Count() )
+ rTarget.SetDefault( aNewDefaults );
+}
+
+static void lcl_CopyFollowPageDesc(
+ SwWrtShell& rTargetShell,
+ const SwPageDesc& rSourcePageDesc,
+ const SwPageDesc& rTargetPageDesc,
+ const sal_uLong nDocNo )
+{
+ //now copy the follow page desc, too
+ const SwPageDesc* pFollowPageDesc = rSourcePageDesc.GetFollow();
+ OUString sFollowPageDesc = pFollowPageDesc->GetName();
+ if( sFollowPageDesc != rSourcePageDesc.GetName() )
+ {
+ SwDoc* pTargetDoc = rTargetShell.GetDoc();
+ OUString sNewFollowPageDesc = lcl_FindUniqueName(&rTargetShell, sFollowPageDesc, nDocNo );
+ sal_uInt16 nNewDesc = pTargetDoc->MakePageDesc( sNewFollowPageDesc );
+ SwPageDesc& rTargetFollowPageDesc = pTargetDoc->GetPageDesc( nNewDesc );
+
+ pTargetDoc->CopyPageDesc( *pFollowPageDesc, rTargetFollowPageDesc, false );
+ SwPageDesc aDesc( rTargetPageDesc );
+ aDesc.SetFollow( &rTargetFollowPageDesc );
+ pTargetDoc->ChgPageDesc( rTargetPageDesc.GetName(), aDesc );
+ }
+}
+
+static void lcl_RemoveSectionLinks( SwWrtShell& rWorkShell )
+{
+ //reset all links of the sections of synchronized labels
+ sal_uInt16 nSections = rWorkShell.GetSectionFmtCount();
+ for( sal_uInt16 nSection = 0; nSection < nSections; ++nSection )
+ {
+ SwSectionData aSectionData( *rWorkShell.GetSectionFmt( nSection ).GetSection() );
+ if( aSectionData.GetType() == FILE_LINK_SECTION )
+ {
+ aSectionData.SetType( CONTENT_SECTION );
+ aSectionData.SetLinkFileName( OUString() );
+ rWorkShell.UpdateSection( nSection, aSectionData );
+ }
+ }
+ rWorkShell.SetLabelDoc( false );
+}
+
+bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
+ const SwMergeDescriptor& rMergeDescriptor)
+{
+ //check if the doc is synchronized and contains at least one linked section
+ bool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFmtCount() > 1;
+ bool bNoError = true;
+ bool bEMail = rMergeDescriptor.nMergeType == DBMGR_MERGE_MAILING;
+ const bool bAsSingleFile = rMergeDescriptor.nMergeType == DBMGR_MERGE_SINGLE_FILE;
+
+ ::rtl::Reference< MailDispatcher > xMailDispatcher;
+ OUString sBodyMimeType;
+ rtl_TextEncoding eEncoding = ::osl_getThreadTextEncoding();
+
+ if(bEMail)
+ {
+ xMailDispatcher.set( new MailDispatcher(rMergeDescriptor.xSmtpServer));
+ if(!rMergeDescriptor.bSendAsAttachment && rMergeDescriptor.bSendAsHTML)
+ {
+ sBodyMimeType = "text/html; charset=";
+ sBodyMimeType += OUString::createFromAscii(
+ rtl_getBestMimeCharsetFromTextEncoding( eEncoding ));
+ SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
+ eEncoding = rHtmlOptions.GetTextEncoding();
+ }
+ else
+ sBodyMimeType =
+ OUString("text/plain; charset=UTF-8; format=flowed");
+ }
+
+ uno::Reference< XPropertySet > xColumnProp;
+ {
+ bool bColumnName = !sEMailAddrFld.isEmpty();
+
+ if (bColumnName)
+ {
+ uno::Reference< XColumnsSupplier > xColsSupp( pImpl->pMergeData->xResultSet, UNO_QUERY );
+ uno::Reference<XNameAccess> xCols = xColsSupp->getColumns();
+ if(!xCols->hasByName(sEMailAddrFld))
+ return false;
+ Any aCol = xCols->getByName(sEMailAddrFld);
+ aCol >>= xColumnProp;
+ }
+
+ // Try saving the source document
+ SfxDispatcher* pSfxDispatcher = pSourceShell->GetView().GetViewFrame()->GetDispatcher();
+ SwDocShell* pSourceDocSh = pSourceShell->GetView().GetDocShell();
+ pSfxDispatcher->Execute( pSourceDocSh->HasName() ? SID_SAVEDOC : SID_SAVEASDOC, SFX_CALLMODE_SYNCHRON|SFX_CALLMODE_RECORD);
+ if( !pSourceDocSh->IsModified() )
+ {
+ const SfxFilter* pStoreToFilter = SwIoSystem::GetFileFilter(
+ pSourceDocSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), ::aEmptyOUStr );
+ SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer();
+ const OUString* pStoreToFilterOptions = 0;
+
+ // if a save_to filter is set then use it - otherwise use the default
+ if( bEMail && !rMergeDescriptor.bSendAsAttachment )
+ {
+ OUString sExtension = rMergeDescriptor.bSendAsHTML ? OUString("html") : OUString("txt");
+ pStoreToFilter = pFilterContainer->GetFilter4Extension(sExtension, SFX_FILTER_EXPORT);
+ }
+ else if( !rMergeDescriptor.sSaveToFilter.isEmpty())
+ {
+ const SfxFilter* pFilter =
+ pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter );
+ if(pFilter)
+ {
+ pStoreToFilter = pFilter;
+ if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty())
+ pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions;
+ }
+ }
+ bCancel = false;
+
+ // in case of creating a single resulting file this has to be created here
+ SwWrtShell* pTargetShell = 0;
+
+ // the shell will be explicitly closed at the end of the method, but it is
+ // still more safe to use SfxObjectShellLock here
+ SfxObjectShellLock xTargetDocShell;
+
+ SwView* pTargetView = 0;
+ boost::scoped_ptr< utl::TempFile > aTempFile;
+ OUString sModifiedStartingPageDesc;
+ OUString sStartingPageDesc;
+ sal_uInt16 nStartingPageNo = 0;
+ bool bPageStylesWithHeaderFooter = false;
+ if(bAsSingleFile || rMergeDescriptor.bCreateSingleFile)
+ {
+ // create a target docshell to put the merged document into
+ xTargetDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
+ xTargetDocShell->DoInitNew( 0 );
+ SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 );
+
+ pTargetView = static_cast<SwView*>( pTargetFrame->GetViewShell() );
+
+ //initiate SelectShell() to create sub shells
+ pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() );
+ pTargetShell = pTargetView->GetWrtShellPtr();
+ //copy the styles from the source to the target document
+ pTargetView->GetDocShell()->_LoadStyles( *pSourceDocSh, true );
+ //determine the page style and number used at the start of the source document
+ pSourceShell->SttEndDoc(true);
+ nStartingPageNo = pSourceShell->GetVirtPageNum();
+ sStartingPageDesc = sModifiedStartingPageDesc = pSourceShell->GetPageDesc(
+ pSourceShell->GetCurPageDesc()).GetName();
+ // copy compatibility options
+ lcl_CopyCompatibilityOptions( *pSourceShell, *pTargetShell);
+ // #72821# copy dynamic defaults
+ lcl_CopyDynamicDefaults( *pSourceShell->GetDoc(), *pTargetShell->GetDoc() );
+ // #i72517#
+ const SwPageDesc* pSourcePageDesc = pSourceShell->FindPageDescByName( sStartingPageDesc );
+ const SwFrmFmt& rMaster = pSourcePageDesc->GetMaster();
+ bPageStylesWithHeaderFooter = rMaster.GetHeader().IsActive() ||
+ rMaster.GetFooter().IsActive();
+
+ }
+
+ PrintMonitor aPrtMonDlg(&pSourceShell->GetView().GetEditWin(), PrintMonitor::MONITOR_TYPE_PRINT);
+ aPrtMonDlg.m_pDocName->SetText(pSourceShell->GetView().GetDocShell()->GetTitle(22));
+
+ aPrtMonDlg.m_pCancel->SetClickHdl(LINK(this, SwDBManager, PrtCancelHdl));
+ if (!IsMergeSilent())
+ aPrtMonDlg.Show();
+
+ // Progress, to prohibit KeyInputs
+ SfxProgress aProgress(pSourceDocSh, ::aEmptyOUStr, 1);
+
+ // lock all dispatchers
+ SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst(pSourceDocSh);
+ while (pViewFrm)
+ {
+ pViewFrm->GetDispatcher()->Lock(true);
+ pViewFrm = SfxViewFrame::GetNext(*pViewFrm, pSourceDocSh);
+ }
+ sal_uLong nDocNo = 1;
+
+ long nStartRow, nEndRow;
+ bool bFreezedLayouts = false;
+ // collect temporary files
+ ::std::vector< OUString> aFilesToRemove;
+ do
+ {
+ nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
+ {
+ OUString sPath(sSubject);
+
+ OUString sAddress;
+ if( !bEMail && bColumnName )
+ {
+ SwDBFormatData aDBFormat;
+ aDBFormat.xFormatter = pImpl->pMergeData->xFormatter;
+ aDBFormat.aNullDate = pImpl->pMergeData->aNullDate;
+ sAddress = GetDBField( xColumnProp, aDBFormat);
+ if (sAddress.isEmpty())
+ sAddress = "_";
+ sPath += sAddress;
+ }
+
+ // create a new temporary file name - only done once in case of bCreateSingleFile
+ if( 1 == nDocNo || (!rMergeDescriptor.bCreateSingleFile && !bAsSingleFile) )
+ {
+ INetURLObject aEntry(sPath);
+ OUString sLeading;
+ //#i97667# if the name is from a database field then it will be used _as is_
+ if( !sAddress.isEmpty() )
+ sLeading = sAddress;
+ else
+ sLeading = aEntry.GetBase();
+ aEntry.removeSegment();
+ sPath = aEntry.GetMainURL( INetURLObject::NO_DECODE );
+ OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
+ aTempFile.reset(
+ new utl::TempFile(sLeading, true, &sExt, &sPath));
+ if( bAsSingleFile )
+ aTempFile->EnableKillingFile();
+ }
+
+ if( !aTempFile->IsValid() )
+ {
+ ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED );
+ bNoError = false;
+ bCancel = true;
+ }
+ else
+ {
+ INetURLObject aTempFileURL(aTempFile->GetURL());
+ aPrtMonDlg.m_pPrinter->SetText( aTempFileURL.GetBase() );
+ OUString sStat(SW_RES(STR_STATSTR_LETTER)); // Brief
+ sStat += " ";
+ sStat += OUString::number( nDocNo );
+ aPrtMonDlg.m_pPrintInfo->SetText(sStat);
+
+ // computation time for Save-Monitor:
+ for (sal_uInt16 i = 0; i < 25; i++)
+ Application::Reschedule();
+
+ // The SfxObjectShell will be closed explicitly later but it is more safe to use SfxObjectShellLock here
+ SfxObjectShellLock xWorkDocSh;
+ // copy the source document
+ if( 1 == nDocNo && (bAsSingleFile || rMergeDescriptor.bCreateSingleFile) )
+ {
+ uno::Reference< util::XCloneable > xClone( pSourceDocSh->GetModel(), uno::UNO_QUERY);
+ uno::Reference< lang::XUnoTunnel > xWorkDocShell( xClone->createClone(), uno::UNO_QUERY);
+ SwXTextDocument* pWorkModel = reinterpret_cast<SwXTextDocument*>(xWorkDocShell->getSomething(SwXTextDocument::getUnoTunnelId()));
+ xWorkDocSh = pWorkModel->GetDocShell();
+ }
+ else
+ xWorkDocSh = pSourceDocSh->GetDoc()->CreateCopy( true );
+
+ {
+ //create a view frame for the document
+ SfxViewFrame* pWorkFrame = SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 );
+ //request the layout calculation
+ SwWrtShell& rWorkShell =
+ static_cast< SwView* >(pWorkFrame->GetViewShell())->GetWrtShell();
+ rWorkShell.CalcLayout();
+ SwDoc* pWorkDoc = ((SwDocShell*)(&xWorkDocSh))->GetDoc();
+ SwDBManager* pOldDBManager = pWorkDoc->GetDBManager();
+ pWorkDoc->SetDBManager( this );
+ SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), xWorkDocSh));
+ pWorkDoc->UpdateFlds(NULL, false);
+ SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh));
+
+ pWorkDoc->RemoveInvisibleContent();
+
+ // launch MailMergeEvent if required
+ const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
+ if(pEvtSrc)
+ {
+ uno::Reference< XInterface > xRef( (XMailMergeBroadcaster *) pEvtSrc );
+ text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() );
+ pEvtSrc->LaunchMailMergeEvent( aEvt );
+ }
+
+ if(rMergeDescriptor.bCreateSingleFile || bAsSingleFile )
+ {
+ OSL_ENSURE( pTargetShell, "no target shell available!" );
+ // copy created file into the target document
+ rWorkShell.ConvertFieldsToText();
+ rWorkShell.SetNumberingRestart();
+ if( bSynchronizedDoc )
+ {
+ lcl_RemoveSectionLinks( rWorkShell );
+ }
+
+ // insert the document into the target document
+ rWorkShell.SttEndDoc(false);
+ rWorkShell.SttEndDoc(true);
+ rWorkShell.SelAll();
+ pTargetShell->SwCrsrShell::SttEndDoc( false );
+ //#i72517# the headers and footers are still those from the source - update in case of fields inside header/footer
+ if( !nDocNo && bPageStylesWithHeaderFooter )
+ pTargetShell->GetView().GetDocShell()->_LoadStyles( *rWorkShell.GetView().GetDocShell(), true );
+ //#i72517# put the styles to the target document
+ //if the source uses headers or footers each new copy need to copy a new page styles
+ if(bPageStylesWithHeaderFooter)
+ {
+ //create a new pagestyle
+ //copy the pagedesc from the current document to the new document and change the name of the to-be-applied style
+
+ SwDoc* pTargetDoc = pTargetShell->GetDoc();
+ SwPageDesc* pSourcePageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc );
+ OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo );
+ pTargetDoc->MakePageDesc( sNewPageDescName );
+ SwPageDesc* pTargetPageDesc = pTargetShell->FindPageDescByName( sNewPageDescName );
+ if(pSourcePageDesc && pTargetPageDesc)
+ {
+ pTargetDoc->CopyPageDesc( *pSourcePageDesc, *pTargetPageDesc, false );
+ sModifiedStartingPageDesc = sNewPageDescName;
+ lcl_CopyFollowPageDesc( *pTargetShell, *pSourcePageDesc, *pTargetPageDesc, nDocNo );
+ }
+ }
+
+ if(nDocNo > 1)
+ pTargetShell->InsertPageBreak( &sModifiedStartingPageDesc, nStartingPageNo );
+ else
+ pTargetShell->SetPageStyle(sModifiedStartingPageDesc);
+ OSL_ENSURE(!pTargetShell->GetTableFmt(),"target document ends with a table - paragraph should be appended");
+ //#i51359# add a second paragraph in case there's only one
+ {
+ SwNodeIndex aIdx( pWorkDoc->GetNodes().GetEndOfExtras(), 2 );
+ SwPosition aTestPos( aIdx );
+ SwCursor aTestCrsr(aTestPos,0,false);
+ if(!aTestCrsr.MovePara(fnParaNext, fnParaStart))
+ {
+ //append a paragraph
+ pWorkDoc->AppendTxtNode( aTestPos );
+ }
+ }
+ pTargetShell->Paste( rWorkShell.GetDoc(), true );
+
+ //convert fields in page styles (header/footer - has to be done after the first document has been pasted
+ if(1 == nDocNo)
+ {
+ pTargetShell->CalcLayout();
+ pTargetShell->ConvertFieldsToText();
+ }
+ }
+ else
+ {
+ OUString sFileURL = aTempFileURL.GetMainURL( INetURLObject::NO_DECODE );
+ SfxMedium* pDstMed = new SfxMedium(
+ sFileURL,
+ STREAM_STD_READWRITE );
+ pDstMed->SetFilter( pStoreToFilter );
+ if(pDstMed->GetItemSet())
+ {
+ if(pStoreToFilterOptions )
+ pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions));
+ if(rMergeDescriptor.aSaveToFilterData.getLength())
+ pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, makeAny(rMergeDescriptor.aSaveToFilterData)));
+ }
+
+ //convert fields to text if we are exporting to PDF
+ //this prevents a second merge while updating the fields in SwXTextDocument::getRendererCount()
+ if( pStoreToFilter && pStoreToFilter->GetFilterName().equalsAscii("writer_pdf_Export"))
+ rWorkShell.ConvertFieldsToText();
+ xWorkDocSh->DoSaveAs(*pDstMed);
+ xWorkDocSh->DoSaveCompleted(pDstMed);
+ if( xWorkDocSh->GetError() )
+ {
+ // error message ??
+ ErrorHandler::HandleError( xWorkDocSh->GetError() );
+ bCancel = true;
+ bNoError = false;
+ }
+ if( bEMail )
+ {
+ SwDBFormatData aDBFormat;
+ aDBFormat.xFormatter = pImpl->pMergeData->xFormatter;
+ aDBFormat.aNullDate = pImpl->pMergeData->aNullDate;
+ OUString sMailAddress = GetDBField( xColumnProp, aDBFormat);
+ if(!SwMailMergeHelper::CheckMailAddress( sMailAddress ))
+ {
+ OSL_FAIL("invalid e-Mail address in database column");
+ }
+ else
+ {
+ SwMailMessage* pMessage = new SwMailMessage;
+ uno::Reference< mail::XMailMessage > xMessage = pMessage;
+ if(rMergeDescriptor.pMailMergeConfigItem->IsMailReplyTo())
+ pMessage->setReplyToAddress(rMergeDescriptor.pMailMergeConfigItem->GetMailReplyTo());
+ pMessage->addRecipient( sMailAddress );
+ pMessage->SetSenderAddress( rMergeDescriptor.pMailMergeConfigItem->GetMailAddress() );
+ OUString sBody;
+ if(rMergeDescriptor.bSendAsAttachment)
+ {
+ sBody = rMergeDescriptor.sMailBody;
+ mail::MailAttachment aAttach;
+ aAttach.Data = new SwMailTransferable(
+ sFileURL,
+ rMergeDescriptor.sAttachmentName,
+ pStoreToFilter->GetMimeType());
+ aAttach.ReadableName = rMergeDescriptor.sAttachmentName;
+ pMessage->addAttachment( aAttach );
+ }
+ else
+ {
+ {
+ //read in the temporary file and use it as mail body
+ SfxMedium aMedium( sFileURL, STREAM_READ);
+ SvStream* pInStream = aMedium.GetInStream();
+ OSL_ENSURE(pInStream, "no output file created?");
+ if(pInStream)
+ {
+ pInStream->SetStreamCharSet( eEncoding );
+ OString sLine;
+ bool bDone = pInStream->ReadLine( sLine );
+ while ( bDone )
+ {
+ sBody += OStringToOUString(sLine, eEncoding);
+ sBody += "\n";
+ bDone = pInStream->ReadLine( sLine );
+ }
+ }
+ }
+ }
+ pMessage->setSubject( rMergeDescriptor.sSubject );
+ uno::Reference< datatransfer::XTransferable> xBody =
+ new SwMailTransferable(
+ sBody,
+ sBodyMimeType);
+ pMessage->setBody( xBody );
+
+ if(rMergeDescriptor.aCopiesTo.getLength())
+ {
+ const OUString* pCopies = rMergeDescriptor.aCopiesTo.getConstArray();
+ for( sal_Int32 nToken = 0; nToken < rMergeDescriptor.aCopiesTo.getLength(); ++nToken)
+ pMessage->addCcRecipient( pCopies[nToken] );
+ }
+ if(rMergeDescriptor.aBlindCopiesTo.getLength())
+ {
+ const OUString* pCopies = rMergeDescriptor.aBlindCopiesTo.getConstArray();
+ for( sal_Int32 nToken = 0; nToken < rMergeDescriptor.aBlindCopiesTo.getLength(); ++nToken)
+ pMessage->addBccRecipient( pCopies[nToken] );
+ }
+ xMailDispatcher->enqueueMailMessage( xMessage );
+ if(!xMailDispatcher->isStarted())
+ xMailDispatcher->start();
+ //schedule for removal
+ aFilesToRemove.push_back(sFileURL);
+ }
+ }
+ }
+ pWorkDoc->SetDBManager( pOldDBManager );
+ }
+ xWorkDocSh->DoClose();
+ }
+ }
+ nDocNo++;
+ nEndRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
+
+ // Freeze the layouts of the target document after the first inserted
+ // sub-document, to get the correct PageDesc.
+ if(!bFreezedLayouts && (rMergeDescriptor.bCreateSingleFile || bAsSingleFile))
+ {
+ std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
+ std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
+ ::std::bind2nd(::std::mem_fun(&SwRootFrm::FreezeLayout), true));
+ bFreezedLayouts = true;
+ }
+ } while( !bCancel &&
+ (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord()));
+
+ // Unfreeze target document layouts and correct all PageDescs.
+ if(rMergeDescriptor.bCreateSingleFile || bAsSingleFile)
+ {
+ std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
+ std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
+ ::std::bind2nd(::std::mem_fun(&SwRootFrm::FreezeLayout), false));
+ std::for_each( aAllLayouts.begin(), aAllLayouts.end(),std::mem_fun(&SwRootFrm::AllCheckPageDescs));
+ }
+
+ aPrtMonDlg.Show( false );
+
+ // save the single output document
+ if(rMergeDescriptor.bCreateSingleFile || bAsSingleFile)
+ {
+ if( rMergeDescriptor.nMergeType != DBMGR_MERGE_MAILMERGE )
+ {
+ OSL_ENSURE( aTempFile.get(), "Temporary file not available" );
+ OUString sSub(sSubject);
+ INetURLObject aTempFileURL(bAsSingleFile ? sSub : aTempFile->GetURL());
+ SfxMedium* pDstMed = new SfxMedium(
+ aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),
+ STREAM_STD_READWRITE );
+ pDstMed->SetFilter( pStoreToFilter );
+ if(pDstMed->GetItemSet())
+ {
+ if(pStoreToFilterOptions )
+ pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions));
+ if(rMergeDescriptor.aSaveToFilterData.getLength())
+ pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, makeAny(rMergeDescriptor.aSaveToFilterData)));
+ }
+
+ xTargetDocShell->DoSaveAs(*pDstMed);
+ xTargetDocShell->DoSaveCompleted(pDstMed);
+ if( xTargetDocShell->GetError() )
+ {
+ // error message ??
+ ErrorHandler::HandleError( xTargetDocShell->GetError() );
+ bNoError = false;
+ }
+ }
+ else if( pTargetView ) // must be available!
+ {
+ //print the target document
+ #if OSL_DEBUG_LEVEL > 1
+ bool _bVal;
+ sal_Int16 _nVal;
+ OUString _sVal;
+ const beans::PropertyValue* pDbgPrintOptions = rMergeDescriptor.aPrintOptions.getConstArray();
+ for( sal_Int32 nOption = 0; nOption < rMergeDescriptor.aPrintOptions.getLength(); ++nOption)
+ {
+ OUString aName( pDbgPrintOptions[nOption].Name );
+ uno::Any aVal( pDbgPrintOptions[nOption].Value );
+ aVal >>= _bVal;
+ aVal >>= _nVal;
+ aVal >>= _sVal;
+ }
+ #endif
+ // printing should be done synchronously otherwise the document
+ // might already become invalid during the process
+ uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
+
+ aOptions.realloc( 1 );
+ aOptions[ 0 ].Name = "Wait";
+ aOptions[ 0 ].Value <<= sal_True ;
+ // move print options
+ const beans::PropertyValue* pPrintOptions = rMergeDescriptor.aPrintOptions.getConstArray();
+ for( sal_Int32 nOption = 0, nIndex = 1 ; nOption < rMergeDescriptor.aPrintOptions.getLength(); ++nOption)
+ {
+ if( pPrintOptions[nOption].Name == "CopyCount" || pPrintOptions[nOption].Name == "FileName"
+ || pPrintOptions[nOption].Name == "Collate" || pPrintOptions[nOption].Name == "Pages"
+ || pPrintOptions[nOption].Name == "Wait" || pPrintOptions[nOption].Name == "PrinterName" )
+ {
+ // add an option
+ aOptions.realloc( nIndex + 1 );
+ aOptions[ nIndex ].Name = pPrintOptions[nOption].Name;
+ aOptions[ nIndex++ ].Value = pPrintOptions[nOption].Value ;
+ }
+ }
+
+ pTargetView->ExecPrint( aOptions, IsMergeSilent(), rMergeDescriptor.bPrintAsync );
+ }
+ xTargetDocShell->DoClose();
+ }
+
+ //remove the temporary files
+ ::std::vector<OUString>::iterator aFileIter;
+ for(aFileIter = aFilesToRemove.begin();
+ aFileIter != aFilesToRemove.end(); ++aFileIter)
+ SWUnoHelper::UCB_DeleteFile( *aFileIter );
+
+ // unlock all dispatchers
+ pViewFrm = SfxViewFrame::GetFirst(pSourceDocSh);
+ while (pViewFrm)
+ {
+ pViewFrm->GetDispatcher()->Lock(false);
+ pViewFrm = SfxViewFrame::GetNext(*pViewFrm, pSourceDocSh);
+ }
+
+ SW_MOD()->SetView(&pSourceShell->GetView());
+ }
+ }
+
+ if(bEMail)
+ {
+ xMailDispatcher->stop();
+ xMailDispatcher->shutdown();
+ }
+
+ return bNoError;
+}
+
+void SwDBManager::MergeCancel()
+{
+ bCancel = true;
+}
+
+IMPL_LINK_INLINE_START( SwDBManager, PrtCancelHdl, Button *, pButton )
+{
+ pButton->GetParent()->Hide();
+ MergeCancel();
+ return 0;
+}
+IMPL_LINK_INLINE_END( SwDBManager, PrtCancelHdl, Button *, pButton )
+
+// determine the column's Numberformat and transfer to the forwarded Formatter,
+// if applicable.
+sal_uLong SwDBManager::GetColumnFmt( const OUString& rDBName,
+ const OUString& rTableName,
+ const OUString& rColNm,
+ SvNumberFormatter* pNFmtr,
+ long nLanguage )
+{
+ sal_uLong nRet = 0;
+ if(pNFmtr)
+ {
+ uno::Reference< XDataSource> xSource;
+ uno::Reference< XConnection> xConnection;
+ bool bUseMergeData = false;
+ uno::Reference< XColumnsSupplier> xColsSupp;
+ bool bDisposeConnection = false;
+ if(pImpl->pMergeData &&
+ pImpl->pMergeData->sDataSource.equals(rDBName) && pImpl->pMergeData->sCommand.equals(rTableName))
+ {
+ xConnection = pImpl->pMergeData->xConnection;
+ xSource = SwDBManager::getDataSourceAsParent(xConnection,rDBName);
+ bUseMergeData = true;
+ xColsSupp = xColsSupp.query( pImpl->pMergeData->xResultSet );
+ }
+ if(!xConnection.is())
+ {
+ SwDBData aData;
+ aData.sDataSource = rDBName;
+ aData.sCommand = rTableName;
+ aData.nCommandType = -1;
+ SwDSParam* pParam = FindDSData(aData, false);
+ if(pParam && pParam->xConnection.is())
+ {
+ xConnection = pParam->xConnection;
+ xColsSupp = xColsSupp.query( pParam->xResultSet );
+ }
+ else
+ {
+ OUString sDBName(rDBName);
+ xConnection = RegisterConnection( sDBName );
+ bDisposeConnection = true;
+ }
+ if(bUseMergeData)
+ pImpl->pMergeData->xConnection = xConnection;
+ }
+ bool bDispose = !xColsSupp.is();
+ if(bDispose)
+ {
+ xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
+ }
+ if(xColsSupp.is())
+ {
+ uno::Reference<XNameAccess> xCols;
+ try
+ {
+ xCols = xColsSupp->getColumns();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Exception in getColumns()");
+ }
+ if(!xCols.is() || !xCols->hasByName(rColNm))
+ return nRet;
+ Any aCol = xCols->getByName(rColNm);
+ uno::Reference< XPropertySet > xColumn;
+ aCol >>= xColumn;
+ nRet = GetColumnFmt(xSource, xConnection, xColumn, pNFmtr, nLanguage);
+ if(bDispose)
+ {
+ ::comphelper::disposeComponent( xColsSupp );
+ }
+ if(bDisposeConnection)
+ {
+ ::comphelper::disposeComponent( xConnection );
+ }
+ }
+ else
+ nRet = pNFmtr->GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_SYSTEM );
+ }
+ return nRet;
+}
+
+sal_uLong SwDBManager::GetColumnFmt( uno::Reference< XDataSource> xSource,
+ uno::Reference< XConnection> xConnection,
+ uno::Reference< XPropertySet> xColumn,
+ SvNumberFormatter* pNFmtr,
+ long nLanguage )
+{
+ // set the NumberFormat in the doc if applicable
+ sal_uLong nRet = 0;
+
+ if(!xSource.is())
+ {
+ uno::Reference<XChild> xChild(xConnection, UNO_QUERY);
+ if ( xChild.is() )
+ xSource = uno::Reference<XDataSource>(xChild->getParent(), UNO_QUERY);
+ }
+ if(xSource.is() && xConnection.is() && xColumn.is() && pNFmtr)
+ {
+ SvNumberFormatsSupplierObj* pNumFmt = new SvNumberFormatsSupplierObj( pNFmtr );
+ uno::Reference< util::XNumberFormatsSupplier > xDocNumFmtsSupplier = pNumFmt;
+ uno::Reference< XNumberFormats > xDocNumberFormats = xDocNumFmtsSupplier->getNumberFormats();
+ uno::Reference< XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, UNO_QUERY);
+
+ com::sun::star::lang::Locale aLocale( LanguageTag( (LanguageType)nLanguage ).getLocale());
+
+ //get the number formatter of the data source
+ uno::Reference<XPropertySet> xSourceProps(xSource, UNO_QUERY);
+ uno::Reference< XNumberFormats > xNumberFormats;
+ if(xSourceProps.is())
+ {
+ Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
+ if(aFormats.hasValue())
+ {
+ uno::Reference<XNumberFormatsSupplier> xSuppl;
+ aFormats >>= xSuppl;
+ if(xSuppl.is())
+ {
+ xNumberFormats = xSuppl->getNumberFormats();
+ }
+ }
+ }
+ bool bUseDefault = true;
+ try
+ {
+ Any aFormatKey = xColumn->getPropertyValue("FormatKey");
+ if(aFormatKey.hasValue())
+ {
+ sal_Int32 nFmt = 0;
+ aFormatKey >>= nFmt;
+ if(xNumberFormats.is())
+ {
+ try
+ {
+ uno::Reference<XPropertySet> xNumProps = xNumberFormats->getByKey( nFmt );
+ Any aFormatString = xNumProps->getPropertyValue("FormatString");
+ Any aLocaleVal = xNumProps->getPropertyValue("Locale");
+ OUString sFormat;
+ aFormatString >>= sFormat;
+ lang::Locale aLoc;
+ aLocaleVal >>= aLoc;
+ nFmt = xDocNumberFormats->queryKey( sFormat, aLoc, sal_False );
+ if(NUMBERFORMAT_ENTRY_NOT_FOUND == sal::static_int_cast< sal_uInt32, sal_Int32>(nFmt))
+ nFmt = xDocNumberFormats->addNew( sFormat, aLoc );
+ nRet = nFmt;
+ bUseDefault = false;
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("illegal number format key");
+ }
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("no FormatKey property found");
+ }
+ if(bUseDefault)
+ nRet = SwDBManager::GetDbtoolsClient().getDefaultNumberFormat(xColumn, xDocNumberFormatTypes, aLocale);
+ }
+ return nRet;
+}
+
+sal_Int32 SwDBManager::GetColumnType( const OUString& rDBName,
+ const OUString& rTableName,
+ const OUString& rColNm )
+{
+ sal_Int32 nRet = DataType::SQLNULL;
+ SwDBData aData;
+ aData.sDataSource = rDBName;
+ aData.sCommand = rTableName;
+ aData.nCommandType = -1;
+ SwDSParam* pParam = FindDSData(aData, false);
+ uno::Reference< XConnection> xConnection;
+ uno::Reference< XColumnsSupplier > xColsSupp;
+ bool bDispose = false;
+ if(pParam && pParam->xConnection.is())
+ {
+ xConnection = pParam->xConnection;
+ xColsSupp = uno::Reference< XColumnsSupplier >( pParam->xResultSet, UNO_QUERY );
+ }
+ else
+ {
+ OUString sDBName(rDBName);
+ xConnection = RegisterConnection( sDBName );
+ }
+ if( !xColsSupp.is() )
+ {
+ xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
+ bDispose = true;
+ }
+ if(xColsSupp.is())
+ {
+ uno::Reference<XNameAccess> xCols = xColsSupp->getColumns();
+ if(xCols->hasByName(rColNm))
+ {
+ Any aCol = xCols->getByName(rColNm);
+ uno::Reference<XPropertySet> xCol;
+ aCol >>= xCol;
+ Any aType = xCol->getPropertyValue("Type");
+ aType >>= nRet;
+ }
+ if(bDispose)
+ ::comphelper::disposeComponent( xColsSupp );
+ }
+ return nRet;
+}
+
+uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rDataSource,
+ uno::Reference<XDataSource>& rxSource)
+{
+ Reference< sdbc::XConnection> xConnection;
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ try
+ {
+ Reference<XCompletedConnection> xComplConnection(SwDBManager::GetDbtoolsClient().getDataSource(rDataSource, xContext),UNO_QUERY);
+ if ( xComplConnection.is() )
+ {
+ rxSource.set(xComplConnection,UNO_QUERY);
+ Reference< XInteractionHandler > xHandler( InteractionHandler::createWithParent(xContext, 0), UNO_QUERY_THROW );
+ xConnection = xComplConnection->connectWithCompletion( xHandler );
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+
+ return xConnection;
+}
+
+uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference<sdbc::XConnection> xConnection,
+ const OUString& rTableOrQuery,
+ sal_uInt8 eTableOrQuery)
+{
+ Reference< sdbcx::XColumnsSupplier> xRet;
+ try
+ {
+ if(eTableOrQuery == SW_DB_SELECT_UNKNOWN)
+ {
+ //search for a table with the given command name
+ Reference<XTablesSupplier> xTSupplier = Reference<XTablesSupplier>(xConnection, UNO_QUERY);
+ if(xTSupplier.is())
+ {
+ Reference<XNameAccess> xTbls = xTSupplier->getTables();
+ eTableOrQuery = xTbls->hasByName(rTableOrQuery) ?
+ SW_DB_SELECT_TABLE : SW_DB_SELECT_QUERY;
+ }
+ }
+ sal_Int32 nCommandType = SW_DB_SELECT_TABLE == eTableOrQuery ?
+ CommandType::TABLE : CommandType::QUERY;
+ Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
+ Reference<XRowSet> xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), UNO_QUERY);
+
+ OUString sDataSource;
+ Reference<XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection, sDataSource);
+ Reference<XPropertySet> xSourceProperties(xSource, UNO_QUERY);
+ if(xSourceProperties.is())
+ {
+ xSourceProperties->getPropertyValue("Name") >>= sDataSource;
+ }
+
+ Reference<XPropertySet> xRowProperties(xRowSet, UNO_QUERY);
+ xRowProperties->setPropertyValue("DataSourceName", makeAny(sDataSource));
+ xRowProperties->setPropertyValue("Command", makeAny(OUString(rTableOrQuery)));
+ xRowProperties->setPropertyValue("CommandType", makeAny(nCommandType));
+ xRowProperties->setPropertyValue("FetchSize", makeAny((sal_Int32)10));
+ xRowProperties->setPropertyValue("ActiveConnection", makeAny(xConnection));
+ xRowSet->execute();
+ xRet = Reference<XColumnsSupplier>( xRowSet, UNO_QUERY );
+ }
+ catch(const uno::Exception&)
+ {
+ OSL_FAIL("Exception in SwDBManager::GetColumnSupplier");
+ }
+
+ return xRet;
+}
+
+OUString SwDBManager::GetDBField(uno::Reference<XPropertySet> xColumnProps,
+ const SwDBFormatData& rDBFormatData,
+ double* pNumber)
+{
+ uno::Reference< XColumn > xColumn(xColumnProps, UNO_QUERY);
+ OUString sRet;
+ OSL_ENSURE(xColumn.is(), "SwDBManager::::ImportDBField: illegal arguments");
+ if(!xColumn.is())
+ return sRet;
+
+ Any aType = xColumnProps->getPropertyValue("Type");
+ sal_Int32 eDataType = 0;
+ aType >>= eDataType;
+ switch(eDataType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ try
+ {
+ sRet = xColumn->getString();
+ }
+ catch(const SQLException&)
+ {
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ {
+
+ try
+ {
+ SwDbtoolsClient& aClient = SwDBManager::GetDbtoolsClient();
+ sRet = aClient.getFormattedValue(
+ xColumnProps,
+ rDBFormatData.xFormatter,
+ rDBFormatData.aLocale,
+ rDBFormatData.aNullDate);
+ if (pNumber)
+ {
+ double fVal = xColumn->getDouble();
+ if(!xColumn->wasNull())
+ {
+ *pNumber = fVal;
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("exception caught");
+ }
+
+ }
+ break;
+ }
+
+ return sRet;
+}
+
+// releases the merge data source table or query after merge is completed
+void SwDBManager::EndMerge()
+{
+ OSL_ENSURE(bInMerge, "merge is not active");
+ bInMerge = false;
+ delete pImpl->pMergeData;
+ pImpl->pMergeData = 0;
+}
+
+// checks if a desired data source table or query is open
+bool SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
+ const OUString& rTableOrQuery, bool bMergeOnly)
+{
+ if(pImpl->pMergeData)
+ {
+ return !bMergeLock &&
+ ((rDataSource == pImpl->pMergeData->sDataSource &&
+ rTableOrQuery == pImpl->pMergeData->sCommand)
+ ||(rDataSource.isEmpty() && rTableOrQuery.isEmpty()))
+ &&
+ pImpl->pMergeData->xResultSet.is();
+ }
+ else if(!bMergeOnly)
+ {
+ SwDBData aData;
+ aData.sDataSource = rDataSource;
+ aData.sCommand = rTableOrQuery;
+ aData.nCommandType = -1;
+ SwDSParam* pFound = FindDSData(aData, false);
+ return (pFound && pFound->xResultSet.is());
+ }
+ return false;
+}
+
+// read column data at a specified position
+bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
+ const OUString& rColumnName, sal_uInt32 nAbsRecordId,
+ long nLanguage,
+ OUString& rResult, double* pNumber)
+{
+ bool bRet = false;
+ SwDSParam* pFound = 0;
+ //check if it's the merge data source
+ if(pImpl->pMergeData &&
+ rSourceName == pImpl->pMergeData->sDataSource &&
+ rTableName == pImpl->pMergeData->sCommand)
+ {
+ pFound = pImpl->pMergeData;
+ }
+ else
+ {
+ SwDBData aData;
+ aData.sDataSource = rSourceName;
+ aData.sCommand = rTableName;
+ aData.nCommandType = -1;
+ pFound = FindDSData(aData, false);
+ }
+ if (!pFound)
+ return false;
+ //check validity of supplied record Id
+ if(pFound->aSelection.getLength())
+ {
+ //the destination has to be an element of the selection
+ const Any* pSelection = pFound->aSelection.getConstArray();
+ bool bFound = false;
+ for(sal_Int32 nPos = 0; !bFound && nPos < pFound->aSelection.getLength(); nPos++)
+ {
+ sal_Int32 nSelection = 0;
+ pSelection[nPos] >>= nSelection;
+ if(nSelection == static_cast<sal_Int32>(nAbsRecordId))
+ bFound = true;
+ }
+ if(!bFound)
+ return false;
+ }
+ if(pFound->xResultSet.is() && !pFound->bAfterSelection)
+ {
+ sal_Int32 nOldRow = 0;
+ try
+ {
+ nOldRow = pFound->xResultSet->getRow();
+ }
+ catch(const Exception&)
+ {
+ return false;
+ }
+ //position to the desired index
+ bool bMove = true;
+ if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
+ bMove = lcl_MoveAbsolute(pFound, nAbsRecordId);
+ if(bMove)
+ {
+ bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber);
+ }
+ if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
+ bMove = lcl_MoveAbsolute(pFound, nOldRow);
+ }
+ return bRet;
+}
+
+// reads the column data at the current position
+bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, sal_uInt16 nLanguage,
+ OUString &rResult, double *pNumber, sal_uInt32 * /*pFormat*/)
+{
+ if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is() || pImpl->pMergeData->bAfterSelection )
+ {
+ rResult = "";
+ return false;
+ }
+
+ bool bRet = lcl_GetColumnCnt(pImpl->pMergeData, rColumnName, nLanguage, rResult, pNumber);
+ return bRet;
+}
+
+bool SwDBManager::ToNextMergeRecord()
+{
+ OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge");
+ return ToNextRecord(pImpl->pMergeData);
+}
+
+bool SwDBManager::ToNextRecord(
+ const OUString& rDataSource, const OUString& rCommand, sal_Int32 /*nCommandType*/)
+{
+ SwDSParam* pFound = 0;
+ if(pImpl->pMergeData &&
+ rDataSource == pImpl->pMergeData->sDataSource &&
+ rCommand == pImpl->pMergeData->sCommand)
+ pFound = pImpl->pMergeData;
+ else
+ {
+ SwDBData aData;
+ aData.sDataSource = rDataSource;
+ aData.sCommand = rCommand;
+ aData.nCommandType = -1;
+ pFound = FindDSData(aData, false);
+ }
+ return ToNextRecord(pFound);
+}
+
+bool SwDBManager::ToNextRecord(SwDSParam* pParam)
+{
+ bool bRet = true;
+ if(!pParam || !pParam->xResultSet.is() || pParam->bEndOfDB ||
+ (pParam->aSelection.getLength() && pParam->aSelection.getLength() <= pParam->nSelectionIndex))
+ {
+ if(pParam)
+ pParam->CheckEndOfDB();
+ return false;
+ }
+ try
+ {
+ if(pParam->aSelection.getLength())
+ {
+ sal_Int32 nPos = 0;
+ pParam->aSelection.getConstArray()[ pParam->nSelectionIndex++ ] >>= nPos;
+ pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
+ pParam->CheckEndOfDB();
+ bRet = !pParam->bEndOfDB;
+ if(pParam->nSelectionIndex >= pParam->aSelection.getLength())
+ pParam->bEndOfDB = true;
+ }
+ else
+ {
+ sal_Int32 nBefore = pParam->xResultSet->getRow();
+ pParam->bEndOfDB = !pParam->xResultSet->next();
+ if( !pParam->bEndOfDB && nBefore == pParam->xResultSet->getRow())
+ {
+ //next returned true but it didn't move
+ pParam->bEndOfDB = true;
+ }
+
+ pParam->CheckEndOfDB();
+ bRet = !pParam->bEndOfDB;
+ ++pParam->nSelectionIndex;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ return bRet;
+}
+
+// synchronized labels contain a next record field at their end
+// to assure that the next page can be created in mail merge
+// the cursor position must be validated
+bool SwDBManager::ExistsNextRecord() const
+{
+ return pImpl->pMergeData && !pImpl->pMergeData->bEndOfDB;
+}
+
+sal_uInt32 SwDBManager::GetSelectedRecordId()
+{
+ sal_uInt32 nRet = 0;
+ OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge");
+ if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is())
+ return sal_False;
+ try
+ {
+ nRet = pImpl->pMergeData->xResultSet->getRow();
+ }
+ catch(const Exception&)
+ {
+ }
+ return nRet;
+}
+
+bool SwDBManager::ToRecordId(sal_Int32 nSet)
+{
+ OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge");
+ if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is()|| nSet < 0)
+ return false;
+ bool bRet = false;
+ sal_Int32 nAbsPos = nSet;
+
+ if(nAbsPos >= 0)
+ {
+ bRet = lcl_MoveAbsolute(pImpl->pMergeData, nAbsPos);
+ pImpl->pMergeData->bEndOfDB = !bRet;
+ pImpl->pMergeData->CheckEndOfDB();
+ }
+ return bRet;
+}
+
+bool SwDBManager::OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery,
+ sal_Int32 nCommandType, bool bCreate)
+{
+ SwDBData aData;
+ aData.sDataSource = rDataSource;
+ aData.sCommand = rTableOrQuery;
+ aData.nCommandType = nCommandType;
+
+ SwDSParam* pFound = FindDSData(aData, true);
+ uno::Reference< XDataSource> xSource;
+ if(pFound->xResultSet.is())
+ return true;
+ SwDSParam* pParam = FindDSConnection(rDataSource, false);
+ uno::Reference< XConnection> xConnection;
+ if(pParam && pParam->xConnection.is())
+ pFound->xConnection = pParam->xConnection;
+ else if(bCreate)
+ {
+ OUString sDataSource(rDataSource);
+ pFound->xConnection = RegisterConnection( sDataSource );
+ }
+ if(pFound->xConnection.is())
+ {
+ try
+ {
+ uno::Reference< sdbc::XDatabaseMetaData > xMetaData = pFound->xConnection->getMetaData();
+ try
+ {
+ pFound->bScrollable = xMetaData
+ ->supportsResultSetType((sal_Int32)ResultSetType::SCROLL_INSENSITIVE);
+ }
+ catch(const Exception&)
+ {
+ // DB driver may not be ODBC 3.0 compliant
+ pFound->bScrollable = true;
+ }
+ pFound->xStatement = pFound->xConnection->createStatement();
+ OUString aQuoteChar = xMetaData->getIdentifierQuoteString();
+ OUString sStatement("SELECT * FROM ");
+ sStatement = "SELECT * FROM ";
+ sStatement += aQuoteChar;
+ sStatement += rTableOrQuery;
+ sStatement += aQuoteChar;
+ pFound->xResultSet = pFound->xStatement->executeQuery( sStatement );
+
+ //after executeQuery the cursor must be positioned
+ pFound->bEndOfDB = !pFound->xResultSet->next();
+ pFound->bAfterSelection = false;
+ pFound->CheckEndOfDB();
+ ++pFound->nSelectionIndex;
+ }
+ catch (const Exception&)
+ {
+ pFound->xResultSet = 0;
+ pFound->xStatement = 0;
+ pFound->xConnection = 0;
+ }
+ }
+ return pFound->xResultSet.is();
+}
+
+uno::Reference< XConnection> SwDBManager::RegisterConnection(OUString& rDataSource)
+{
+ SwDSParam* pFound = SwDBManager::FindDSConnection(rDataSource, true);
+ uno::Reference< XDataSource> xSource;
+ if(!pFound->xConnection.is())
+ {
+ pFound->xConnection = SwDBManager::GetConnection(rDataSource, xSource );
+ try
+ {
+ uno::Reference<XComponent> xComponent(pFound->xConnection, UNO_QUERY);
+ if(xComponent.is())
+ xComponent->addEventListener(pImpl->xDisposeListener);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return pFound->xConnection;
+}
+
+sal_uInt32 SwDBManager::GetSelectedRecordId(
+ const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType)
+{
+ sal_uInt32 nRet = 0xffffffff;
+ //check for merge data source first
+ if(pImpl->pMergeData && rDataSource == pImpl->pMergeData->sDataSource &&
+ rTableOrQuery == pImpl->pMergeData->sCommand &&
+ (nCommandType == -1 || nCommandType == pImpl->pMergeData->nCommandType) &&
+ pImpl->pMergeData->xResultSet.is())
+ nRet = GetSelectedRecordId();
+ else
+ {
+ SwDBData aData;
+ aData.sDataSource = rDataSource;
+ aData.sCommand = rTableOrQuery;
+ aData.nCommandType = nCommandType;
+ SwDSParam* pFound = FindDSData(aData, false);
+ if(pFound && pFound->xResultSet.is())
+ {
+ try
+ { //if a selection array is set the current row at the result set may not be set yet
+ if(pFound->aSelection.getLength())
+ {
+ sal_Int32 nSelIndex = pFound->nSelectionIndex;
+ if(nSelIndex >= pFound->aSelection.getLength())
+ nSelIndex = pFound->aSelection.getLength() -1;
+ pFound->aSelection.getConstArray()[nSelIndex] >>= nRet;
+
+ }
+ else
+ nRet = pFound->xResultSet->getRow();
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ }
+ return nRet;
+}
+
+// close all data sources - after fields were updated
+void SwDBManager::CloseAll(bool bIncludingMerge)
+{
+ //the only thing done here is to reset the selection index
+ //all connections stay open
+ for(sal_uInt16 nPos = 0; nPos < aDataSourceParams.size(); nPos++)
+ {
+ SwDSParam* pParam = &aDataSourceParams[nPos];
+ if(bIncludingMerge || pParam != pImpl->pMergeData)
+ {
+ pParam->nSelectionIndex = 0;
+ pParam->bAfterSelection = false;
+ pParam->bEndOfDB = false;
+ try
+ {
+ if(!bInMerge && pParam->xResultSet.is())
+ pParam->xResultSet->first();
+ }
+ catch(const Exception&)
+ {}
+ }
+ }
+}
+
+SwDSParam* SwDBManager::FindDSData(const SwDBData& rData, bool bCreate)
+{
+ //prefer merge data if available
+ if(pImpl->pMergeData && rData.sDataSource == pImpl->pMergeData->sDataSource &&
+ rData.sCommand == pImpl->pMergeData->sCommand &&
+ (rData.nCommandType == -1 || rData.nCommandType == pImpl->pMergeData->nCommandType ||
+ (bCreate && pImpl->pMergeData->nCommandType == -1)))
+ {
+ return pImpl->pMergeData;
+ }
+
+ SwDSParam* pFound = 0;
+ for(sal_uInt16 nPos = aDataSourceParams.size(); nPos; nPos--)
+ {
+ SwDSParam* pParam = &aDataSourceParams[nPos - 1];
+ if(rData.sDataSource == pParam->sDataSource &&
+ rData.sCommand == pParam->sCommand &&
+ (rData.nCommandType == -1 || rData.nCommandType == pParam->nCommandType ||
+ (bCreate && pParam->nCommandType == -1)))
+ {
+ // calls from the calculator may add a connection with an invalid commandtype
+ //later added "real" data base connections have to re-use the already available
+ //DSData and set the correct CommandType
+ if(bCreate && pParam->nCommandType == -1)
+ pParam->nCommandType = rData.nCommandType;
+ pFound = pParam;
+ break;
+ }
+ }
+ if(bCreate)
+ {
+ if(!pFound)
+ {
+ pFound = new SwDSParam(rData);
+ aDataSourceParams.push_back(pFound);
+ try
+ {
+ uno::Reference<XComponent> xComponent(pFound->xConnection, UNO_QUERY);
+ if(xComponent.is())
+ xComponent->addEventListener(pImpl->xDisposeListener);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ }
+ return pFound;
+}
+
+SwDSParam* SwDBManager::FindDSConnection(const OUString& rDataSource, bool bCreate)
+{
+ //prefer merge data if available
+ if(pImpl->pMergeData && rDataSource == pImpl->pMergeData->sDataSource )
+ {
+ return pImpl->pMergeData;
+ }
+ SwDSParam* pFound = 0;
+ for(sal_uInt16 nPos = 0; nPos < aDataSourceParams.size(); nPos++)
+ {
+ SwDSParam* pParam = &aDataSourceParams[nPos];
+ if(rDataSource == pParam->sDataSource)
+ {
+ pFound = pParam;
+ break;
+ }
+ }
+ if(bCreate && !pFound)
+ {
+ SwDBData aData;
+ aData.sDataSource = rDataSource;
+ pFound = new SwDSParam(aData);
+ aDataSourceParams.push_back(pFound);
+ try
+ {
+ uno::Reference<XComponent> xComponent(pFound->xConnection, UNO_QUERY);
+ if(xComponent.is())
+ xComponent->addEventListener(pImpl->xDisposeListener);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return pFound;
+}
+
+const SwDBData& SwDBManager::GetAddressDBName()
+{
+ return SW_MOD()->GetDBConfig()->GetAddressSource();
+}
+
+Sequence<OUString> SwDBManager::GetExistingDatabaseNames()
+{
+ Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+ Reference<XDatabaseContext> xDBContext = DatabaseContext::create(xContext);
+ return xDBContext->getElementNames();
+}
+
+OUString SwDBManager::LoadAndRegisterDataSource()
+{
+ sfx2::FileDialogHelper aDlgHelper( TemplateDescription::FILEOPEN_SIMPLE, 0 );
+ Reference < XFilePicker > xFP = aDlgHelper.GetFilePicker();
+
+ OUString sHomePath(SvtPathOptions().GetWorkPath());
+ aDlgHelper.SetDisplayDirectory( sHomePath );
+
+ Reference<XFilterManager> xFltMgr(xFP, UNO_QUERY);
+
+ OUString sFilterAll(SW_RES(STR_FILTER_ALL));
+ OUString sFilterAllData(SW_RES(STR_FILTER_ALL_DATA));
+ OUString sFilterSXB(SW_RES(STR_FILTER_SXB));
+ OUString sFilterSXC(SW_RES(STR_FILTER_SXC));
+ OUString sFilterDBF(SW_RES(STR_FILTER_DBF));
+ OUString sFilterXLS(SW_RES(STR_FILTER_XLS));
+ OUString sFilterTXT(SW_RES(STR_FILTER_TXT));
+ OUString sFilterCSV(SW_RES(STR_FILTER_CSV));
+#ifdef WNT
+ OUString sFilterMDB(SW_RES(STR_FILTER_MDB));
+ OUString sFilterACCDB(SW_RES(STR_FILTER_ACCDB));
+#endif
+ xFltMgr->appendFilter( sFilterAll, "*" );
+ xFltMgr->appendFilter( sFilterAllData, "*.ods;*.sxc;*.dbf;*.xls;*.txt;*.csv");
+
+ xFltMgr->appendFilter( sFilterSXB, "*.odb" );
+ xFltMgr->appendFilter( sFilterSXC, "*.ods;*.sxc" );
+ xFltMgr->appendFilter( sFilterDBF, "*.dbf" );
+ xFltMgr->appendFilter( sFilterXLS, "*.xls" );
+ xFltMgr->appendFilter( sFilterTXT, "*.txt" );
+ xFltMgr->appendFilter( sFilterCSV, "*.csv" );
+#ifdef WNT
+ xFltMgr->appendFilter( sFilterMDB, "*.mdb" );
+ xFltMgr->appendFilter( sFilterACCDB, "*.accdb" );
+#endif
+
+ xFltMgr->setCurrentFilter( sFilterAll ) ;
+ OUString sFind;
+ bool bTextConnection = false;
+ if( ERRCODE_NONE == aDlgHelper.Execute() )
+ {
+ OUString sURL = xFP->getFiles().getConstArray()[0];
+ //data sources have to be registered depending on their extensions
+ INetURLObject aURL( sURL );
+ OUString sExt( aURL.GetExtension() );
+ Any aURLAny;
+ Any aTableFilterAny;
+ Any aSuppressVersionsAny;
+ Any aInfoAny;
+ INetURLObject aTempURL(aURL);
+ bool bStore = true;
+ if(sExt == "odb")
+ {
+ bStore = false;
+ }
+ else if(sExt.equalsIgnoreAsciiCase("sxc")
+ || sExt.equalsIgnoreAsciiCase("ods")
+ || sExt.equalsIgnoreAsciiCase("xls"))
+ {
+ OUString sDBURL("sdbc:calc:");
+ sDBURL += aTempURL.GetMainURL(INetURLObject::NO_DECODE);
+ aURLAny <<= sDBURL;
+ }
+ else if(sExt.equalsIgnoreAsciiCase("dbf"))
+ {
+ aTempURL.removeSegment();
+ aTempURL.removeFinalSlash();
+ OUString sDBURL("sdbc:dbase:");
+ sDBURL += aTempURL.GetMainURL(INetURLObject::NO_DECODE);
+ aURLAny <<= sDBURL;
+ //set the filter to the file name without extension
+ Sequence<OUString> aFilters(1);
+ aFilters[0] = aURL.getBase();
+ aTableFilterAny <<= aFilters;
+ }
+ else if(sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
+ {
+ aTempURL.removeSegment();
+ aTempURL.removeFinalSlash();
+ OUString sDBURL("sdbc:flat:");
+ //only the 'path' has to be added
+ sDBURL += aTempURL.GetMainURL(INetURLObject::NO_DECODE);
+ aURLAny <<= sDBURL;
+
+ bTextConnection = true;
+ //set the filter to the file name without extension
+ Sequence<OUString> aFilters(1);
+ aFilters[0] = aURL.getBase();
+ aTableFilterAny <<= aFilters;
+ }
+#ifdef WNT
+ else if(sExt.equalsIgnoreAsciiCase("mdb"))
+ {
+ OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=");
+ sDBURL += aTempURL.PathToFileName();
+ aURLAny <<= sDBURL;
+ aSuppressVersionsAny <<= makeAny(true);
+ }
+ else if(sExt.equalsIgnoreAsciiCase("accdb"))
+ {
+ OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=");
+ sDBURL += aTempURL.PathToFileName();
+ aURLAny <<= sDBURL;
+ aSuppressVersionsAny <<= makeAny(true);
+ }
+#endif
+ try
+ {
+ Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+ Reference<XDatabaseContext> xDBContext = DatabaseContext::create(xContext);
+
+ OUString sNewName = INetURLObject::decode( aURL.getName(),
+ '%',
+ INetURLObject::DECODE_UNAMBIGUOUS,
+ RTL_TEXTENCODING_UTF8 );
+ sal_Int32 nExtLen = aURL.GetExtension().getLength();
+ sNewName = sNewName.replaceAt( sNewName.getLength() - nExtLen - 1, nExtLen + 1, "" );
+
+ //find a unique name if sNewName already exists
+ sFind = sNewName;
+ sal_Int32 nIndex = 0;
+ while(xDBContext->hasByName(sFind))
+ {
+ sFind = sNewName;
+ sFind += OUString::number(++nIndex);
+ }
+
+ Reference<XInterface> xNewInstance;
+ if(!bStore)
+ {
+ //odb-file
+ Any aDataSource = xDBContext->getByName(aTempURL.GetMainURL(INetURLObject::NO_DECODE));
+ aDataSource >>= xNewInstance;
+ }
+ else
+ {
+ xNewInstance = xDBContext->createInstance();
+ Reference<XPropertySet> xDataProperties(xNewInstance, UNO_QUERY);
+
+ if(aURLAny.hasValue())
+ xDataProperties->setPropertyValue("URL", aURLAny);
+ if(aTableFilterAny.hasValue())
+ xDataProperties->setPropertyValue("TableFilter", aTableFilterAny);
+ if(aSuppressVersionsAny.hasValue())
+ xDataProperties->setPropertyValue("SuppressVersionColumns", aSuppressVersionsAny);
+ if(aInfoAny.hasValue())
+ xDataProperties->setPropertyValue("Info", aInfoAny);
+
+ if( bTextConnection )
+ {
+ uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
+ if( xSettingsDlg->execute() )
+ {
+ uno::Any aSettings = xDataProperties->getPropertyValue( "Settings" );
+ uno::Reference < beans::XPropertySet > xDSSettings;
+ aSettings >>= xDSSettings;
+ ::comphelper::copyProperties(
+ uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ),
+ xDSSettings );
+ xDSSettings->setPropertyValue( "Extension", uno::makeAny( sExt ));
+ }
+ }
+
+ Reference<XDocumentDataSource> xDS(xNewInstance, UNO_QUERY_THROW);
+ Reference<XStorable> xStore(xDS->getDatabaseDocument(), UNO_QUERY_THROW);
+ OUString sOutputExt = ".odb";
+ OUString sTmpName;
+ {
+ utl::TempFile aTempFile(sNewName, true, &sOutputExt, &sHomePath);
+ aTempFile.EnableKillingFile(true);
+ sTmpName = aTempFile.GetURL();
+ }
+ xStore->storeAsURL(sTmpName, Sequence< PropertyValue >());
+ }
+ xDBContext->registerObject( sFind, xNewInstance );
+
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return sFind;
+
+}
+
+void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
+ const Sequence<PropertyValue>& rProperties,
+ bool bWithDataSourceBrowser)
+{
+ //prevent second call
+ if(pImpl->pMergeDialog)
+ return ;
+ OUString sDataSource, sDataTableOrQuery;
+ Sequence<Any> aSelection;
+
+ sal_Int32 nCmdType = CommandType::TABLE;
+ uno::Reference< XConnection> xConnection;
+
+ ODataAccessDescriptor aDescriptor(rProperties);
+ sDataSource = aDescriptor.getDataSource();
+ OSL_VERIFY(aDescriptor[daCommand] >>= sDataTableOrQuery);
+ OSL_VERIFY(aDescriptor[daCommandType] >>= nCmdType);
+
+ if ( aDescriptor.has(daSelection) )
+ aDescriptor[daSelection] >>= aSelection;
+ if ( aDescriptor.has(daConnection) )
+ aDescriptor[daConnection] >>= xConnection;
+
+ if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty())
+ {
+ OSL_FAIL("PropertyValues missing or unset");
+ return;
+ }
+
+ //always create a connection for the dialog and dispose it after the dialog has been closed
+ SwDSParam* pFound = 0;
+ if(!xConnection.is())
+ {
+ xConnection = SwDBManager::RegisterConnection(sDataSource);
+ pFound = FindDSConnection(sDataSource, true);
+ }
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ OSL_ENSURE(pFact, "Dialogdiet fail!");
+ pImpl->pMergeDialog = pFact->CreateMailMergeDlg( DLG_MAILMERGE,
+ &rSh.GetView().GetViewFrame()->GetWindow(), rSh,
+ sDataSource,
+ sDataTableOrQuery,
+ nCmdType,
+ xConnection,
+ bWithDataSourceBrowser ? 0 : &aSelection);
+ OSL_ENSURE(pImpl->pMergeDialog, "Dialogdiet fail!");
+ if(pImpl->pMergeDialog->Execute() == RET_OK)
+ {
+ aDescriptor[daSelection] <<= pImpl->pMergeDialog->GetSelection();
+
+ uno::Reference<XResultSet> xResSet = pImpl->pMergeDialog->GetResultSet();
+ if(xResSet.is())
+ aDescriptor[daCursor] <<= xResSet;
+
+ // SfxObjectShellRef is ok, since there should be no control over the document lifetime here
+ SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame()->GetObjectShell();
+ SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE), xDocShell));
+ {
+ //copy rSh to aTempFile
+ OUString sTempURL;
+ const SfxFilter *pSfxFlt = SwIoSystem::GetFilterOfFormat(
+ OUString(FILTER_XML),
+ SwDocShell::Factory().GetFilterContainer() );
+ try
+ {
+
+ uno::Sequence< beans::PropertyValue > aValues(1);
+ beans::PropertyValue* pValues = aValues.getArray();
+ pValues[0].Name = "FilterName";
+ pValues[0].Value <<= OUString(pSfxFlt->GetFilterName());
+ uno::Reference< XStorable > xStore( xDocShell->GetModel(), uno::UNO_QUERY);
+ sTempURL = URIHelper::SmartRel2Abs( INetURLObject(), utl::TempFile::CreateTempName() );
+ xStore->storeToURL( sTempURL, aValues );
+ }
+ catch(const uno::Exception&)
+ {
+ }
+ if( xDocShell->GetError() )
+ {
+ // error message ??
+ ErrorHandler::HandleError( xDocShell->GetError() );
+ }
+ else
+ {
+ // the shell will be explicitly closed, but it is more safe to use SfxObjectShellLock here
+ // especially for the case that the loading has failed
+ SfxObjectShellLock xWorkDocSh( new SwDocShell( SFX_CREATE_MODE_INTERNAL ));
+ SfxMedium* pWorkMed = new SfxMedium( sTempURL, STREAM_STD_READ );
+ pWorkMed->SetFilter( pSfxFlt );
+ if( xWorkDocSh->DoLoad(pWorkMed) )
+ {
+ SfxViewFrame *pFrame = SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 );
+ SwView *pView = (SwView*) pFrame->GetViewShell();
+ pView->AttrChangedNotify( &pView->GetWrtShell() );// in order for SelectShell to be called
+ //set the current DBManager
+ SwDoc* pWorkDoc = pView->GetWrtShell().GetDoc();
+ SwDBManager* pWorkDBManager = pWorkDoc->GetDBManager();
+ pWorkDoc->SetDBManager( this );
+
+ SwMergeDescriptor aMergeDesc( pImpl->pMergeDialog->GetMergeType(), pView->GetWrtShell(), aDescriptor );
+ aMergeDesc.sSaveToFilter = pImpl->pMergeDialog->GetSaveFilter();
+ aMergeDesc.bCreateSingleFile = !pImpl->pMergeDialog->IsSaveIndividualDocs();
+ if( !aMergeDesc.bCreateSingleFile && pImpl->pMergeDialog->IsGenerateFromDataBase() )
+ {
+ aMergeDesc.sAddressFromColumn = pImpl->pMergeDialog->GetColumnName();
+ aMergeDesc.sSubject = pImpl->pMergeDialog->GetPath();
+ }
+
+ MergeNew(aMergeDesc);
+
+ pWorkDoc->SetDBManager( pWorkDBManager );
+ //close the temporary file
+ uno::Reference< util::XCloseable > xClose( xWorkDocSh->GetModel(), uno::UNO_QUERY );
+ if (xClose.is())
+ {
+ try
+ {
+ //! 'sal_True' -> transfer ownership to vetoing object if vetoed!
+ //! I.e. now that object is responsible for closing the model and doc shell.
+ xClose->close( sal_True );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ //remove the temporary file
+ SWUnoHelper::UCB_DeleteFile( sTempURL );
+ }
+ SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE_END, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END), rSh.GetView().GetViewFrame()->GetObjectShell()));
+
+ // reset the cursor inside
+ xResSet = NULL;
+ aDescriptor[daCursor] <<= xResSet;
+ }
+ if(pFound)
+ {
+ for(sal_uInt16 nPos = 0; nPos < aDataSourceParams.size(); nPos++)
+ {
+ SwDSParam* pParam = &aDataSourceParams[nPos];
+ if(pParam == pFound)
+ {
+ try
+ {
+ uno::Reference<XComponent> xComp(pParam->xConnection, UNO_QUERY);
+ if(xComp.is())
+ xComp->dispose();
+ }
+ catch(const RuntimeException&)
+ {
+ //may be disposed already since multiple entries may have used the same connection
+ }
+ break;
+ }
+ //pFound doesn't need to be removed/deleted -
+ //this has been done by the SwConnectionDisposedListener_Impl already
+ }
+ }
+ DELETEZ(pImpl->pMergeDialog);
+}
+
+void SwDBManager::InsertText(SwWrtShell& rSh,
+ const Sequence< PropertyValue>& rProperties)
+{
+ OUString sDataSource, sDataTableOrQuery;
+ uno::Reference<XResultSet> xResSet;
+ Sequence<Any> aSelection;
+ sal_Int16 nCmdType = CommandType::TABLE;
+ const PropertyValue* pValues = rProperties.getConstArray();
+ uno::Reference< XConnection> xConnection;
+ for(sal_Int32 nPos = 0; nPos < rProperties.getLength(); nPos++)
+ {
+ if ( pValues[nPos].Name == cDataSourceName )
+ pValues[nPos].Value >>= sDataSource;
+ else if ( pValues[nPos].Name == cCommand )
+ pValues[nPos].Value >>= sDataTableOrQuery;
+ else if ( pValues[nPos].Name == cCursor )
+ pValues[nPos].Value >>= xResSet;
+ else if ( pValues[nPos].Name == cSelection )
+ pValues[nPos].Value >>= aSelection;
+ else if ( pValues[nPos].Name == cCommandType )
+ pValues[nPos].Value >>= nCmdType;
+ else if ( pValues[nPos].Name == cActiveConnection )
+ pValues[nPos].Value >>= xConnection;
+ }
+ if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty() || !xResSet.is())
+ {
+ OSL_FAIL("PropertyValues missing or unset");
+ return;
+ }
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ uno::Reference<XDataSource> xSource;
+ uno::Reference<XChild> xChild(xConnection, UNO_QUERY);
+ if(xChild.is())
+ xSource = uno::Reference<XDataSource>(xChild->getParent(), UNO_QUERY);
+ if(!xSource.is())
+ xSource = SwDBManager::GetDbtoolsClient().getDataSource(sDataSource, xContext);
+ uno::Reference< XColumnsSupplier > xColSupp( xResSet, UNO_QUERY );
+ SwDBData aDBData;
+ aDBData.sDataSource = sDataSource;
+ aDBData.sCommand = sDataTableOrQuery;
+ aDBData.nCommandType = nCmdType;
+
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ OSL_ENSURE(pFact, "SwAbstractDialogFactory fail!");
+
+ boost::scoped_ptr<AbstractSwInsertDBColAutoPilot> pDlg(pFact->CreateSwInsertDBColAutoPilot( rSh.GetView(),
+ xSource,
+ xColSupp,
+ aDBData ));
+ OSL_ENSURE(pDlg, "Dialogdiet fail!");
+ if( RET_OK == pDlg->Execute() )
+ {
+ OUString sDummy;
+ if(!xConnection.is())
+ xConnection = xSource->getConnection(sDummy, sDummy);
+ try
+ {
+ pDlg->DataToDoc( aSelection , xSource, xConnection, xResSet);
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("exception caught");
+ }
+ }
+}
+
+SwDbtoolsClient* SwDBManager::pDbtoolsClient = NULL;
+
+SwDbtoolsClient& SwDBManager::GetDbtoolsClient()
+{
+ if ( !pDbtoolsClient )
+ pDbtoolsClient = new SwDbtoolsClient;
+ return *pDbtoolsClient;
+}
+
+void SwDBManager::RemoveDbtoolsClient()
+{
+ delete pDbtoolsClient;
+ pDbtoolsClient = 0;
+}
+
+uno::Reference<XDataSource> SwDBManager::getDataSourceAsParent(const uno::Reference< XConnection>& _xConnection,const OUString& _sDataSourceName)
+{
+ uno::Reference<XDataSource> xSource;
+ try
+ {
+ uno::Reference<XChild> xChild(_xConnection, UNO_QUERY);
+ if ( xChild.is() )
+ xSource = uno::Reference<XDataSource>(xChild->getParent(), UNO_QUERY);
+ if ( !xSource.is() )
+ xSource = SwDBManager::GetDbtoolsClient().getDataSource(_sDataSourceName, ::comphelper::getProcessComponentContext());
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("exception in getDataSourceAsParent caught");
+ }
+ return xSource;
+}
+
+uno::Reference<XResultSet> SwDBManager::createCursor(const OUString& _sDataSourceName,
+ const OUString& _sCommand,
+ sal_Int32 _nCommandType,
+ const uno::Reference<XConnection>& _xConnection
+ )
+{
+ uno::Reference<XResultSet> xResultSet;
+ try
+ {
+ uno::Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
+ if( xMgr.is() )
+ {
+ uno::Reference<XInterface> xInstance = xMgr->createInstance("com.sun.star.sdb.RowSet");
+ uno::Reference<XPropertySet> xRowSetPropSet(xInstance, UNO_QUERY);
+ if(xRowSetPropSet.is())
+ {
+ xRowSetPropSet->setPropertyValue("DataSourceName", makeAny(_sDataSourceName));
+ xRowSetPropSet->setPropertyValue("ActiveConnection", makeAny(_xConnection));
+ xRowSetPropSet->setPropertyValue("Command", makeAny(_sCommand));
+ xRowSetPropSet->setPropertyValue("CommandType", makeAny(_nCommandType));
+
+ uno::Reference< XCompletedExecution > xRowSet(xInstance, UNO_QUERY);
+
+ if ( xRowSet.is() )
+ {
+ uno::Reference< XInteractionHandler > xHandler( InteractionHandler::createWithParent(comphelper::getComponentContext(xMgr), 0), UNO_QUERY_THROW );
+ xRowSet->executeWithCompletion(xHandler);
+ }
+ xResultSet = uno::Reference<XResultSet>(xRowSet, UNO_QUERY);
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Caught exception while creating a new RowSet!");
+ }
+ return xResultSet;
+}
+
+// merge all data into one resulting document and return the number of merged documents
+sal_Int32 SwDBManager::MergeDocuments( SwMailMergeConfigItem& rMMConfig,
+ SwView& rSourceView )
+{
+ // check the availability of all data in the config item
+ uno::Reference< XResultSet> xResultSet = rMMConfig.GetResultSet();
+ if(!xResultSet.is())
+ return 0;
+ bInMerge = true;
+ sal_Int32 nRet = 0;
+ pImpl->pMergeData = new SwDSParam(
+ rMMConfig.GetCurrentDBData(), xResultSet, rMMConfig.GetSelection());
+
+ try{
+ //set to start position
+ if(pImpl->pMergeData->aSelection.getLength())
+ {
+ sal_Int32 nPos = 0;
+ pImpl->pMergeData->aSelection.getConstArray()[ pImpl->pMergeData->nSelectionIndex++ ] >>= nPos;
+ pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->absolute( nPos );
+ pImpl->pMergeData->CheckEndOfDB();
+ if(pImpl->pMergeData->nSelectionIndex >= pImpl->pMergeData->aSelection.getLength())
+ pImpl->pMergeData->bEndOfDB = true;
+ }
+ else
+ {
+ pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->first();
+ pImpl->pMergeData->CheckEndOfDB();
+ }
+ }
+ catch(const Exception&)
+ {
+ pImpl->pMergeData->bEndOfDB = true;
+ pImpl->pMergeData->CheckEndOfDB();
+ OSL_FAIL("exception in MergeNew()");
+ }
+
+ //bCancel is set from the PrintMonitor
+ bCancel = false;
+
+ CreateMonitor aMonitorDlg(&rSourceView.GetEditWin());
+ aMonitorDlg.SetCancelHdl(LINK(this, SwDBManager, PrtCancelHdl));
+ if (!IsMergeSilent())
+ {
+ aMonitorDlg.Show();
+ aMonitorDlg.Invalidate();
+ aMonitorDlg.Update();
+ // the print monitor needs some time to act
+ for( sal_uInt16 i = 0; i < 25; i++)
+ Application::Reschedule();
+ }
+
+ SwWrtShell& rSourceShell = rSourceView.GetWrtShell();
+ bool bSynchronizedDoc = rSourceShell.IsLabelDoc() && rSourceShell.GetSectionFmtCount() > 1;
+ //save the settings of the first
+ rSourceShell.SttEndDoc(true);
+ sal_uInt16 nStartingPageNo = rSourceShell.GetVirtPageNum();
+ OUString sModifiedStartingPageDesc;
+ OUString sStartingPageDesc = sModifiedStartingPageDesc = rSourceShell.GetPageDesc(
+ rSourceShell.GetCurPageDesc()).GetName();
+
+ try
+ {
+ // create a target docshell to put the merged document into
+ SfxObjectShellRef xTargetDocShell( new SwDocShell( SFX_CREATE_MODE_STANDARD ) );
+ xTargetDocShell->DoInitNew( 0 );
+ SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 );
+
+ //the created window has to be located at the same position as the source window
+ Window& rTargetWindow = pTargetFrame->GetFrame().GetWindow();
+ Window& rSourceWindow = rSourceView.GetViewFrame()->GetFrame().GetWindow();
+ rTargetWindow.SetPosPixel(rSourceWindow.GetPosPixel());
+
+ SwView* pTargetView = static_cast<SwView*>( pTargetFrame->GetViewShell() );
+ rMMConfig.SetTargetView(pTargetView);
+ //initiate SelectShell() to create sub shells
+ pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() );
+ SwWrtShell* pTargetShell = pTargetView->GetWrtShellPtr();
+ // #i63806#
+ const SwPageDesc* pSourcePageDesc = rSourceShell.FindPageDescByName( sStartingPageDesc );
+ const SwFrmFmt& rMaster = pSourcePageDesc->GetMaster();
+ bool bPageStylesWithHeaderFooter = rMaster.GetHeader().IsActive() ||
+ rMaster.GetFooter().IsActive();
+
+ // copy compatibility options
+ lcl_CopyCompatibilityOptions( rSourceShell, *pTargetShell);
+ // #72821# copy dynamic defaults
+ lcl_CopyDynamicDefaults( *rSourceShell.GetDoc(), *pTargetShell->GetDoc() );
+
+ long nStartRow, nEndRow;
+ sal_uLong nDocNo = 1;
+ sal_Int32 nDocCount = 0;
+ if( !IsMergeSilent() && lcl_getCountFromResultSet( nDocCount, pImpl->pMergeData->xResultSet ) )
+ aMonitorDlg.SetTotalCount( nDocCount );
+
+ do
+ {
+ nStartRow = pImpl->pMergeData->xResultSet->getRow();
+ if (!IsMergeSilent())
+ {
+ aMonitorDlg.SetCurrentPosition( nDocNo );
+ aMonitorDlg.Invalidate();
+ aMonitorDlg.Update();
+ // the print monitor needs some time to act
+ for( sal_uInt16 i = 0; i < 25; i++)
+ Application::Reschedule();
+ }
+
+ // copy the source document
+ // the copy will be closed later, but it is more safe to use SfxObjectShellLock here
+ SfxObjectShellLock xWorkDocSh;
+ if(nDocNo == 1 )
+ {
+ uno::Reference< util::XCloneable > xClone( rSourceView.GetDocShell()->GetModel(), uno::UNO_QUERY);
+ uno::Reference< lang::XUnoTunnel > xWorkDocShell( xClone->createClone(), uno::UNO_QUERY);
+ SwXTextDocument* pWorkModel = reinterpret_cast<SwXTextDocument*>(xWorkDocShell->getSomething(SwXTextDocument::getUnoTunnelId()));
+ xWorkDocSh = pWorkModel->GetDocShell();
+ }
+ else
+ {
+ xWorkDocSh = rSourceView.GetDocShell()->GetDoc()->CreateCopy(true);
+ }
+ //create a ViewFrame
+ SwView* pWorkView = static_cast< SwView* >( SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 )->GetViewShell() );
+ SwWrtShell& rWorkShell = pWorkView->GetWrtShell();
+ pWorkView->AttrChangedNotify( &rWorkShell );// in order for SelectShell to be called
+
+ // merge the data
+ SwDoc* pWorkDoc = rWorkShell.GetDoc();
+ SwDBManager* pWorkDBManager = pWorkDoc->GetDBManager();
+ pWorkDoc->SetDBManager( this );
+ pWorkDoc->EmbedAllLinks();
+ SwUndoId nLastUndoId(UNDO_EMPTY);
+ if (rWorkShell.GetLastUndoInfo(0, & nLastUndoId))
+ {
+ if (UNDO_UI_DELETE_INVISIBLECNTNT == nLastUndoId)
+ {
+ rWorkShell.Undo();
+ }
+ }
+ // #i69485# lock fields to prevent access to the result set while calculating layout
+ rWorkShell.LockExpFlds();
+ // create a layout
+ rWorkShell.CalcLayout();
+ rWorkShell.UnlockExpFlds();
+ SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), rWorkShell.GetView().GetViewFrame()->GetObjectShell()));
+ rWorkShell.SwViewShell::UpdateFlds();
+ SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), rWorkShell.GetView().GetViewFrame()->GetObjectShell()));
+
+ // strip invisible content and convert fields to text
+ rWorkShell.RemoveInvisibleContent();
+ rWorkShell.ConvertFieldsToText();
+ rWorkShell.SetNumberingRestart();
+ if( bSynchronizedDoc )
+ {
+ lcl_RemoveSectionLinks( rWorkShell );
+ }
+
+ // insert the document into the target document
+ rWorkShell.SttEndDoc(false);
+ rWorkShell.SttEndDoc(true);
+ rWorkShell.SelAll();
+ pTargetShell->SttEndDoc(false);
+
+ //#i63806# put the styles to the target document
+ //if the source uses headers or footers each new copy need to copy a new page styles
+ if(bPageStylesWithHeaderFooter)
+ {
+ //create a new pagestyle
+ //copy the pagedesc from the current document to the new document and change the name of the to-be-applied style
+
+ SwDoc* pTargetDoc = pTargetShell->GetDoc();
+ OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo );
+ pTargetShell->GetDoc()->MakePageDesc( sNewPageDescName );
+ SwPageDesc* pTargetPageDesc = pTargetShell->FindPageDescByName( sNewPageDescName );
+ const SwPageDesc* pWorkPageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc );
+
+ if(pWorkPageDesc && pTargetPageDesc)
+ {
+ pTargetDoc->CopyPageDesc( *pWorkPageDesc, *pTargetPageDesc, false );
+ sModifiedStartingPageDesc = sNewPageDescName;
+ lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo );
+ }
+ }
+ if(nDocNo == 1 || bPageStylesWithHeaderFooter)
+ {
+ pTargetView->GetDocShell()->_LoadStyles( *rSourceView.GetDocShell(), true );
+ }
+ if(nDocNo > 1)
+ {
+ pTargetShell->InsertPageBreak( &sModifiedStartingPageDesc, nStartingPageNo );
+ }
+ else
+ {
+ pTargetShell->SetPageStyle(sModifiedStartingPageDesc);
+ }
+ sal_uInt16 nPageCountBefore = pTargetShell->GetPageCnt();
+ OSL_ENSURE(!pTargetShell->GetTableFmt(),"target document ends with a table - paragraph should be appended");
+ //#i51359# add a second paragraph in case there's only one
+ {
+ SwNodeIndex aIdx( pWorkDoc->GetNodes().GetEndOfExtras(), 2 );
+ SwPosition aTestPos( aIdx );
+ SwCursor aTestCrsr(aTestPos,0,false);
+ if(!aTestCrsr.MovePara(fnParaNext, fnParaStart))
+ {
+ //append a paragraph
+ pWorkDoc->AppendTxtNode( aTestPos );
+ }
+ }
+ pTargetShell->Paste( rWorkShell.GetDoc(), true );
+ //convert fields in page styles (header/footer - has to be done after the first document has been pasted
+ if(1 == nDocNo)
+ {
+ pTargetShell->CalcLayout();
+ pTargetShell->ConvertFieldsToText();
+ }
+ //add the document info to the config item
+ SwDocMergeInfo aMergeInfo;
+ aMergeInfo.nStartPageInTarget = nPageCountBefore;
+ //#i72820# calculate layout to be able to find the correct page index
+ pTargetShell->CalcLayout();
+ aMergeInfo.nEndPageInTarget = pTargetShell->GetPageCnt();
+ aMergeInfo.nDBRow = nStartRow;
+ rMMConfig.AddMergedDocument( aMergeInfo );
+ ++nRet;
+
+ // the print monitor needs some time to act
+ for( sal_uInt16 i = 0; i < 25; i++)
+ Application::Reschedule();
+
+ //restore the ole DBManager
+ pWorkDoc->SetDBManager( pWorkDBManager );
+ //now the temporary document should be closed
+ SfxObjectShellRef xDocSh(pWorkView->GetDocShell());
+ xDocSh->DoClose();
+ nEndRow = pImpl->pMergeData->xResultSet->getRow();
+ ++nDocNo;
+ } while( !bCancel &&
+ (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord()));
+
+ //deselect all, go out of the frame and go to the beginning of the document
+ Point aPt(LONG_MIN, LONG_MIN);
+ pTargetShell->SelectObj(aPt, SW_LEAVE_FRAME);
+ if (pTargetShell->IsSelFrmMode())
+ {
+ pTargetShell->UnSelectFrm();
+ pTargetShell->LeaveSelFrmMode();
+ }
+ pTargetShell->EnterStdMode();
+ pTargetShell->SttDoc();
+
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("exception caught in SwDBManager::MergeDocuments");
+ }
+ DELETEZ(pImpl->pMergeData);
+ bInMerge = false;
+ return nRet;
+}
+
+SwConnectionDisposedListener_Impl::SwConnectionDisposedListener_Impl(SwDBManager& rMgr) :
+ rDBManager(rMgr)
+{
+};
+
+SwConnectionDisposedListener_Impl::~SwConnectionDisposedListener_Impl()
+{
+};
+
+void SwConnectionDisposedListener_Impl::disposing( const EventObject& rSource )
+ throw (RuntimeException, std::exception)
+{
+ ::SolarMutexGuard aGuard;
+ uno::Reference<XConnection> xSource(rSource.Source, UNO_QUERY);
+ for(sal_uInt16 nPos = rDBManager.aDataSourceParams.size(); nPos; nPos--)
+ {
+ SwDSParam* pParam = &rDBManager.aDataSourceParams[nPos - 1];
+ if(pParam->xConnection.is() &&
+ (xSource == pParam->xConnection))
+ {
+ rDBManager.aDataSourceParams.erase(rDBManager.aDataSourceParams.begin() + nPos - 1);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */