[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.0' - sw/source

Szymon Kłos (via logerrit) logerrit at kemper.freedesktop.org
Sun May 19 19:20:04 UTC 2019


 sw/source/uibase/dbui/dbmgr.cxx |  723 ++++++++++++++++++++--------------------
 1 file changed, 365 insertions(+), 358 deletions(-)

New commits:
commit 8e13c14a1221430cdbd79be5b5c27a1c781ffb1d
Author:     Szymon Kłos <eszkadev at gmail.com>
AuthorDate: Tue May 14 23:14:34 2019 +0200
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Sun May 19 21:19:30 2019 +0200

    tdf#117480 fix crash in mailmerge
    
    Catch exceptions and hide progress dialog.
    
    b2d85f9207bc9bf7489d0a1fd9b35f062502639d
    Reviewed-on: https://gerrit.libreoffice.org/65815
    Reviewed-by: Szymon Kłos <szymon.klos at collabora.com>
    Tested-by: Szymon Kłos <szymon.klos at collabora.com>
    
    Change-Id: Ie63c8d7e001c90f40cf7504fd8248a6742e9d244
    Reviewed-on: https://gerrit.libreoffice.org/72398
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 55e82e50e8f0..21e104e20be7 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -1240,442 +1240,449 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     vcl::Window *pSourceWindow = nullptr;
     VclPtr<CancelableDialog> pProgressDlg;
 
-    if( !bIsMergeSilent )
-    {
-        // construct the process dialog
-        pSourceWindow = &pSourceShell->GetView().GetEditWin();
-        vcl::Window* pParent = pSourceWindow;
-        if( !bMT_PRINTER )
-            pProgressDlg = VclPtr<CreateMonitor>::Create(
-                pParent, pParent != pSourceWindow );
-        else {
-            pProgressDlg = VclPtr<PrintMonitor>::Create(
-                pParent, pParent != pSourceWindow,
-                PrintMonitor::MONITOR_TYPE_PRINT );
-            static_cast<PrintMonitor*>( pProgressDlg.get() )->SetText(
-                pSourceDocSh->GetTitle(22) );
-        }
-        pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) );
-        pProgressDlg->Show();
-
-        Application::Reschedule( true );
-    }
-
-    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<CreateMonitor>::Create(
+                    pParent, pParent != pSourceWindow );
+            else {
+                pProgressDlg = VclPtr<PrintMonitor>::Create(
+                    pParent, pParent != pSourceWindow,
+                    PrintMonitor::MONITOR_TYPE_PRINT );
+                static_cast<PrintMonitor*>( 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();
-    }
+            Application::Reschedule( true );
+        }
 
-    // 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;
 
-        // Synchronized 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<CreateMonitor*>( 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;
+            // Synchronized 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<CreateMonitor*>( 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 = sDescriptorPrefix;
-            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 = sDescriptorPrefix;
+                OUString sLeading;
 
-        if( IsMergeOk() )
-        {
-            std::unique_ptr< INetURLObject > aTempFileURL;
-            if( bNeedsTempFiles )
-                aTempFileURL.reset( new INetURLObject(aTempFile->GetURL()));
-            if( !bIsMergeSilent ) {
-                if( !bMT_PRINTER )
-                    static_cast<CreateMonitor*>( pProgressDlg.get() )->SetCurrentPosition( nDocNo );
-                else {
-                    PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>( pProgressDlg.get() );
-                    pPrintMonDlg->m_pPrinter->SetText( bNeedsTempFiles
-                        ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 22 ) );
-                    OUString sStat( SwResId(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 = "_";
                 }
-                pProgressDlg->Update();
-            }
-
-            Application::Reschedule( true );
-
-            // 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();
-                // tdf#121168: Now force correct page descriptions applied to page frames. Without
-                // this, e.g., page frames starting with sections could have page descriptions set
-                // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below.
-                pWorkShell->GetViewOptions()->SetIdle(true);
-                for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts())
+                else
                 {
-                    aLayout->FreezeLayout(false);
-                    aLayout->AllCheckPageDescs();
+                    INetURLObject aEntry( sPrefix );
+                    sLeading = aEntry.GetBase();
+                    aEntry.removeSegment();
+                    sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                 }
-            }
-
-            lcl_emitEvent(SfxEventHintId::SwEventFieldMerge, 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(SfxEventHintId::SwEventFieldMergeFinished, 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<text::XMailMergeBroadcaster*>(const_cast<SwXMailMerge*>(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<CreateMonitor*>( pProgressDlg.get() )->SetCurrentPosition( nDocNo );
+                    else {
+                        PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>( pProgressDlg.get() );
+                        pPrintMonDlg->m_pPrinter->SetText( bNeedsTempFiles
+                            ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 22 ) );
+                        OUString sStat( SwResId(STR_STATSTR_LETTER) );
+                        sStat += " " + OUString::number( nDocNo );
+                        pPrintMonDlg->m_pPrintInfo->SetText( sStat );
+                    }
+                    pProgressDlg->Update();
+                }
 
-                // prepare working copy and target to append
+                Application::Reschedule( true );
 
-                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();
+                    // tdf#121168: Now force correct page descriptions applied to page frames. Without
+                    // this, e.g., page frames starting with sections could have page descriptions set
+                    // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below.
+                    pWorkShell->GetViewOptions()->SetIdle(true);
+                    for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts())
+                    {
+                        aLayout->FreezeLayout(false);
+                        aLayout->AllCheckPageDescs();
+                    }
                 }
 
-                if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
-                    lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
+                lcl_emitEvent(SfxEventHintId::SwEventFieldMerge, 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(SfxEventHintId::SwEventFieldMergeFinished, 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<text::XMailMergeBroadcaster*>(const_cast<SwXMailMerge*>(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
-    {
-        Application::Reschedule( true );
-
-        // 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();
-        }
+            Application::Reschedule( true );
 
-        Application::Reschedule( true );
+            // 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 (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename)
-                aTempFileURL.SetURL( aTempFile->GetURL() );
-            else
+            Application::Reschedule( true );
+
+            if( IsMergeOk() && bMT_FILE )
             {
-                aTempFileURL.SetURL(sDescriptorPrefix);
-                // remove the unneeded temporary file
-                aTempFile->EnableKillingFile();
+                // save merged document
+                assert( aTempFile.get() );
+                INetURLObject aTempFileURL;
+                if (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename)
+                    aTempFileURL.SetURL( aTempFile->GetURL() );
+                else
+                {
+                    aTempFileURL.SetURL(sDescriptorPrefix);
+                    // 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, 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, 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();
 
-    Application::Reschedule( true );
+        Application::Reschedule( true );
 
-    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();
 }


More information about the Libreoffice-commits mailing list