From d8ff907197037045fd0cb173e341f515968b65b1 Mon Sep 17 00:00:00 2001 From: Juergen Funk Date: Thu, 3 Dec 2015 16:04:15 +0100 Subject: tdf93236 N-UP printing in combination with mailmerge broken file-print 1/4 Refactory the methode "MergeMailFiles" Change-Id: I65441ade522c06335b0da23cb2fed9afc5bcb72e Reviewed-on: https://gerrit.libreoffice.org/20714 Reviewed-by: Katarina Behrens Tested-by: Katarina Behrens --- include/vcl/print.hxx | 2 +- sw/CppunitTest_sw_globalfilter.mk | 1 + sw/CppunitTest_sw_odfexport.mk | 1 + sw/CppunitTest_sw_odfimport.mk | 1 + sw/CppunitTest_sw_ooxmlfieldexport.mk | 1 + sw/CppunitTest_sw_ooxmlimport.mk | 1 + sw/CppunitTest_sw_ooxmlw14export.mk | 1 + sw/CppunitTest_sw_rtfexport.mk | 1 + sw/CppunitTest_sw_rtfimport.mk | 1 + sw/CppunitTest_sw_ww8import.mk | 1 + sw/inc/dbmgr.hxx | 99 +++- sw/ooxmlexport_setup.mk | 1 + sw/qa/extras/inc/swmodeltestbase.hxx | 2 + sw/source/uibase/dbui/dbmgr.cxx | 995 ++++++++++++++++++++-------------- 14 files changed, 685 insertions(+), 423 deletions(-) diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx index b8f32ff300b0..bb30f8ee3371 100644 --- a/include/vcl/print.hxx +++ b/include/vcl/print.hxx @@ -574,7 +574,7 @@ public: VCL_PLUGIN_PUBLIC void createProgressDialog(); VCL_PLUGIN_PUBLIC bool isProgressCanceled() const; SAL_DLLPRIVATE void setMultipage( const MultiPageSetup& ); - SAL_DLLPRIVATE const MultiPageSetup& + VCL_PLUGIN_PUBLIC const MultiPageSetup& getMultipage() const; VCL_PLUGIN_PUBLIC void setLastPage( bool i_bLastPage ); SAL_DLLPRIVATE void setReversePrint( bool i_bReverse ); diff --git a/sw/CppunitTest_sw_globalfilter.mk b/sw/CppunitTest_sw_globalfilter.mk index 66502663862c..a74cb66abf0d 100644 --- a/sw/CppunitTest_sw_globalfilter.mk +++ b/sw/CppunitTest_sw_globalfilter.mk @@ -39,6 +39,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_globalfilter,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_odfexport.mk b/sw/CppunitTest_sw_odfexport.mk index c6434ac1574e..aa5a40ada328 100644 --- a/sw/CppunitTest_sw_odfexport.mk +++ b/sw/CppunitTest_sw_odfexport.mk @@ -38,6 +38,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_odfexport,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_odfimport.mk b/sw/CppunitTest_sw_odfimport.mk index eaa3542993d4..c5937d3f2ef5 100644 --- a/sw/CppunitTest_sw_odfimport.mk +++ b/sw/CppunitTest_sw_odfimport.mk @@ -40,6 +40,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_odfimport,\ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/source/uibase/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_ooxmlfieldexport.mk b/sw/CppunitTest_sw_ooxmlfieldexport.mk index ae67c2087438..086e53ea115e 100644 --- a/sw/CppunitTest_sw_ooxmlfieldexport.mk +++ b/sw/CppunitTest_sw_ooxmlfieldexport.mk @@ -30,6 +30,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_ooxmlfieldexport,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_ooxmlimport.mk b/sw/CppunitTest_sw_ooxmlimport.mk index 4074255a7cf3..1a275bfcfbab 100644 --- a/sw/CppunitTest_sw_ooxmlimport.mk +++ b/sw/CppunitTest_sw_ooxmlimport.mk @@ -39,6 +39,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_ooxmlimport,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_ooxmlw14export.mk b/sw/CppunitTest_sw_ooxmlw14export.mk index 5958019b8820..d6bcd07be9ee 100644 --- a/sw/CppunitTest_sw_ooxmlw14export.mk +++ b/sw/CppunitTest_sw_ooxmlw14export.mk @@ -30,6 +30,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_ooxmlw14export,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_rtfexport.mk b/sw/CppunitTest_sw_rtfexport.mk index b47c9068a705..0228ee00112b 100644 --- a/sw/CppunitTest_sw_rtfexport.mk +++ b/sw/CppunitTest_sw_rtfexport.mk @@ -37,6 +37,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_rtfexport,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_rtfimport.mk b/sw/CppunitTest_sw_rtfimport.mk index 3eafcea38e58..9cfa5b4aea25 100644 --- a/sw/CppunitTest_sw_rtfimport.mk +++ b/sw/CppunitTest_sw_rtfimport.mk @@ -39,6 +39,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_rtfimport,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/CppunitTest_sw_ww8import.mk b/sw/CppunitTest_sw_ww8import.mk index ed28ae9d641c..80cde283bcc2 100644 --- a/sw/CppunitTest_sw_ww8import.mk +++ b/sw/CppunitTest_sw_ww8import.mk @@ -36,6 +36,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_ww8import,\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/inc/dbmgr.hxx b/sw/inc/dbmgr.hxx index f5b752fc9af8..580b0f1ecdad 100644 --- a/sw/inc/dbmgr.hxx +++ b/sw/inc/dbmgr.hxx @@ -30,6 +30,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -40,6 +45,7 @@ namespace com{namespace sun{namespace star{ class XStatement; class XDataSource; class XResultSet; + class xRowSet; } namespace beans{ @@ -82,6 +88,8 @@ class SwMailMergeConfigItem; class SwCalc; class INetURLObject; class SwDocShell; +class SwDoc; +class SfxFilter; enum DBManagerOptions { @@ -223,7 +231,80 @@ friend class SwConnectionDisposedListener_Impl; /// merge to file _and_ merge to e-Mail SAL_DLLPRIVATE bool MergeMailFiles(SwWrtShell* pSh, const SwMergeDescriptor& rMergeDescriptor, vcl::Window* pParent ); - SAL_DLLPRIVATE bool ToNextRecord(SwDSParam* pParam); + SAL_DLLPRIVATE bool ToNextRecord(SwDSParam* pParam, bool bReset); + + static css::uno::Reference< css::sdbc::XRowSet> + GetRowSet(css::uno::Reference< css::sdbc::XConnection>, + const OUString& rTableOrQuery, SwDBSelect eTableOrQuery); + + SAL_DLLPRIVATE static css::uno::Reference< css::beans::XPropertySet> + GetRowSupplier(css::uno::Reference< css::sdbc::XConnection> xConnection, + const OUString& rTableOrQuery, SwDBSelect eTableOrQuery) + { + css::uno::Reference xRowSet = GetRowSet(xConnection, rTableOrQuery, eTableOrQuery); + + return css::uno::Reference( xRowSet, css::uno::UNO_QUERY ); + } + + SAL_DLLPRIVATE void CreateDumpDocs(sal_Int32 &nMaxDumpDocs); + + SAL_DLLPRIVATE void SetSourceProp(SwDocShell* pSourceDocSh); + + SAL_DLLPRIVATE void GetPathAddress(OUString &sPath, OUString &sAddress, + css::uno::Reference< css::beans::XPropertySet > xColumnProp); + + SAL_DLLPRIVATE bool CreateNewTemp(OUString &sPath, const OUString &sAddress, + std::unique_ptr< utl::TempFile > &aTempFile, + const SwMergeDescriptor& rMergeDescriptor, const SfxFilter* pStoreToFilter); + + SAL_DLLPRIVATE void UpdateProgressDlg(bool bMergeShell, VclPtr pProgressDlg, bool createTempFile, + std::unique_ptr< INetURLObject > &aTempFileURL, + SwDocShell *pSourceDocSh, sal_Int32 nDocNo); + + SAL_DLLPRIVATE bool CreateTargetDocShell(sal_Int32 nMaxDumpDocs, bool bMergeShell, vcl::Window *pSourceWindow, + SwWrtShell *pSourceShell, SwDocShell *pSourceDocSh, + SfxObjectShellRef &xTargetDocShell, SwDoc *&pTargetDoc, + SwWrtShell *&pTargetShell, SwView *&pTargetView, + sal_uInt16 &nStartingPageNo, OUString &sStartingPageDesc); + + SAL_DLLPRIVATE void LockUnlockDisp(bool bLock, SwDocShell *pSourceDocSh); + + SAL_DLLPRIVATE void CreateProgessDlg(vcl::Window *&pSourceWindow, VclPtr &pProgressDlg, + bool bMergeShell, SwWrtShell *pSourceShell, vcl::Window *pParent); + + SAL_DLLPRIVATE void CreateWorkDoc(SfxObjectShellLock &xWorkDocSh, SwView *&pWorkView, SwDoc *&pWorkDoc, SwDBManager *&pOldDBManager, + SwDocShell *pSourceDocSh, sal_Int32 nMaxDumpDocs, sal_Int32 nDocNo); + + SAL_DLLPRIVATE void UpdateExpFields(SwWrtShell& rWorkShell, SfxObjectShellLock xWorkDocSh); + + SAL_DLLPRIVATE void CreateStoreToFilter(const SfxFilter *&pStoreToFilter, const OUString *&pStoreToFilterOptions, + SwDocShell *pSourceDocSh, bool bEMail, const SwMergeDescriptor &rMergeDescriptor); + + SAL_DLLPRIVATE void MergeSingleFiles(SwDoc *pWorkDoc, SwWrtShell &rWorkShell, SwWrtShell *pTargetShell, SwDoc *pTargetDoc, + SfxObjectShellLock &xWorkDocSh, SfxObjectShellRef xTargetDocShell, + bool bPageStylesWithHeaderFooter, bool bSynchronizedDoc, + OUString &sModifiedStartingPageDesc, OUString &sStartingPageDesc, sal_Int32 nDocNo, + long nStartRow, sal_uInt16 nStartingPageNo, int &targetDocPageCount, const bool bMergeShell, + const SwMergeDescriptor& rMergeDescriptor, sal_Int32 nMaxDumpDocs); + + SAL_DLLPRIVATE void ResetWorkDoc(SwDoc *pWorkDoc, SfxObjectShellLock &xWorkDocSh, SwDBManager *pOldDBManager); + + SAL_DLLPRIVATE void FreezeLayouts(SwWrtShell *pTargetShell, bool freeze); + + SAL_DLLPRIVATE void FinishMailMergeFile(SfxObjectShellLock &xWorkDocSh, SwView *pWorkView, SwDoc *pTargetDoc, + SwWrtShell *pTargetShell, bool bCreateSingleFile, bool bPrinter, + SwDoc *pWorkDoc, SwDBManager *pOldDBManager); + + SAL_DLLPRIVATE bool SavePrintDoc(SfxObjectShellRef xTargetDocShell, SwView *pTargetView, + const SwMergeDescriptor &rMergeDescriptor, + std::unique_ptr< utl::TempFile > &aTempFile, + const SfxFilter *&pStoreToFilter, const OUString *&pStoreToFilterOptions, + const bool bMergeShell, bool bCreateSingleFile, const bool bPrinter); + + SAL_DLLPRIVATE void SetPrinterOptions(const SwMergeDescriptor &rMergeDescriptor, + css::uno::Sequence< css::beans::PropertyValue > &aOptions); + + SAL_DLLPRIVATE void RemoveTmpFiles(::std::vector< OUString> &aFilesToRemove); SwDBManager(SwDBManager const&) = delete; SwDBManager& operator=(SwDBManager const&) = delete; @@ -278,6 +359,13 @@ public: SvNumberFormatter* pNFormatr, long nLanguage ); + sal_Int32 GetRowCount(const OUString& rDBName, const OUString& rTableName); + + static sal_Int32 GetRowCount(css::uno::Reference< css::sdbc::XConnection> xConnection, + const OUString& rTableName); + + sal_Int32 GetRowCount() const; + sal_uLong GetColumnFormat( const OUString& rDBName, const OUString& rTableName, const OUString& rColNm, @@ -342,9 +430,14 @@ public: css::uno::Reference< css::sdbc::XDataSource>& rxSource); static css::uno::Reference< css::sdbcx::XColumnsSupplier> - GetColumnSupplier(css::uno::Reference< css::sdbc::XConnection>, + GetColumnSupplier(css::uno::Reference< css::sdbc::XConnection> xConnection, const OUString& rTableOrQuery, - SwDBSelect eTableOrQuery = SwDBSelect::UNKNOWN); + SwDBSelect eTableOrQuery = SwDBSelect::UNKNOWN) + { + css::uno::Reference xRowSet = GetRowSet(xConnection, rTableOrQuery, eTableOrQuery); + + return css::uno::Reference( xRowSet, css::uno::UNO_QUERY ); + } static css::uno::Sequence GetExistingDatabaseNames(); diff --git a/sw/ooxmlexport_setup.mk b/sw/ooxmlexport_setup.mk index c4a0981c30f9..9c89c28dd433 100644 --- a/sw/ooxmlexport_setup.mk +++ b/sw/ooxmlexport_setup.mk @@ -93,6 +93,7 @@ $(eval $(call gb_CppunitTest_set_include,sw_ooxmlexport$(1),\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/qa/extras/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ $$(INCLUDE) \ )) diff --git a/sw/qa/extras/inc/swmodeltestbase.hxx b/sw/qa/extras/inc/swmodeltestbase.hxx index 273bdfce3338..ce02b3e51cf3 100644 --- a/sw/qa/extras/inc/swmodeltestbase.hxx +++ b/sw/qa/extras/inc/swmodeltestbase.hxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx index 0c0a7c7aaf2d..3074fde75728 100644 --- a/sw/source/uibase/dbui/dbmgr.cxx +++ b/sw/source/uibase/dbui/dbmgr.cxx @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -73,7 +72,6 @@ #include #include #include -#include #include #include #include @@ -89,9 +87,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -450,29 +446,7 @@ bool SwDBManager::MergeNew( const SwMergeDescriptor& rMergeDesc, vcl::Window* pP 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 uno::Exception& e) - { - pImpl->pMergeData->bEndOfDB = true; - pImpl->pMergeData->CheckEndOfDB(); - SAL_WARN("sw.mailmerge", "exception in MergeNew(): " << e.Message); - } + ToNextRecord(pImpl->pMergeData, true); uno::Reference xSource = SwDBManager::getDataSourceAsParent(xConnection,aData.sDataSource); @@ -740,18 +714,8 @@ void SwDBManager::GetColumnNames(ListBox* pListBox, OUString sDBName(rDBName); xConnection = RegisterConnection( sDBName ); } - uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName); - if(xColsSupp.is()) - { - uno::Reference xCols = xColsSupp->getColumns(); - const uno::Sequence aColNames = xCols->getElementNames(); - const OUString* pColNames = aColNames.getConstArray(); - for(int nCol = 0; nCol < aColNames.getLength(); nCol++) - { - pListBox->InsertEntry(pColNames[nCol]); - } - ::comphelper::disposeComponent( xColsSupp ); - } + + GetColumnNames(pListBox, xConnection, rTableName, bAppend); } void SwDBManager::GetColumnNames(ListBox* pListBox, @@ -774,6 +738,56 @@ void SwDBManager::GetColumnNames(ListBox* pListBox, } } + +sal_Int32 SwDBManager::GetRowCount(const OUString& rDBName, const OUString& rTableName) +{ + SwDBData aData; + aData.sDataSource = rDBName; + aData.sCommand = rTableName; + aData.nCommandType = -1; + SwDSParam* pParam = FindDSData(aData, false); + uno::Reference xConnection; + if(pParam && pParam->xConnection.is()) + xConnection = pParam->xConnection; + else + { + OUString sDBName(rDBName); + xConnection = RegisterConnection( sDBName ); + } + + return GetRowCount(xConnection, rTableName); +} + + +sal_Int32 SwDBManager::GetRowCount(uno::Reference xConnection, + const OUString& rTableName) +{ + uno::Reference xRow = GetRowSupplier(xConnection, rTableName, SwDBSelect::UNKNOWN); + sal_Int32 nCnt = 0; + + if(xRow.is()) + xRow->getPropertyValue( "RowCount" ) >>= nCnt; + + return nCnt; +} + + + +sal_Int32 SwDBManager::GetRowCount() const +{ + sal_Int32 nCnt = pImpl->pMergeData->aSelection.getLength(); + + if(nCnt == 0) + { + uno::Reference xProp(pImpl->pMergeData->xResultSet, uno::UNO_QUERY); + if(xProp.is()) + xProp->getPropertyValue("RowCount") >>= nCnt; + } + + return nCnt; +} + + SwDBManager::SwDBManager(SwDoc* pDoc) : bCancel(false) , bInitDBFields(false) @@ -913,16 +927,9 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, OUString sBodyMimeType; rtl_TextEncoding eEncoding = ::osl_getThreadTextEncoding(); - static const char *sMaxDumpDocs = nullptr; static sal_Int32 nMaxDumpDocs = 0; - if (!sMaxDumpDocs) - { - sMaxDumpDocs = getenv("SW_DEBUG_MAILMERGE_DOCS"); - if (!sMaxDumpDocs) - sMaxDumpDocs = ""; - else - nMaxDumpDocs = rtl_ustr_toInt32(reinterpret_cast( sMaxDumpDocs ), 10); - } + + CreateDumpDocs(nMaxDumpDocs); if(bEMail) { @@ -957,40 +964,17 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, SfxDispatcher* pSfxDispatcher = pSourceShell->GetView().GetViewFrame()->GetDispatcher(); SwDocShell* pSourceDocSh = pSourceShell->GetView().GetDocShell(); - uno::Reference xSourceDocProps; - { - uno::Reference - xDPS(pSourceDocSh->GetModel(), uno::UNO_QUERY); - xSourceDocProps.set(xDPS->getDocumentProperties()); - OSL_ENSURE(xSourceDocProps.is(), "DocumentProperties is null"); - } + SetSourceProp(pSourceDocSh); if( !bMergeShell && pSourceDocSh->IsModified() ) pSfxDispatcher->Execute( pSourceDocSh->HasName() ? SID_SAVEDOC : SID_SAVEASDOC, SfxCallMode::SYNCHRON|SfxCallMode::RECORD); if( bMergeShell || !pSourceDocSh->IsModified() ) { - const SfxFilter* pStoreToFilter = SwIoSystem::GetFileFilter( - pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::NO_DECODE)); - SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer(); + const SfxFilter* pStoreToFilter = nullptr; const OUString* pStoreToFilterOptions = nullptr; - // 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, SfxFilterFlags::EXPORT); - } - else if( !rMergeDescriptor.sSaveToFilter.isEmpty()) - { - const SfxFilter* pFilter = - pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter ); - if(pFilter) - { - pStoreToFilter = pFilter; - if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty()) - pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions; - } - } + CreateStoreToFilter(pStoreToFilter, pStoreToFilterOptions, pSourceDocSh, bEMail, rMergeDescriptor); + bCancel = false; // in case of creating a single resulting file this has to be created here @@ -1001,7 +985,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, SwView* pTargetView = nullptr; std::unique_ptr< utl::TempFile > aTempFile; - bool createTempFile = ( rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL || rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE ); + bool createTempFile = ( bEMail || rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE ); OUString sModifiedStartingPageDesc; OUString sStartingPageDesc; sal_uInt16 nStartingPageNo = 0; @@ -1010,78 +994,21 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, vcl::Window *pSourceWindow = nullptr; VclPtr pProgressDlg; - if (!IsMergeSilent()) { - pSourceWindow = &pSourceShell->GetView().GetEditWin(); - if( ! pParent ) - pParent = pSourceWindow; - if( bMergeShell ) - pProgressDlg = VclPtr::Create( pParent, pParent != pSourceWindow ); - else { - pProgressDlg = VclPtr::Create( pParent, pParent != pSourceWindow, PrintMonitor::MONITOR_TYPE_PRINT ); - static_cast( pProgressDlg.get() )->SetText(pSourceShell->GetView().GetDocShell()->GetTitle(22)); - } - pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) ); - pProgressDlg->Show(); - - for( sal_uInt16 i = 0; i < 25; i++) - Application::Reschedule(); - } + CreateProgessDlg(pSourceWindow, pProgressDlg, bMergeShell, pSourceShell, pParent); if(bCreateSingleFile) { - // create a target docshell to put the merged document into - xTargetDocShell = new SwDocShell( SfxObjectCreateMode::STANDARD ); - xTargetDocShell->DoInitNew(); - if (nMaxDumpDocs) - lcl_SaveDoc( xTargetDocShell, "MergeDoc" ); - SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 ); - if (bMergeShell && pSourceWindow) { - //the created window has to be located at the same position as the source window - vcl::Window& rTargetWindow = pTargetFrame->GetFrame().GetWindow(); - rTargetWindow.SetPosPixel(pSourceWindow->GetPosPixel()); - } - - pTargetView = static_cast( pTargetFrame->GetViewShell() ); - - //initiate SelectShell() to create sub shells - pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() ); - pTargetShell = pTargetView->GetWrtShellPtr(); - pTargetDoc = pTargetShell->GetDoc(); - pTargetDoc->SetInMailMerge(true); - - //copy the styles from the source to the target document - pTargetView->GetDocShell()->_LoadStyles( *pSourceDocSh, true ); + bPageStylesWithHeaderFooter = CreateTargetDocShell(nMaxDumpDocs, bMergeShell, pSourceWindow, pSourceShell, + pSourceDocSh, xTargetDocShell, pTargetDoc, pTargetShell, + pTargetView, nStartingPageNo, sStartingPageDesc); - //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(); - - // #i72517# - const SwPageDesc* pSourcePageDesc = pSourceShell->FindPageDescByName( sStartingPageDesc ); - const SwFrameFormat& rMaster = pSourcePageDesc->GetMaster(); - bPageStylesWithHeaderFooter = rMaster.GetHeader().IsActive() || - rMaster.GetFooter().IsActive(); - - // copy compatibility options - pTargetShell->GetDoc()->ReplaceCompatibilityOptions( *pSourceShell->GetDoc()); - // #72821# copy dynamic defaults - pTargetShell->GetDoc()->ReplaceDefaults( *pSourceShell->GetDoc()); - - pTargetShell->GetDoc()->ReplaceDocumentProperties( *pSourceShell->GetDoc()); + sModifiedStartingPageDesc = sStartingPageDesc; } - // Progress, to prohibit KeyInputs SfxProgress aProgress(pSourceDocSh, ::aEmptyOUStr, 1); // lock all dispatchers - SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); - while (pViewFrame) - { - pViewFrame->GetDispatcher()->Lock(true); - pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); - } + LockUnlockDisp(true, pSourceDocSh); sal_Int32 nDocNo = 1; sal_Int32 nDocCount = 0; @@ -1115,168 +1042,38 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, 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; - } + GetPathAddress(sPath, sAddress, xColumnProp); // create a new temporary file name - only done once in case of bCreateSingleFile if( createTempFile && ( 1 == nDocNo || !bCreateSingleFile )) - { - 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( rMergeDescriptor.bSubjectIsFilename ) - aTempFile->EnableKillingFile(); - if( !aTempFile->IsValid() ) - { - ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED ); - bNoError = false; - bCancel = true; - } - } + bNoError = CreateNewTemp(sPath, sAddress, aTempFile, rMergeDescriptor, pStoreToFilter); if( !bCancel ) { std::unique_ptr< INetURLObject > aTempFileURL; if( createTempFile ) aTempFileURL.reset( new INetURLObject(aTempFile->GetURL())); - if (!IsMergeSilent()) { - if( bMergeShell ) - static_cast( pProgressDlg.get() )->SetCurrentPosition( nDocNo ); - else { - PrintMonitor *pPrintMonDlg = static_cast( pProgressDlg.get() ); - pPrintMonDlg->m_pPrinter->SetText( createTempFile ? aTempFileURL->GetBase() : OUString( pSourceDocSh->GetTitle( 22 ))); - OUString sStat(SW_RES(STR_STATSTR_LETTER)); // Brief - sStat += " "; - sStat += OUString::number( nDocNo ); - pPrintMonDlg->m_pPrintInfo->SetText( sStat ); - } - pProgressDlg->Update(); - } - // Computation time for the GUI - for( sal_uInt16 i = 0; i < 25; i++ ) - Application::Reschedule(); + UpdateProgressDlg(bMergeShell, pProgressDlg, createTempFile, aTempFileURL, pSourceDocSh, nDocNo); + // Create a copy of the source document and work with that one instead of the source. // If we're not in the single file mode (which requires modifying the document for the merging), // it is enough to do this just once. if( 1 == nDocNo || bCreateSingleFile ) - { - assert( !xWorkDocSh.Is()); - // copy the source document - xWorkDocSh = pSourceDocSh->GetDoc()->CreateCopy( true ); - - //create a view frame for the document - pWorkView = static_cast< SwView* >( SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 )->GetViewShell() ); - //request the layout calculation - SwWrtShell& rWorkShell = pWorkView->GetWrtShell(); - pWorkView->AttrChangedNotify( &rWorkShell );// in order for SelectShell to be called - - pWorkDoc = rWorkShell.GetDoc(); - pWorkDoc->ReplaceDocumentProperties( *pSourceDocSh->GetDoc()); - if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) - lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo ); - pOldDBManager = pWorkDoc->GetDBManager(); - pWorkDoc->SetDBManager( this ); - pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks(); - - // #i69458# lock fields to prevent access to the result set while calculating layout - // tdf#92324: and do not unlock: keep document locked during printing to avoid - // ExpFields update during printing, generation of preview, etc. - rWorkShell.LockExpFields(); - rWorkShell.CalcLayout(); - } + CreateWorkDoc(xWorkDocSh, pWorkView, pWorkDoc, pOldDBManager, pSourceDocSh, nMaxDumpDocs, nDocNo); - SwWrtShell& rWorkShell = pWorkView->GetWrtShell(); - SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), xWorkDocSh)); - // tdf#92324: Allow ExpFields update only by explicit instruction to avoid - // database cursor movement on any other fields update, for example during - // print preview and other operations - if ( rWorkShell.IsExpFieldsLocked() ) - rWorkShell.UnlockExpFields(); - rWorkShell.SwViewShell::UpdateFields(); - rWorkShell.LockExpFields(); - SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh)); - - // launch MailMergeEvent if required - const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc(); - if(pEvtSrc) - { - uno::Reference< uno::XInterface > xRef( const_cast(static_cast(pEvtSrc)) ); - text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() ); - pEvtSrc->LaunchMailMergeEvent( aEvt ); - } + SwWrtShell &rWorkShell = pWorkView->GetWrtShell(); + + UpdateExpFields(rWorkShell, xWorkDocSh); if(bCreateSingleFile) { - pWorkDoc->RemoveInvisibleContent(); + MergeSingleFiles(pWorkDoc, rWorkShell, pTargetShell, pTargetDoc, xWorkDocSh, xTargetDocShell, + bPageStylesWithHeaderFooter, bSynchronizedDoc, sModifiedStartingPageDesc, + sStartingPageDesc, nDocNo, nStartRow, nStartingPageNo, targetDocPageCount, + bMergeShell, rMergeDescriptor, nMaxDumpDocs); - 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 - - //#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 - SwPageDesc* pTargetPageDesc(nullptr); - 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 - OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo ); - pTargetPageDesc = pTargetDoc->MakePageDesc( sNewPageDescName ); - const SwPageDesc* pWorkPageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc ); - - if(pWorkPageDesc && pTargetPageDesc) - { - pTargetDoc->CopyPageDesc( *pWorkPageDesc, *pTargetPageDesc, false ); - sModifiedStartingPageDesc = sNewPageDescName; - lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo ); - } - } - else - pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc ); - - if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) - lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo ); - if( targetDocPageCount % 2 == 1 ) - ++targetDocPageCount; // Docs always start on odd pages (so offset must be even). - SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc(*rWorkShell.GetDoc(), - nStartingPageNo, pTargetPageDesc, nDocNo == 1, targetDocPageCount); - targetDocPageCount += rWorkShell.GetPageCnt(); - if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) - lcl_SaveDoc( xTargetDocShell, "MergeDoc" ); - if (bMergeShell) - { - SwDocMergeInfo aMergeInfo; - // Name of the mark is actually irrelevant, UNO bookmarks have internals names. - aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark( appendedDocStart, "", - IDocumentMarkAccess::MarkType::UNO_BOOKMARK ); - aMergeInfo.nDBRow = nStartRow; - rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo ); - } } else if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER ) { @@ -1293,19 +1090,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, aOptions[ 1 ].Name = "MonitorVisible"; aOptions[ 1 ].Value <<= sal_False; // 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 ; - } - } + SetPrinterOptions(rMergeDescriptor, aOptions); pWorkView->StartPrint( aOptions, IsMergeSilent(), rMergeDescriptor.bPrintAsync ); SfxPrinter* pDocPrt = pWorkView->GetPrinter(); JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : SfxViewShell::GetJobSetup(); @@ -1427,9 +1212,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } if( bCreateSingleFile ) { - pWorkDoc->SetDBManager( pOldDBManager ); - xWorkDocSh->DoClose(); - xWorkDocSh = nullptr; + ResetWorkDoc(pWorkDoc, xWorkDocSh, pOldDBManager); } } } @@ -1440,149 +1223,506 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, // sub-document, to get the correct PageDesc. if(!bFreezedLayouts && bCreateSingleFile) { - for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) - aLayout->FreezeLayout(true); + FreezeLayouts(pTargetShell, true); bFreezedLayouts = true; } } while( !bCancel && (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord())); - if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() ) - { - // Unlock document fields after merge complete - pWorkView->GetWrtShell().UnlockExpFields(); - } + FinishMailMergeFile(xWorkDocSh, pWorkView, pTargetDoc, pTargetShell, bCreateSingleFile, rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER, + pWorkDoc, pOldDBManager); - if( !bCreateSingleFile ) - { - if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER ) - { - Printer::FinishPrintJob( pWorkView->GetPrinterController()); + pProgressDlg.disposeAndClear(); + + // save the single output document + bNoError = SavePrintDoc(xTargetDocShell, pTargetView, rMergeDescriptor, aTempFile, + pStoreToFilter, pStoreToFilterOptions, + bMergeShell, bCreateSingleFile, rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER); + + + //remove the temporary files + RemoveTmpFiles(aFilesToRemove); + + // unlock all dispatchers + LockUnlockDisp(false, pSourceDocSh); + + SW_MOD()->SetView(&pSourceShell->GetView()); + } + } + + if(bEMail) + { + xMailDispatcher->stop(); + xMailDispatcher->shutdown(); + } + + return bNoError; +} + +void SwDBManager::CreateDumpDocs(sal_Int32 &nMaxDumpDocs) +{ + static const char *sMaxDumpDocs = nullptr; + + if (!sMaxDumpDocs) + { + sMaxDumpDocs = getenv("SW_DEBUG_MAILMERGE_DOCS"); + if (!sMaxDumpDocs) + sMaxDumpDocs = ""; + else + nMaxDumpDocs = rtl_ustr_toInt32(reinterpret_cast( sMaxDumpDocs ), 10); + } +} + +void SwDBManager::SetSourceProp(SwDocShell* pSourceDocSh) +{ + uno::Reference xSourceDocProps; + { + uno::Reference + xDPS(pSourceDocSh->GetModel(), uno::UNO_QUERY); + xSourceDocProps.set(xDPS->getDocumentProperties()); + OSL_ENSURE(xSourceDocProps.is(), "DocumentProperties is null"); + } +} + +void SwDBManager::GetPathAddress(OUString &sPath, OUString &sAddress, uno::Reference< beans::XPropertySet > xColumnProp) +{ + SwDBFormatData aDBFormat; + aDBFormat.xFormatter = pImpl->pMergeData->xFormatter; + aDBFormat.aNullDate = pImpl->pMergeData->aNullDate; + sAddress = GetDBField( xColumnProp, aDBFormat); + if (sAddress.isEmpty()) + sAddress = "_"; + sPath += sAddress; +} + +bool SwDBManager::CreateNewTemp(OUString &sPath, const OUString &sAddress, + std::unique_ptr< utl::TempFile > &aTempFile, + const SwMergeDescriptor& rMergeDescriptor, const SfxFilter* pStoreToFilter) +{ + INetURLObject aEntry(sPath); + OUString sLeading; + bool bErr = true; + + //#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( rMergeDescriptor.bSubjectIsFilename ) + aTempFile->EnableKillingFile(); + + if( !aTempFile->IsValid() ) + { + ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED ); + bErr = false; + bCancel = true; + } + + return bErr; +} + +void SwDBManager::UpdateProgressDlg(bool bMergeShell, VclPtr pProgressDlg, bool createTempFile, + std::unique_ptr< INetURLObject > &aTempFileURL, + SwDocShell *pSourceDocSh, sal_Int32 nDocNo) +{ + if (!IsMergeSilent()) + { + if( bMergeShell ) + static_cast( pProgressDlg.get() )->SetCurrentPosition( nDocNo ); + else + { + PrintMonitor *pPrintMonDlg = static_cast( pProgressDlg.get() ); + pPrintMonDlg->m_pPrinter->SetText( createTempFile ? aTempFileURL->GetBase() : OUString( pSourceDocSh->GetTitle( 22 ))); + OUString sStat(SW_RES(STR_STATSTR_LETTER)); // Brief + sStat += " "; + sStat += OUString::number( nDocNo ); + pPrintMonDlg->m_pPrintInfo->SetText( sStat ); + } + + pProgressDlg->Update(); + + // Computation time for the GUI + for( sal_uInt16 i = 0; i < 25; i++ ) + Application::Reschedule(); + } +} + +bool SwDBManager::CreateTargetDocShell(sal_Int32 nMaxDumpDocs, bool bMergeShell, vcl::Window *pSourceWindow, + SwWrtShell *pSourceShell, SwDocShell *pSourceDocSh, + SfxObjectShellRef &xTargetDocShell, SwDoc *&pTargetDoc, + SwWrtShell *&pTargetShell, SwView *&pTargetView, + sal_uInt16 &nStartingPageNo, OUString &sStartingPageDesc) +{ + // create a target docshell to put the merged document into + xTargetDocShell = new SwDocShell( SfxObjectCreateMode::STANDARD ); + xTargetDocShell->DoInitNew( ); + if (nMaxDumpDocs) + lcl_SaveDoc( xTargetDocShell, "MergeDoc" ); + SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 ); + if (bMergeShell && pSourceWindow) + { + //the created window has to be located at the same position as the source window + vcl::Window& rTargetWindow = pTargetFrame->GetFrame().GetWindow(); + rTargetWindow.SetPosPixel(pSourceWindow->GetPosPixel()); + } + + pTargetView = static_cast( pTargetFrame->GetViewShell() ); + + //initiate SelectShell() to create sub shells + pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() ); + pTargetShell = pTargetView->GetWrtShellPtr(); + pTargetDoc = pTargetShell->GetDoc(); + pTargetDoc->SetInMailMerge(true); + + //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 = pSourceShell->GetPageDesc( + pSourceShell->GetCurPageDesc()).GetName(); + + // #i72517# + const SwPageDesc* pSourcePageDesc = pSourceShell->FindPageDescByName( sStartingPageDesc ); + const SwFrameFormat& rMaster = pSourcePageDesc->GetMaster(); + bool bPageStylesWithHeaderFooter = rMaster.GetHeader().IsActive() || + rMaster.GetFooter().IsActive(); + + // copy compatibility options + pTargetShell->GetDoc()->ReplaceCompatibilityOptions( *pSourceShell->GetDoc()); + // #72821# copy dynamic defaults + pTargetShell->GetDoc()->ReplaceDefaults( *pSourceShell->GetDoc()); + + pTargetShell->GetDoc()->ReplaceDocumentProperties( *pSourceShell->GetDoc()); + + return bPageStylesWithHeaderFooter; +} + +void SwDBManager::LockUnlockDisp(bool bLock, SwDocShell *pSourceDocSh) +{ + SfxViewFrame *pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); + while (pViewFrame) + { + pViewFrame->GetDispatcher()->Lock(bLock); + pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); + } +} + +void SwDBManager::CreateProgessDlg(vcl::Window *&pSourceWindow, VclPtr &pProgressDlg, bool bMergeShell, + SwWrtShell *pSourceShell, vcl::Window *pParent) +{ + if (!IsMergeSilent()) + { + pSourceWindow = &pSourceShell->GetView().GetEditWin(); + if( ! pParent ) + pParent = pSourceWindow; + if( bMergeShell ) + pProgressDlg = VclPtr::Create( pParent, pParent != pSourceWindow ); + else + { + pProgressDlg = VclPtr::Create( pParent, pParent != pSourceWindow, PrintMonitor::MONITOR_TYPE_PRINT ); + static_cast( pProgressDlg.get() )->SetText(pSourceShell->GetView().GetDocShell()->GetTitle(22)); + } + pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) ); + pProgressDlg->Show(); + + for( sal_uInt16 i = 0; i < 25; i++) + Application::Reschedule(); + } +} + +void SwDBManager::CreateWorkDoc(SfxObjectShellLock &xWorkDocSh, SwView *&pWorkView, SwDoc *&pWorkDoc, SwDBManager *&pOldDBManager, + SwDocShell *pSourceDocSh, sal_Int32 nMaxDumpDocs, sal_Int32 nDocNo) +{ + assert( !xWorkDocSh.Is()); + // copy the source document + xWorkDocSh = pSourceDocSh->GetDoc()->CreateCopy( true ); + + //create a view frame for the document + pWorkView = static_cast< SwView* >( SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 )->GetViewShell() ); + //request the layout calculation + SwWrtShell& rWorkShell = pWorkView->GetWrtShell(); + pWorkView->AttrChangedNotify( &rWorkShell );// in order for SelectShell to be called + + pWorkDoc = rWorkShell.GetDoc(); + pWorkDoc->ReplaceDocumentProperties( *pSourceDocSh->GetDoc()); + if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) + lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo ); + pOldDBManager = pWorkDoc->GetDBManager(); + pWorkDoc->SetDBManager( this ); + pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks(); + + // #i69458# lock fields to prevent access to the result set while calculating layout + // tdf#92324: and do not unlock: keep document locked during printing to avoid + // ExpFields update during printing, generation of preview, etc. + rWorkShell.LockExpFields(); + rWorkShell.CalcLayout(); +} + +void SwDBManager::UpdateExpFields(SwWrtShell& rWorkShell, SfxObjectShellLock xWorkDocSh) +{ + SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), xWorkDocSh)); + // tdf#92324: Allow ExpFields update only by explicit instruction to avoid + // database cursor movement on any other fields update, for example during + // print preview and other operations + if ( rWorkShell.IsExpFieldsLocked() ) + rWorkShell.UnlockExpFields(); + rWorkShell.SwViewShell::UpdateFields(); + rWorkShell.LockExpFields(); + SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh)); + + // launch MailMergeEvent if required + const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc(); + if(pEvtSrc) + { + uno::Reference< uno::XInterface > xRef( const_cast(static_cast(pEvtSrc)) ); + text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() ); + pEvtSrc->LaunchMailMergeEvent( aEvt ); + } +} + +void SwDBManager::CreateStoreToFilter(const SfxFilter *&pStoreToFilter, const OUString *&pStoreToFilterOptions, + SwDocShell *pSourceDocSh, bool bEMail, const SwMergeDescriptor &rMergeDescriptor) +{ + pStoreToFilter = SwIoSystem::GetFileFilter( + pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::NO_DECODE)); + SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer(); + + // 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, SfxFilterFlags::EXPORT); + } + else if( !rMergeDescriptor.sSaveToFilter.isEmpty()) + { + const SfxFilter* pFilter = + pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter ); + if(pFilter) + { + pStoreToFilter = pFilter; + if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty()) + pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions; + } + } +} + +void SwDBManager::MergeSingleFiles(SwDoc *pWorkDoc, SwWrtShell &rWorkShell, SwWrtShell *pTargetShell, SwDoc *pTargetDoc, + SfxObjectShellLock &xWorkDocSh, SfxObjectShellRef xTargetDocShell, + bool bPageStylesWithHeaderFooter, bool bSynchronizedDoc, + OUString &sModifiedStartingPageDesc, OUString &sStartingPageDesc, sal_Int32 nDocNo, + long nStartRow, sal_uInt16 nStartingPageNo, int &targetDocPageCount, const bool bMergeShell, + const SwMergeDescriptor& rMergeDescriptor, sal_Int32 nMaxDumpDocs) +{ + pWorkDoc->RemoveInvisibleContent(); + + 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 + + //#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 + SwPageDesc* pTargetPageDesc(nullptr); + 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 + OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo ); + pTargetPageDesc = pTargetDoc->MakePageDesc( sNewPageDescName ); + const SwPageDesc* pWorkPageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc ); + + if(pWorkPageDesc && pTargetPageDesc) + { + pTargetDoc->CopyPageDesc( *pWorkPageDesc, *pTargetPageDesc, false ); + sModifiedStartingPageDesc = sNewPageDescName; + lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo ); + } + } + else + pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc ); + + if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) + lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo ); + if( targetDocPageCount % 2 == 1 ) + ++targetDocPageCount; // Docs always start on odd pages (so offset must be even). + SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc(*rWorkShell.GetDoc(), + nStartingPageNo, pTargetPageDesc, nDocNo == 1, targetDocPageCount); + targetDocPageCount += rWorkShell.GetPageCnt(); + if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) + lcl_SaveDoc( xTargetDocShell, "MergeDoc" ); + if (bMergeShell) + { + SwDocMergeInfo aMergeInfo; + // Name of the mark is actually irrelevant, UNO bookmarks have internals names. + aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark( appendedDocStart, "", + IDocumentMarkAccess::MarkType::UNO_BOOKMARK ); + aMergeInfo.nDBRow = nStartRow; + rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo ); + } +} + +void SwDBManager::ResetWorkDoc(SwDoc *pWorkDoc, SfxObjectShellLock &xWorkDocSh, SwDBManager *pOldDBManager) +{ + pWorkDoc->SetDBManager( pOldDBManager ); + xWorkDocSh->DoClose(); + xWorkDocSh = nullptr; +} + +void SwDBManager::FreezeLayouts(SwWrtShell *pTargetShell, bool freeze) +{ + for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) + { + aLayout->FreezeLayout(freeze); + if(!freeze) + aLayout->AllCheckPageDescs(); + } +} + +void SwDBManager::FinishMailMergeFile(SfxObjectShellLock &xWorkDocSh, SwView *pWorkView, SwDoc *pTargetDoc, + SwWrtShell *pTargetShell, bool bCreateSingleFile, bool bPrinter, + SwDoc *pWorkDoc, SwDBManager *pOldDBManager) +{ + if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() ) + { + // Unlock document fields after merge complete + pWorkView->GetWrtShell().UnlockExpFields(); + } + + if(!bCreateSingleFile) + { + if(bPrinter) + { + Printer::FinishPrintJob( pWorkView->GetPrinterController() ); #if ENABLE_CUPS && !defined(MACOSX) - psp::PrinterInfoManager::get().flushBatchPrint(); + psp::PrinterInfoManager::get().flushBatchPrint(); #endif - } - pWorkDoc->SetDBManager( pOldDBManager ); - xWorkDocSh->DoClose(); - } + } - if (bCreateSingleFile) - { - // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate - // unique fly names, do it here once. - pTargetDoc->SetInMailMerge(false); - pTargetDoc->SetAllUniqueFlyNames(); - } + ResetWorkDoc(pWorkDoc, xWorkDocSh, pOldDBManager); + } - for( sal_uInt16 i = 0; i < 25; i++) - Application::Reschedule(); + if( bCreateSingleFile ) + { + // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate + // unique fly names, do it here once. + pTargetDoc->SetInMailMerge(false); + pTargetDoc->SetAllUniqueFlyNames(); + } - // Unfreeze target document layouts and correct all PageDescs. - if(bCreateSingleFile) - { - pTargetShell->CalcLayout(); - for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) - { - aLayout->FreezeLayout(false); - aLayout->AllCheckPageDescs(); - } - } + for( sal_uInt16 i = 0; i < 25; i++) + Application::Reschedule(); - pProgressDlg.disposeAndClear(); + if( bCreateSingleFile ) + { + // Unfreeze target document layouts and correct all PageDescs. + pTargetShell->CalcLayout(); + FreezeLayouts(pTargetShell, false); + } +} - // save the single output document - if (bMergeShell) - { - rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); - } - else if(bCreateSingleFile) +bool SwDBManager::SavePrintDoc(SfxObjectShellRef xTargetDocShell, SwView *pTargetView, const SwMergeDescriptor &rMergeDescriptor, + std::unique_ptr< utl::TempFile > &aTempFile, + const SfxFilter *&pStoreToFilter, const OUString *&pStoreToFilterOptions, + const bool bMergeShell, bool bCreateSingleFile, const bool bPrinter) +{ + bool bNoError = true; + + if (bMergeShell) + { + rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); + } + else if(bCreateSingleFile) + { + if(!bCancel) + { + if( !bPrinter ) { - if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER ) + assert( aTempFile.get()); + INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : aTempFile->GetURL()); + SfxMedium* pDstMed = new SfxMedium( + aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ), + STREAM_STD_READWRITE ); + pDstMed->SetFilter( pStoreToFilter ); + if(pDstMed->GetItemSet()) { - if( !bCancel ) - { - assert( aTempFile.get()); - INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : 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, uno::makeAny(rMergeDescriptor.aSaveToFilterData))); - } - - xTargetDocShell->DoSaveAs(*pDstMed); - xTargetDocShell->DoSaveCompleted(pDstMed); - if( xTargetDocShell->GetError() ) - { - // error message ?? - ErrorHandler::HandleError( xTargetDocShell->GetError() ); - bNoError = false; - } - } + if(pStoreToFilterOptions ) + pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions)); + if(rMergeDescriptor.aSaveToFilterData.getLength()) + pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, uno::makeAny(rMergeDescriptor.aSaveToFilterData))); } - else if( pTargetView ) // must be available! - { - //print the target document - // 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->DoSaveAs(*pDstMed); + xTargetDocShell->DoSaveCompleted(pDstMed); + if( xTargetDocShell->GetError() ) + { + // error message ?? + ErrorHandler::HandleError( xTargetDocShell->GetError() ); + bNoError = false; } - - // Leave docshell available for caller (e.g. MM wizard) - if (!bMergeShell) - xTargetDocShell->DoClose(); } + else if( pTargetView ) // must be available! + { + //print the target document + // printing should be done synchronously otherwise the document + // might already become invalid during the process + uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions ); - //remove the temporary files - ::std::vector::iterator aFileIter; - for(aFileIter = aFilesToRemove.begin(); - aFileIter != aFilesToRemove.end(); ++aFileIter) - SWUnoHelper::UCB_DeleteFile( *aFileIter ); + aOptions.realloc( 1 ); + aOptions[ 0 ].Name = "Wait"; + aOptions[ 0 ].Value <<= sal_True ; - // unlock all dispatchers - pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); - while (pViewFrame) - { - pViewFrame->GetDispatcher()->Lock(false); - pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); - } + SetPrinterOptions(rMergeDescriptor, aOptions); - SW_MOD()->SetView(&pSourceShell->GetView()); + pTargetView->ExecPrint( aOptions, IsMergeSilent(), rMergeDescriptor.bPrintAsync ); + } } + + // Leave docshell available for caller (e.g. MM wizard) + if (!bMergeShell) + xTargetDocShell->DoClose(); } - if(bEMail) + return bNoError; +} + +void SwDBManager::SetPrinterOptions(const SwMergeDescriptor &rMergeDescriptor, uno::Sequence< beans::PropertyValue > &aOptions) +{ + // move print options + const beans::PropertyValue* pPrintOptions = rMergeDescriptor.aPrintOptions.getConstArray(); + for( sal_Int32 nOption = 0, nIndex = aOptions.getLength() ; nOption < rMergeDescriptor.aPrintOptions.getLength(); ++nOption) { - xMailDispatcher->stop(); - xMailDispatcher->shutdown(); + 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 ; + } } +} - return bNoError; +void SwDBManager::RemoveTmpFiles(::std::vector< OUString> &aFilesToRemove) +{ + ::std::vector::iterator aFileIter; + for(aFileIter = aFilesToRemove.begin(); + aFileIter != aFilesToRemove.end(); ++aFileIter) + SWUnoHelper::UCB_DeleteFile( *aFileIter ); } void SwDBManager::MergeCancel() @@ -1827,11 +1967,11 @@ uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rD return xConnection; } -uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference xConnection, +uno::Reference SwDBManager::GetRowSet(uno::Reference xConnection, const OUString& rTableOrQuery, SwDBSelect eTableOrQuery) { - uno::Reference< sdbcx::XColumnsSupplier> xRet; + uno::Reference xRet; try { if(eTableOrQuery == SwDBSelect::UNKNOWN) @@ -1865,7 +2005,7 @@ uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Ref xRowProperties->setPropertyValue("FetchSize", uno::makeAny((sal_Int32)10)); xRowProperties->setPropertyValue("ActiveConnection", uno::makeAny(xConnection)); xRowSet->execute(); - xRet.set( xRowSet, uno::UNO_QUERY ); + xRet = xRowSet; } catch (const uno::Exception& e) { @@ -2052,7 +2192,7 @@ bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, sal_uInt16 n bool SwDBManager::ToNextMergeRecord() { OSL_ENSURE(pImpl->pMergeData && pImpl->pMergeData->xResultSet.is(), "no data source in merge"); - return ToNextRecord(pImpl->pMergeData); + return ToNextRecord(pImpl->pMergeData, false); } bool SwDBManager::FillCalcWithMergeData( SvNumberFormatter *pDocFormatter, @@ -2142,12 +2282,21 @@ bool SwDBManager::ToNextRecord( aData.nCommandType = -1; pFound = FindDSData(aData, false); } - return ToNextRecord(pFound); + return ToNextRecord(pFound, false); } -bool SwDBManager::ToNextRecord(SwDSParam* pParam) + +bool SwDBManager::ToNextRecord(SwDSParam* pParam, bool bReset) { bool bRet = true; + + if( bReset ) + { + pParam->nSelectionIndex = 0; + pParam->bEndOfDB = + pParam->bAfterSelection = false; + } + if(!pParam || !pParam->xResultSet.is() || pParam->bEndOfDB || (pParam->aSelection.getLength() && pParam->aSelection.getLength() <= pParam->nSelectionIndex)) { @@ -2167,6 +2316,11 @@ bool SwDBManager::ToNextRecord(SwDSParam* pParam) if(pParam->nSelectionIndex >= pParam->aSelection.getLength()) pParam->bEndOfDB = true; } + else if (bReset) + { + pImpl->pMergeData->bEndOfDB = !pImpl->pMergeData->xResultSet->first(); + pImpl->pMergeData->CheckEndOfDB(); + } else { sal_Int32 nBefore = pParam->xResultSet->getRow(); @@ -2182,8 +2336,11 @@ bool SwDBManager::ToNextRecord(SwDSParam* pParam) ++pParam->nSelectionIndex; } } - catch(const uno::Exception&) + catch(const uno::Exception &e) { + pParam->bEndOfDB = true; + pParam->CheckEndOfDB(); + SAL_WARN("sw.mailmerge", "exception in ToNextRecord(): " << e.Message); } return bRet; } -- cgit