From ea4320be0d12f75ef14372e094d1a2c178b5b0c3 Mon Sep 17 00:00:00 2001 From: Szymon Kłos Date: Thu, 16 May 2019 15:24:10 +0200 Subject: tdf#117480 fix crash in mailmerge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch exceptions and hide progress dialog. b2d85f9207bc9bf7489d0a1fd9b35f062502639d Reviewed-on: https://gerrit.libreoffice.org/65815 Reviewed-by: Szymon Kłos Tested-by: Szymon Kłos Change-Id: Ie63c8d7e001c90f40cf7504fd8248a6742e9d244 Reviewed-on: https://gerrit.libreoffice.org/72413 Reviewed-by: Andras Timar Tested-by: Andras Timar --- sw/source/uibase/dbui/dbmgr.cxx | 709 ++++++++++++++++++++-------------------- 1 file changed, 358 insertions(+), 351 deletions(-) diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx index a404a206be21..1849f9fa5e00 100644 --- a/sw/source/uibase/dbui/dbmgr.cxx +++ b/sw/source/uibase/dbui/dbmgr.cxx @@ -1247,433 +1247,440 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, vcl::Window *pSourceWindow = nullptr; VclPtr pProgressDlg; - if( !bIsMergeSilent ) - { - // construct the process dialog - pSourceWindow = &pSourceShell->GetView().GetEditWin(); - vcl::Window* pParent = pSourceWindow; - if( !bMT_PRINTER ) - pProgressDlg = VclPtr::Create( - pParent, pParent != pSourceWindow ); - else { - pProgressDlg = VclPtr::Create( - pParent, pParent != pSourceWindow, - PrintMonitor::MONITOR_TYPE_PRINT ); - static_cast( pProgressDlg.get() )->SetText( - pSourceDocSh->GetTitle(22) ); - } - pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) ); - pProgressDlg->Show(); - - rescheduleGui(); - } - - if( bCreateSingleFile && !pTargetView ) - { - // create a target docshell to put the merged document into - xTargetDocShell = lcl_CreateWorkingDocument( WorkingDocType::TARGET, - *pSourceShell, bMT_SHELL ? pSourceWindow : nullptr, - nullptr, &pTargetView, &pTargetShell, &pTargetDoc ); - if (nMaxDumpDocs) - lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" ); - } - else if( pTargetView ) + try { - pTargetShell = pTargetView->GetWrtShellPtr(); - pTargetDoc = pTargetShell->GetDoc(); - xTargetDocShell = pTargetView->GetDocShell(); - } + if( !bIsMergeSilent ) + { + // construct the process dialog + pSourceWindow = &pSourceShell->GetView().GetEditWin(); + vcl::Window* pParent = pSourceWindow; + if( !bMT_PRINTER ) + pProgressDlg = VclPtr::Create( + pParent, pParent != pSourceWindow ); + else { + pProgressDlg = VclPtr::Create( + pParent, pParent != pSourceWindow, + PrintMonitor::MONITOR_TYPE_PRINT ); + static_cast( pProgressDlg.get() )->SetText( + pSourceDocSh->GetTitle(22) ); + } + pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) ); + pProgressDlg->Show(); - if( bCreateSingleFile ) - { - // determine the page style and number used at the start of the source document - pSourceShell->SttEndDoc(true); - nStartingPageNo = pSourceShell->GetVirtPageNum(); - } + rescheduleGui(); + } - // Progress, to prohibit KeyInputs - SfxProgress aProgress(pSourceDocSh, ::aEmptyOUStr, 1); + if( bCreateSingleFile && !pTargetView ) + { + // create a target docshell to put the merged document into + xTargetDocShell = lcl_CreateWorkingDocument( WorkingDocType::TARGET, + *pSourceShell, bMT_SHELL ? pSourceWindow : nullptr, + nullptr, &pTargetView, &pTargetShell, &pTargetDoc ); + if (nMaxDumpDocs) + lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" ); + } + else if( pTargetView ) + { + pTargetShell = pTargetView->GetWrtShellPtr(); + pTargetDoc = pTargetShell->GetDoc(); + xTargetDocShell = pTargetView->GetDocShell(); + } - // lock all dispatchers - SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); - while (pViewFrame) - { - pViewFrame->GetDispatcher()->Lock(true); - pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); - } + if( bCreateSingleFile ) + { + // determine the page style and number used at the start of the source document + pSourceShell->SttEndDoc(true); + nStartingPageNo = pSourceShell->GetVirtPageNum(); + } - sal_Int32 nDocNo = 1; + // Progress, to prohibit KeyInputs + SfxProgress aProgress(pSourceDocSh, ::aEmptyOUStr, 1); - // For single file mode, the number of pages in the target document so far, which is used - // by AppendDoc() to adjust position of page-bound objects. Getting this information directly - // from the target doc would require repeated layouts of the doc, which is expensive, but - // it can be manually computed from the source documents (for which we do layouts, so the page - // count is known, and there is a blank page between each of them in the target document). - int targetDocPageCount = 0; + // lock all dispatchers + SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); + while (pViewFrame) + { + pViewFrame->GetDispatcher()->Lock(true); + pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); + } - if( !bIsMergeSilent && !bMT_PRINTER ) - { - sal_Int32 nRecordCount = 1; - lcl_getCountFromResultSet( nRecordCount, pImpl->pMergeData ); + sal_Int32 nDocNo = 1; - // syncronized docs don't auto-advance the record set, but there is a - // "security" check, which will always advance the record set, if there - // is no "next record" field in a synchronized doc => nRecordPerDoc > 0 - sal_Int32 nRecordPerDoc = pSourceShell->GetDoc() - ->getIDocumentFieldsAccess().GetRecordsPerDocument(); - if ( bSynchronizedDoc && (nRecordPerDoc > 1) ) - --nRecordPerDoc; - assert( nRecordPerDoc > 0 ); + // For single file mode, the number of pages in the target document so far, which is used + // by AppendDoc() to adjust position of page-bound objects. Getting this information directly + // from the target doc would require repeated layouts of the doc, which is expensive, but + // it can be manually computed from the source documents (for which we do layouts, so the page + // count is known, and there is a blank page between each of them in the target document). + int targetDocPageCount = 0; - sal_Int32 nMaxDocs = nRecordCount / nRecordPerDoc; - if ( 0 != nRecordCount % nRecordPerDoc ) - nMaxDocs += 1; - static_cast( pProgressDlg.get() )->SetTotalCount( nMaxDocs ); - } + if( !bIsMergeSilent && !bMT_PRINTER ) + { + sal_Int32 nRecordCount = 1; + lcl_getCountFromResultSet( nRecordCount, pImpl->pMergeData ); - long nStartRow, nEndRow; - bool bFreezedLayouts = false; - // to collect temporary email files - std::vector< OUString> aFilesToRemove; + // syncronized docs don't auto-advance the record set, but there is a + // "security" check, which will always advance the record set, if there + // is no "next record" field in a synchronized doc => nRecordPerDoc > 0 + sal_Int32 nRecordPerDoc = pSourceShell->GetDoc() + ->getIDocumentFieldsAccess().GetRecordsPerDocument(); + if ( bSynchronizedDoc && (nRecordPerDoc > 1) ) + --nRecordPerDoc; + assert( nRecordPerDoc > 0 ); - // The SfxObjectShell will be closed explicitly later but - // it is more safe to use SfxObjectShellLock here - SfxObjectShellLock xWorkDocSh; - SwView* pWorkView = nullptr; - SwDoc* pWorkDoc = nullptr; - SwDBManager* pWorkDocOrigDBManager = nullptr; - SwWrtShell* pWorkShell = nullptr; - bool bWorkDocInitialized = false; + sal_Int32 nMaxDocs = nRecordCount / nRecordPerDoc; + if ( 0 != nRecordCount % nRecordPerDoc ) + nMaxDocs += 1; + static_cast( pProgressDlg.get() )->SetTotalCount( nMaxDocs ); + } - do - { - nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0; + long nStartRow, nEndRow; + bool bFreezedLayouts = false; + // to collect temporary email files + std::vector< OUString> aFilesToRemove; - OUString sColumnData; + // The SfxObjectShell will be closed explicitly later but + // it is more safe to use SfxObjectShellLock here + SfxObjectShellLock xWorkDocSh; + SwView* pWorkView = nullptr; + SwDoc* pWorkDoc = nullptr; + SwDBManager* pWorkDocOrigDBManager = nullptr; + SwWrtShell* pWorkShell = nullptr; + bool bWorkDocInitialized = false; - // Read the indicated data column, which should contain a valid mail - // address or an optional file name - if( bMT_EMAIL || bColumnName ) + do { - sColumnData = GetDBField( xColumnProp, aColumnDBFormat ); - } + nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0; - // create a new temporary file name - only done once in case of bCreateSingleFile - if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile )) - { - OUString sPrefix = rMergeDescriptor.sPrefix; - OUString sLeading; + OUString sColumnData; - //#i97667# if the name is from a database field then it will be used _as is_ - if( bColumnName && !bMT_EMAIL ) - { - if (!sColumnData.isEmpty()) - sLeading = sColumnData; - else - sLeading = "_"; - } - else + // Read the indicated data column, which should contain a valid mail + // address or an optional file name + if( bMT_EMAIL || bColumnName ) { - INetURLObject aEntry( sPrefix ); - sLeading = aEntry.GetBase(); - aEntry.removeSegment(); - sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + sColumnData = GetDBField( xColumnProp, aColumnDBFormat ); } - OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*')); - aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPrefix, true) ); - if( !aTempFile->IsValid() ) + // create a new temporary file name - only done once in case of bCreateSingleFile + if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile )) { - ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED ); - m_aMergeStatus = MergeStatus::ERROR; - } - } + OUString sPrefix = rMergeDescriptor.sPrefix; + OUString sLeading; - if( IsMergeOk() ) - { - std::unique_ptr< INetURLObject > aTempFileURL; - if( bNeedsTempFiles ) - aTempFileURL.reset( new INetURLObject(aTempFile->GetURL())); - if( !bIsMergeSilent ) { - if( !bMT_PRINTER ) - static_cast( pProgressDlg.get() )->SetCurrentPosition( nDocNo ); - else { - PrintMonitor *pPrintMonDlg = static_cast( pProgressDlg.get() ); - pPrintMonDlg->m_pPrinter->SetText( bNeedsTempFiles - ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 22 ) ); - OUString sStat( SW_RES(STR_STATSTR_LETTER) ); - sStat += " " + OUString::number( nDocNo ); - pPrintMonDlg->m_pPrintInfo->SetText( sStat ); + //#i97667# if the name is from a database field then it will be used _as is_ + if( bColumnName && !bMT_EMAIL ) + { + if (!sColumnData.isEmpty()) + sLeading = sColumnData; + else + sLeading = "_"; + } + else + { + INetURLObject aEntry( sPrefix ); + sLeading = aEntry.GetBase(); + aEntry.removeSegment(); + sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ); } - pProgressDlg->Update(); - } - - rescheduleGui(); - - // 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. Currently PDF also has to be treated special. - if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport ) - { - assert( !xWorkDocSh.Is()); - pWorkDocOrigDBManager = this; - xWorkDocSh = lcl_CreateWorkingDocument( WorkingDocType::COPY, - *pSourceShell, nullptr, &pWorkDocOrigDBManager, - &pWorkView, &pWorkShell, &pWorkDoc ); - if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) - lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo ); - - // #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. - pWorkShell->LockExpFields(); - pWorkShell->CalcLayout(); - } - - lcl_emitEvent(SW_EVENT_FIELD_MERGE, 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 ( pWorkShell->IsExpFieldsLocked() ) - pWorkShell->UnlockExpFields(); - pWorkShell->SwViewShell::UpdateFields(); - pWorkShell->LockExpFields(); - - lcl_emitEvent(SW_EVENT_FIELD_MERGE_FINISHED, STR_SW_EVENT_FIELD_MERGE_FINISHED, xWorkDocSh); - // also emit MailMergeEvent on XInterface if possible - const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc(); - if(pEvtSrc) - { - uno::Reference< uno::XInterface > xRef( - static_cast(const_cast(pEvtSrc)) ); - text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() ); - pEvtSrc->LaunchMailMergeEvent( aEvt ); + OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*')); + aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPrefix, true) ); + if( !aTempFile->IsValid() ) + { + ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED ); + m_aMergeStatus = MergeStatus::ERROR; + } } - // working copy is merged - prepare final steps depending on merge options - - if( bCreateSingleFile ) + if( IsMergeOk() ) { - assert( pTargetShell && "no target shell available!" ); + std::unique_ptr< INetURLObject > aTempFileURL; + if( bNeedsTempFiles ) + aTempFileURL.reset( new INetURLObject(aTempFile->GetURL())); + if( !bIsMergeSilent ) { + if( !bMT_PRINTER ) + static_cast( pProgressDlg.get() )->SetCurrentPosition( nDocNo ); + else { + PrintMonitor *pPrintMonDlg = static_cast( pProgressDlg.get() ); + pPrintMonDlg->m_pPrinter->SetText( bNeedsTempFiles + ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 22 ) ); + OUString sStat( SW_RES(STR_STATSTR_LETTER) ); + sStat += " " + OUString::number( nDocNo ); + pPrintMonDlg->m_pPrintInfo->SetText( sStat ); + } + pProgressDlg->Update(); + } - // prepare working copy and target to append + rescheduleGui(); - pWorkDoc->RemoveInvisibleContent(); - pWorkShell->ConvertFieldsToText(); - pWorkShell->SetNumberingRestart(); - if( bSynchronizedDoc ) + // 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. Currently PDF also has to be treated special. + if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport ) { - lcl_RemoveSectionLinks( *pWorkShell ); + assert( !xWorkDocSh.Is()); + pWorkDocOrigDBManager = this; + xWorkDocSh = lcl_CreateWorkingDocument( WorkingDocType::COPY, + *pSourceShell, nullptr, &pWorkDocOrigDBManager, + &pWorkView, &pWorkShell, &pWorkDoc ); + if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) + lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo ); + + // #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. + pWorkShell->LockExpFields(); + pWorkShell->CalcLayout(); } - if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) - lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo ); + lcl_emitEvent(SW_EVENT_FIELD_MERGE, STR_SW_EVENT_FIELD_MERGE, xWorkDocSh); - // append the working document to the target document - if( targetDocPageCount % 2 == 1 ) - ++targetDocPageCount; // Docs always start on odd pages (so offset must be even). - SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc( *pWorkDoc, - nStartingPageNo, !bWorkDocInitialized, targetDocPageCount, nDocNo); - targetDocPageCount += pWorkShell->GetPageCnt(); + // 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 ( pWorkShell->IsExpFieldsLocked() ) + pWorkShell->UnlockExpFields(); + pWorkShell->SwViewShell::UpdateFields(); + pWorkShell->LockExpFields(); - if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) - lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" ); + lcl_emitEvent(SW_EVENT_FIELD_MERGE_FINISHED, STR_SW_EVENT_FIELD_MERGE_FINISHED, xWorkDocSh); - if (bMT_SHELL) + // also emit MailMergeEvent on XInterface if possible + const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc(); + if(pEvtSrc) { - SwDocMergeInfo aMergeInfo; - // Name of the mark is actually irrelevant, UNO bookmarks have internals names. - aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark( - appendedDocStart, "", IDocumentMarkAccess::MarkType::UNO_BOOKMARK, - ::sw::mark::InsertMode::New); - aMergeInfo.nDBRow = nStartRow; - rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo ); + uno::Reference< uno::XInterface > xRef( + static_cast(const_cast(pEvtSrc)) ); + text::MailMergeEvent aEvt( xRef, xWorkDocSh->GetModel() ); + pEvtSrc->LaunchMailMergeEvent( aEvt ); } - } - else - { - assert( bNeedsTempFiles ); - assert( pWorkShell->IsExpFieldsLocked() ); - // fields are locked, so it's fine to - // restore the old / empty DB manager for save - pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); + // working copy is merged - prepare final steps depending on merge options - // save merged document - OUString sFileURL; - if( !lcl_SaveDoc( aTempFileURL.get(), pStoreToFilter, pStoreToFilterOptions, - &rMergeDescriptor.aSaveToFilterData, bIsPDFexport, - xWorkDocSh, *pWorkShell, &sFileURL ) ) + if( bCreateSingleFile ) { - m_aMergeStatus = MergeStatus::ERROR; - } + assert( pTargetShell && "no target shell available!" ); - // back to the MM DB manager - pWorkDoc->SetDBManager( this ); + // prepare working copy and target to append - if( bMT_EMAIL && !IsMergeError() ) - { - // schedule file for later removal - aFilesToRemove.push_back( sFileURL ); + pWorkDoc->RemoveInvisibleContent(); + pWorkShell->ConvertFieldsToText(); + pWorkShell->SetNumberingRestart(); + if( bSynchronizedDoc ) + { + lcl_RemoveSectionLinks( *pWorkShell ); + } - if( !SwMailMergeHelper::CheckMailAddress( sColumnData ) ) + if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) + lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo ); + + // append the working document to the target document + if( targetDocPageCount % 2 == 1 ) + ++targetDocPageCount; // Docs always start on odd pages (so offset must be even). + SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc( *pWorkDoc, + nStartingPageNo, !bWorkDocInitialized, targetDocPageCount, nDocNo); + targetDocPageCount += pWorkShell->GetPageCnt(); + + if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) ) + lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" ); + + if (bMT_SHELL) { - OSL_FAIL("invalid e-Mail address in database column"); + SwDocMergeInfo aMergeInfo; + // Name of the mark is actually irrelevant, UNO bookmarks have internals names. + aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark( + appendedDocStart, "", IDocumentMarkAccess::MarkType::UNO_BOOKMARK, + ::sw::mark::InsertMode::New); + aMergeInfo.nDBRow = nStartRow; + rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo ); } - else + } + else + { + assert( bNeedsTempFiles ); + assert( pWorkShell->IsExpFieldsLocked() ); + + // fields are locked, so it's fine to + // restore the old / empty DB manager for save + pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); + + // save merged document + OUString sFileURL; + if( !lcl_SaveDoc( aTempFileURL.get(), pStoreToFilter, pStoreToFilterOptions, + &rMergeDescriptor.aSaveToFilterData, bIsPDFexport, + xWorkDocSh, *pWorkShell, &sFileURL ) ) + { + m_aMergeStatus = MergeStatus::ERROR; + } + + // back to the MM DB manager + pWorkDoc->SetDBManager( this ); + + if( bMT_EMAIL && !IsMergeError() ) { - uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc( - rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType, - sMailEncoding, pStoreToFilter->GetMimeType() ); - if( xMessage.is() ) + // schedule file for later removal + aFilesToRemove.push_back( sFileURL ); + + if( !SwMailMergeHelper::CheckMailAddress( sColumnData ) ) + { + OSL_FAIL("invalid e-Mail address in database column"); + } + else { - osl::MutexGuard aGuard( pImpl->m_aAllEmailSendMutex ); - pImpl->m_xLastMessage.set( xMessage ); - xMailDispatcher->enqueueMailMessage( xMessage ); - if( !xMailDispatcher->isStarted() ) - xMailDispatcher->start(); + uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc( + rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType, + sMailEncoding, pStoreToFilter->GetMimeType() ); + if( xMessage.is() ) + { + osl::MutexGuard aGuard( pImpl->m_aAllEmailSendMutex ); + pImpl->m_xLastMessage.set( xMessage ); + xMailDispatcher->enqueueMailMessage( xMessage ); + if( !xMailDispatcher->isStarted() ) + xMailDispatcher->start(); + } } } } + if( bCreateSingleFile || bIsPDFexport ) + { + pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); + xWorkDocSh->DoClose(); + xWorkDocSh = nullptr; + } } - if( bCreateSingleFile || bIsPDFexport ) + + bWorkDocInitialized = true; + 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 && bCreateSingleFile) { - pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); - xWorkDocSh->DoClose(); - xWorkDocSh = nullptr; + for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) + aLayout->FreezeLayout(true); + bFreezedLayouts = true; } - } + } while( IsMergeOk() && + ((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord())); - bWorkDocInitialized = true; - 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 && bCreateSingleFile) + if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() ) { - for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) - aLayout->FreezeLayout(true); - bFreezedLayouts = true; + // Unlock document fields after merge complete + pWorkView->GetWrtShell().UnlockExpFields(); } - } while( IsMergeOk() && - ((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord())); - if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() ) - { - // Unlock document fields after merge complete - pWorkView->GetWrtShell().UnlockExpFields(); - } - - if( !bCreateSingleFile ) - { - if( bMT_PRINTER ) - Printer::FinishPrintJob( pWorkView->GetPrinterController()); - if( !bIsPDFexport ) + if( !bCreateSingleFile ) { - pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); - xWorkDocSh->DoClose(); + if( bMT_PRINTER ) + Printer::FinishPrintJob( pWorkView->GetPrinterController()); + if( !bIsPDFexport ) + { + pWorkDoc->SetDBManager( pWorkDocOrigDBManager ); + xWorkDocSh->DoClose(); + } } - } - else if( IsMergeOk() ) // && bCreateSingleFile - { - rescheduleGui(); - - // 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. - SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" ); - pTargetShell->CalcLayout(); - SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" ); - pTargetShell->GetViewOptions()->SetIdle( true ); - pTargetDoc->GetIDocumentUndoRedo().DoUndo( true ); - for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) + else if( IsMergeOk() ) // && bCreateSingleFile { - aLayout->FreezeLayout(false); - aLayout->AllCheckPageDescs(); - } + rescheduleGui(); - rescheduleGui(); + // 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. + SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" ); + pTargetShell->CalcLayout(); + SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" ); + pTargetShell->GetViewOptions()->SetIdle( true ); + pTargetDoc->GetIDocumentUndoRedo().DoUndo( true ); + for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() ) + { + aLayout->FreezeLayout(false); + aLayout->AllCheckPageDescs(); + } - if( IsMergeOk() && bMT_FILE ) - { - // save merged document - assert( aTempFile.get() ); - INetURLObject aTempFileURL; - if( rMergeDescriptor.sPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename ) - aTempFileURL.SetURL( aTempFile->GetURL() ); - else + rescheduleGui(); + + if( IsMergeOk() && bMT_FILE ) { - aTempFileURL.SetURL( rMergeDescriptor.sPrefix ); - // remove the unneeded temporary file - aTempFile->EnableKillingFile(); + // save merged document + assert( aTempFile.get() ); + INetURLObject aTempFileURL; + if( rMergeDescriptor.sPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename ) + aTempFileURL.SetURL( aTempFile->GetURL() ); + else + { + aTempFileURL.SetURL( rMergeDescriptor.sPrefix ); + // remove the unneeded temporary file + aTempFile->EnableKillingFile(); + } + if( !lcl_SaveDoc( &aTempFileURL, pStoreToFilter, + pStoreToFilterOptions, &rMergeDescriptor.aSaveToFilterData, + bIsPDFexport, xTargetDocShell.get(), *pTargetShell ) ) + { + m_aMergeStatus = MergeStatus::ERROR; + } } - if( !lcl_SaveDoc( &aTempFileURL, pStoreToFilter, - pStoreToFilterOptions, &rMergeDescriptor.aSaveToFilterData, - bIsPDFexport, xTargetDocShell.get(), *pTargetShell ) ) + else if( IsMergeOk() && bMT_PRINTER ) { - m_aMergeStatus = MergeStatus::ERROR; + // print the target document + uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions ); + lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, true, aOptions ); + pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ ); } } - else if( IsMergeOk() && bMT_PRINTER ) - { - // print the target document - uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions ); - lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, true, aOptions ); - pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ ); - } - } - // we also show canceled documents, as long as there was no error - if( !IsMergeError() && bMT_SHELL ) - // leave docshell available for caller (e.g. MM wizard) - rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); - else if( xTargetDocShell.Is() ) - xTargetDocShell->DoClose(); + // we also show canceled documents, as long as there was no error + if( !IsMergeError() && bMT_SHELL ) + // leave docshell available for caller (e.g. MM wizard) + rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); + else if( xTargetDocShell.Is() ) + xTargetDocShell->DoClose(); - rescheduleGui(); + rescheduleGui(); - pProgressDlg.disposeAndClear(); + pProgressDlg.disposeAndClear(); - // unlock all dispatchers - pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); - while (pViewFrame) - { - pViewFrame->GetDispatcher()->Lock(false); - pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); - } + // unlock all dispatchers + pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); + while (pViewFrame) + { + pViewFrame->GetDispatcher()->Lock(false); + pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh); + } - SW_MOD()->SetView(&pSourceShell->GetView()); + SW_MOD()->SetView(&pSourceShell->GetView()); - if( xMailDispatcher.is() ) - { - if( IsMergeOk() ) + if( xMailDispatcher.is() ) { - // TODO: Instead of polling via an AutoTimer, post an Idle event, - // if the main loop has been made thread-safe. - AutoTimer aEmailDispatcherPollTimer; - aEmailDispatcherPollTimer.SetDebugName( - "sw::SwDBManager aEmailDispatcherPollTimer" ); - aEmailDispatcherPollTimer.SetTimeout( 500 ); - aEmailDispatcherPollTimer.Start(); - while( IsMergeOk() && pImpl->m_xLastMessage.is() ) - Application::Yield(); - aEmailDispatcherPollTimer.Stop(); + if( IsMergeOk() ) + { + // TODO: Instead of polling via an AutoTimer, post an Idle event, + // if the main loop has been made thread-safe. + AutoTimer aEmailDispatcherPollTimer; + aEmailDispatcherPollTimer.SetDebugName( + "sw::SwDBManager aEmailDispatcherPollTimer" ); + aEmailDispatcherPollTimer.SetTimeout( 500 ); + aEmailDispatcherPollTimer.Start(); + while( IsMergeOk() && pImpl->m_xLastMessage.is() ) + Application::Yield(); + aEmailDispatcherPollTimer.Stop(); + } + xMailDispatcher->stop(); + xMailDispatcher->shutdown(); } - xMailDispatcher->stop(); - xMailDispatcher->shutdown(); - } - // remove the temporary files - // has to be done after xMailDispatcher is finished, as mails may be - // delivered as message attachments! - for( const OUString &sFileURL : aFilesToRemove ) - SWUnoHelper::UCB_DeleteFile( sFileURL ); + // remove the temporary files + // has to be done after xMailDispatcher is finished, as mails may be + // delivered as message attachments! + for( const OUString &sFileURL : aFilesToRemove ) + SWUnoHelper::UCB_DeleteFile( sFileURL ); + } + catch (const uno::Exception&) + { + m_aMergeStatus = MergeStatus::ERROR; + } return !IsMergeError(); } -- cgit v1.2.3