    /* -*- 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 <cmdid.h>
    #include <init.hxx>
    #include <svx/svdmodel.hxx>
    #include <editeng/ulspitem.hxx>
    #include <editeng/paperinf.hxx>
    #include <editeng/frmdiritem.hxx>
    #include <sfx2/bindings.hxx>
    #include <sfx2/dispatch.hxx>
    #include <sfx2/printer.hxx>
    #include <tools/globname.hxx>
    #include <sal/log.hxx>
    #include <fmtfsize.hxx>
    #include <fmthdft.hxx>
    #include <fmtcntnt.hxx>
    #include <ftninfo.hxx>
    #include <fesh.hxx>
    #include <ndole.hxx>
    #include <mdiexp.hxx>
    #include <doc.hxx>
    #include <IDocumentUndoRedo.hxx>
    #include <IDocumentFieldsAccess.hxx>
    #include <DocumentContentOperationsManager.hxx>
    #include <IDocumentState.hxx>
    #include <IDocumentLayoutAccess.hxx>
    #include <docary.hxx>
    #include <rootfrm.hxx>
    #include <frmtool.hxx>
    #include <poolfmt.hxx>
    #include <docsh.hxx>
    #include <ftnidx.hxx>
    #include <fmtftn.hxx>
    #include <txtftn.hxx>
    #include <fntcache.hxx>
    #include <viewopt.hxx>
    #include <fldbas.hxx>
    #include <swwait.hxx>
    #include <GetMetricVal.hxx>
    #include <strings.hrc>
    #include <hints.hxx>
    #include <SwUndoPageDesc.hxx>
    #include <pagedeschint.hxx>
    #include <tgrditem.hxx>
    #include <unotools/configmgr.hxx>
    #include <unotools/syslocale.hxx>
    #include <svx/swframetypes.hxx>
    #include <svx/svxids.hrc>

    using namespace com::sun::star;

    static void lcl_DefaultPageFormat( sal_uInt16 nPoolFormatId,
                                    SwFrameFormat &rFormat1,
                                    SwFrameFormat &rFormat2,
                                    SwFrameFormat &rFormat3,
                                    SwFrameFormat &rFormat4)
    {
        // --> #i41075# Printer on demand
        // This function does not require a printer anymore.
        // The default page size is obtained from the application
        //locale

        SwFormatFrameSize aFrameSize( ATT_FIX_SIZE );
        const Size aPhysSize = SvxPaperInfo::GetDefaultPaperSize();
        aFrameSize.SetSize( aPhysSize );

        // Prepare for default margins.
        // Margins have a default minimum size.
        // If the printer forces a larger margins, that's ok too.
        // The HTML page desc had A4 as page size always.
        // This has been changed to take the page size from the printer.
        // Unfortunately, the margins of the HTML page desc are smaller than
        // the margins used here in general, so one extra case is required.
        // In the long term, this needs to be changed to always keep the
        // margins from the page desc.
        sal_Int32 nMinTop, nMinBottom, nMinLeft, nMinRight;
        if( RES_POOLPAGE_HTML == nPoolFormatId )
        {
            nMinRight = nMinTop = nMinBottom = GetMetricVal( CM_1 );
            nMinLeft = nMinRight * 2;
        }
        else if (!utl::ConfigManager::IsFuzzing() && MeasurementSystem::Metric == SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() )
        {
            nMinTop = nMinBottom = nMinLeft = nMinRight = 1134; // 2 centimeters
        }
        else
        {
            nMinTop = nMinBottom = 1440;    // as in MS Word: 1 Inch
            nMinLeft = nMinRight = 1800;    //                1,25 Inch
        }

        // set margins
        SvxLRSpaceItem aLR( RES_LR_SPACE );
        SvxULSpaceItem aUL( RES_UL_SPACE );

        aUL.SetUpper( static_cast<sal_uInt16>(nMinTop) );
        aUL.SetLower( static_cast<sal_uInt16>(nMinBottom) );
        aLR.SetRight( nMinRight );
        aLR.SetLeft( nMinLeft );

        rFormat1.SetFormatAttr( aFrameSize );
        rFormat1.SetFormatAttr( aLR );
        rFormat1.SetFormatAttr( aUL );

        rFormat2.SetFormatAttr( aFrameSize );
        rFormat2.SetFormatAttr( aLR );
        rFormat2.SetFormatAttr( aUL );

        rFormat3.SetFormatAttr( aFrameSize );
        rFormat3.SetFormatAttr( aLR );
        rFormat3.SetFormatAttr( aUL );

        rFormat4.SetFormatAttr( aFrameSize );
        rFormat4.SetFormatAttr( aLR );
        rFormat4.SetFormatAttr( aUL );
    }

    static void lcl_DescSetAttr( const SwFrameFormat &rSource, SwFrameFormat &rDest,
                             const bool bPage = true )
    {
        // We should actually use ItemSet's Intersect here, but that doesn't work
        // correctly if we have different WhichRanges.

        // Take over the attributes which are of interest.
        sal_uInt16 const aIdArr[] = {
            RES_FRM_SIZE,                   RES_UL_SPACE,                   // [83..86
            RES_BACKGROUND,                 RES_SHADOW,                     // [99..101
            RES_COL,                        RES_COL,                        // [103
            RES_TEXTGRID,                   RES_TEXTGRID,                   // [109
            RES_FRAMEDIR,                   RES_FRAMEDIR,                   // [114
            RES_HEADER_FOOTER_EAT_SPACING,  RES_HEADER_FOOTER_EAT_SPACING,  // [115
            RES_UNKNOWNATR_CONTAINER,       RES_UNKNOWNATR_CONTAINER,       // [143

            // take over DrawingLayer FillStyles
            XATTR_FILL_FIRST,               XATTR_FILL_LAST,                // [1014

            0};

        const SfxPoolItem* pItem;
        for( sal_uInt16 n = 0; aIdArr[ n ]; n += 2 )
        {
            for( sal_uInt16 nId = aIdArr[ n ]; nId <= aIdArr[ n+1]; ++nId )
            {
                // #i45539#
                // bPage == true:
                // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING
                // bPage == false:
                // All in aIdArr except from RES_COL and RES_PAPER_BIN:
                bool bExecuteId(true);

                if(bPage)
                {
                    // When Page
                    switch(nId)
                    {
                        // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING
                        case RES_HEADER_FOOTER_EAT_SPACING:
                        // take out SvxBrushItem; it's the result of the fallback
                        // at SwFormat::GetItemState and not really in state SfxItemState::SET
                        case RES_BACKGROUND:
                            bExecuteId = false;
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    // When not Page
                    switch(nId)
                    {
                        // When not Page: All in aIdArr except from RES_COL and RES_PAPER_BIN:
                        case RES_COL:
                        case RES_PAPER_BIN:
                            bExecuteId = false;
                            break;
                        default:
                            break;
                    }
                }

                if(bExecuteId)
                {
                    if (SfxItemState::SET == rSource.GetItemState(nId, false, &pItem))
                    {
                        rDest.SetFormatAttr(*pItem);
                    }
                    else
                    {
                        rDest.ResetFormatAttr(nId);
                    }
                }
            }
        }

        // Transmit pool and help IDs too
        rDest.SetPoolFormatId( rSource.GetPoolFormatId() );
        rDest.SetPoolHelpId( rSource.GetPoolHelpId() );
        rDest.SetPoolHlpFileId( rSource.GetPoolHlpFileId() );
    }

    namespace
    {
        SwFrameFormat& getFrameFormat(SwPageDesc &rDesc, bool bLeft, bool bFirst)
        {
            if (bFirst)
            {
                if (bLeft)
                    return rDesc.GetFirstLeft();
                return rDesc.GetFirstMaster();
            }
            return rDesc.GetLeft();
        }

        const SwFrameFormat& getConstFrameFormat(const SwPageDesc &rDesc, bool bLeft, bool bFirst)
        {
            return getFrameFormat(const_cast<SwPageDesc&>(rDesc), bLeft, bFirst);
        }
    }

    void SwDoc::CopyMasterHeader(const SwPageDesc &rChged, const SwFormatHeader &rHead, SwPageDesc &rDesc, bool bLeft, bool bFirst)
    {
        assert(bLeft || bFirst);
        SwFrameFormat& rDescFrameFormat = getFrameFormat(rDesc, bLeft, bFirst);
        if (bFirst && bLeft)
        {
            // special case: always shared with something
            rDescFrameFormat.SetFormatAttr( rChged.IsFirstShared()
                    ? rDesc.GetLeft().GetHeader()
                    : rDesc.GetFirstMaster().GetHeader());
        }
        else if ((bFirst ? rChged.IsFirstShared() : rChged.IsHeaderShared())
             || !rHead.IsActive())
        {
            // Left or first shares the header with the Master.
            rDescFrameFormat.SetFormatAttr( rDesc.GetMaster().GetHeader() );
        }
        else if ( rHead.IsActive() )
        {   // Left or first gets its own header if the Format doesn't already have one.
            // If it already has one and it points to the same Section as the
            // Right one, it needs to get an own Header.
            // The content is evidently copied.
            const SwFormatHeader &rFormatHead = rDescFrameFormat.GetHeader();
            if ( !rFormatHead.IsActive() )
            {
                SwFormatHeader aHead( getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::HEADERL, nullptr ) );
                rDescFrameFormat.SetFormatAttr( aHead );
                // take over additional attributes (margins, borders ...)
                ::lcl_DescSetAttr( *rHead.GetHeaderFormat(), *aHead.GetHeaderFormat(), false);
            }
            else
            {
                const SwFrameFormat *pRight = rHead.GetHeaderFormat();
                const SwFormatContent &aRCnt = pRight->GetContent();
                const SwFormatContent &aCnt = rFormatHead.GetHeaderFormat()->GetContent();

                if (!aCnt.GetContentIdx())
                {
                    const SwFrameFormat& rChgedFrameFormat = getConstFrameFormat(rChged, bLeft, bFirst);
                    rDescFrameFormat.SetFormatAttr( rChgedFrameFormat.GetHeader() );
                }
                else if ((*aRCnt.GetContentIdx() == *aCnt.GetContentIdx()) ||
                    // The ContentIdx is _always_ different when called from
                    // SwDocStyleSheet::SetItemSet, because it deep-copies the
                    // PageDesc.  So check if it was previously shared.
                     (bFirst ? rDesc.IsFirstShared() : rDesc.IsHeaderShared()))
                {
                    SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(),
                            bFirst ? "First header" : "Left header",
                                                    GetDfltFrameFormat() );
                    ::lcl_DescSetAttr( *pRight, *pFormat, false );
                    // The section which the right header attribute is pointing
                    // is copied, and the Index to the StartNode is set to
                    // the left or first header attribute.
                    SwNodeIndex aTmp( GetNodes().GetEndOfAutotext() );
                    SwStartNode* pSttNd = SwNodes::MakeEmptySection( aTmp, SwHeaderStartNode );
                    SwNodeRange aRange( aRCnt.GetContentIdx()->GetNode(), 0,
                                *aRCnt.GetContentIdx()->GetNode().EndOfSectionNode() );
                    aTmp = *pSttNd->EndOfSectionNode();
                    GetNodes().Copy_( aRange, aTmp, false );
                    aTmp = *pSttNd;
                    GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRange, 0, aTmp);

                    pFormat->SetFormatAttr( SwFormatContent( pSttNd ) );
                    rDescFrameFormat.SetFormatAttr( SwFormatHeader( pFormat ) );
                }
                else
                    ::lcl_DescSetAttr( *pRight,
                                   *const_cast<SwFrameFormat*>(rFormatHead.GetHeaderFormat()), false );
            }
        }
    }

    void SwDoc::CopyMasterFooter(const SwPageDesc &rChged, const SwFormatFooter &rFoot, SwPageDesc &rDesc, bool bLeft, bool bFirst)
    {
        assert(bLeft || bFirst);
        SwFrameFormat& rDescFrameFormat = getFrameFormat(rDesc, bLeft, bFirst);
        if (bFirst && bLeft)
        {
            // special case: always shared with something
            rDescFrameFormat.SetFormatAttr( rChged.IsFirstShared()
                    ? rDesc.GetLeft().GetFooter()
                    : rDesc.GetFirstMaster().GetFooter());
        }
        else if ((bFirst ? rChged.IsFirstShared() : rChged.IsFooterShared())
            || !rFoot.IsActive())
        {
            // Left or first shares the Header with the Master.
            rDescFrameFormat.SetFormatAttr( rDesc.GetMaster().GetFooter() );
        }
        else if ( rFoot.IsActive() )
        {   // Left or first gets its own Footer if the Format does not already have one.
            // If the Format already has a Footer and it points to the same section as the Right one,
            // it needs to get an own one.
            // The content is evidently copied.
            const SwFormatFooter &rFormatFoot = rDescFrameFormat.GetFooter();
            if ( !rFormatFoot.IsActive() )
            {
                SwFormatFooter aFoot( getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::FOOTER, nullptr ) );
                rDescFrameFormat.SetFormatAttr( aFoot );
                // Take over additional attributes (margins, borders ...).
                ::lcl_DescSetAttr( *rFoot.GetFooterFormat(), *aFoot.GetFooterFormat(), false);
            }
            else
            {
                const SwFrameFormat *pRight = rFoot.GetFooterFormat();
                const SwFormatContent &aRCnt = pRight->GetContent();
                const SwFormatContent &aLCnt = rFormatFoot.GetFooterFormat()->GetContent();
                if( !aLCnt.GetContentIdx() )
                {
                    const SwFrameFormat& rChgedFrameFormat = getConstFrameFormat(rChged, bLeft, bFirst);
                    rDescFrameFormat.SetFormatAttr( rChgedFrameFormat.GetFooter() );
                }
                else if ((*aRCnt.GetContentIdx() == *aLCnt.GetContentIdx()) ||
                    // The ContentIdx is _always_ different when called from
                    // SwDocStyleSheet::SetItemSet, because it deep-copies the
                    // PageDesc.  So check if it was previously shared.
                     (bFirst ? rDesc.IsFirstShared() : rDesc.IsFooterShared()))
                {
                    SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(),
                            bFirst ? "First footer" : "Left footer",
                                                    GetDfltFrameFormat() );
                    ::lcl_DescSetAttr( *pRight, *pFormat, false );
                    // The section to which the right footer attribute is pointing
                    // is copied, and the Index to the StartNode is set to
                    // the left footer attribute.
                    SwNodeIndex aTmp( GetNodes().GetEndOfAutotext() );
                    SwStartNode* pSttNd = SwNodes::MakeEmptySection( aTmp, SwFooterStartNode );
                    SwNodeRange aRange( aRCnt.GetContentIdx()->GetNode(), 0,
                                *aRCnt.GetContentIdx()->GetNode().EndOfSectionNode() );
                    aTmp = *pSttNd->EndOfSectionNode();
                    GetNodes().Copy_( aRange, aTmp, false );
                    aTmp = *pSttNd;
                    GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRange, 0, aTmp);

                    pFormat->SetFormatAttr( SwFormatContent( pSttNd ) );
                    rDescFrameFormat.SetFormatAttr( SwFormatFooter( pFormat ) );
                }
                else
                    ::lcl_DescSetAttr( *pRight,
                                   *const_cast<SwFrameFormat*>(rFormatFoot.GetFooterFormat()), false );
            }
        }
    }

    void SwDoc::ChgPageDesc( size_t i, const SwPageDesc &rChged )
    {
        OSL_ENSURE(i < m_PageDescs.size(), "PageDescs is out of range.");

        SwPageDesc& rDesc = *m_PageDescs[i];
        SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();

        if (GetIDocumentUndoRedo().DoesUndo())
        {
            SwUndo *const pUndo(new SwUndoPageDesc(rDesc, rChged, this));
            GetIDocumentUndoRedo().AppendUndo(pUndo);
        }
        ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());

        // Mirror at first if needed.
        if ( rChged.GetUseOn() == UseOnPage::Mirror )
            const_cast<SwPageDesc&>(rChged).Mirror();
        else
        {
            // Or else transfer values from Master to Left
            ::lcl_DescSetAttr(rChged.GetMaster(),
                       const_cast<SwPageDesc&>(rChged).GetLeft());
        }
        ::lcl_DescSetAttr(rChged.GetMaster(),
                       const_cast<SwPageDesc&>(rChged).GetFirstMaster());
        ::lcl_DescSetAttr(rChged.GetLeft(),
                       const_cast<SwPageDesc&>(rChged).GetFirstLeft());

        // Take over NumType.
        if( rChged.GetNumType().GetNumberingType() != rDesc.GetNumType().GetNumberingType() )
        {
            rDesc.SetNumType( rChged.GetNumType() );
            // Notify page number fields that NumFormat has changed
            getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::PageNumber )->UpdateFields();
            getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::RefPageGet )->UpdateFields();

            // If the numbering scheme has changed we could have QuoVadis/ErgoSum texts
            // that refer to a changed page, so we invalidate foot notes.
            SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs();
            for( SwFootnoteIdxs::size_type nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos )
            {
                SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ];
                const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
                pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumStr());
            }
        }

        // Take over orientation
        rDesc.SetLandscape( rChged.GetLandscape() );

        // #i46909# no undo if header or footer changed
        bool bHeaderFooterChanged = false;

        // Synch header.
        const SwFormatHeader &rHead = rChged.GetMaster().GetHeader();
        if (undoGuard.UndoWasEnabled())
        {
            // #i46909# no undo if header or footer changed
            // Did something change in the nodes?
            const SwFormatHeader &rOldHead = rDesc.GetMaster().GetHeader();
            bHeaderFooterChanged |=
                ( rHead.IsActive() != rOldHead.IsActive() ||
                  rChged.IsHeaderShared() != rDesc.IsHeaderShared() ||
                  rChged.IsFirstShared() != rDesc.IsFirstShared() );
        }
        rDesc.GetMaster().SetFormatAttr( rHead );
        CopyMasterHeader(rChged, rHead, rDesc, true, false); // Copy left header
        CopyMasterHeader(rChged, rHead, rDesc, false, true); // Copy first master
        CopyMasterHeader(rChged, rHead, rDesc, true, true);  // Copy first left
        rDesc.ChgHeaderShare( rChged.IsHeaderShared() );

        // Synch Footer.
        const SwFormatFooter &rFoot = rChged.GetMaster().GetFooter();
        if (undoGuard.UndoWasEnabled())
        {
            // #i46909# no undo if header or footer changed
            // Did something change in the Nodes?
            const SwFormatFooter &rOldFoot = rDesc.GetMaster().GetFooter();
            bHeaderFooterChanged |=
                ( rFoot.IsActive() != rOldFoot.IsActive() ||
                  rChged.IsFooterShared() != rDesc.IsFooterShared() );
        }
        rDesc.GetMaster().SetFormatAttr( rFoot );
        CopyMasterFooter(rChged, rFoot, rDesc, true, false); // Copy left footer
        CopyMasterFooter(rChged, rFoot, rDesc, false, true); // Copy first master
        CopyMasterFooter(rChged, rFoot, rDesc, true, true);  // Copy first left
        rDesc.ChgFooterShare( rChged.IsFooterShared() );
        // there is just one first shared flag for both header and footer?
        rDesc.ChgFirstShare( rChged.IsFirstShared() );

        if ( rDesc.GetName() != rChged.GetName() )
            rDesc.SetName( rChged.GetName() );

        // A RegisterChange is triggered, if necessary
        rDesc.SetRegisterFormatColl( rChged.GetRegisterFormatColl() );

        // If UseOn or the Follow change, the paragraphs need to know about it.
        bool bUseOn  = false;
        bool bFollow = false;
        if (rDesc.GetUseOn() != rChged.GetUseOn())
        {
            rDesc.SetUseOn( rChged.GetUseOn() );
            bUseOn = true;
        }
        if (rDesc.GetFollow() != rChged.GetFollow())
        {
            if (rChged.GetFollow() == &rChged)
            {
                if (rDesc.GetFollow() != &rDesc)
                {
                    rDesc.SetFollow( &rDesc );
                    bFollow = true;
                }
            }
            else
            {
                rDesc.SetFollow( rChged.m_pFollow );
                bFollow = true;
            }
        }

        if ( (bUseOn || bFollow) && pTmpRoot)
            // Inform layout!
        {
            for( auto aLayout : GetAllLayouts() )
                aLayout->AllCheckPageDescs();
        }

        // Take over the page attributes.
        ::lcl_DescSetAttr( rChged.GetMaster(), rDesc.GetMaster() );
        ::lcl_DescSetAttr( rChged.GetLeft(), rDesc.GetLeft() );
        ::lcl_DescSetAttr( rChged.GetFirstMaster(), rDesc.GetFirstMaster() );
        ::lcl_DescSetAttr( rChged.GetFirstLeft(), rDesc.GetFirstLeft() );

        // If the FootnoteInfo changes, the pages are triggered.
        if( !(rDesc.GetFootnoteInfo() == rChged.GetFootnoteInfo()) )
        {
            rDesc.SetFootnoteInfo( rChged.GetFootnoteInfo() );
            sw::PageFootnoteHint aHint;
            rDesc.GetMaster().CallSwClientNotify(aHint);
            rDesc.GetLeft().CallSwClientNotify(aHint);
            rDesc.GetFirstMaster().CallSwClientNotify(aHint);
            rDesc.GetFirstLeft().CallSwClientNotify(aHint);
        }
        getIDocumentState().SetModified();

        // #i46909# no undo if header or footer changed
        if( bHeaderFooterChanged )
        {
            GetIDocumentUndoRedo().DelAllUndoObj();
        }

        SfxBindings* pBindings =
            ( GetDocShell() && GetDocShell()->GetDispatcher() ) ? GetDocShell()->GetDispatcher()->GetBindings() : nullptr;
        if ( pBindings )
        {
            pBindings->Invalidate( SID_ATTR_PAGE_COLUMN );
            pBindings->Invalidate( SID_ATTR_PAGE );
            pBindings->Invalidate( SID_ATTR_PAGE_SIZE );
            pBindings->Invalidate( SID_ATTR_PAGE_ULSPACE );
            pBindings->Invalidate( SID_ATTR_PAGE_LRSPACE );
        }

        //h/f of first-left page must not be unique but same as first master or left
        assert((rDesc.IsFirstShared())
            ? rDesc.GetFirstLeft().GetHeader().GetHeaderFormat() == rDesc.GetLeft().GetHeader().GetHeaderFormat()
            : rDesc.GetFirstLeft().GetHeader().GetHeaderFormat() == rDesc.GetFirstMaster().GetHeader().GetHeaderFormat());
        assert((rDesc.IsFirstShared())
            ? rDesc.GetFirstLeft().GetFooter().GetFooterFormat() == rDesc.GetLeft().GetFooter().GetFooterFormat()
            : rDesc.GetFirstLeft().GetFooter().GetFooterFormat() == rDesc.GetFirstMaster().GetFooter().GetFooterFormat());
    }

    /// All descriptors whose Follow point to the to-be-deleted have to be adapted.
    // #i7983#
    void SwDoc::PreDelPageDesc(SwPageDesc const * pDel)
    {
        if (nullptr == pDel)
            return;

        // mba: test iteration as clients are removed while iteration
        SwPageDescHint aHint( m_PageDescs[0] );
        pDel->CallSwClientNotify( aHint );

        bool bHasLayout = getIDocumentLayoutAccess().HasLayout();
        if ( mpFootnoteInfo->DependsOn( pDel ) )
        {
            mpFootnoteInfo->ChgPageDesc( m_PageDescs[0] );
            if ( bHasLayout )
            {
                for( auto aLayout : GetAllLayouts() )
                    aLayout->CheckFootnotePageDescs(false);
            }
        }
        else if ( mpEndNoteInfo->DependsOn( pDel ) )
        {
            mpEndNoteInfo->ChgPageDesc( m_PageDescs[0] );
            if ( bHasLayout )
            {
                for( auto aLayout : GetAllLayouts() )
                    aLayout->CheckFootnotePageDescs(true);
            }
        }

        for (SwPageDesc* pPageDesc : m_PageDescs)
        {
            if (pPageDesc->GetFollow() == pDel)
            {
                pPageDesc->SetFollow(nullptr);
                if( bHasLayout )
                {
                    for( auto aLayout : GetAllLayouts() )
                        aLayout->AllCheckPageDescs();
                }
            }
        }
    }

    void SwDoc::BroadcastStyleOperation(const OUString& rName, SfxStyleFamily eFamily,
                                        SfxHintId nOp)
    {
        if (mpDocShell)
        {
            SfxStyleSheetBasePool * pPool = mpDocShell->GetStyleSheetPool();

            if (pPool)
            {
                pPool->SetSearchMask(eFamily);
                SfxStyleSheetBase * pBase = pPool->Find(rName);

                if (pBase != nullptr)
                    pPool->Broadcast(SfxStyleSheetHint( nOp, *pBase ));
            }
        }
    }

    void SwDoc::DelPageDesc( size_t i, bool bBroadcast )
    {
        OSL_ENSURE(i < m_PageDescs.size(), "PageDescs is out of range.");
        OSL_ENSURE( i != 0, "You cannot delete the default Pagedesc.");
        if ( i == 0 )
            return;

        SwPageDesc &rDel = *m_PageDescs[i];

        if (bBroadcast)
            BroadcastStyleOperation(rDel.GetName(), SfxStyleFamily::Page,
                                    SfxHintId::StyleSheetErased);

        if (GetIDocumentUndoRedo().DoesUndo())
        {
            SwUndo *const pUndo(new SwUndoPageDescDelete(rDel, this));
            GetIDocumentUndoRedo().AppendUndo(pUndo);
        }

        PreDelPageDesc(&rDel); // #i7983#

        m_PageDescs.erase(m_PageDescs.begin() + i);
        getIDocumentState().SetModified();
    }

    SwPageDesc* SwDoc::MakePageDesc(const OUString &rName, const SwPageDesc *pCpy,
                                bool bRegardLanguage, bool bBroadcast)
    {
        SwPageDesc *pNew;
        if( pCpy )
        {
            pNew = new SwPageDesc( *pCpy );
            pNew->SetName( rName );
            if( rName != pCpy->GetName() )
            {
                pNew->SetPoolFormatId( USHRT_MAX );
                pNew->SetPoolHelpId( USHRT_MAX );
                pNew->SetPoolHlpFileId( UCHAR_MAX );
            }
        }
        else
        {
            pNew = new SwPageDesc( rName, GetDfltFrameFormat(), this );
            // Set the default page format.
            lcl_DefaultPageFormat( USHRT_MAX, pNew->GetMaster(), pNew->GetLeft(), pNew->GetFirstMaster(), pNew->GetFirstLeft() );

            SvxFrameDirection aFrameDirection = bRegardLanguage ?
                GetDefaultFrameDirection(GetAppLanguage())
                : SvxFrameDirection::Horizontal_LR_TB;

            pNew->GetMaster().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
            pNew->GetLeft().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
            pNew->GetFirstMaster().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
            pNew->GetFirstLeft().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
        }

        std::pair<SwPageDescs::const_iterator, bool> res = m_PageDescs.push_back( pNew );
        SAL_WARN_IF(!res.second, "sw", "MakePageDesc called with existing name" );

        if (bBroadcast)
            BroadcastStyleOperation(rName, SfxStyleFamily::Page,
                                    SfxHintId::StyleSheetCreated);

        if (GetIDocumentUndoRedo().DoesUndo())
        {
            GetIDocumentUndoRedo().AppendUndo(new SwUndoPageDescCreate(pNew, this));
        }

        getIDocumentState().SetModified();
        return pNew;
    }

    void SwDoc::PrtOLENotify( bool bAll )
    {
        SwFEShell *pShell = nullptr;
        {
            SwViewShell *pSh = getIDocumentLayoutAccess().GetCurrentViewShell();
            if ( pSh )
            {
                for(SwViewShell& rShell : pSh->GetRingContainer())
                {
                    if(dynamic_cast<const SwFEShell*>( &rShell) !=  nullptr)
                    {
                        pShell = static_cast<SwFEShell*>(&rShell);
                        break;
                    }
                }
            }
        }
        if ( !pShell )
        {
            // This doesn't make sense without a Shell and thus without a client, because
            // the communication about size changes is implemented by these components.
            // Because we don't have a Shell we remember this unfortunate situation
            // in the document,
            // which is made up for later on when creating the first Shell.
            mbOLEPrtNotifyPending = true;
            if ( bAll )
                mbAllOLENotify = true;
        }
        else
        {
            if ( mbAllOLENotify )
                bAll = true;

            mbOLEPrtNotifyPending = mbAllOLENotify = false;

            SwOLENodes *pNodes = SwContentNode::CreateOLENodesArray( *GetDfltGrfFormatColl(), !bAll );
            if ( pNodes )
            {
                ::StartProgress( STR_STATSTR_SWGPRTOLENOTIFY,
                                 0, pNodes->size(), GetDocShell());
                getIDocumentLayoutAccess().GetCurrentLayout()->StartAllAction();

                for( SwOLENodes::size_type i = 0; i < pNodes->size(); ++i )
                {
                    ::SetProgressState( i, GetDocShell() );

                    SwOLENode* pOLENd = (*pNodes)[i];
                    pOLENd->SetOLESizeInvalid( false );

                    // At first load the Infos and see if it's not already in the exclude list.
                    SvGlobalName aName;

                    svt::EmbeddedObjectRef& xObj = pOLENd->GetOLEObj().GetObject();
                    if ( xObj.is() )
                        aName = SvGlobalName( xObj->getClassID() );
                    else  // Not yet loaded
                    {
                            // TODO/LATER: retrieve ClassID of an unloaded object
                            // aName = ????
                    }

                    bool bFound = false;
                    for ( std::vector<SvGlobalName*>::size_type j = 0;
                          j < pGlobalOLEExcludeList->size() && !bFound;
                          ++j )
                    {
                        bFound = *(*pGlobalOLEExcludeList)[j] == aName;
                    }
                    if ( bFound )
                        continue;

                    // We don't know it, so the object has to be loaded.
                    // If it doesn't want to be informed
                    if ( xObj.is() )
                    {
                            pGlobalOLEExcludeList->push_back( new SvGlobalName( aName ) );
                    }
                }
                delete pNodes;
                getIDocumentLayoutAccess().GetCurrentLayout()->EndAllAction();
                ::EndProgress( GetDocShell() );
            }
        }
    }

    IMPL_LINK_NOARG( SwDoc, DoUpdateModifiedOLE, Timer *, void )
    {
        SwFEShell* pSh = static_cast<SwFEShell*>(GetEditShell());
        if( pSh )
        {
            mbOLEPrtNotifyPending = mbAllOLENotify = false;

            SwOLENodes *pNodes = SwContentNode::CreateOLENodesArray( *GetDfltGrfFormatColl(), true );
            if( pNodes )
            {
                ::StartProgress( STR_STATSTR_SWGPRTOLENOTIFY,
                                 0, pNodes->size(), GetDocShell());
                getIDocumentLayoutAccess().GetCurrentLayout()->StartAllAction();
                SwMsgPoolItem aMsgHint( RES_UPDATE_ATTR );

                for( SwOLENodes::size_type i = 0; i < pNodes->size(); ++i )
                {
                    ::SetProgressState( i, GetDocShell() );

                    SwOLENode* pOLENd = (*pNodes)[i];
                    pOLENd->SetOLESizeInvalid( false );

                    // We don't know it, so the object has to be loaded.
                    // If it doesn't want to be informed
                    if( pOLENd->GetOLEObj().GetOleRef().is() ) // Broken?
                    {
                        pOLENd->ModifyNotification( &aMsgHint, &aMsgHint );
                    }
                }
                getIDocumentLayoutAccess().GetCurrentLayout()->EndAllAction();
                ::EndProgress( GetDocShell() );
                delete pNodes;
            }
        }
    }

    static SwPageDesc* lcl_FindPageDesc( const SwPageDescs *pPageDescs,
                                         size_t *pPos, const OUString &rName )
    {
        SwPageDesc* res = nullptr;
        SwPageDescs::const_iterator it = pPageDescs->find( rName );
        if( it != pPageDescs->end() )
        {
            res = *it;
            if( pPos )
                *pPos = std::distance( pPageDescs->begin(), it );
        }
        else if( pPos )
            *pPos = SIZE_MAX;
        return res;
    }

    SwPageDesc* SwDoc::FindPageDesc( const OUString & rName, size_t* pPos ) const
    {
        return lcl_FindPageDesc( &m_PageDescs, pPos, rName );
    }

    bool SwDoc::ContainsPageDesc( const SwPageDesc *pDesc, size_t* pPos ) const
    {
        if( pDesc == nullptr )
            return false;
        if( !m_PageDescs.contains( const_cast <SwPageDesc*>( pDesc ) ) ) {
            if( pPos )
                *pPos = SIZE_MAX;
            return false;
        }
        if( ! pPos )
            return true;

        SwPageDesc* desc = lcl_FindPageDesc(
            &m_PageDescs, pPos, pDesc->GetName() );
        SAL_WARN_IF( desc != pDesc, "sw", "SwPageDescs container is broken!" );
        return true;
    }

    void SwDoc::DelPageDesc( const OUString & rName, bool bBroadcast )
    {
        size_t nI;

        if (FindPageDesc(rName, &nI))
            DelPageDesc(nI, bBroadcast);
    }

    void SwDoc::ChgPageDesc( const OUString & rName, const SwPageDesc & rDesc)
    {
        size_t nI;

        if (FindPageDesc(rName, &nI))
            ChgPageDesc(nI, rDesc);
    }

    /*
     * The HTML import cannot resist changing the page descriptions, I don't
     * know why. This function is meant to check the page descriptors for invalid
     * values.
     */
    void SwDoc::CheckDefaultPageFormat()
    {
        for ( size_t i = 0; i < GetPageDescCnt(); ++i )
        {
            SwPageDesc& rDesc = GetPageDesc( i );

            SwFrameFormat& rMaster = rDesc.GetMaster();
            SwFrameFormat& rLeft   = rDesc.GetLeft();

            const SwFormatFrameSize& rMasterSize  = rMaster.GetFrameSize();
            const SwFormatFrameSize& rLeftSize    = rLeft.GetFrameSize();

            const bool bSetSize = INVALID_TWIPS == rMasterSize.GetWidth() ||
                                  INVALID_TWIPS == rMasterSize.GetHeight() ||
                                  INVALID_TWIPS == rLeftSize.GetWidth() ||
                                  INVALID_TWIPS == rLeftSize.GetHeight();

            if ( bSetSize )
                lcl_DefaultPageFormat( rDesc.GetPoolFormatId(), rDesc.GetMaster(), rDesc.GetLeft(), rDesc.GetFirstMaster(), rDesc.GetFirstLeft() );
        }
    }

    void SwDoc::SetDefaultPageMode(bool bSquaredPageMode)
    {
        if( !bSquaredPageMode == !IsSquaredPageMode() )
            return;

        const SwTextGridItem& rGrid = GetDefault( RES_TEXTGRID );
        SwTextGridItem aNewGrid = rGrid;
        aNewGrid.SetSquaredMode(bSquaredPageMode);
        aNewGrid.Init();
        SetDefault(aNewGrid);

        for ( size_t i = 0; i < GetPageDescCnt(); ++i )
        {
            SwPageDesc& rDesc = GetPageDesc( i );

            SwFrameFormat& rMaster = rDesc.GetMaster();
            SwFrameFormat& rLeft = rDesc.GetLeft();

            SwTextGridItem aGrid(rMaster.GetFormatAttr(RES_TEXTGRID));
            aGrid.SwitchPaperMode( bSquaredPageMode );
            rMaster.SetFormatAttr(aGrid);
            rLeft.SetFormatAttr(aGrid);
        }
    }

    bool SwDoc::IsSquaredPageMode() const
    {
        const SwTextGridItem& rGrid = GetDefault( RES_TEXTGRID );
        return rGrid.IsSquaredMode();
    }

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

↑ V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'SetFollow' function.