[Libreoffice-commits] core.git: Branch 'distro/cib/libreoffice-6-1' - 2 commits - sw/source

Szymon Kłos (via logerrit) logerrit at kemper.freedesktop.org
Fri Oct 11 07:43:03 UTC 2019


 sw/source/uibase/dbui/dbmgr.cxx |  746 ++++++++++++++++++++--------------------
 1 file changed, 380 insertions(+), 366 deletions(-)

New commits:
commit 30496b80fd061afe10f6842fe257babb2b2b4bf5
Author:     Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Wed Jan 2 19:03:25 2019 +0100
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Fri Oct 11 09:42:22 2019 +0200

    tdf#117480 fix crash in mailmerge
    
    Catch exceptions and hide progress dialog.
    
    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>
    Reviewed-on: https://gerrit.libreoffice.org/72280
    Reviewed-by: Michael Stahl <Michael.Stahl at cib.de>
    Tested-by: Jenkins
    (cherry picked from commit 4bba6c122c3bb3468bccd69d53d70d00fd00bdcc)
    
    Change-Id: Ie63c8d7e001c90f40cf7504fd8248a6742e9d244
    Reviewed-on: https://gerrit.libreoffice.org/80553
    Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
    Tested-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index de0a9ad8869d..a4c618462f5f 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -1319,453 +1319,464 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     vcl::Window *pSourceWindow = nullptr;
     std::shared_ptr<weld::GenericDialogController> xProgressDlg;
 
-    if( !bIsMergeSilent )
+    try
     {
-        // construct the process dialog
-        pSourceWindow = &pSourceShell->GetView().GetEditWin();
-        if (!bMT_PRINTER)
-            xProgressDlg.reset(new CreateMonitor(pSourceWindow->GetFrameWeld()));
-        else
+        if( !bIsMergeSilent )
         {
-            xProgressDlg.reset(new PrintMonitor(pSourceWindow->GetFrameWeld()));
-            static_cast<PrintMonitor*>(xProgressDlg.get())->set_title(
-                pSourceDocSh->GetTitle(22));
-        }
-        weld::DialogController::runAsync(xProgressDlg, [this, &xProgressDlg](sal_Int32 nResult){
-            if (nResult == RET_CANCEL)
-                MergeCancel();
-            xProgressDlg.reset();
-        });
-
-        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 );
+            // construct the process dialog
+            pSourceWindow = &pSourceShell->GetView().GetEditWin();
+            if (!bMT_PRINTER)
+                xProgressDlg.reset(new CreateMonitor(pSourceWindow->GetFrameWeld()));
+            else
+            {
+                xProgressDlg.reset(new PrintMonitor(pSourceWindow->GetFrameWeld()));
+                static_cast<PrintMonitor*>(xProgressDlg.get())->set_title(
+                    pSourceDocSh->GetTitle(22));
+            }
+            weld::DialogController::runAsync(xProgressDlg, [this, &xProgressDlg](sal_Int32 nResult){
+                if (nResult == RET_CANCEL)
+                    MergeCancel();
+                xProgressDlg.reset();
+            });
 
-        // import current print settings
-        const SwPrintData &rPrintData = pSourceShell->getIDocumentDeviceAccess().getPrintData();
-        pTargetDoc->getIDocumentDeviceAccess().setPrintData(rPrintData);
+            Application::Reschedule( true );
+        }
 
-        if (nMaxDumpDocs)
-            lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
-    }
-    else if( pTargetView )
-    {
-        pTargetShell = pTargetView->GetWrtShellPtr();
-        pTargetDoc = pTargetShell->GetDoc();
-        xTargetDocShell = pTargetView->GetDocShell();
-    }
+        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( bCreateSingleFile )
-    {
-        // determine the page style and number used at the start of the source document
-        pSourceShell->SttEndDoc(true);
-        nStartingPageNo = pSourceShell->GetVirtPageNum();
-    }
+            // import current print settings
+            const SwPrintData &rPrintData = pSourceShell->getIDocumentDeviceAccess().getPrintData();
+            pTargetDoc->getIDocumentDeviceAccess().setPrintData(rPrintData);
 
-    // Progress, to prohibit KeyInputs
-    SfxProgress aProgress(pSourceDocSh, ::aEmptyOUStr, 1);
+            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*>(xProgressDlg.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*>(xProgressDlg.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*>(xProgressDlg.get())->SetCurrentPosition(nDocNo);
-                else {
-                    PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>(xProgressDlg.get());
-                    pPrintMonDlg->m_xPrinter->set_label(bNeedsTempFiles
-                        ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 2));
-                    OUString sStat( SwResId(STR_STATSTR_LETTER) );
-                    sStat += " " + OUString::number( nDocNo );
-                    pPrintMonDlg->m_xPrintInfo->set_label(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 = "_";
                 }
-                //TODO xProgressDlg->queue_draw();
-            }
-
-            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*>(xProgressDlg.get())->SetCurrentPosition(nDocNo);
+                    else {
+                        PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>(xProgressDlg.get());
+                        pPrintMonDlg->m_xPrinter->set_label(bNeedsTempFiles
+                            ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 2));
+                        OUString sStat( SwResId(STR_STATSTR_LETTER) );
+                        sStat += " " + OUString::number( nDocNo );
+                        pPrintMonDlg->m_xPrintInfo->set_label(sStat);
+                    }
+                    //TODO xProgressDlg->queue_draw();
+                }
 
-                // 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);
-                // ensure layout is up to date in order to get correct page count
-                pWorkShell->CalcLayout();
-                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();
+                    // remove of invisible content has influence on page count and so on fields for page count,
+                    // therefore layout has to be updated before fields are converted to text
+                    pWorkShell->CalcLayout();
+                    pWorkShell->ConvertFieldsToText();
+                    pWorkShell->SetNumberingRestart();
+                    if( bSynchronizedDoc )
+                    {
+                        lcl_RemoveSectionLinks( *pWorkShell );
+                    }
+
+                    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( !SwMailMergeHelper::CheckMailAddress( sColumnData ) )
+                    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 ) )
                     {
-                        uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc(
-                            rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType,
-                            sMailEncoding, pStoreToFilter->GetMimeType() );
-                        if( xMessage.is() )
+                        m_aMergeStatus = MergeStatus::Error;
+                    }
+
+                    // back to the MM DB manager
+                    pWorkDoc->SetDBManager( this );
+
+                    if( bMT_EMAIL && !IsMergeError() )
+                    {
+                        // 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 )
+
+        // 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 );
+
+        if (xProgressDlg)
         {
-            // print the target document
-            uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
-            lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, aOptions );
-            pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ );
+            xProgressDlg->response(RET_OK);
         }
-    }
 
-    // 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();
+        // unlock all dispatchers
+        pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
+        while (pViewFrame)
+        {
+            pViewFrame->GetDispatcher()->Lock(false);
+            pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
+        }
 
-    Application::Reschedule( true );
+        SW_MOD()->SetView(&pSourceShell->GetView());
 
-    if (xProgressDlg)
-    {
-        xProgressDlg->response(RET_OK);
-    }
+        if( xMailDispatcher.is() )
+        {
+            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();
+        }
 
-    // unlock all dispatchers
-    pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
-    while (pViewFrame)
-    {
-        pViewFrame->GetDispatcher()->Lock(false);
-        pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
+        // 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 );
     }
-
-    SW_MOD()->SetView(&pSourceShell->GetView());
-
-    if( xMailDispatcher.is() )
+    catch (const uno::Exception&)
     {
-        if( IsMergeOk() )
+        if (xProgressDlg)
         {
-            // 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();
+            xProgressDlg->response(RET_CANCEL);
         }
-        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 );
-
     return !IsMergeError();
 }
 
commit 68fde939500888a4feb094b9f31c3917e93f4d26
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Tue Jul 3 21:38:48 2018 +1000
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Fri Oct 11 09:42:07 2019 +0200

    Avoid failing assert in SwDBManager::MergeMailFiles
    
    The failing assert reproducing scenario is the steps in
    https://bugs.documentfoundation.org/show_bug.cgi?id=116543#c0
    
    rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER;
    rMergeDescriptor.bPrefixIsFilename is true;
    rMergeDescriptor.sPrefix is empty.
    
    The failing assert is unrelated to the crash in tdf#116543.
    It looks like the assertion was incorrect; assert on empty
    prefix instead.
    
    Change-Id: Ibeedb90a9fac810124283fc06aa756777fa04720
    Reviewed-on: https://gerrit.libreoffice.org/56863
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/80552
    Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
    Tested-by: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index bb3c5c97b7bb..de0a9ad8869d 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -1200,19 +1200,22 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     const bool bIsMergeSilent = IsMergeSilent();
 
     bool bCheckSingleFile_ = rMergeDescriptor.bCreateSingleFile;
+    OUString sPrefix_ = rMergeDescriptor.sPrefix;
     if( bMT_EMAIL )
     {
         assert( !rMergeDescriptor.bPrefixIsFilename );
-        assert( bMT_EMAIL && !bCheckSingleFile_ );
+        assert(!bCheckSingleFile_);
         bCheckSingleFile_ = false;
     }
     else if( bMT_SHELL || bMT_PRINTER )
     {
-        assert( !rMergeDescriptor.bPrefixIsFilename );
-        assert( (bMT_SHELL || bMT_PRINTER) && bCheckSingleFile_ );
+        assert(bCheckSingleFile_);
         bCheckSingleFile_ = true;
+        assert(sPrefix_.isEmpty());
+        sPrefix_.clear();
     }
     const bool bCreateSingleFile = bCheckSingleFile_;
+    const OUString sDescriptorPrefix = sPrefix_;
 
     // Setup for dumping debugging documents
     static const char *sMaxDumpDocs = nullptr;
@@ -1435,7 +1438,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
         // create a new temporary file name - only done once in case of bCreateSingleFile
         if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile ))
         {
-            OUString sPrefix = rMergeDescriptor.sPrefix;
+            OUString sPrefix = sDescriptorPrefix;
             OUString sLeading;
 
             //#i97667# if the name is from a database field then it will be used _as is_
@@ -1690,11 +1693,11 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             // save merged document
             assert( aTempFile.get() );
             INetURLObject aTempFileURL;
-            if( rMergeDescriptor.sPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename )
+            if (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename)
                 aTempFileURL.SetURL( aTempFile->GetURL() );
             else
             {
-                aTempFileURL.SetURL( rMergeDescriptor.sPrefix );
+                aTempFileURL.SetURL(sDescriptorPrefix);
                 // remove the unneeded temporary file
                 aTempFile->EnableKillingFile();
             }


More information about the Libreoffice-commits mailing list