    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #include <cstdarg>

    #include <hintids.hxx>

    #include <comphelper/string.hxx>
    #include <sfx2/request.hxx>
    #include <svx/svxids.hrc>

    #include <svtools/svmedit.hxx>
    #include <vcl/svapp.hxx>
    #include <vcl/wrkwin.hxx>
    #include <sfx2/app.hxx>
    #include <sfx2/docfac.hxx>
    #include <sfx2/printer.hxx>
    #include <sfx2/dispatch.hxx>
    #include <editeng/boxitem.hxx>
    #include <editeng/lrspitem.hxx>
    #include <editeng/ulspitem.hxx>
    #include <editeng/pbinitem.hxx>
    #include <editeng/paperinf.hxx>
    #include <editeng/formatbreakitem.hxx>
    #include <fmthdft.hxx>
    #include <swwait.hxx>
    #include <paratr.hxx>
    #include <swmodule.hxx>
    #include <wrtsh.hxx>
    #include <view.hxx>
    #include <docsh.hxx>
    #include <frmatr.hxx>
    #include <fldbas.hxx>
    #include <swundo.hxx>
    #include <IDocumentDeviceAccess.hxx>
    #include <dbmgr.hxx>
    #include <fmtcol.hxx>
    #include <frmmgr.hxx>
    #include <fldmgr.hxx>
    #include <pagedesc.hxx>
    #include <poolfmt.hxx>
    #include <expfld.hxx>
    #include <SwStyleNameMapper.hxx>
    #include <fmtpdsc.hxx>

    #include <cmdid.h>
    #include <globals.hrc>
    #include <app.hrc>
    #include <strings.hrc>
    #include <swabstdlg.hxx>
    #include <envimg.hxx>
    #include "appenv.hxx"

    #include <memory>

    #define ENV_NEWDOC      RET_OK
    #define ENV_INSERT      RET_USER

    // Function used for labels and envelopes in applab.cxx and appenv.cxx
    OUString InsertLabEnvText( SwWrtShell& rSh, SwFieldMgr& rFieldMgr, const OUString& rText )
    {
        OUString sRet;
        OUString aText = rText.replaceAll("\r", "");

        sal_Int32 nTokenPos = 0;
        while( -1 != nTokenPos )
        {
            OUString aLine = aText.getToken( 0, '\n', nTokenPos );
            while ( !aLine.isEmpty() )
            {
                OUString sTmpText;
                bool bField = false;

                sal_Int32 nPos = aLine.indexOf( '<' );
                if (0 != nPos)
                {
                    sal_Int32 const nCopy((nPos != -1) ? nPos : aLine.getLength());
                    sTmpText = aLine.copy(0, nCopy);
                    aLine = aLine.copy(nCopy);
                }
                else
                {
                    nPos = aLine.indexOf( '>' );
                    if ( nPos == -1 )
                    {
                        sTmpText = aLine;
                        aLine.clear();
                    }
                    else
                    {
                        sTmpText = aLine.copy( 0, nPos + 1);
                        aLine = aLine.copy( nPos + 1);

                        // Database fields must contain at least 3 points!
                        OUString sDBName( sTmpText.copy( 1, sTmpText.getLength() - 2));
                        sal_uInt16 nCnt = comphelper::string::getTokenCount(sDBName, '.');
                        if (nCnt >= 3)
                        {
                            sDBName = ::ReplacePoint(sDBName, true);
                            SwInsertField_Data aData(TYP_DBFLD, 0, sDBName, aEmptyOUStr, 0, &rSh );
                            rFieldMgr.InsertField( aData );
                            sRet = sDBName;
                            bField = true;
                        }
                    }
                }
                if ( !bField )
                    rSh.Insert( sTmpText );
            }
            rSh.SplitNode();
        }
        rSh.DelLeft();  // Again remove last linebreak

        return sRet;
    }

    static void lcl_CopyCollAttr(SwWrtShell const * pOldSh, SwWrtShell* pNewSh, sal_uInt16 nCollId)
    {
        sal_uInt16 nCollCnt = pOldSh->GetTextFormatCollCount();
        for( sal_uInt16 nCnt = 0; nCnt < nCollCnt; ++nCnt )
        {
            SwTextFormatColl* pColl = &pOldSh->GetTextFormatColl(nCnt);
            if(nCollId == pColl->GetPoolFormatId())
                pNewSh->GetTextCollFromPool(nCollId)->SetFormatAttr(pColl->GetAttrSet());
        }
    }

    void SwModule::InsertEnv( SfxRequest& rReq )
    {
        static sal_uInt16 nTitleNo = 0;

        SwDocShell      *pMyDocSh;
        SfxViewFrame    *pFrame;
        SwView          *pNewView;
        SwWrtShell      *pOldSh,
                        *pSh;

        // Get current shell
        pMyDocSh = static_cast<SwDocShell*>( SfxObjectShell::Current());
        pOldSh   = pMyDocSh ? pMyDocSh->GetWrtShell() : nullptr;

        // Create new document (don't show!)
        SfxObjectShellLock xDocSh( new SwDocShell( SfxObjectCreateMode::STANDARD ) );
        xDocSh->DoInitNew();
        pFrame = SfxViewFrame::LoadHiddenDocument( *xDocSh, SFX_INTERFACE_NONE );
        pNewView = static_cast<SwView*>( pFrame->GetViewShell());
        pNewView->AttrChangedNotify( &pNewView->GetWrtShell() ); // so that SelectShell is being called
        pSh = pNewView->GetWrtShellPtr();

        OUString aTmp( SwResId(STR_ENV_TITLE) );
        aTmp += OUString::number( ++nTitleNo );
        xDocSh->SetTitle( aTmp );

        // if applicable, copy the old Collections "Sender" and "Receiver" to
        // a new document
        if ( pOldSh )
        {
            ::lcl_CopyCollAttr(pOldSh, pSh, RES_POOLCOLL_JAKETADRESS);
            ::lcl_CopyCollAttr(pOldSh, pSh, RES_POOLCOLL_SENDADRESS);
        }

        // Read SwEnvItem from config
        SwEnvCfgItem aEnvCfg;

        // Check if there's already an envelope.
        bool bEnvChange = false;

        SfxItemSet aSet(GetPool(), svl::Items<FN_ENVELOP, FN_ENVELOP>{});
        aSet.Put(aEnvCfg.GetItem());

        SfxPrinter* pTempPrinter = pSh->getIDocumentDeviceAccess().getPrinter( true );
        if(pOldSh )
        {
            const SwPageDesc& rCurPageDesc = pOldSh->GetPageDesc(pOldSh->GetCurPageDesc());
            OUString sJacket;
            SwStyleNameMapper::FillUIName( RES_POOLPAGE_JAKET, sJacket );
            bEnvChange = rCurPageDesc.GetName() == sJacket;

            IDocumentDeviceAccess& rIDDA_old = pOldSh->getIDocumentDeviceAccess();
            if( rIDDA_old.getPrinter( false ) )
            {
                IDocumentDeviceAccess& rIDDA = pSh->getIDocumentDeviceAccess();
                rIDDA.setJobsetup( *rIDDA_old.getJobsetup() );
                //#69563# if it isn't the same printer then the pointer has been invalidated!
                pTempPrinter = rIDDA.getPrinter( true );
            }
            pTempPrinter->SetPaperBin(rCurPageDesc.GetMaster().GetPaperBin().GetValue());

        }

        vcl::Window *pParent = pOldSh ? pOldSh->GetWin() : nullptr;
        ScopedVclPtr<SfxAbstractTabDialog> pDlg;
        short nMode = ENV_INSERT;

        const SwEnvItem* pItem = rReq.GetArg<SwEnvItem>(FN_ENVELOP);
        if ( !pItem )
        {
            SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
            pDlg.disposeAndReset(pFact->CreateSwEnvDlg(pParent ? pParent->GetFrameWeld() : nullptr, aSet, pOldSh, pTempPrinter, !bEnvChange));
            nMode = pDlg->Execute();
        }
        else
        {
            const SfxBoolItem* pBoolItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_1);
            if ( pBoolItem && pBoolItem->GetValue() )
                nMode = ENV_NEWDOC;
        }

        if (nMode == ENV_NEWDOC || nMode == ENV_INSERT)
        {
            SwWait aWait( static_cast<SwDocShell&>(*xDocSh), true );

            // Read dialog and save item to config
            const SwEnvItem& rItem = pItem ? *pItem : static_cast<const SwEnvItem&>( pDlg->GetOutputItemSet()->Get(FN_ENVELOP) );
            aEnvCfg.GetItem() = rItem;
            aEnvCfg.Commit();

            // When we print we take the Jobsetup that is set up in the dialog.
            // Information has to be set here, before a possible destruction of
            // the new shell because the shell's printer has been handed to the
            // dialog.
            if ( nMode != ENV_NEWDOC )
            {
                OSL_ENSURE(pOldSh, "No document - wasn't 'Insert' disabled???");
                SvxPaperBinItem aItem( RES_PAPER_BIN );
                aItem.SetValue(static_cast<sal_uInt8>(pSh->getIDocumentDeviceAccess().getPrinter(true)->GetPaperBin()));
                pOldSh->GetPageDescFromPool(RES_POOLPAGE_JAKET)->GetMaster().SetFormatAttr(aItem);
            }

            SwWrtShell *pTmp = nMode == ENV_INSERT ? pOldSh : pSh;
            const SwPageDesc* pFollow = nullptr;
            SwTextFormatColl *pSend = pTmp->GetTextCollFromPool( RES_POOLCOLL_SENDADRESS ),
                         *pAddr = pTmp->GetTextCollFromPool( RES_POOLCOLL_JAKETADRESS);
            const OUString sSendMark = pSend->GetName();
            const OUString sAddrMark = pAddr->GetName();

            if (nMode == ENV_INSERT)
            {

                SetView(&pOldSh->GetView()); // Set pointer to top view

                // Delete new document
                xDocSh->DoClose();
                pSh = pOldSh;
                //#i4251# selected text or objects in the document should
                //not be deleted on inserting envelopes
                pSh->EnterStdMode();
                // Here it goes (insert)
                pSh->StartUndo(SwUndoId::UI_INSERT_ENVELOPE);
                pSh->StartAllAction();
                pSh->SttEndDoc(true);

                if (bEnvChange)
                {
                    // followup template: page 2
                    pFollow = pSh->GetPageDesc(pSh->GetCurPageDesc()).GetFollow();

                    // Delete text from the first page
                    if ( !pSh->SttNxtPg(true) )
                        pSh->EndPg(true);
                    pSh->DelRight();
                    // Delete frame of the first page
                    if ( pSh->GotoFly(sSendMark) )
                    {
                        pSh->EnterSelFrameMode();
                        pSh->DelRight();
                    }
                    if ( pSh->GotoFly(sAddrMark) )
                    {
                        pSh->EnterSelFrameMode();
                        pSh->DelRight();
                    }
                    pSh->SttEndDoc(true);
                }
                else
                    // Followup template: page 1
                    pFollow = &pSh->GetPageDesc(pSh->GetCurPageDesc());

                // Insert page break
                if ( pSh->IsCursorInTable() )
                {
                    pSh->SplitNode();
                    pSh->Right( CRSR_SKIP_CHARS, false, 1, false );
                    SfxItemSet aBreakSet( pSh->GetAttrPool(), svl::Items<RES_PAGEDESC, RES_PAGEDESC>{} );
                    aBreakSet.Put( SwFormatPageDesc( pFollow ) );
                    pSh->SetTableAttr( aBreakSet );
                }
                else
                {
                    OUString sFollowName(pFollow->GetName());
                    pSh->InsertPageBreak(&sFollowName, boost::none);
                }
                pSh->SttEndDoc(true);
            }
            else
            {
                pFollow = &pSh->GetPageDesc(pSh->GetCurPageDesc());
                // Let's go (print)
                pSh->StartAllAction();
                pSh->DoUndo(false);

                // Again, copy the new collections "Sender" and "Receiver" to
                // a new document
                if ( pOldSh )
                {
                    ::lcl_CopyCollAttr(pOldSh, pSh, RES_POOLCOLL_JAKETADRESS);
                    ::lcl_CopyCollAttr(pOldSh, pSh, RES_POOLCOLL_SENDADRESS);
                }
            }

            SET_CURR_SHELL(pSh);
            pSh->SetNewDoc();   // Avoid performance problems

            // Remember Flys of this site
            std::vector<SwFrameFormat*> aFlyArr;
            if( ENV_NEWDOC != nMode && !bEnvChange )
                pSh->GetPageObjs( aFlyArr );

            // Get page description
            SwPageDesc* pDesc = pSh->GetPageDescFromPool(RES_POOLPAGE_JAKET);
            SwFrameFormat&   rFormat  = pDesc->GetMaster();

            Printer *pPrt = pSh->getIDocumentDeviceAccess().getPrinter( true );

        // Borders (are put together by Shift-Offset and alignment)
            Size aPaperSize = pPrt->PixelToLogic( pPrt->GetPaperSizePixel(),
                                                  MapMode(MapUnit::MapTwip));
            if ( !aPaperSize.Width() && !aPaperSize.Height() )
                        aPaperSize = SvxPaperInfo::GetPaperSize(PAPER_A4);
            if ( aPaperSize.Width() > aPaperSize.Height() )
                Swap( aPaperSize );

            long lLeft  = rItem.m_nShiftRight,
                 lUpper = rItem.m_nShiftDown;

            sal_uInt16 nPageW = static_cast<sal_uInt16>(std::max(rItem.m_nWidth, rItem.m_nHeight)),
                   nPageH = static_cast<sal_uInt16>(std::min(rItem.m_nWidth, rItem.m_nHeight));

            switch (rItem.m_eAlign)
            {
                case ENV_HOR_LEFT: break;
                case ENV_HOR_CNTR: lLeft  += std::max(0L, long(aPaperSize.Width() - nPageW)) / 2;
                                   break;
                case ENV_HOR_RGHT: lLeft  += std::max(0L, long(aPaperSize.Width() - nPageW));
                                   break;
                case ENV_VER_LEFT: lUpper += std::max(0L, long(aPaperSize.Width() - nPageH));
                                   break;
                case ENV_VER_CNTR: lUpper += std::max(0L, long(aPaperSize.Width() - nPageH)) / 2;
                                   break;
                case ENV_VER_RGHT: break;
            }
            SvxLRSpaceItem aLRMargin( RES_LR_SPACE );
            SvxULSpaceItem aULMargin( RES_UL_SPACE );
            aLRMargin.SetLeft (static_cast<sal_uInt16>(lLeft) );
            aULMargin.SetUpper(static_cast<sal_uInt16>(lUpper));
            aLRMargin.SetRight(0);
            aULMargin.SetLower(0);
            rFormat.SetFormatAttr(aLRMargin);
            rFormat.SetFormatAttr(aULMargin);

            // Header and footer
            rFormat.SetFormatAttr(SwFormatHeader(false));
            pDesc->ChgHeaderShare(false);
            rFormat.SetFormatAttr(SwFormatFooter(false));
            pDesc->ChgFooterShare(false);

            // Page numbering
            pDesc->SetUseOn(UseOnPage::All);

            // Page size
            rFormat.SetFormatAttr(SwFormatFrameSize(ATT_FIX_SIZE,
                                                nPageW + lLeft, nPageH + lUpper));

            // Set type of page numbering
            SvxNumberType aType;
            aType.SetNumberingType(SVX_NUM_NUMBER_NONE);
            pDesc->SetNumType(aType);

            // Followup template
            if (pFollow)
                pDesc->SetFollow(pFollow);

            // Landscape
            pDesc->SetLandscape( rItem.m_eAlign >= ENV_VER_LEFT &&
                                 rItem.m_eAlign <= ENV_VER_RGHT);

            // Apply page description

            size_t nPos;
            pSh->FindPageDescByName( pDesc->GetName(),
                                        false,
                                        &nPos );

            pSh->ChgPageDesc( nPos, *pDesc);
            pSh->ChgCurPageDesc(*pDesc);

            // Insert Frame
            SwFlyFrameAttrMgr aMgr(false, pSh, Frmmgr_Type::ENVELP);
            SwFieldMgr aFieldMgr;
            aMgr.SetHeightSizeType(ATT_VAR_SIZE);

            // Overwrite defaults!
            aMgr.GetAttrSet().Put( SvxBoxItem(RES_BOX) );
            aMgr.SetULSpace( 0, 0 );
            aMgr.SetLRSpace( 0, 0 );

            // Sender
            if (rItem.m_bSend)
            {
                pSh->SttEndDoc(true);
                aMgr.InsertFlyFrame(RndStdIds::FLY_AT_PAGE,
                    Point(rItem.m_nSendFromLeft + lLeft, rItem.m_nSendFromTop  + lUpper),
                    Size (rItem.m_nAddrFromLeft - rItem.m_nSendFromLeft, 0));

                pSh->EnterSelFrameMode();
                pSh->SetFlyName(sSendMark);
                pSh->UnSelectFrame();
                pSh->LeaveSelFrameMode();
                pSh->SetTextFormatColl( pSend );
                InsertLabEnvText( *pSh, aFieldMgr, rItem.m_aSendText );
                aMgr.UpdateAttrMgr();
            }

            // Addressee
            pSh->SttEndDoc(true);

            aMgr.InsertFlyFrame(RndStdIds::FLY_AT_PAGE,
                Point(rItem.m_nAddrFromLeft + lLeft, rItem.m_nAddrFromTop  + lUpper),
                Size (nPageW - rItem.m_nAddrFromLeft - 566, 0));
            pSh->EnterSelFrameMode();
            pSh->SetFlyName(sAddrMark);
            pSh->UnSelectFrame();
            pSh->LeaveSelFrameMode();
            pSh->SetTextFormatColl( pAddr );
            InsertLabEnvText(*pSh, aFieldMgr, rItem.m_aAddrText);

            // Move Flys to the "old" pages
            if (!aFlyArr.empty())
                pSh->SetPageObjsNewPage(aFlyArr);

            // Finished
            pSh->SttEndDoc(true);

            pSh->EndAllAction();

            if (nMode == ENV_NEWDOC)
                pSh->DoUndo();
            else
                pSh->EndUndo(SwUndoId::UI_INSERT_ENVELOPE);

            if (nMode == ENV_NEWDOC)
            {
                pFrame->GetFrame().Appear();

                if ( rItem.m_aAddrText.indexOf('<') >= 0 )
                {
                    static sal_uInt16 const aInva[] =
                                        {
                                            SID_SBA_BRW_UPDATE,
                                            SID_SBA_BRW_INSERT,
                                            SID_SBA_BRW_MERGE,
                                            0
                                        };
                    pFrame->GetBindings().Invalidate( aInva );

                    // Open database beamer
                    ShowDBObj(*pNewView, pSh->GetDBData());
                }
            }

            if ( !pItem )
            {
                rReq.AppendItem( rItem );
                if ( nMode == ENV_NEWDOC )
                    rReq.AppendItem( SfxBoolItem( FN_PARAM_1, true ) );
            }

            rReq.Done();
        }
        else    // Abort
        {
            rReq.Ignore();

            xDocSh->DoClose();
            --nTitleNo;

            // Set pointer to top view
            if (pOldSh)
                SetView(&pOldSh->GetView());
        }
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V1016 Expression 'rItem.m_eAlign <= ENV_VER_RGHT' is always true.