/* -*- 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 <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/embed/EmbedMisc.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>

#include <cmdid.h>
#include <hintids.hxx>
#include <bitmaps.hlst>
#include <o3tl/safeint.hxx>
#include <vcl/mnemonic.hxx>
#include <svl/stritem.hxx>
#include <sfx2/htmlmode.hxx>
#include <editeng/opaqitem.hxx>
#include <editeng/protitem.hxx>
#include <editeng/prntitem.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <svx/swframeposstrings.hxx>
#include <svx/swframevalidation.hxx>
#include <svx/sdangitm.hxx>
#include <comphelper/classids.hxx>
#include <tools/globname.hxx>
#include <tools/urlobj.hxx>
#include <fmturl.hxx>
#include <fmteiro.hxx>
#include <fmtcnct.hxx>
#include <fmtsrnd.hxx>
#include <view.hxx>
#include <wrtsh.hxx>
#include <swmodule.hxx>
#include <uitool.hxx>
#include <docsh.hxx>
#include <viewopt.hxx>
#include <frmdlg.hxx>
#include <frmmgr.hxx>
#include <frmpage.hxx>
#include <colmgr.hxx>
#include <grfatr.hxx>
#include <fmtfollowtextflow.hxx>
#include <svx/sdtaitm.hxx>
#include <sal/macros.h>
#include <osl/diagnose.h>

#include <strings.hrc>
#include <formatflysplit.hxx>
#include <fmtcntnt.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <svx/graphichelper.hxx>
#include <sfx2/filedlghelper.hxx>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#include <vcl/graphicfilter.hxx>
#include <svtools/embedhlp.hxx>
#include <comphelper/lok.hxx>
#include <memory>

using namespace ::com::sun::star;
using namespace ::sfx2;

#define SwFPos SvxSwFramePosString

namespace {

struct StringIdPair_Impl
{
    SvxSwFramePosString::StringId eHori;
    SvxSwFramePosString::StringId eVert;
};

}

#define MAX_PERCENT_WIDTH   SAL_CONST_INT64(254)
#define MAX_PERCENT_HEIGHT  SAL_CONST_INT64(254)

namespace {

enum class LB {
    NONE                = 0x00000000L,
    Frame               = 0x00000001L,  // text region of the paragraph
    PrintArea           = 0x00000002L,  // text region of the paragraph + indentions
    VertFrame           = 0x00000004L,  // vertical text region of the paragraph
    VertPrintArea       = 0x00000008L,  // vertical text region of the paragraph + indentions
    RelFrameLeft        = 0x00000010L,  // left paragraph edge
    RelFrameRight       = 0x00000020L,  // right paragraph edge

    RelPageLeft         = 0x00000040L,  // left page edge
    RelPageRight        = 0x00000080L,  // right page edge
    RelPageFrame        = 0x00000100L,  // whole page
    RelPagePrintArea    = 0x00000200L,  // text region of the page

    FlyRelPageLeft      = 0x00000400L,  // left frame edge
    FlyRelPageRight     = 0x00000800L,   // right frame edge
    FlyRelPageFrame     = 0x00001000L,  // whole frame
    FlyRelPagePrintArea = 0x00002000L,  // inside of the frame

    RelBase             = 0x00010000L,  // character alignment Base
    RelChar             = 0x00020000L,  // character alignment Character
    RelRow              = 0x00040000L,  // character alignment Row

    FlyVertFrame        = 0x00100000L,  // vertical entire frame
    FlyVertPrintArea    = 0x00200000L,  // vertical frame text area

    VertLine            = 0x00400000L,  // vertical text line
};

}

namespace o3tl {
    template<> struct typed_flags<LB> : is_typed_flags<LB, 0x00773fffL> {};
}

namespace {

struct RelationMap
{
    SvxSwFramePosString::StringId eStrId;
    SvxSwFramePosString::StringId eMirrorStrId;
    LB         nLBRelation;
    sal_Int16  nRelation;
};

}

struct FrameMap
{
    SvxSwFramePosString::StringId eStrId;
    SvxSwFramePosString::StringId eMirrorStrId;
    sal_Int16  nAlign;
    LB         nLBRelations;
};


RelationMap const aRelationMap[] =
{
    {SwFPos::FRAME,  SwFPos::FRAME, LB::Frame, text::RelOrientation::FRAME},
    {SwFPos::PRTAREA,           SwFPos::PRTAREA,                LB::PrintArea,             text::RelOrientation::PRINT_AREA},
    {SwFPos::REL_PG_LEFT,       SwFPos::MIR_REL_PG_LEFT,        LB::RelPageLeft,         text::RelOrientation::PAGE_LEFT},
    {SwFPos::REL_PG_RIGHT,      SwFPos::MIR_REL_PG_RIGHT,       LB::RelPageRight,        text::RelOrientation::PAGE_RIGHT},
    {SwFPos::REL_FRM_LEFT,      SwFPos::MIR_REL_FRM_LEFT,       LB::RelFrameLeft,        text::RelOrientation::FRAME_LEFT},
    {SwFPos::REL_FRM_RIGHT,     SwFPos::MIR_REL_FRM_RIGHT,      LB::RelFrameRight,       text::RelOrientation::FRAME_RIGHT},
    {SwFPos::REL_PG_FRAME,      SwFPos::REL_PG_FRAME,           LB::RelPageFrame,        text::RelOrientation::PAGE_FRAME},
    {SwFPos::REL_PG_PRTAREA,    SwFPos::REL_PG_PRTAREA,         LB::RelPagePrintArea,      text::RelOrientation::PAGE_PRINT_AREA},
    {SwFPos::REL_CHAR,          SwFPos::REL_CHAR,               LB::RelChar,            text::RelOrientation::CHAR},

    {SwFPos::FLY_REL_PG_LEFT,       SwFPos::FLY_MIR_REL_PG_LEFT,    LB::FlyRelPageLeft,     text::RelOrientation::PAGE_LEFT},
    {SwFPos::FLY_REL_PG_RIGHT,      SwFPos::FLY_MIR_REL_PG_RIGHT,   LB::FlyRelPageRight,    text::RelOrientation::PAGE_RIGHT},
    {SwFPos::FLY_REL_PG_FRAME,      SwFPos::FLY_REL_PG_FRAME,       LB::FlyRelPageFrame,    text::RelOrientation::PAGE_FRAME},
    {SwFPos::FLY_REL_PG_PRTAREA,    SwFPos::FLY_REL_PG_PRTAREA,     LB::FlyRelPagePrintArea,  text::RelOrientation::PAGE_PRINT_AREA},

    {SwFPos::REL_BORDER,        SwFPos::REL_BORDER,             LB::VertFrame,          text::RelOrientation::FRAME},
    {SwFPos::REL_PRTAREA,       SwFPos::REL_PRTAREA,            LB::VertPrintArea,        text::RelOrientation::PRINT_AREA},

    {SwFPos::FLY_REL_PG_FRAME,      SwFPos::FLY_REL_PG_FRAME,   LB::FlyVertFrame,      text::RelOrientation::FRAME},
    {SwFPos::FLY_REL_PG_PRTAREA,    SwFPos::FLY_REL_PG_PRTAREA,     LB::FlyVertPrintArea,    text::RelOrientation::PRINT_AREA},

    {SwFPos::REL_LINE,  SwFPos::REL_LINE,   LB::VertLine,   text::RelOrientation::TEXT_LINE}
};

RelationMap const aAsCharRelationMap[] =
{
    {SwFPos::REL_BASE,  SwFPos::REL_BASE,   LB::RelBase,    text::RelOrientation::FRAME},
    {SwFPos::REL_CHAR,   SwFPos::REL_CHAR,   LB::RelChar,   text::RelOrientation::FRAME},
    {SwFPos::REL_ROW,    SwFPos::REL_ROW,   LB::RelRow,     text::RelOrientation::FRAME}
};

// site anchored
constexpr auto HORI_PAGE_REL = LB::RelPageFrame | LB::RelPagePrintArea | LB::RelPageLeft |
                        LB::RelPageRight;

FrameMap const aHPageMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,      HORI_PAGE_REL},
    {SwFPos::RIGHT,         SwFPos::MIR_RIGHT,      text::HoriOrientation::RIGHT,     HORI_PAGE_REL},
    {SwFPos::CENTER_HORI,   SwFPos::CENTER_HORI,    text::HoriOrientation::CENTER,    HORI_PAGE_REL},
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      HORI_PAGE_REL}
};

FrameMap const aHPageHtmlMap[] =
{
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      LB::RelPageFrame}
};

#define VERT_PAGE_REL   (LB::RelPageFrame|LB::RelPagePrintArea)

FrameMap const aVPageMap[] =
{
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,       VERT_PAGE_REL},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::BOTTOM,    VERT_PAGE_REL},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CENTER,    VERT_PAGE_REL},
    {SwFPos::FROMTOP,       SwFPos::FROMTOP,        text::VertOrientation::NONE,      VERT_PAGE_REL}
};

FrameMap const aVPageHtmlMap[] =
{
    {SwFPos::FROMTOP,       SwFPos::FROMTOP,        text::VertOrientation::NONE,      LB::RelPageFrame}
};

// frame anchored
constexpr auto HORI_FRAME_REL = LB::FlyRelPageFrame | LB::FlyRelPagePrintArea |
                                       LB::FlyRelPageLeft | LB::FlyRelPageRight;

FrameMap const aHFrameMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,  HORI_FRAME_REL},
    {SwFPos::RIGHT,         SwFPos::MIR_RIGHT,      text::HoriOrientation::RIGHT,     HORI_FRAME_REL},
    {SwFPos::CENTER_HORI,   SwFPos::CENTER_HORI,    text::HoriOrientation::CENTER,    HORI_FRAME_REL},
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      HORI_FRAME_REL}
};

FrameMap const aHFlyHtmlMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,      LB::FlyRelPageFrame},
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      LB::FlyRelPageFrame}
};

// own vertical alignment map for objects anchored to frame
#define VERT_FRAME_REL   (LB::FlyVertFrame|LB::FlyVertPrintArea)

FrameMap const aVFrameMap[] =
{
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,       VERT_FRAME_REL},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::BOTTOM,    VERT_FRAME_REL},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CENTER,    VERT_FRAME_REL},
    {SwFPos::FROMTOP,       SwFPos::FROMTOP,        text::VertOrientation::NONE,      VERT_FRAME_REL}
};

FrameMap const aVFlyHtmlMap[] =
{
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,       LB::FlyVertFrame},
    {SwFPos::FROMTOP,       SwFPos::FROMTOP,        text::VertOrientation::NONE,      LB::FlyVertFrame}
};

// paragraph anchored
constexpr auto HORI_PARA_REL = LB::Frame | LB::PrintArea | LB::RelPageLeft | LB::RelPageRight |
                        LB::RelPageFrame | LB::RelPagePrintArea | LB::RelFrameLeft |
                        LB::RelFrameRight;

FrameMap const aHParaMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,      HORI_PARA_REL},
    {SwFPos::RIGHT,         SwFPos::MIR_RIGHT,      text::HoriOrientation::RIGHT,     HORI_PARA_REL},
    {SwFPos::CENTER_HORI,   SwFPos::CENTER_HORI,    text::HoriOrientation::CENTER,    HORI_PARA_REL},
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      HORI_PARA_REL}
};

#define HTML_HORI_PARA_REL  (LB::Frame|LB::PrintArea)

FrameMap const aHParaHtmlMap[] =
{
    {SwFPos::LEFT,  SwFPos::LEFT,   text::HoriOrientation::LEFT,      HTML_HORI_PARA_REL},
    {SwFPos::RIGHT, SwFPos::RIGHT,  text::HoriOrientation::RIGHT,     HTML_HORI_PARA_REL}
};

FrameMap const aHParaHtmlAbsMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,      HTML_HORI_PARA_REL},
    {SwFPos::RIGHT,         SwFPos::MIR_RIGHT,      text::HoriOrientation::RIGHT,     HTML_HORI_PARA_REL}
};

// allow vertical alignment at page areas
constexpr auto VERT_PARA_REL = LB::VertFrame | LB::VertPrintArea |
                                      LB::RelPageFrame | LB::RelPagePrintArea;

FrameMap const aVParaMap[] =
{
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,       VERT_PARA_REL},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::BOTTOM,    VERT_PARA_REL},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CENTER,    VERT_PARA_REL},
    {SwFPos::FROMTOP,       SwFPos::FROMTOP,        text::VertOrientation::NONE,      VERT_PARA_REL}
};

FrameMap const aVParaHtmlMap[] =
{
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,       LB::VertPrintArea}
};

// anchored relative to the character
constexpr auto HORI_CHAR_REL = LB::Frame|LB::PrintArea | LB::RelPageLeft | LB::RelPageRight |
                                      LB::RelPageFrame | LB::RelPagePrintArea | LB::RelFrameLeft |
                                      LB::RelFrameRight | LB::RelChar;

FrameMap const aHCharMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,      HORI_CHAR_REL},
    {SwFPos::RIGHT,         SwFPos::MIR_RIGHT,      text::HoriOrientation::RIGHT,     HORI_CHAR_REL},
    {SwFPos::CENTER_HORI,   SwFPos::CENTER_HORI,    text::HoriOrientation::CENTER,    HORI_CHAR_REL},
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      HORI_CHAR_REL}
};

#define HTML_HORI_CHAR_REL  (LB::Frame|LB::PrintArea|LB::RelChar)

FrameMap const aHCharHtmlMap[] =
{
    {SwFPos::LEFT,          SwFPos::LEFT,           text::HoriOrientation::LEFT,      HTML_HORI_CHAR_REL},
    {SwFPos::RIGHT,         SwFPos::RIGHT,          text::HoriOrientation::RIGHT,     HTML_HORI_CHAR_REL}
};

FrameMap const aHCharHtmlAbsMap[] =
{
    {SwFPos::LEFT,          SwFPos::MIR_LEFT,       text::HoriOrientation::LEFT,      LB::PrintArea|LB::RelChar},
    {SwFPos::RIGHT,         SwFPos::MIR_RIGHT,      text::HoriOrientation::RIGHT,     LB::PrintArea},
    {SwFPos::FROMLEFT,      SwFPos::MIR_FROMLEFT,   text::HoriOrientation::NONE,      LB::RelPageFrame}
};

// allow vertical alignment at page areas
constexpr auto VERT_CHAR_REL = LB::VertFrame | LB::VertPrintArea |
                                      LB::RelPageFrame | LB::RelPagePrintArea;

FrameMap const aVCharMap[] =
{
    // introduce mappings for new vertical alignment at top of line <LB::VertLine>
    // and correct mapping for vertical alignment at character for position <FROM_BOTTOM>
    // Note: Because of these adjustments the map becomes ambiguous in its values
    //       <eStrId>/<eMirrorStrId> and <nAlign>. These ambiguities are considered
    //       in the methods <SwFramePage::FillRelLB(..)>, <SwFramePage::GetAlignment(..)>
    //       and <SwFramePage::FillPosLB(..)>
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,           VERT_CHAR_REL|LB::RelChar},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::BOTTOM,        VERT_CHAR_REL|LB::RelChar},
    {SwFPos::BELOW,         SwFPos::BELOW,          text::VertOrientation::CHAR_BOTTOM,   LB::RelChar},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CENTER,        VERT_CHAR_REL|LB::RelChar},
    {SwFPos::FROMTOP,       SwFPos::FROMTOP,        text::VertOrientation::NONE,          VERT_CHAR_REL},
    {SwFPos::FROMBOTTOM,    SwFPos::FROMBOTTOM,     text::VertOrientation::NONE,          LB::RelChar|LB::VertLine},
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::LINE_TOP,      LB::VertLine},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::LINE_BOTTOM,   LB::VertLine},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::LINE_CENTER,   LB::VertLine}
};

FrameMap const aVCharHtmlMap[] =
{
    {SwFPos::BELOW,         SwFPos::BELOW,          text::VertOrientation::CHAR_BOTTOM,   LB::RelChar}
};

FrameMap const aVCharHtmlAbsMap[] =
{
    {SwFPos::TOP,           SwFPos::TOP,            text::VertOrientation::TOP,           LB::RelChar},
    {SwFPos::BELOW,             SwFPos::BELOW,          text::VertOrientation::CHAR_BOTTOM,   LB::RelChar}
};

// anchored as character
FrameMap const aVAsCharMap[] =
{
    {SwFPos::TOP,               SwFPos::TOP,            text::VertOrientation::TOP,           LB::RelBase},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::BOTTOM,        LB::RelBase},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CENTER,        LB::RelBase},

    {SwFPos::TOP,               SwFPos::TOP,            text::VertOrientation::CHAR_TOP,      LB::RelChar},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::CHAR_BOTTOM,   LB::RelChar},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CHAR_CENTER,   LB::RelChar},

    {SwFPos::TOP,               SwFPos::TOP,            text::VertOrientation::LINE_TOP,      LB::RelRow},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::LINE_BOTTOM,   LB::RelRow},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::LINE_CENTER,   LB::RelRow},

    {SwFPos::FROMBOTTOM,    SwFPos::FROMBOTTOM,     text::VertOrientation::NONE,          LB::RelBase}
};

FrameMap const aVAsCharHtmlMap[] =
{
    {SwFPos::TOP,               SwFPos::TOP,            text::VertOrientation::TOP,           LB::RelBase},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::CENTER,        LB::RelBase},

    {SwFPos::TOP,               SwFPos::TOP,            text::VertOrientation::CHAR_TOP,      LB::RelChar},

    {SwFPos::TOP,               SwFPos::TOP,            text::VertOrientation::LINE_TOP,      LB::RelRow},
    {SwFPos::BOTTOM,        SwFPos::BOTTOM,         text::VertOrientation::LINE_BOTTOM,   LB::RelRow},
    {SwFPos::CENTER_VERT,   SwFPos::CENTER_VERT,    text::VertOrientation::LINE_CENTER,   LB::RelRow}
};

const WhichRangesContainer SwFramePage::s_aPageRg(svl::Items<
    RES_FRM_SIZE, RES_FRM_SIZE,
    RES_PROTECT, RES_PROTECT,
    RES_VERT_ORIENT, RES_ANCHOR,
    RES_COL, RES_COL,
    RES_FOLLOW_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW
>);
const WhichRangesContainer SwFrameAddPage::s_aAddPgRg(svl::Items<
    RES_PRINT,              RES_PRINT,
    FN_SET_FRM_NAME,        FN_SET_FRM_NAME,
    FN_SET_FRM_ALT_NAME,    FN_SET_FRM_ALT_NAME,
    FN_UNO_DESCRIPTION,     FN_UNO_DESCRIPTION
>);

static size_t lcl_GetFrameMapCount( const FrameMap* pMap)
{
    if ( pMap )
    {
        if( pMap == aVParaHtmlMap)
            return std::size(aVParaHtmlMap);
        if( pMap == aVAsCharHtmlMap)
            return std::size(aVAsCharHtmlMap);
        if( pMap == aHParaHtmlMap)
            return std::size(aHParaHtmlMap);
        if( pMap == aHParaHtmlAbsMap)
            return std::size(aHParaHtmlAbsMap);
        if ( pMap == aVPageMap )
            return std::size(aVPageMap);
        if ( pMap == aVPageHtmlMap )
            return std::size(aVPageHtmlMap);
        if ( pMap == aVAsCharMap )
            return std::size(aVAsCharMap);
        if ( pMap == aVParaMap )
            return std::size(aVParaMap);
        if ( pMap == aHParaMap )
            return std::size(aHParaMap);
        if ( pMap == aHFrameMap )
            return std::size(aHFrameMap);
        if ( pMap == aVFrameMap )
            return std::size(aVFrameMap);
        if ( pMap == aHCharMap )
            return std::size(aHCharMap);
        if ( pMap == aHCharHtmlMap )
            return std::size(aHCharHtmlMap);
        if ( pMap == aHCharHtmlAbsMap )
            return std::size(aHCharHtmlAbsMap);
        if ( pMap == aVCharMap )
            return std::size(aVCharMap);
        if ( pMap == aVCharHtmlMap )
            return std::size(aVCharHtmlMap);
        if ( pMap == aVCharHtmlAbsMap )
            return std::size(aVCharHtmlAbsMap);
        if ( pMap == aHPageHtmlMap )
            return std::size(aHPageHtmlMap);
        if ( pMap == aHFlyHtmlMap )
            return std::size(aHFlyHtmlMap);
        if ( pMap == aVFlyHtmlMap )
            return std::size(aVFlyHtmlMap);
        return std::size(aHPageMap);
    }
    return 0;
}

static void lcl_InsertVectors(weld::ComboBox& rBox,
    const std::vector< UIName >& rPrev, const std::vector< UIName >& rThis,
    const std::vector< UIName >& rNext, const std::vector< UIName >& rRemain)
{
    for(const auto& rItem : rPrev)
        rBox.append_text(rItem.toString());
    for(const auto& rItem : rThis)
        rBox.append_text(rItem.toString());
    for(const auto& rItem : rNext)
        rBox.append_text(rItem.toString());
    rBox.append_separator(u""_ustr);
    //now insert all strings sorted
    const auto nStartPos = rBox.get_count();

    for(const auto& rItem : rPrev)
        ::InsertStringSorted(u""_ustr, rItem.toString(), rBox, nStartPos );
    for(const auto& rItem : rThis)
        ::InsertStringSorted(u""_ustr, rItem.toString(), rBox, nStartPos );
    for(const auto& rItem : rNext)
        ::InsertStringSorted(u""_ustr, rItem.toString(), rBox, nStartPos );
    for(const auto& rItem : rRemain)
        ::InsertStringSorted(u""_ustr, rItem.toString(), rBox, nStartPos );
}

// --> OD 2009-08-31 #mongolianlayout#
// add input parameter
static SvxSwFramePosString::StringId lcl_ChangeResIdToVerticalOrRTL(SvxSwFramePosString::StringId eStringId, bool bVertical, bool bVerticalL2R, bool bRTL)
{
    //special handling of STR_FROMLEFT
    if ( SwFPos::FROMLEFT == eStringId )
    {
        eStringId = bVertical
                    ? ( bRTL
                        ? SwFPos::FROMBOTTOM
                        : SwFPos::FROMTOP )
                    : ( bRTL
                        ? SwFPos::FROMRIGHT
                        : SwFPos::FROMLEFT );
        return eStringId;
    }
    // --> OD 2009-08-31 #mongolianlayout#
    // special handling of STR_FROMTOP in case of mongolianlayout (vertical left-to-right)
    if ( SwFPos::FROMTOP == eStringId &&
         bVertical && bVerticalL2R )
    {
        eStringId = SwFPos::FROMLEFT;
        return eStringId;
    }
    if ( bVertical )
    {
        //exchange horizontal strings with vertical strings and vice versa
        static const StringIdPair_Impl aHoriIds[] =
        {
            {SwFPos::LEFT,           SwFPos::TOP},
            {SwFPos::RIGHT,          SwFPos::BOTTOM},
            {SwFPos::CENTER_HORI,    SwFPos::CENTER_VERT},
            {SwFPos::FROMTOP,        SwFPos::FROMRIGHT},
            {SwFPos::REL_PG_LEFT,    SwFPos::REL_PG_TOP},
            {SwFPos::REL_PG_RIGHT,   SwFPos::REL_PG_BOTTOM} ,
            {SwFPos::REL_FRM_LEFT,   SwFPos::REL_FRM_TOP},
            {SwFPos::REL_FRM_RIGHT,  SwFPos::REL_FRM_BOTTOM}
        };
        static const StringIdPair_Impl aVertIds[] =
        {
            {SwFPos::TOP,            SwFPos::RIGHT},
            {SwFPos::BOTTOM,         SwFPos::LEFT },
            {SwFPos::CENTER_VERT,    SwFPos::CENTER_HORI},
            {SwFPos::FROMTOP,        SwFPos::FROMRIGHT },
            {SwFPos::REL_PG_TOP,     SwFPos::REL_PG_LEFT },
            {SwFPos::REL_PG_BOTTOM,  SwFPos::REL_PG_RIGHT } ,
            {SwFPos::REL_FRM_TOP,    SwFPos::REL_FRM_LEFT },
            {SwFPos::REL_FRM_BOTTOM, SwFPos::REL_FRM_RIGHT }
        };
        // --> OD 2009-08-31 #monglianlayout#
        static const StringIdPair_Impl aVertL2RIds[] =
        {
            {SwFPos::TOP,            SwFPos::LEFT },
            {SwFPos::BOTTOM,         SwFPos::RIGHT },
            {SwFPos::CENTER_VERT,    SwFPos::CENTER_HORI },
            {SwFPos::FROMTOP,        SwFPos::FROMLEFT },
            {SwFPos::REL_PG_TOP,     SwFPos::REL_PG_LEFT },
            {SwFPos::REL_PG_BOTTOM,  SwFPos::REL_PG_RIGHT } ,
            {SwFPos::REL_FRM_TOP,    SwFPos::REL_FRM_LEFT },
            {SwFPos::REL_FRM_BOTTOM, SwFPos::REL_FRM_RIGHT }
        };
        for(const StringIdPair_Impl & rHoriId : aHoriIds)
        {
            if(rHoriId.eHori == eStringId)
            {
                eStringId = rHoriId.eVert;
                return eStringId;
            }
        }
        for(size_t nIndex = 0; nIndex < SAL_N_ELEMENTS(aVertIds); ++nIndex)
        {
            // --> OD 2009-08-31 #mongolianlayout#
            if ( !bVerticalL2R )
            {
                if(aVertIds[nIndex].eHori == eStringId)
                {
                    eStringId = aVertIds[nIndex].eVert;
                    break;
                }
            }
            else
            {
                if(aVertL2RIds[nIndex].eHori == eStringId)
                {
                    eStringId = aVertL2RIds[nIndex].eVert;
                    break;
                }
            }
        }
    }
    return eStringId;
}

// helper method in order to determine all possible
// listbox relations in a relation map for a given relation
static LB lcl_GetLBRelationsForRelations( const sal_Int16 _nRel )
{
    LB nLBRelations = LB::NONE;

    for (RelationMap const & i : aRelationMap)
    {
        if ( i.nRelation == _nRel )
        {
            nLBRelations |= i.nLBRelation;
        }
    }

    return nLBRelations;
}

// helper method on order to determine all possible
// listbox relations in a relation map for a given string ID
static LB lcl_GetLBRelationsForStrID( const FrameMap* _pMap,
                                             const SvxSwFramePosString::StringId _eStrId,
                                             const bool _bUseMirrorStr )
{
    LB nLBRelations = LB::NONE;

    size_t nRelMapSize = lcl_GetFrameMapCount( _pMap );
    for ( size_t nRelMapPos = 0; nRelMapPos < nRelMapSize; ++nRelMapPos )
    {
        if ( ( !_bUseMirrorStr && _pMap[nRelMapPos].eStrId == _eStrId ) ||
             ( _bUseMirrorStr && _pMap[nRelMapPos].eMirrorStrId == _eStrId ) )
        {
            nLBRelations |= _pMap[nRelMapPos].nLBRelations;
        }
    }

    return nLBRelations;
}

// standard frame TabPage
namespace
{
    void HandleAutoCB(bool _bChecked, weld::Label& _rFT_man, weld::Label& _rFT_auto, weld::MetricSpinButton& _rPF_Edit)
    {
        _rFT_man.set_visible( !_bChecked );
        _rFT_auto.set_visible( _bChecked );
        OUString accName = _bChecked ? _rFT_auto.get_label() : _rFT_man.get_label();
        _rPF_Edit.set_accessible_name(accName);
    }
}

SwFramePage::SwFramePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet)
    : SfxTabPage(pPage, pController, u"modules/swriter/ui/frmtypepage.ui"_ustr, u"FrameTypePage"_ustr, &rSet)
    , m_bAtHorzPosModified(false)
    , m_bAtVertPosModified(false)
    , m_bFormat(false)
    , m_bNew(true)
    , m_bNoModifyHdl(true)
    , m_bIsVerticalFrame(false)
    , m_bIsVerticalL2R(false)
    , m_bIsInRightToLeft(false)
    , m_bHtmlMode(false)
    , m_nHtmlMode(0)
    , m_nUpperBorder(0)
    , m_nLowerBorder(0)
    , m_fWidthHeightRatio(1.0)
    , mpToCharContentPos(nullptr)
    , m_nOldH(text::HoriOrientation::CENTER)
    , m_nOldHRel(text::RelOrientation::FRAME)
    , m_nOldV(text::VertOrientation::TOP)
    , m_nOldVRel(text::RelOrientation::PRINT_AREA)
    , m_pVMap(nullptr)
    , m_pHMap(nullptr)
    , m_bAllowVertPositioning( true )
    , m_bIsMathOLE(false)
    , m_bIsMathBaselineAlignment(true)
    , m_aRatioTop(ConnectorType::Top)
    , m_aRatioBottom(ConnectorType::Bottom)
    , m_xWidthFT(m_xBuilder->weld_label(u"widthft"_ustr))
    , m_xWidthAutoFT(m_xBuilder->weld_label(u"autowidthft"_ustr))
    , m_xRelWidthCB(m_xBuilder->weld_check_button(u"relwidth"_ustr))
    , m_xRelWidthRelationLB(m_xBuilder->weld_combo_box(u"relwidthrelation"_ustr))
    , m_xAutoWidthCB(m_xBuilder->weld_check_button(u"autowidth"_ustr))
    , m_xHeightFT(m_xBuilder->weld_label(u"heightft"_ustr))
    , m_xHeightAutoFT(m_xBuilder->weld_label(u"autoheightft"_ustr))
    , m_xRelHeightCB(m_xBuilder->weld_check_button(u"relheight"_ustr))
    , m_xRelHeightRelationLB(m_xBuilder->weld_combo_box(u"relheightrelation"_ustr))
    , m_xAutoHeightCB(m_xBuilder->weld_check_button(u"autoheight"_ustr))
    , m_xFixedRatioCB(m_xBuilder->weld_check_button(u"CBX_SCALE"_ustr))
    , m_xCbxScaleImg(m_xBuilder->weld_image(u"imRatio"_ustr))
    , m_xImgRatioTop(new weld::CustomWeld(*m_xBuilder, u"daRatioTop"_ustr, m_aRatioTop))
    , m_xImgRatioBottom(new weld::CustomWeld(*m_xBuilder, u"daRatioBottom"_ustr, m_aRatioBottom))
    , m_xRealSizeBT(m_xBuilder->weld_button(u"origsize"_ustr))
    , m_xProtectFrame(m_xBuilder->weld_widget(u"protect"_ustr))
    , m_xProtectContentCB(m_xBuilder->weld_check_button(u"protectcontent"_ustr))
    , m_xProtectFrameCB(m_xBuilder->weld_check_button(u"protectframe"_ustr))
    , m_xProtectSizeCB(m_xBuilder->weld_check_button(u"protectsize"_ustr))
    , m_xAnchorFrame(m_xBuilder->weld_widget(u"anchorframe"_ustr))
    , m_xAnchorAtPageRB(m_xBuilder->weld_radio_button(u"topage"_ustr))
    , m_xAnchorAtParaRB(m_xBuilder->weld_radio_button(u"topara"_ustr))
    , m_xAnchorAtCharRB(m_xBuilder->weld_radio_button(u"tochar"_ustr))
    , m_xAnchorAsCharRB(m_xBuilder->weld_radio_button(u"aschar"_ustr))
    , m_xAnchorAtFrameRB(m_xBuilder->weld_radio_button(u"toframe"_ustr))
    , m_xHorizontalFT(m_xBuilder->weld_label(u"horiposft"_ustr))
    , m_xHorizontalDLB(m_xBuilder->weld_combo_box(u"horipos"_ustr))
    , m_xAtHorzPosFT(m_xBuilder->weld_label(u"horibyft"_ustr))
    , m_xAtHorzPosED(m_xBuilder->weld_metric_spin_button(u"byhori"_ustr, FieldUnit::CM))
    , m_xHoriRelationFT(m_xBuilder->weld_label(u"horitoft"_ustr))
    , m_xHoriRelationLB(m_xBuilder->weld_combo_box(u"horianchor"_ustr))
    , m_xMirrorPagesCB(m_xBuilder->weld_check_button(u"mirror"_ustr))
    , m_xVerticalFT(m_xBuilder->weld_label(u"vertposft"_ustr))
    , m_xVerticalDLB(m_xBuilder->weld_combo_box(u"vertpos"_ustr))
    , m_xAtVertPosFT(m_xBuilder->weld_label(u"vertbyft"_ustr))
    , m_xAtVertPosED(m_xBuilder->weld_metric_spin_button(u"byvert"_ustr, FieldUnit::CM))
    , m_xVertRelationFT(m_xBuilder->weld_label(u"verttoft"_ustr))
    , m_xVertRelationLB(m_xBuilder->weld_combo_box(u"vertanchor"_ustr))
    , m_xFollowTextFlowCB(m_xBuilder->weld_check_button(u"followtextflow"_ustr))
    , m_xFlySplitCB(m_xBuilder->weld_check_button(u"flysplit"_ustr))
    , m_xExampleWN(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aExampleWN))
    , m_xWidthED(new SwPercentField(m_xBuilder->weld_metric_spin_button(u"width"_ustr, FieldUnit::CM)))
    , m_xHeightED(new SwPercentField(m_xBuilder->weld_metric_spin_button(u"height"_ustr, FieldUnit::CM)))
{
    const auto nWidthRequest = m_xAtHorzPosED->get_preferred_size().Width();
    m_xAtHorzPosED->set_size_request(nWidthRequest, -1);
    m_xAtVertPosED->set_size_request(nWidthRequest, -1);

    setOptimalFrameWidth();
    setOptimalRelWidth();

    SetExchangeSupport();

    Link<weld::MetricSpinButton&,void> aLk3 = LINK(this, SwFramePage, ModifyHdl);
    m_xWidthED->connect_value_changed( aLk3 );
    m_xHeightED->connect_value_changed( aLk3 );
    m_xAtHorzPosED->connect_value_changed( aLk3 );
    m_xAtVertPosED->connect_value_changed( aLk3 );
    m_xFollowTextFlowCB->connect_toggled(LINK(this, SwFramePage, RangeModifyClickHdl));

    Link<weld::Toggleable&,void> aLk2 = LINK(this, SwFramePage, AnchorTypeHdl);
    m_xAnchorAtPageRB->connect_toggled( aLk2 );
    m_xAnchorAtParaRB->connect_toggled( aLk2 );
    m_xAnchorAtCharRB->connect_toggled( aLk2 );
    m_xAnchorAsCharRB->connect_toggled( aLk2 );
    m_xAnchorAtFrameRB->connect_toggled( aLk2 );

    m_xHorizontalDLB->connect_changed(LINK(this, SwFramePage, PosHdl));
    m_xVerticalDLB->connect_changed(LINK(this, SwFramePage, PosHdl));

    m_xHoriRelationLB->connect_changed(LINK(this, SwFramePage, RelHdl));
    m_xVertRelationLB->connect_changed(LINK(this, SwFramePage, RelHdl));

    m_xMirrorPagesCB->connect_toggled(LINK(this, SwFramePage, MirrorHdl));

    aLk2 = LINK(this, SwFramePage, RelSizeClickHdl);
    m_xRelWidthCB->connect_toggled(aLk2);
    m_xRelHeightCB->connect_toggled(aLk2);

    m_xRelWidthRelationLB->connect_changed(LINK(this, SwFramePage, RelRelationClickHdl));
    m_xRelHeightRelationLB->connect_changed(LINK(this, SwFramePage, RelRelationClickHdl));

    m_xAutoWidthCB->connect_toggled(LINK(this, SwFramePage, AutoWidthClickHdl));
    m_xAutoHeightCB->connect_toggled(LINK(this, SwFramePage, AutoHeightClickHdl));

    m_xFixedRatioCB->connect_toggled(LINK(this, SwFramePage, RatioClickHdl));

    if (comphelper::LibreOfficeKit::isActive())
    {
        m_xAnchorAtPageRB->hide();
        m_xAnchorAtFrameRB->hide();
    }
}

SwFramePage::~SwFramePage()
{
}

namespace
{
    struct FrameMaps
    {
        FrameMap const * pMap;
        size_t nCount;
    };
}

void SwFramePage::setOptimalFrameWidth()
{
    static FrameMaps const aMaps[] = {
        { aHPageMap, std::size(aHPageMap) },
        { aHPageHtmlMap, std::size(aHPageHtmlMap) },
        { aVPageMap, std::size(aVPageMap) },
        { aVPageHtmlMap, std::size(aVPageHtmlMap) },
        { aHFrameMap, std::size(aHFrameMap) },
        { aHFlyHtmlMap, std::size(aHFlyHtmlMap) },
        { aVFrameMap, std::size(aVFrameMap) },
        { aVFlyHtmlMap, std::size(aVFlyHtmlMap) },
        { aHParaMap, std::size(aHParaMap) },
        { aHParaHtmlMap, std::size(aHParaHtmlMap) },
        { aHParaHtmlAbsMap, std::size(aHParaHtmlAbsMap) },
        { aVParaMap, std::size(aVParaMap) },
        { aVParaHtmlMap, std::size(aVParaHtmlMap) },
        { aHCharMap, std::size(aHCharMap) },
        { aHCharHtmlMap, std::size(aHCharHtmlMap) },
        { aHCharHtmlAbsMap, std::size(aHCharHtmlAbsMap) },
        { aVCharMap, std::size(aVCharMap) },
        { aVCharHtmlMap, std::size(aVCharHtmlMap) },
        { aVCharHtmlAbsMap, std::size(aVCharHtmlAbsMap) },
        { aVAsCharMap, std::size(aVAsCharMap) },
        { aVAsCharHtmlMap, std::size(aVAsCharHtmlMap) }
    };

    std::vector<SvxSwFramePosString::StringId> aFrames;
    for (const FrameMaps & rMap : aMaps)
    {
        for (size_t j = 0; j < rMap.nCount; ++j)
        {
            aFrames.push_back(rMap.pMap[j].eStrId);
            aFrames.push_back(rMap.pMap[j].eMirrorStrId);
        }
    }

    std::sort(aFrames.begin(), aFrames.end());
    aFrames.erase(std::unique(aFrames.begin(), aFrames.end()), aFrames.end());

    for (const auto& rFrame : aFrames)
    {
        m_xHorizontalDLB->append_text(SvxSwFramePosString::GetString(rFrame));
    }

    Size aBiggest(m_xHorizontalDLB->get_preferred_size());
    m_xHorizontalDLB->set_size_request(aBiggest.Width(), -1);
    m_xVerticalDLB->set_size_request(aBiggest.Width(), -1);
    m_xHorizontalDLB->clear();
}

namespace
{
    struct RelationMaps
    {
        RelationMap const * pMap;
        size_t nCount;
    };

/// Checks if the current fly frame contains exactly one table.
bool ContainsSingleTable(const SwFrameFormat& rFlyFormat)
{
    const SwNodeIndex* pStartNode = rFlyFormat.GetContent().GetContentIdx();
    if (!pStartNode)
    {
        return false;
    }

    // Check if the frame content starts with a table.
    SwNodeIndex aNodeIndex(*pStartNode);
    ++aNodeIndex;
    if (!aNodeIndex.GetNode().IsTableNode())
    {
        return false;
    }

    // Check if the frame content ends with the same table.
    SwNodeIndex aEndIndex(*aNodeIndex.GetNode().EndOfSectionNode());
    ++aEndIndex;
    if (&aEndIndex.GetNode() != pStartNode->GetNode().EndOfSectionNode())
    {
        return false;
    }

    return true;
}

bool ContainsChain(const SwFrameFormat& rFlyFormat)
{
    const SwFormatChain& rChain = rFlyFormat.GetChain();
    return rChain.GetPrev() || rChain.GetNext();
}

/// Determines if rFlyFormat is anchored in a fly frame that is part of a draw-format + fly-format
/// ("textbox") pair.
bool InTextBox(const SwFrameFormat& rFlyFormat)
{
    const SwFormatAnchor& rAnchor = rFlyFormat.GetAnchor();
    SwNode* pAnchorNode = rAnchor.GetAnchorNode();
    if (!pAnchorNode)
    {
        return false;
    }

    const SwStartNode* pFlyNode = pAnchorNode->FindFlyStartNode();
    if (!pFlyNode)
    {
        return false;
    }

    if (!pFlyNode->GetFlyFormat()->GetOtherTextBoxFormats())
    {
        return false;
    }

    return true;
}
}

void SwFramePage::setOptimalRelWidth()
{
    static const RelationMaps aMaps[] = {
        { aRelationMap, SAL_N_ELEMENTS(aRelationMap) },
        { aAsCharRelationMap, SAL_N_ELEMENTS(aAsCharRelationMap) }
    };

    std::vector<SvxSwFramePosString::StringId> aRels;
    for (const RelationMaps & rMap : aMaps)
    {
        for (size_t j = 0; j < rMap.nCount; ++j)
        {
            aRels.push_back(rMap.pMap[j].eStrId);
            aRels.push_back(rMap.pMap[j].eMirrorStrId);
        }
    }

    std::sort(aRels.begin(), aRels.end());
    aRels.erase(std::unique(aRels.begin(), aRels.end()), aRels.end());

    for (const auto& rRel : aRels)
    {
        m_xHoriRelationLB->append_text(SvxSwFramePosString::GetString(rRel));
    }

    Size aBiggest(m_xHoriRelationLB->get_preferred_size());
    m_xHoriRelationLB->set_size_request(aBiggest.Width(), -1);
    m_xVertRelationLB->set_size_request(aBiggest.Width(), -1);
    m_xRelWidthRelationLB->set_size_request(aBiggest.Width(), -1);
    m_xRelHeightRelationLB->set_size_request(aBiggest.Width(), -1);
    m_xHoriRelationLB->clear();
}

std::unique_ptr<SfxTabPage> SwFramePage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet)
{
    return std::make_unique<SwFramePage>(pPage, pController, *rSet);
}

void SwFramePage::EnableGraficMode()
{
    // i#39692 - mustn't be called more than once
    if (!m_xRealSizeBT->get_visible())
    {
        m_xWidthFT->show();
        m_xWidthAutoFT->hide();
        m_xAutoHeightCB->hide();

        m_xHeightFT->show();
        m_xHeightAutoFT->hide();
        m_xAutoWidthCB->hide();

        m_xRealSizeBT->show();
    }
}

SwWrtShell *SwFramePage::getFrameDlgParentShell()
{
    return static_cast<SwFrameDlg*>(GetDialogController())->GetWrtShell();
}

void SwFramePage::Reset( const SfxItemSet *rSet )
{
    SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell() :
            getFrameDlgParentShell();
    OSL_ENSURE(pSh , "shell not found");
    if (!pSh)
        return;

    m_nHtmlMode = ::GetHtmlMode(pSh->GetView().GetDocShell());
    m_bHtmlMode = (m_nHtmlMode & HTMLMODE_ON) != 0;

    FieldUnit aMetric = ::GetDfltMetric(m_bHtmlMode);
    m_xWidthED->SetMetric(aMetric);
    m_xHeightED->SetMetric(aMetric);
    ::SetFieldUnit(*m_xAtHorzPosED, aMetric);
    ::SetFieldUnit(*m_xAtVertPosED, aMetric);

    const SwFormatAnchor& rAnchor = rSet->Get(RES_ANCHOR);

    if (const SfxBoolItem* pMathItem = rSet->GetItemIfSet(FN_OLE_IS_MATH, false))
        m_bIsMathOLE = pMathItem->GetValue();
    if (const SfxBoolItem* pAlignItem = rSet->GetItemIfSet(FN_MATH_BASELINE_ALIGNMENT, false))
        m_bIsMathBaselineAlignment = pAlignItem->GetValue();
    EnableVerticalPositioning( !(m_bIsMathOLE && m_bIsMathBaselineAlignment
            && RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) );

    if (m_bFormat)
    {
        // at formats no to-fly anchor
        m_xAnchorAtFrameRB->set_sensitive(false);
        if (rSet->GetItemState(FN_KEEP_ASPECT_RATIO) != SfxItemState::SET)
        {
            m_xFixedRatioCB->set_sensitive(false);
        }
    }
    else
    {
        if (rAnchor.GetAnchorId() != RndStdIds::FLY_AT_FLY && !pSh->IsFlyInFly())
            m_xAnchorAtFrameRB->hide();
        if ( pSh->IsFrameVertical( true, m_bIsInRightToLeft, m_bIsVerticalL2R ) )
        {
            OUString sHLabel = m_xHorizontalFT->get_label();
            m_xHorizontalFT->set_label(m_xVerticalFT->get_label());
            m_xVerticalFT->set_label(sHLabel);
            m_bIsVerticalFrame = true;
        }
    }

    if ( m_sDlgType == "PictureDialog" || m_sDlgType == "ObjectDialog" )
    {
        pSh->GetGrfSize( m_aGrfSize );

        if ( !m_bNew )
        {
            m_xRealSizeBT->connect_clicked(LINK(this, SwFramePage, RealSizeHdl));
            EnableGraficMode();
        }

        if (m_sDlgType == "PictureDialog")
        {
            m_xFixedRatioCB->set_active(false);
            m_xCbxScaleImg->set_from_icon_name(RID_SVXBMP_UNLOCKED);
        }
        else
        {
            if ( m_bNew )
                SetPageTitle(SwResId(STR_FRMUI_OLE_INSERT));
            else
                SetPageTitle(SwResId(STR_FRMUI_OLE_EDIT));
        }
    }
    else
    {
        m_aGrfSize = rSet->Get(RES_FRM_SIZE).GetSize();
    }

    // entering percent value made possible

    // the available space is not yet known so the RefValue has to be calculated from size and relative size values
    // this is needed only if relative values are already set
    const SwFormatFrameSize& rFrameSize = rSet->Get(RES_FRM_SIZE);

    m_xRelWidthRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::FRAME));
    m_xRelWidthRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::REL_PG_FRAME));
    if (rFrameSize.GetWidthPercent() != SwFormatFrameSize::SYNCED && rFrameSize.GetWidthPercent() != 0)
    {
        //calculate the reference value from the width and relative width values
        sal_Int32 nSpace = rFrameSize.GetWidth() * 100 / rFrameSize.GetWidthPercent();
        m_xWidthED->SetRefValue( nSpace );

        m_xRelWidthRelationLB->set_sensitive(true);
    }
    else
        m_xRelWidthRelationLB->set_sensitive(false);

    m_xRelHeightRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::FRAME));
    m_xRelHeightRelationLB->append_text(SvxSwFramePosString::GetString(SwFPos::REL_PG_FRAME));
    if (rFrameSize.GetHeightPercent() != SwFormatFrameSize::SYNCED && rFrameSize.GetHeightPercent() != 0)
    {
        //calculate the reference value from the with and relative width values
        sal_Int32 nSpace = rFrameSize.GetHeight() * 100 / rFrameSize.GetHeightPercent();
        m_xHeightED->SetRefValue( nSpace );

        m_xRelHeightRelationLB->set_sensitive(true);
    }
    else
        m_xRelHeightRelationLB->set_sensitive(false);

    // general initialisation part
    switch(rAnchor.GetAnchorId())
    {
        case RndStdIds::FLY_AT_PAGE: m_xAnchorAtPageRB->set_active(true); break;
        case RndStdIds::FLY_AT_PARA: m_xAnchorAtParaRB->set_active(true); break;
        case RndStdIds::FLY_AT_CHAR: m_xAnchorAtCharRB->set_active(true); break;
        case RndStdIds::FLY_AS_CHAR: m_xAnchorAsCharRB->set_active(true); break;
        case RndStdIds::FLY_AT_FLY: m_xAnchorAtFrameRB->set_active(true);break;
        default:; //prevent warning
    }

    // i#22341 - determine content position of character
    // Note: content position can be NULL
    mpToCharContentPos = rAnchor.GetAnchorNode() ? &rAnchor : nullptr;

    // i#18732 - init checkbox value
    {
        const bool bFollowTextFlow =
            rSet->Get(RES_FOLLOW_TEXT_FLOW).GetValue();
        m_xFollowTextFlowCB->set_active(bFollowTextFlow);
    }
    {
        const bool bFlySplit = rSet->Get(RES_FLY_SPLIT).GetValue();
        m_xFlySplitCB->set_active(bFlySplit);
    }

    if(m_bHtmlMode)
    {
        m_xAutoHeightCB->set_sensitive(false);
        m_xAutoWidthCB->set_sensitive(false);
        m_xMirrorPagesCB->hide();
        if (m_sDlgType == "FrameDialog")
            m_xFixedRatioCB->set_sensitive(false);
        // i#18732 hide checkbox in HTML mode
        m_xFollowTextFlowCB->hide();
        m_xProtectFrame->hide();
    }
    else
    {
        // enable/disable of check box 'Mirror on..'
        m_xMirrorPagesCB->set_sensitive(!m_xAnchorAsCharRB->get_active());

        // enable/disable check box 'Follow text flow'.
        // enable check box 'Follow text
        // flow' also for anchor type to-frame.
        m_xFollowTextFlowCB->set_sensitive(m_xAnchorAtParaRB->get_active() ||
                                           m_xAnchorAtCharRB->get_active() ||
                                           m_xAnchorAtFrameRB->get_active());
        m_xFlySplitCB->set_sensitive(m_xAnchorAtParaRB->get_active());
    }

    const SwFrameFormat* pFlyFormat = pSh->GetFlyFrameFormat();
    if (!pFlyFormat || !ContainsSingleTable(*pFlyFormat) || ContainsChain(*pFlyFormat))
    {
        bool bSingleTable = false;
        if (!pFlyFormat && m_bNew)
        {
            // No fly is selected: check if a whole table is selected. If so, allow moving that into
            // a split fly.
            if (SwFlyFrameAttrMgr::SingleTableSelected(*pSh))
            {
                bSingleTable = true;
            }
        }

        // Only allow fly split if the frame contains a single table, otherwise it would be hard to
        // save the resulting model to Word formats.
        if (!bSingleTable)
        {
            m_xFlySplitCB->hide();
        }
    }
    else if (!m_bNew && InTextBox(*pFlyFormat))
    {
        // Disallow split flys in fly frames which form a textbox, i.e. non-editeng shape text.
        m_xFlySplitCB->hide();
    }

    // Pos Protected
    const SvxProtectItem& rProt = rSet->Get(RES_PROTECT);
    m_xProtectFrameCB->set_active(rProt.IsPosProtected());
    m_xProtectContentCB->set_active(rProt.IsContentProtected());
    m_xProtectSizeCB->set_active(rProt.IsSizeProtected());

    Init(*rSet);
    m_xAtVertPosED->save_value();
    m_xAtHorzPosED->save_value();
    m_xFollowTextFlowCB->save_state();
    m_xFlySplitCB->save_state();

    m_xWidthED->save_value();
    m_xHeightED->save_value();

    m_bNoModifyHdl = false;
    //lock PercentFields
    m_xWidthED->LockAutoCalculation(true);
    m_xHeightED->LockAutoCalculation(true);
    RangeModifyHdl();  // set all maximum values initially
    m_xHeightED->LockAutoCalculation(false);
    m_xWidthED->LockAutoCalculation(false);

    m_xAutoHeightCB->save_state();
    m_xAutoWidthCB->save_state();

    SwTwips nWidth  = static_cast< SwTwips >(m_xWidthED->DenormalizePercent(m_xWidthED->get_value(FieldUnit::TWIP)));
    SwTwips nHeight = static_cast< SwTwips >(m_xHeightED->DenormalizePercent(m_xHeightED->get_value(FieldUnit::TWIP)));
    m_fWidthHeightRatio = nHeight ? double(nWidth) / double(nHeight) : 1.0;
}

// stuff attributes into the set when OK
bool SwFramePage::FillItemSet(SfxItemSet *rSet)
{
    bool bRet = false;

    const SfxPoolItem* pOldItem;
    SvxProtectItem aProt(GetItemSet().Get(RES_PROTECT));
    aProt.SetContentProtect(m_xProtectContentCB->get_active());
    aProt.SetSizeProtect(m_xProtectSizeCB->get_active());
    aProt.SetPosProtect(m_xProtectFrameCB->get_active());
    if (nullptr == (pOldItem = GetOldItem(*rSet, FN_SET_PROTECT)) || aProt != *pOldItem)
        bRet |= nullptr != rSet->Put(aProt);

    const SfxItemSet& rOldSet = GetItemSet();
    pOldItem = nullptr;

    RndStdIds eAnchorId = GetAnchor();

    if ( !m_bFormat || eAnchorId != RndStdIds::FLY_AT_FLY )
    {
        pOldItem = GetOldItem(*rSet, RES_ANCHOR);
        if (m_bNew || !pOldItem || eAnchorId != static_cast<const SwFormatAnchor*>(pOldItem)->GetAnchorId())
        {
            SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell()
                                : getFrameDlgParentShell();
            OSL_ENSURE( pSh , "shell not found");
            if (pSh)
            {
                SwFormatAnchor aAnc( eAnchorId, eAnchorId == RndStdIds::FLY_AT_PAGE ? pSh->GetPhyPageNum() : 0 );
                bRet = nullptr != rSet->Put( aAnc );
            }
        }
    }

    if ( m_pHMap )
    {
        SwFormatHoriOrient aHoriOrient( rOldSet.Get(RES_HORI_ORIENT) );

        const sal_Int32 nMapPos = GetMapPos(m_pHMap, *m_xHorizontalDLB);
        const sal_Int16 eHOri = GetAlignment(m_pHMap, nMapPos, *m_xHoriRelationLB);
        const sal_Int16 eRel = GetRelation(*m_xHoriRelationLB);

        aHoriOrient.SetHoriOrient( eHOri );
        aHoriOrient.SetRelationOrient( eRel );
        aHoriOrient.SetPosToggle(m_xMirrorPagesCB->get_active());

        bool bMod = m_xAtHorzPosED->get_value_changed_from_saved();
        bMod |= m_xMirrorPagesCB->get_state_changed_from_saved();

        if ( eHOri == text::HoriOrientation::NONE &&
             (m_bNew || (m_bAtHorzPosModified || bMod) || m_nOldH != eHOri ) )
        {
            SwTwips nX = static_cast< SwTwips >(m_xAtHorzPosED->denormalize(m_xAtHorzPosED->get_value(FieldUnit::TWIP)));
            aHoriOrient.SetPos( nX );
        }

        pOldItem = GetOldItem(*rSet, FN_HORI_ORIENT);
        bool bSame = false;
        if ((m_bNew == m_bFormat) && pOldItem)
        {
             bSame = aHoriOrient == static_cast<const SwFormatHoriOrient&>(*pOldItem);
        }
        if ((m_bNew && !m_bFormat) || ((m_bAtHorzPosModified || bMod) && !bSame))
        {
            bRet |= nullptr != rSet->Put( aHoriOrient );
        }
    }

    if ( m_pVMap )
    {
        // alignment vertical
        SwFormatVertOrient aVertOrient( rOldSet.Get(RES_VERT_ORIENT) );

        const sal_Int32 nMapPos = GetMapPos(m_pVMap, *m_xVerticalDLB);
        const sal_Int16 eVOri = GetAlignment(m_pVMap, nMapPos, *m_xVertRelationLB);
        const sal_Int16 eRel = GetRelation(*m_xVertRelationLB);

        aVertOrient.SetVertOrient    ( eVOri);
        aVertOrient.SetRelationOrient( eRel );

        bool bMod = m_xAtVertPosED->get_value_changed_from_saved();

        if ( eVOri == text::VertOrientation::NONE &&
             ( m_bNew || (m_bAtVertPosModified || bMod) || m_nOldV != eVOri) )
        {
            // vertical position
            // recalculate offset for character bound frames
            SwTwips nY = static_cast< SwTwips >(m_xAtVertPosED->denormalize(m_xAtVertPosED->get_value(FieldUnit::TWIP)));
            if (eAnchorId == RndStdIds::FLY_AS_CHAR)
            {
                nY *= -1;
            }
            aVertOrient.SetPos( nY );
        }
        pOldItem = GetOldItem(*rSet, FN_VERT_ORIENT);
        bool bSame = false;
        if((m_bNew == m_bFormat) && pOldItem)
        {
             bSame = m_bFormat ?
                      aVertOrient.GetVertOrient() == static_cast<const SwFormatVertOrient*>(pOldItem)->GetVertOrient() &&
                      aVertOrient.GetRelationOrient() == static_cast<const SwFormatVertOrient*>(pOldItem)->GetRelationOrient() &&
                      aVertOrient.GetPos() == static_cast<const SwFormatVertOrient*>(pOldItem)->GetPos()
                    : aVertOrient == static_cast<const SwFormatVertOrient&>(*pOldItem);
        }
        if( ( m_bNew && !m_bFormat ) || ((m_bAtVertPosModified || bMod) && !bSame ))
        {
            bRet |= nullptr != rSet->Put( aVertOrient );
        }
    }

    // set size
    // new exception: when the size of pMgr(, 0), then the properties
    // for a graphic that isn't even loaded, are set. Then no SetSize
    // is done here when the size settings were not changed by the
    // user.
    const SwFormatFrameSize& rOldSize = rOldSet.Get(RES_FRM_SIZE);
    SwFormatFrameSize aSz( rOldSize );

    auto nRelWidthRelation = m_xRelWidthRelationLB->get_active();
    if (nRelWidthRelation != -1)
    {
        if (nRelWidthRelation == 0)
            aSz.SetWidthPercentRelation(text::RelOrientation::FRAME);
        else if (nRelWidthRelation == 1)
            aSz.SetWidthPercentRelation(text::RelOrientation::PAGE_FRAME);
    }
    auto nRelHeightRelation = m_xRelHeightRelationLB->get_active();
    if (nRelHeightRelation != -1)
    {
        if (nRelHeightRelation == 0)
            aSz.SetHeightPercentRelation(text::RelOrientation::FRAME);
        else if (nRelHeightRelation == 1)
            aSz.SetHeightPercentRelation(text::RelOrientation::PAGE_FRAME);
    }

    bool bValueModified = m_xWidthED->get_value_changed_from_saved()
                          || m_xHeightED->get_value_changed_from_saved()
                          || m_xRelWidthRelationLB->get_value_changed_from_saved()
                          || m_xRelHeightRelationLB->get_value_changed_from_saved();
    bool bCheckChanged = m_xRelWidthCB->get_state_changed_from_saved() ||
                         m_xRelHeightCB->get_state_changed_from_saved() ||
                         m_xFixedRatioCB->get_state_changed_from_saved();

    bool bLegalValue = !(!rOldSize.GetWidth () && !rOldSize.GetHeight() &&
                            m_xWidthED->get_value() == m_xWidthED->get_min() &&
                            m_xHeightED->get_value() == m_xHeightED->get_min());

    if ((m_bNew && !m_bFormat) || ((bValueModified || bCheckChanged) && bLegalValue))
    {
        sal_Int64 nNewWidth  = m_xWidthED->DenormalizePercent(m_xWidthED->GetRealValue(FieldUnit::TWIP));
        sal_Int64 nNewHeight = m_xHeightED->DenormalizePercent(m_xHeightED->GetRealValue(FieldUnit::TWIP));
        aSz.SetWidth (static_cast< SwTwips >(nNewWidth));
        aSz.SetHeight(static_cast< SwTwips >(nNewHeight));

        if (m_xRelWidthCB->get_active())
        {
            aSz.SetWidthPercent(static_cast<sal_uInt8>(std::min(MAX_PERCENT_WIDTH, m_xWidthED->Convert(m_xWidthED->NormalizePercent(nNewWidth), FieldUnit::TWIP, FieldUnit::PERCENT))));
        }
        else
            aSz.SetWidthPercent(0);
        if (m_xRelHeightCB->get_active())
            aSz.SetHeightPercent(static_cast<sal_uInt8>(std::min(MAX_PERCENT_HEIGHT, m_xHeightED->Convert(m_xHeightED->NormalizePercent(nNewHeight), FieldUnit::TWIP, FieldUnit::PERCENT))));
        else
            aSz.SetHeightPercent(0);

        if (m_xFixedRatioCB->get_active() && (m_xRelWidthCB->get_active() != m_xRelHeightCB->get_active()))
        {
            if (m_xRelWidthCB->get_active())
                aSz.SetHeightPercent(SwFormatFrameSize::SYNCED);
            else
                aSz.SetWidthPercent(SwFormatFrameSize::SYNCED);
        }
    }

    if( !IsInGraficMode() )
    {
        if (m_xAutoHeightCB->get_state_changed_from_saved())
        {
            SwFrameSize eFrameSize = m_xAutoHeightCB->get_active()? SwFrameSize::Minimum : SwFrameSize::Fixed;
            if( eFrameSize != aSz.GetHeightSizeType() )
                aSz.SetHeightSizeType(eFrameSize);
        }
        if (m_xAutoWidthCB->get_state_changed_from_saved())
        {
            SwFrameSize eFrameSize = m_xAutoWidthCB->get_active()? SwFrameSize::Minimum : SwFrameSize::Fixed;
            if( eFrameSize != aSz.GetWidthSizeType() )
                aSz.SetWidthSizeType( eFrameSize );
        }
    }
    if (m_xFixedRatioCB->get_state_changed_from_saved())
        bRet |= nullptr != rSet->Put(SfxBoolItem(FN_KEEP_ASPECT_RATIO, m_xFixedRatioCB->get_active()));

    pOldItem = GetOldItem(*rSet, RES_FRM_SIZE);

    bool bSizeChanged = pOldItem && aSz != *pOldItem;
    if (!bSizeChanged && m_bNew)
    {
        // If no custom size is provided, always set a size for a new frame, to avoid ~zero width.
        bSizeChanged = true;
    }
    if (bSizeChanged || (!pOldItem && !m_bFormat) ||
            (m_bFormat &&
                (aSz.GetWidth() > 0 || aSz.GetWidthPercent() > 0) &&
                    (aSz.GetHeight() > 0 || aSz.GetHeightPercent() > 0)))
    {
        if (aSz.GetHeightSizeType() == SwFrameSize::Variable)    // there is no VAR_SIZE in frames
            aSz.SetHeightSizeType(SwFrameSize::Minimum);

        bRet |= nullptr != rSet->Put( aSz );
        // and now set the size for "external" - e.g.:Crop - tabpages
        if (bRet)
        {
            SwFormatFrameSize aSizeCopy = rSet->Get(RES_FRM_SIZE);
            SvxSizeItem aSzItm( SID_ATTR_GRAF_FRMSIZE, aSizeCopy.GetSize() );
            rSet->Put( aSzItm );

            Size aGrpSz( aSizeCopy.GetWidthPercent(), aSizeCopy.GetHeightPercent() );
            if( SwFormatFrameSize::SYNCED == aGrpSz.Width() )   aGrpSz.setWidth( 0 );
            if( SwFormatFrameSize::SYNCED == aGrpSz.Height() )  aGrpSz.setHeight( 0 );

            aSzItm.SetSize( aGrpSz );
            aSzItm.SetWhich( SID_ATTR_GRAF_FRMSIZE_PERCENT );
            bRet |= nullptr != rSet->Put( aSzItm );
        }
    }
    if (m_xFollowTextFlowCB->get_state_changed_from_saved())
    {
        bRet |= nullptr != rSet->Put(SwFormatFollowTextFlow(m_xFollowTextFlowCB->get_active()));
    }
    if (m_xFlySplitCB->get_state_changed_from_saved())
    {
        bRet |= rSet->Put(SwFormatFlySplit(m_xFlySplitCB->get_active())) != nullptr;
    }
    return bRet;
}

// initialise horizontal and vertical Pos
void SwFramePage::InitPos(RndStdIds eId,
                                sal_Int16 nH,
                                sal_Int16 nHRel,
                                sal_Int16 nV,
                                sal_Int16 nVRel,
                                tools::Long   nX,
                                tools::Long   nY)
{
    auto nPos = m_xVerticalDLB->get_active();
    if (nPos != -1 && m_pVMap)
    {
        m_nOldV    = m_pVMap[nPos].nAlign;

        nPos = m_xVertRelationLB->get_active();
        if (nPos != -1)
            m_nOldVRel = weld::fromId<RelationMap*>(m_xVertRelationLB->get_id(nPos))->nRelation;
    }

    nPos = m_xHorizontalDLB->get_active();
    if (nPos != -1 && m_pHMap)
    {
        m_nOldH    = m_pHMap[nPos].nAlign;

        nPos = m_xHoriRelationLB->get_active();
        if (nPos != -1)
            m_nOldHRel = weld::fromId<RelationMap*>(m_xHoriRelationLB->get_id(nPos))->nRelation;
    }

    bool bEnable = true;
    if ( eId == RndStdIds::FLY_AT_PAGE )
    {
        m_pVMap = m_bHtmlMode ? aVPageHtmlMap : aVPageMap;
        m_pHMap = m_bHtmlMode ? aHPageHtmlMap : aHPageMap;
    }
    else if ( eId == RndStdIds::FLY_AT_FLY )
    {
        // own vertical alignment map for to frame
        // anchored objects.
        m_pVMap = m_bHtmlMode ? aVFlyHtmlMap : aVFrameMap;
        m_pHMap = m_bHtmlMode ? aHFlyHtmlMap : aHFrameMap;
    }
    else if ( eId == RndStdIds::FLY_AT_PARA )
    {
        if(m_bHtmlMode)
        {
            m_pVMap = aVParaHtmlMap;
            m_pHMap = aHParaHtmlAbsMap;
        }
        else
        {
            m_pVMap = aVParaMap;
            m_pHMap = aHParaMap;
        }
    }
    else if ( eId == RndStdIds::FLY_AT_CHAR )
    {
        if(m_bHtmlMode)
        {
            m_pVMap = aVCharHtmlAbsMap;
            m_pHMap = aHCharHtmlAbsMap;
        }
        else
        {
            m_pVMap = aVCharMap;
            m_pHMap = aHCharMap;
        }
    }
    else if ( eId == RndStdIds::FLY_AS_CHAR )
    {
        m_pVMap = m_bHtmlMode ? aVAsCharHtmlMap     : aVAsCharMap;
        m_pHMap = nullptr;
        bEnable = false;
    }
    m_xHorizontalDLB->set_sensitive( bEnable );
    m_xHorizontalFT->set_sensitive( bEnable );

    // select current Pos
    // horizontal
    if ( nH < 0 )
    {
        nH    = m_nOldH;
        nHRel = m_nOldHRel;
    }
    sal_Int32 nMapPos = FillPosLB(m_pHMap, nH, nHRel, *m_xHorizontalDLB);
    FillRelLB(m_pHMap, nMapPos, nH, nHRel, *m_xHoriRelationLB, *m_xHoriRelationFT);

    // vertical
    if ( nV < 0 )
    {
        nV    = m_nOldV;
        nVRel = m_nOldVRel;
    }
    nMapPos = FillPosLB(m_pVMap, nV, nVRel, *m_xVerticalDLB);
    FillRelLB(m_pVMap, nMapPos, nV, nVRel, *m_xVertRelationLB, *m_xVertRelationFT);

    bEnable = nH == text::HoriOrientation::NONE && eId != RndStdIds::FLY_AS_CHAR;
    if (!bEnable)
        m_xAtHorzPosED->set_value(0, FieldUnit::TWIP);
    else
    {
        if (nX != LONG_MAX)
            m_xAtHorzPosED->set_value(m_xAtHorzPosED->normalize(nX), FieldUnit::TWIP);
    }
    m_xAtHorzPosFT->set_sensitive( bEnable );
    m_xAtHorzPosED->set_sensitive( bEnable );

    bEnable = nV == text::VertOrientation::NONE;
    if ( !bEnable )
        m_xAtVertPosED->set_value(0, FieldUnit::TWIP);
    else
    {
        if (eId == RndStdIds::FLY_AS_CHAR)
        {
            if ( nY == LONG_MAX )
                nY = 0;
            else
                nY *= -1;
        }
        if ( nY != LONG_MAX )
            m_xAtVertPosED->set_value(m_xAtVertPosED->normalize(nY), FieldUnit::TWIP);
    }
    m_xAtVertPosFT->set_sensitive( bEnable && m_bAllowVertPositioning );
    m_xAtVertPosED->set_sensitive( bEnable && m_bAllowVertPositioning );
    UpdateExample();
}

sal_Int32 SwFramePage::FillPosLB(const FrameMap* _pMap,
                            const sal_Int16 _nAlign,
                            const sal_Int16 _nRel,
                            weld::ComboBox& _rLB )
{
    OUString sSelEntry;
    const OUString sOldEntry = _rLB.get_active_text();

    _rLB.clear();

    // i#22341 determine all possible listbox relations for
    // given relation for map <aVCharMap>
    const LB nLBRelations = (_pMap != aVCharMap)
                               ? LB::NONE
                               : ::lcl_GetLBRelationsForRelations( _nRel );

    // fill Listbox
    size_t nCount = ::lcl_GetFrameMapCount(_pMap);
    for (size_t i = 0; _pMap && i < nCount; ++i)
    {
//      Why not from the left/from inside or from above?
        SvxSwFramePosString::StringId eStrId = m_xMirrorPagesCB->get_active() ? _pMap[i].eMirrorStrId : _pMap[i].eStrId;
        // --> OD 2009-08-31 #mongolianlayout#
        eStrId = lcl_ChangeResIdToVerticalOrRTL( eStrId,
                                                 m_bIsVerticalFrame,
                                                 m_bIsVerticalL2R,
                                                 m_bIsInRightToLeft);
        OUString sEntry(SvxSwFramePosString::GetString(eStrId));
        if (_rLB.find_text(sEntry) == -1)
        {
            // don't insert entries when frames are character bound
            _rLB.append_text(sEntry);
        }
        // i#22341 - add condition to handle map <aVCharMap>
        // that is ambiguous in the alignment.
        if ( _pMap[i].nAlign == _nAlign &&
             ( (_pMap != aVCharMap) || _pMap[i].nLBRelations & nLBRelations ) )
        {
            sSelEntry = sEntry;
        }
    }

    _rLB.set_active_text(sSelEntry);
    if (_rLB.get_active() == -1)
        _rLB.set_active_text(sOldEntry);

    if (_rLB.get_active() == -1 && _rLB.get_count())
        _rLB.set_active(0);

    PosHdl(_rLB);

    return GetMapPos(_pMap, _rLB);
}

void SwFramePage::FillRelLB(const FrameMap* _pMap,
                            const sal_uInt16 _nLBSelPos,
                            const sal_Int16 _nAlign,
                            const sal_Int16 _nRel,
                            weld::ComboBox& _rLB,
                            weld::Label& _rFT)
{
    OUString sSelEntry;
    LB       nLBRelations = LB::NONE;
    size_t   nMapCount = ::lcl_GetFrameMapCount(_pMap);

    _rLB.clear();

    if (_nLBSelPos < nMapCount)
    {
        if (_pMap == aVAsCharHtmlMap || _pMap == aVAsCharMap)
        {
            const OUString sOldEntry(_rLB.get_active_text());
            SvxSwFramePosString::StringId eStrId = _pMap[_nLBSelPos].eStrId;

            for (size_t nMapPos = 0; nMapPos < nMapCount; nMapPos++)
            {
                if (_pMap[nMapPos].eStrId == eStrId)
                {
                    nLBRelations = _pMap[nMapPos].nLBRelations;
                    for (RelationMap const & rCharMap : aAsCharRelationMap)
                    {
                        if (nLBRelations & rCharMap.nLBRelation)
                        {
                            // --> OD 2009-08-31 #mongolianlayout#
                            SvxSwFramePosString::StringId sStrId1 =
                                lcl_ChangeResIdToVerticalOrRTL( rCharMap.eStrId,
                                                                m_bIsVerticalFrame,
                                                                m_bIsVerticalL2R,
                                                                m_bIsInRightToLeft);
                            const OUString sEntry = SvxSwFramePosString::GetString(sStrId1);
                            _rLB.append(weld::toId(&rCharMap), sEntry);
                            if (_pMap[nMapPos].nAlign == _nAlign)
                                sSelEntry = sEntry;
                            break;
                        }
                    }
                }
            }
            if (!sSelEntry.isEmpty())
                _rLB.set_active_text(sSelEntry);
            else
            {
                _rLB.set_active_text(sOldEntry);

                if (_rLB.get_active() == -1)
                {
                    for (int i = 0; i < _rLB.get_count(); i++)
                    {
                        RelationMap *pEntry = weld::fromId<RelationMap*>(_rLB.get_id(i));
                        if (pEntry->nLBRelation == LB::RelChar) // default
                        {
                            _rLB.set_active(i);
                            break;
                        }
                    }
                }
            }
        }
        else
        {
            // special handling for map <aVCharMap>,
            // because its ambiguous in its <eStrId>/<eMirrorStrId>.
            if ( _pMap == aVCharMap )
            {
                nLBRelations = ::lcl_GetLBRelationsForStrID( _pMap,
                                             ( m_xMirrorPagesCB->get_active()
                                               ? _pMap[_nLBSelPos].eMirrorStrId
                                               : _pMap[_nLBSelPos].eStrId),
                                             m_xMirrorPagesCB->get_active() );
            }
            else
            {
                nLBRelations = _pMap[_nLBSelPos].nLBRelations;
            }

            for (sal_uLong nBit = 1; nBit < 0x80000000; nBit <<= 1)
            {
                if (nLBRelations & static_cast<LB>(nBit))
                {
                    for (RelationMap const & rMap : aRelationMap)
                    {
                        if (rMap.nLBRelation == static_cast<LB>(nBit))
                        {
                            SvxSwFramePosString::StringId eStrId1 = m_xMirrorPagesCB->get_active() ?
                                            rMap.eMirrorStrId : rMap.eStrId;
                            // --> OD 2009-08-31 #mongolianlayout#
                            eStrId1 =
                                lcl_ChangeResIdToVerticalOrRTL( eStrId1,
                                                                m_bIsVerticalFrame,
                                                                m_bIsVerticalL2R,
                                                                m_bIsInRightToLeft);
                            const OUString sEntry = SvxSwFramePosString::GetString(eStrId1);
                            _rLB.append(weld::toId(&rMap), sEntry);
                            if (sSelEntry.isEmpty() && rMap.nRelation == _nRel)
                                sSelEntry = sEntry;
                        }
                    }
                }
            }
            if (!sSelEntry.isEmpty())
                _rLB.set_active_text(sSelEntry);
            else
            {
                // Probably anchor switch. So look for similar relation
                sal_Int16 nSimRel = -1;
                switch (_nRel)
                {
                    case text::RelOrientation::FRAME:
                        nSimRel = text::RelOrientation::PAGE_FRAME;
                        break;
                    case text::RelOrientation::PRINT_AREA:
                        nSimRel = text::RelOrientation::PAGE_PRINT_AREA;
                        break;
                    case text::RelOrientation::PAGE_LEFT:
                        nSimRel = text::RelOrientation::FRAME_LEFT;
                        break;
                    case text::RelOrientation::PAGE_RIGHT:
                        nSimRel = text::RelOrientation::FRAME_RIGHT;
                        break;
                    case text::RelOrientation::FRAME_LEFT:
                        nSimRel = text::RelOrientation::PAGE_LEFT;
                        break;
                    case text::RelOrientation::FRAME_RIGHT:
                        nSimRel = text::RelOrientation::PAGE_RIGHT;
                        break;
                    case text::RelOrientation::PAGE_FRAME:
                        nSimRel = text::RelOrientation::FRAME;
                        break;
                    case text::RelOrientation::PAGE_PRINT_AREA:
                        nSimRel = text::RelOrientation::PRINT_AREA;
                        break;

                    default:
                        if (_rLB.get_active() != -1)
                        {
                            RelationMap *pEntry = weld::fromId<RelationMap*>(_rLB.get_id(_rLB.get_count() - 1));
                            nSimRel = pEntry->nRelation;
                        }
                        break;
                }

                for (int i = 0; i < _rLB.get_count(); i++)
                {
                    RelationMap *pEntry = weld::fromId<RelationMap*>(_rLB.get_id(i));
                    if (pEntry->nRelation == nSimRel)
                    {
                        _rLB.set_active(i);
                        break;
                    }
                }

                if (_rLB.get_active() == -1)
                    _rLB.set_active(0);
            }
        }
    }

    const bool bEnable = _rLB.get_count() != 0
            && (&_rLB != m_xVertRelationLB.get() || m_bAllowVertPositioning);
    _rLB.set_sensitive( bEnable );
    _rFT.set_sensitive( bEnable );

    RelHdl(_rLB);
}

sal_Int16 SwFramePage::GetRelation(const weld::ComboBox& rRelationLB)
{
    const auto nPos = rRelationLB.get_active();
    if (nPos != -1)
    {
        RelationMap *pEntry = weld::fromId<RelationMap *>(rRelationLB.get_id(nPos));
        return pEntry->nRelation;
    }

    return 0;
}

sal_Int16 SwFramePage::GetAlignment(FrameMap const *pMap, sal_Int32 nMapPos,
                                    const weld::ComboBox& rRelationLB)
{
    if (!pMap || nMapPos < 0)
        return 0;

    const size_t nMapCount = ::lcl_GetFrameMapCount(pMap);

    if (o3tl::make_unsigned(nMapPos) >= nMapCount)
        return 0;

    // i#22341 special handling also for map <aVCharMap>,
    // because it contains ambiguous items for alignment
    if ( pMap != aVAsCharHtmlMap && pMap != aVAsCharMap && pMap != aVCharMap )
        return pMap[nMapPos].nAlign;

    if (rRelationLB.get_active() == -1)
        return 0;

    const RelationMap *const pRelationMap = weld::fromId<const RelationMap*>(
        rRelationLB.get_active_id());
    const LB nRel = pRelationMap->nLBRelation;
    const SvxSwFramePosString::StringId eStrId = pMap[nMapPos].eStrId;

    for (size_t i = 0; i < nMapCount; ++i)
    {
        if (pMap[i].eStrId == eStrId && (pMap[i].nLBRelations & nRel))
            return pMap[i].nAlign;
    }

    return 0;
}

sal_Int32 SwFramePage::GetMapPos(const FrameMap *pMap, const weld::ComboBox& rAlignLB)
{
    sal_Int32 nMapPos = 0;
    auto nLBSelPos = rAlignLB.get_active();

    if (nLBSelPos != -1)
    {
        if (pMap == aVAsCharHtmlMap || pMap == aVAsCharMap)
        {
            const size_t nMapCount = ::lcl_GetFrameMapCount(pMap);
            const OUString sSelEntry(rAlignLB.get_active_text());

            for (size_t i = 0; i < nMapCount; i++)
            {
                SvxSwFramePosString::StringId eResId = pMap[i].eStrId;

                OUString sEntry = SvxSwFramePosString::GetString(eResId);
                sEntry = MnemonicGenerator::EraseAllMnemonicChars( sEntry );

                if (sEntry == sSelEntry)
                {
                    nMapPos = static_cast< sal_Int32 >(i);
                    break;
                }
            }
        }
        else
            nMapPos = nLBSelPos;
    }

    return nMapPos;
}

RndStdIds SwFramePage::GetAnchor() const
{
    RndStdIds nRet = RndStdIds::FLY_AT_PAGE;
    if (m_xAnchorAtParaRB->get_active())
    {
        nRet = RndStdIds::FLY_AT_PARA;
    }
    else if (m_xAnchorAtCharRB->get_active())
    {
        nRet = RndStdIds::FLY_AT_CHAR;
    }
    else if (m_xAnchorAsCharRB->get_active())
    {
        nRet = RndStdIds::FLY_AS_CHAR;
    }
    else if (m_xAnchorAtFrameRB->get_active())
    {
        nRet = RndStdIds::FLY_AT_FLY;
    }
    return nRet;
}

// Bsp - Update
void SwFramePage::ActivatePage(const SfxItemSet& rSet)
{
    m_bNoModifyHdl = true;
    Init(rSet);
    m_bNoModifyHdl = false;
    //lock PercentFields
    m_xWidthED->LockAutoCalculation(true);
    m_xHeightED->LockAutoCalculation(true);
    RangeModifyHdl();  // set all maximum values initially
    m_xHeightED->LockAutoCalculation(false);
    m_xWidthED->LockAutoCalculation(false);
    m_xFollowTextFlowCB->save_state();
    m_xFlySplitCB->save_state();
}

DeactivateRC SwFramePage::DeactivatePage(SfxItemSet * _pSet)
{
    if ( _pSet )
    {
        FillItemSet( _pSet );

        if (!m_bFormat) // tdf#112574 no anchor in styles
        {
            //FillItemSet doesn't set the anchor into the set when it matches
            //the original. But for the other pages we need the current anchor.
            SwWrtShell* pSh = getFrameDlgParentShell();
            if (pSh)
            {
                RndStdIds eAnchorId = GetAnchor();
                SwFormatAnchor aAnc( eAnchorId, eAnchorId == RndStdIds::FLY_AT_PAGE ? pSh->GetPhyPageNum() : 0 );
                _pSet->Put( aAnc );
            }
        }
    }

    return DeactivateRC::LeavePage;
}

// swap left/right with inside/outside
IMPL_LINK_NOARG(SwFramePage, MirrorHdl, weld::Toggleable&, void)
{
    RndStdIds eId = GetAnchor();
    InitPos(eId, -1, 0, -1, 0, LONG_MAX, LONG_MAX);
}

IMPL_LINK( SwFramePage, RelSizeClickHdl, weld::Toggleable&, rBtn, void )
{
    if (&rBtn == m_xRelWidthCB.get())
    {
        m_xWidthED->ShowPercent(rBtn.get_active(), MAX_PERCENT_WIDTH);
        m_xRelWidthRelationLB->set_sensitive(rBtn.get_active());
    }
    else // rBtn == m_xRelHeightCB.get()
    {
        m_xHeightED->ShowPercent(rBtn.get_active(), MAX_PERCENT_WIDTH);
        m_xRelHeightRelationLB->set_sensitive(rBtn.get_active());
    }

    RangeModifyHdl();  // correct the values again

    if (&rBtn == m_xRelWidthCB.get())
        ModifyHdl(*m_xWidthED->get());
    else // rBtn == m_xRelHeightCB.get()
        ModifyHdl(*m_xHeightED->get());
}

IMPL_LINK_NOARG(SwFramePage, RelRelationClickHdl, weld::ComboBox&, void)
{
    RangeModifyHdl();
}
// range check
IMPL_LINK_NOARG(SwFramePage, RangeModifyClickHdl, weld::Toggleable&, void)
{
    RangeModifyHdl();
}

void SwFramePage::RangeModifyHdl()
{
    if (m_bNoModifyHdl)
        return;

    SwWrtShell* pSh = m_bFormat ? ::GetActiveWrtShell()
                        : getFrameDlgParentShell();
    OSL_ENSURE(pSh , "shell not found");
    if (!pSh)
        return;

    SwFlyFrameAttrMgr aMgr( m_bNew, pSh, GetItemSet() );
    SvxSwFrameValidation        aVal;

    aVal.nAnchorType = GetAnchor();
    aVal.bAutoHeight = m_xAutoHeightCB->get_active();
    aVal.bMirror = m_xMirrorPagesCB->get_active();
    aVal.bFollowTextFlow = m_xFollowTextFlowCB->get_active();

    if ( m_pHMap )
    {
        // alignment horizontal
        const sal_Int32 nMapPos = GetMapPos(m_pHMap, *m_xHorizontalDLB);
        aVal.nHoriOrient = GetAlignment(m_pHMap, nMapPos, *m_xHoriRelationLB);
        aVal.nHRelOrient = GetRelation(*m_xHoriRelationLB);
    }
    else
        aVal.nHoriOrient = text::HoriOrientation::NONE;

    if ( m_pVMap )
    {
        // alignment vertical
        const sal_Int32 nMapPos = GetMapPos(m_pVMap, *m_xVerticalDLB);
        aVal.nVertOrient = GetAlignment(m_pVMap, nMapPos, *m_xVertRelationLB);
        aVal.nVRelOrient = GetRelation(*m_xVertRelationLB);
    }
    else
        aVal.nVertOrient = text::VertOrientation::NONE;

    const tools::Long nAtHorzPosVal = static_cast< tools::Long >(
                    m_xAtHorzPosED->denormalize(m_xAtHorzPosED->get_value(FieldUnit::TWIP)) );
    const tools::Long nAtVertPosVal = static_cast< tools::Long >(
                    m_xAtVertPosED->denormalize(m_xAtVertPosED->get_value(FieldUnit::TWIP)) );

    aVal.nHPos = nAtHorzPosVal;
    aVal.nVPos = nAtVertPosVal;

    if (m_xRelWidthRelationLB->get_active() == 1)
        aVal.bEntirePageWidth = true;
    if (m_xRelHeightRelationLB->get_active() == 1)
        aVal.bEntirePageHeight = true;

    aMgr.ValidateMetrics(aVal, mpToCharContentPos, true);   // one time, to get reference values for percental values

    // set reference values for percental values (100%) ...
    m_xWidthED->SetRefValue(aVal.aPercentSize.Width());
    m_xHeightED->SetRefValue(aVal.aPercentSize.Height());

    // ... and correctly convert width and height with it
    SwTwips nWidth  = static_cast< SwTwips >(m_xWidthED->DenormalizePercent(m_xWidthED->get_value(FieldUnit::TWIP)));
    SwTwips nHeight = static_cast< SwTwips >(m_xHeightED->DenormalizePercent(m_xHeightED->get_value(FieldUnit::TWIP)));
    aVal.nWidth  = nWidth;
    aVal.nHeight = nHeight;

    aMgr.ValidateMetrics(aVal, mpToCharContentPos);    // one more time, to determine all remaining values with correct width and height.

    // all columns have to be correct
    const SfxItemSet* pExampleSet = GetDialogExampleSet();
    if (pExampleSet && SfxItemState::DEFAULT <= pExampleSet->GetItemState(RES_COL))
    {
        const SwFormatCol& rCol = pExampleSet->Get(RES_COL);
        if ( rCol.GetColumns().size() > 1 )
        {
            for (const SwColumn & i : rCol.GetColumns())
            {
                aVal.nMinWidth += i.GetLeft() +
                                  i.GetRight() +
                                  MINFLY;
            }
            aVal.nMinWidth -= MINFLY;//one was already in there!
        }
    }

    nWidth = aVal.nWidth;
    nHeight = aVal.nHeight;

    // minimum range also for template
    m_xHeightED->set_min(m_xHeightED->NormalizePercent(aVal.nMinHeight), FieldUnit::TWIP);
    m_xWidthED->set_min(m_xWidthED->NormalizePercent(aVal.nMinWidth), FieldUnit::TWIP);

    SwTwips nMaxWidth(aVal.nMaxWidth);
    SwTwips nMaxHeight(aVal.nMaxHeight);

    if (aVal.bAutoHeight && (m_sDlgType == "PictureDialog" || m_sDlgType == "ObjectDialog"))
    {
        SwTwips nTmp = std::min(nWidth * nMaxHeight / std::max(nHeight, SwTwips(1)), nMaxHeight);
        m_xWidthED->set_max(m_xWidthED->NormalizePercent(nTmp), FieldUnit::TWIP);

        nTmp = std::min(nHeight * nMaxWidth / std::max(nWidth, SwTwips(1)), nMaxWidth);
        m_xHeightED->set_max(m_xWidthED->NormalizePercent(nTmp), FieldUnit::TWIP);
    }
    else
    {
        SwTwips nTmp = static_cast< SwTwips >(m_xHeightED->NormalizePercent(nMaxHeight));
        m_xHeightED->set_max(nTmp, FieldUnit::TWIP);

        nTmp = static_cast< SwTwips >(m_xWidthED->NormalizePercent(nMaxWidth));
        m_xWidthED->set_max(nTmp, FieldUnit::TWIP);
    }

    m_xAtHorzPosED->set_range(m_xAtHorzPosED->normalize(aVal.nMinHPos),
                              m_xAtHorzPosED->normalize(aVal.nMaxHPos),
                              FieldUnit::TWIP);
    if (aVal.nHPos != nAtHorzPosVal)
        m_xAtHorzPosED->set_value(m_xAtHorzPosED->normalize(aVal.nHPos), FieldUnit::TWIP);

    const SwTwips nUpperOffset = (aVal.nAnchorType == RndStdIds::FLY_AS_CHAR)
        ? m_nUpperBorder : 0;
    const SwTwips nLowerOffset = (aVal.nAnchorType == RndStdIds::FLY_AS_CHAR)
        ? m_nLowerBorder : 0;

    m_xAtVertPosED->set_range(m_xAtVertPosED->normalize(aVal.nMinVPos + nLowerOffset + nUpperOffset),
                              m_xAtVertPosED->normalize(aVal.nMaxVPos),
                              FieldUnit::TWIP);
    if (aVal.nVPos != nAtVertPosVal)
        m_xAtVertPosED->set_value(m_xAtVertPosED->normalize(aVal.nVPos), FieldUnit::TWIP);
}

IMPL_LINK_NOARG(SwFramePage, AnchorTypeHdl, weld::Toggleable&, void)
{
    m_xMirrorPagesCB->set_sensitive(!m_xAnchorAsCharRB->get_active());

    // i#18732 - enable check box 'Follow text flow' for anchor
    // type to-paragraph' and to-character
    // i#22305 - enable check box 'Follow text
    // flow' also for anchor type to-frame.
    m_xFollowTextFlowCB->set_sensitive(m_xAnchorAtParaRB->get_active() ||
                                       m_xAnchorAtCharRB->get_active() ||
                                       m_xAnchorAtFrameRB->get_active());
    m_xFlySplitCB->set_sensitive(m_xAnchorAtParaRB->get_active());

    RndStdIds eId = GetAnchor();

    InitPos( eId, -1, 0, -1, 0, LONG_MAX, LONG_MAX);
    RangeModifyHdl();

    if(m_bHtmlMode)
    {
        PosHdl(*m_xHorizontalDLB);
        PosHdl(*m_xVerticalDLB);
    }

    EnableVerticalPositioning( !(m_bIsMathOLE && m_bIsMathBaselineAlignment
            && RndStdIds::FLY_AS_CHAR == eId) );
}

IMPL_LINK( SwFramePage, PosHdl, weld::ComboBox&, rLB, void )
{
    bool bHori = &rLB == m_xHorizontalDLB.get();
    weld::ComboBox *pRelLB = bHori ? m_xHoriRelationLB.get() : m_xVertRelationLB.get();
    weld::Label *pRelFT = bHori ? m_xHoriRelationFT.get() : m_xVertRelationFT.get();
    FrameMap const *pMap = bHori ? m_pHMap : m_pVMap;

    const sal_Int32 nMapPos = GetMapPos(pMap, rLB);
    const sal_Int16 nAlign = GetAlignment(pMap, nMapPos, *pRelLB);

    if (bHori)
    {
        bool bEnable = text::HoriOrientation::NONE == nAlign;
        m_xAtHorzPosED->set_sensitive( bEnable );
        m_xAtHorzPosFT->set_sensitive( bEnable );
    }
    else
    {
        bool bEnable = text::VertOrientation::NONE == nAlign && m_bAllowVertPositioning;
        m_xAtVertPosED->set_sensitive( bEnable );
        m_xAtVertPosFT->set_sensitive( bEnable );
    }

    RangeModifyHdl();

    sal_Int16 nRel = 0;
    if (rLB.get_active() != -1)
    {
        if (pRelLB->get_active() != -1)
            nRel = weld::fromId<RelationMap*>(pRelLB->get_active_id())->nRelation;
        FillRelLB(pMap, nMapPos, nAlign, nRel, *pRelLB, *pRelFT);
    }
    else
        pRelLB->clear();

    UpdateExample();

    if (bHori)
        m_bAtHorzPosModified = true;
    else
        m_bAtVertPosModified = true;

    // special treatment for HTML-Mode with horizontal-vertical-dependencies
    if(!(m_bHtmlMode && (RndStdIds::FLY_AT_CHAR == GetAnchor())))
        return;

    bool bSet = false;
    if(bHori)
    {
        // right is allowed only above - from the left only above
        // from the left at character -> below
        if((text::HoriOrientation::LEFT == nAlign || text::HoriOrientation::RIGHT == nAlign) &&
                0 == m_xVerticalDLB->get_active())
        {
            if(text::RelOrientation::FRAME == nRel)
                m_xVerticalDLB->set_active(1);
            else
                m_xVerticalDLB->set_active(0);
            bSet = true;
        }
        else if(text::HoriOrientation::LEFT == nAlign && 1 == m_xVerticalDLB->get_active())
        {
            m_xVerticalDLB->set_active(0);
            bSet = true;
        }
        else if(text::HoriOrientation::NONE == nAlign && 1 == m_xVerticalDLB->get_active())
        {
            m_xVerticalDLB->set_active(0);
            bSet = true;
        }
        if(bSet)
            PosHdl(*m_xVerticalDLB);
    }
    else
    {
        if(text::VertOrientation::TOP == nAlign)
        {
            if (1 == m_xHorizontalDLB->get_active())
            {
                m_xHorizontalDLB->set_active(0);
                bSet = true;
            }
            m_xHoriRelationLB->set_active(1);
        }
        else if(text::VertOrientation::CHAR_BOTTOM == nAlign)
        {
            if (2 == m_xHorizontalDLB->get_active())
            {
                m_xHorizontalDLB->set_active(0);
                bSet = true;
            }
            m_xHoriRelationLB->set_active(0) ;
        }
        if(bSet)
            PosHdl(*m_xHorizontalDLB);
    }
}

//  horizontal Pos
IMPL_LINK( SwFramePage, RelHdl, weld::ComboBox&, rLB, void )
{
    bool bHori = &rLB == m_xHoriRelationLB.get();

    UpdateExample();

    if (bHori)
        m_bAtHorzPosModified = true;
    else
        m_bAtVertPosModified = true;

    if (m_bHtmlMode && (RndStdIds::FLY_AT_CHAR == GetAnchor()))
    {
        if(bHori)
        {
            const sal_Int16 nRel = GetRelation(*m_xHoriRelationLB);
            if(text::RelOrientation::PRINT_AREA == nRel && 0 == m_xVerticalDLB->get_active())
            {
                m_xVerticalDLB->set_active(1);
            }
            else if(text::RelOrientation::CHAR == nRel && 1 == m_xVerticalDLB->get_active())
            {
                m_xVerticalDLB->set_active(0);
            }
        }
    }
    RangeModifyHdl();
}

IMPL_LINK_NOARG(SwFramePage, RealSizeHdl, weld::Button&, void)
{
    m_xWidthED->set_value(m_xWidthED->NormalizePercent(m_aGrfSize.Width()), FieldUnit::TWIP);
    m_xHeightED->set_value(m_xHeightED->NormalizePercent(m_aGrfSize.Height()), FieldUnit::TWIP);
    m_fWidthHeightRatio = m_aGrfSize.Height() ? double(m_aGrfSize.Width()) / double(m_aGrfSize.Height()) : 1.0;
    UpdateExample();
}

IMPL_LINK_NOARG(SwFramePage, AutoWidthClickHdl, weld::Toggleable&, void)
{
    if( !IsInGraficMode() )
        HandleAutoCB( m_xAutoWidthCB->get_active(), *m_xWidthFT, *m_xWidthAutoFT, *m_xWidthED->get() );
}

IMPL_LINK_NOARG(SwFramePage, AutoHeightClickHdl, weld::Toggleable&, void)
{
    if (!IsInGraficMode())
        HandleAutoCB(m_xAutoHeightCB->get_active(), *m_xHeightFT, *m_xHeightAutoFT, *m_xWidthED->get());
}

IMPL_LINK_NOARG(SwFramePage, RatioClickHdl, weld::Toggleable&, void)
{
    m_xCbxScaleImg->set_from_icon_name(m_xFixedRatioCB->get_active() ? RID_SVXBMP_LOCKED : RID_SVXBMP_UNLOCKED);
}

IMPL_LINK( SwFramePage, ModifyHdl, weld::MetricSpinButton&, rEdit, void )
{
    SwTwips nWidth  = static_cast< SwTwips >(m_xWidthED->DenormalizePercent(m_xWidthED->get_value(FieldUnit::TWIP)));
    SwTwips nHeight = static_cast< SwTwips >(m_xHeightED->DenormalizePercent(m_xHeightED->get_value(FieldUnit::TWIP)));
    if (m_xFixedRatioCB->get_active() && !m_bIgnoreFixedRatio)
    {
        if (&rEdit == m_xWidthED->get())
        {
            nHeight = SwTwips(static_cast<double>(nWidth) / m_fWidthHeightRatio);
            m_xHeightED->set_value(m_xHeightED->NormalizePercent(nHeight), FieldUnit::TWIP);
        }
        else if (&rEdit == m_xHeightED->get())
        {
            nWidth = SwTwips(static_cast<double>(nHeight) * m_fWidthHeightRatio);
            m_xWidthED->set_value(m_xWidthED->NormalizePercent(nWidth), FieldUnit::TWIP);
        }
    }
    m_fWidthHeightRatio = nHeight ? double(nWidth) / double(nHeight) : 1.0;
    UpdateExample();
}

void SwFramePage::UpdateExample()
{
    auto nPos = m_xHorizontalDLB->get_active();
    if (m_pHMap && nPos != -1)
    {
        const sal_Int32 nMapPos = GetMapPos(m_pHMap, *m_xHorizontalDLB);
        m_aExampleWN.SetHAlign(GetAlignment(m_pHMap, nMapPos, *m_xHoriRelationLB));
        m_aExampleWN.SetHoriRel(GetRelation(*m_xHoriRelationLB));
    }

    nPos = m_xVerticalDLB->get_active();
    if (m_pVMap && nPos != -1)
    {
        const sal_Int32 nMapPos = GetMapPos(m_pVMap, *m_xVerticalDLB);
        m_aExampleWN.SetVAlign(GetAlignment(m_pVMap, nMapPos, *m_xVertRelationLB));
        m_aExampleWN.SetVertRel(GetRelation(*m_xVertRelationLB));
    }

    // size
    auto nXPos = m_xAtHorzPosED->denormalize(m_xAtHorzPosED->get_value(FieldUnit::TWIP));
    auto nYPos = m_xAtVertPosED->denormalize(m_xAtVertPosED->get_value(FieldUnit::TWIP));
    m_aExampleWN.SetRelPos(Point(nXPos, nYPos));

    m_aExampleWN.SetAnchor(GetAnchor());
    m_aExampleWN.Invalidate();
}

void SwFramePage::Init(const SfxItemSet& rSet)
{
    if(!m_bFormat)
    {
        SwWrtShell* pSh = getFrameDlgParentShell();

        // size
        const bool bSizeFixed = pSh->IsSelObjProtected( FlyProtectFlags::Fixed ) != FlyProtectFlags::NONE;

        m_xWidthED->set_sensitive( !bSizeFixed );
        m_xHeightED->set_sensitive( !bSizeFixed );

        // size controls for math OLE objects
        if ( m_sDlgType == "ObjectDialog" && ! m_bNew )
        {
            // disable width and height for math objects
            const SvGlobalName aFactNm( pSh->GetOLEObject()->getClassID() );

            static struct GlobalNameId {
                sal_uInt32 n1;
                sal_uInt16 n2, n3;
                sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
            } const aGlbNmIds[] = { { SO3_SM_CLASSID_60 }, { SO3_SM_CLASSID_50 },
                                    { SO3_SM_CLASSID_40 }, { SO3_SM_CLASSID_30 } };

            for (const GlobalNameId & rId : aGlbNmIds) {
                SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3,
                                     rId.b8, rId.b9, rId.b10, rId.b11,
                                     rId.b12, rId.b13, rId.b14, rId.b15 );

                if( aFactNm == aGlbNm )
                {
                    // disable size controls for math OLE objects
                    m_xWidthFT->set_sensitive(false);
                    m_xWidthED->set_sensitive(false);
                    m_xRelWidthCB->set_sensitive(false);
                    m_xHeightFT->set_sensitive(false);
                    m_xHeightED->set_sensitive(false);
                    m_xRelHeightCB->set_sensitive(false);
                    m_xFixedRatioCB->set_sensitive(false);
                    m_xRealSizeBT->set_sensitive(false);
                    break;
                }
            }

            // TODO/LATER: get correct aspect
            if(0 != (pSh->GetOLEObject()->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) )
                m_xRealSizeBT->set_sensitive(false);
        }
    }

    SwFormatFrameSize rSize = rSet.Get(RES_FRM_SIZE);
    // size could already have been set from another (Crop) page
    if (const SvxSizeItem* pSizeItem = rSet.GetItemIfSet(SID_ATTR_GRAF_FRMSIZE, false))
    {
        if (pSizeItem->GetSize() != rSize.GetSize())
        {
            const Size& rSz = pSizeItem->GetSize();
            rSize.SetWidth(rSz.Width());
            rSize.SetHeight(rSz.Height());

            pSizeItem = rSet.GetItemIfSet(SID_ATTR_GRAF_FRMSIZE_PERCENT, false);
            if (pSizeItem)
            {
                const Size& rRelativeSize = pSizeItem->GetSize();
                rSize.SetWidthPercent(static_cast<sal_uInt8>(rRelativeSize.Width()));
                rSize.SetHeightPercent(static_cast<sal_uInt8>(rRelativeSize.Height()));
            }
        }
    }

    sal_Int64 nWidth  = m_xWidthED->NormalizePercent(rSize.GetWidth());
    sal_Int64 nHeight = m_xHeightED->NormalizePercent(rSize.GetHeight());

    if (nWidth != m_xWidthED->get_value(FieldUnit::TWIP))
        m_xWidthED->set_value(nWidth, FieldUnit::TWIP);

    if (nHeight != m_xHeightED->get_value(FieldUnit::TWIP))
        m_xHeightED->set_value(nHeight, FieldUnit::TWIP);

    if (!IsInGraficMode())
    {
        SwFrameSize eSize = rSize.GetHeightSizeType();
        bool bCheck = eSize != SwFrameSize::Fixed;
        m_xAutoHeightCB->set_active(bCheck);
        HandleAutoCB( bCheck, *m_xHeightFT, *m_xHeightAutoFT, *m_xWidthED->get() );
        if( eSize == SwFrameSize::Variable )
            m_xHeightED->set_value(m_xHeightED->get_min());

        eSize = rSize.GetWidthSizeType();
        bCheck = eSize != SwFrameSize::Fixed;
        m_xAutoWidthCB->set_active(bCheck);
        HandleAutoCB( bCheck, *m_xWidthFT, *m_xWidthAutoFT, *m_xWidthED->get() );
        if( eSize == SwFrameSize::Variable )
            m_xWidthED->set_value(m_xWidthED->get_min());

        if ( !m_bFormat )
        {
            SwWrtShell* pSh = getFrameDlgParentShell();
            const SwFrameFormat* pFormat = pSh->GetFlyFrameFormat();
            if( pFormat && pFormat->GetChain().GetNext() )
                m_xAutoHeightCB->set_sensitive( false );
        }
    }
    else
        m_xAutoHeightCB->hide();

    // organise circulation-gap for character bound frames
    const SvxULSpaceItem &rUL = rSet.Get(RES_UL_SPACE);
    m_nUpperBorder = rUL.GetUpper();
    m_nLowerBorder = rUL.GetLower();

    if (SfxItemState::SET == rSet.GetItemState(FN_KEEP_ASPECT_RATIO))
        m_xFixedRatioCB->set_active(rSet.Get(FN_KEEP_ASPECT_RATIO).GetValue());
    // see tdf#132591 and tdf#151382 for some examples of FN_KEEP_ASPECT_RATIO cases
    m_xFixedRatioCB->save_state();

    // columns
    SwFormatCol aCol( rSet.Get(RES_COL) );
    ::FitToActualSize( aCol, o3tl::narrowing<sal_uInt16>(rSize.GetWidth()) );

    RndStdIds eAnchorId = GetAnchor();

    if ( m_bNew && !m_bFormat )
        InitPos(eAnchorId, -1, 0, -1, 0, LONG_MAX, LONG_MAX);
    else
    {
        const SwFormatHoriOrient& rHori = rSet.Get(RES_HORI_ORIENT);
        const SwFormatVertOrient& rVert = rSet.Get(RES_VERT_ORIENT);
        m_nOldH    = rHori.GetHoriOrient();
        m_nOldHRel = rHori.GetRelationOrient();
        m_nOldV    = rVert.GetVertOrient();
        m_nOldVRel = rVert.GetRelationOrient();

        if (eAnchorId == RndStdIds::FLY_AT_PAGE)
        {
            if (m_nOldHRel == text::RelOrientation::FRAME)
                m_nOldHRel = text::RelOrientation::PAGE_FRAME;
            else if (m_nOldHRel == text::RelOrientation::PRINT_AREA)
                m_nOldHRel = text::RelOrientation::PAGE_PRINT_AREA;
            if (m_nOldVRel == text::RelOrientation::FRAME)
                m_nOldVRel = text::RelOrientation::PAGE_FRAME;
            else if (m_nOldVRel == text::RelOrientation::PRINT_AREA)
                m_nOldVRel = text::RelOrientation::PAGE_PRINT_AREA;
        }

        m_xMirrorPagesCB->set_active(rHori.IsPosToggle());
        m_xMirrorPagesCB->save_state();

        InitPos(eAnchorId,
                m_nOldH,
                m_nOldHRel,
                m_nOldV,
                m_nOldVRel,
                rHori.GetPos(),
                rVert.GetPos());
    }

    // transparent for example
    // circulation for example
    const SwFormatSurround& rSurround = rSet.Get(RES_SURROUND);
    m_aExampleWN.SetWrap( rSurround.GetSurround() );

    if ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH )
    {
        const SvxOpaqueItem& rOpaque = rSet.Get(RES_OPAQUE);
        m_aExampleWN.SetTransparent(!rOpaque.GetValue());
    }

    // switch to percent if applicable
    RangeModifyHdl();  // set reference values (for 100%)

    if (rSize.GetWidthPercent() == SwFormatFrameSize::SYNCED || rSize.GetHeightPercent() == SwFormatFrameSize::SYNCED)
        m_xFixedRatioCB->set_active(true);
    if (rSize.GetWidthPercent() && rSize.GetWidthPercent() != SwFormatFrameSize::SYNCED &&
        !m_xRelWidthCB->get_active())
    {
        m_xRelWidthCB->set_active(true);
        m_bIgnoreFixedRatio = true;
        RelSizeClickHdl(*m_xRelWidthCB);
        m_bIgnoreFixedRatio = false;
        m_xWidthED->set_value(rSize.GetWidthPercent(), FieldUnit::PERCENT);
    }
    if (rSize.GetHeightPercent() && rSize.GetHeightPercent() != SwFormatFrameSize::SYNCED &&
        !m_xRelHeightCB->get_active())
    {
        m_xRelHeightCB->set_active(true);
        m_bIgnoreFixedRatio = true;
        RelSizeClickHdl(*m_xRelHeightCB);
        m_bIgnoreFixedRatio = false;
        m_xHeightED->set_value(rSize.GetHeightPercent(), FieldUnit::PERCENT);
    }
    m_xRelWidthCB->save_state();
    m_xRelHeightCB->save_state();

    if (rSize.GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME)
        m_xRelWidthRelationLB->set_active(1);
    else
        m_xRelWidthRelationLB->set_active(0);

    if (rSize.GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME)
        m_xRelHeightRelationLB->set_active(1);
    else
        m_xRelHeightRelationLB->set_active(0);
    m_xCbxScaleImg->set_from_icon_name(m_xFixedRatioCB->get_active() ? RID_SVXBMP_LOCKED : RID_SVXBMP_UNLOCKED);
}

void SwFramePage::SetFormatUsed(bool bFormatUsed)
{
    m_bFormat = bFormatUsed;
    if (m_bFormat)
        m_xAnchorAtFrameRB->hide();
}

void SwFramePage::EnableVerticalPositioning( bool bEnable )
{
    m_bAllowVertPositioning = bEnable;
    m_xVerticalFT->set_sensitive( bEnable );
    m_xVerticalDLB->set_sensitive( bEnable );
    m_xAtVertPosFT->set_sensitive( bEnable );
    m_xAtVertPosED->set_sensitive( bEnable );
    m_xVertRelationFT->set_sensitive( bEnable );
    m_xVertRelationLB->set_sensitive( bEnable );
}

SwGrfExtPage::SwGrfExtPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet)
    : SfxTabPage(pPage, pController, u"modules/swriter/ui/picturepage.ui"_ustr, u"PicturePage"_ustr, &rSet)
    , m_bHtmlMode(false)
    , m_xMirror(m_xBuilder->weld_widget(u"flipframe"_ustr))
    , m_xMirrorVertBox(m_xBuilder->weld_check_button(u"vert"_ustr))
    , m_xMirrorHorzBox(m_xBuilder->weld_check_button(u"hori"_ustr))
    , m_xAllPagesRB(m_xBuilder->weld_radio_button(u"allpages"_ustr))
    , m_xLeftPagesRB(m_xBuilder->weld_radio_button(u"leftpages"_ustr))
    , m_xRightPagesRB(m_xBuilder->weld_radio_button(u"rightpages"_ustr))
    , m_xConnectED(m_xBuilder->weld_entry(u"entry"_ustr))
    , m_xBrowseBT(m_xBuilder->weld_button(u"browse"_ustr))
    , m_xLinkFrame(m_xBuilder->weld_frame(u"linkframe"_ustr))
    // RotGrfFlyFrame: Need Angle and RotateControls now
    , m_xFlAngle(m_xBuilder->weld_frame(u"FL_ANGLE"_ustr))
    , m_xNfAngle(m_xBuilder->weld_metric_spin_button(u"NF_ANGLE"_ustr, FieldUnit::DEGREE))
    , m_xCtlAngle(new svx::DialControl)
    , m_xCtlAngleWin(new weld::CustomWeld(*m_xBuilder, u"CTL_ANGLE"_ustr, *m_xCtlAngle))
    , m_xBmpWin(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aBmpWin))
    // tdf#138843 place holder for the graphic type
    , m_xLabelGraphicType(m_xBuilder->weld_label(u"label-graphic-type"_ustr))
{
    m_aBmpWin.SetBitmap(Bitmap(RID_BMP_PREVIEW_FALLBACK));

    m_xCtlAngle->SetLinkedField(m_xNfAngle.get(), 2);

    SetExchangeSupport();
    m_xMirrorHorzBox->connect_toggled(LINK(this, SwGrfExtPage, MirrorHdl));
    m_xMirrorVertBox->connect_toggled(LINK(this, SwGrfExtPage, MirrorHdl));
    m_xBrowseBT->connect_clicked(LINK(this, SwGrfExtPage, BrowseHdl));
}

SwGrfExtPage::~SwGrfExtPage()
{
    m_xBmpWin.reset();
    m_xCtlAngleWin.reset();
    m_xCtlAngle.reset();
    m_xGrfDlg.reset();
}

std::unique_ptr<SfxTabPage> SwGrfExtPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet)
{
    return std::make_unique<SwGrfExtPage>(pPage, pController, *rSet);
}

void SwGrfExtPage::Reset(const SfxItemSet *rSet)
{
    const sal_uInt16 nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current()));
    m_bHtmlMode = (nHtmlMode & HTMLMODE_ON) != 0;

    const SfxBoolItem* pConnectItem = rSet->GetItemIfSet( FN_PARAM_GRF_CONNECT );
    if( pConnectItem && pConnectItem->GetValue() )
    {
        m_xBrowseBT->set_sensitive(true);
        m_xConnectED->set_editable(true);
    }

    // RotGrfFlyFrame: Get RotationAngle and set at control
    if(const SdrAngleItem* pAngleItem = rSet->GetItemIfSet( SID_ATTR_TRANSFORM_ANGLE, false))
    {
        m_xCtlAngle->SetRotation(pAngleItem->GetValue());
    }
    else
    {
        m_xCtlAngle->SetRotation(0_deg100);
    }
    m_xCtlAngle->SaveValue();

    ActivatePage(*rSet);
}

void SwGrfExtPage::ActivatePage(const SfxItemSet& rSet)
{
    const SvxProtectItem& rProt = rSet.Get(RES_PROTECT);
    bool bProtContent = rProt.IsContentProtected();

    const SfxPoolItem* pItem = nullptr;
    bool bEnable = false;
    bool bEnableMirrorRB = false;

    SfxItemState eState = rSet.GetItemState(RES_GRFATR_MIRRORGRF, true, &pItem);
    if (SfxItemState::UNKNOWN != eState && !bProtContent && !m_bHtmlMode)
    {
        if( SfxItemState::SET != eState )
            pItem = &rSet.Get( RES_GRFATR_MIRRORGRF );

        bEnable = true;

        MirrorGraph eMirror = static_cast<const SwMirrorGrf* >(pItem)->GetValue();
        switch( eMirror )
        {
        case MirrorGraph::Dont: break;
        case MirrorGraph::Vertical:    m_xMirrorHorzBox->set_active(true); break;
        case MirrorGraph::Horizontal:  m_xMirrorVertBox->set_active(true); break;
        case MirrorGraph::Both:        m_xMirrorHorzBox->set_active(true);
                                       m_xMirrorVertBox->set_active(true);
                                       break;
        default:
            ;
        }

        const int nPos = (static_cast<const SwMirrorGrf* >(pItem)->IsGrfToggle() ? 1 : 0)
            + ((eMirror == MirrorGraph::Vertical || eMirror == MirrorGraph::Both) ? 2 : 0);

        bEnableMirrorRB = nPos != 0;

        switch (nPos)
        {
            case 1: // mirror at left / even pages
                m_xLeftPagesRB->set_active(true);
                m_xMirrorHorzBox->set_active(true);
                break;
            case 2: // mirror on all pages
                m_xAllPagesRB->set_active(true);
                break;
            case 3: // mirror on right / odd pages
                m_xRightPagesRB->set_active(true);
                break;
            default:
                m_xAllPagesRB->set_active(true);
                break;
        }
    }

    if( const SvxBrushItem* pGraphicBrushItem = rSet.GetItemIfSet( SID_ATTR_GRAF_GRAPHIC, false ) )
    {
        if( !pGraphicBrushItem->GetGraphicLink().isEmpty() )
        {
            m_aGrfName = m_aNewGrfName = pGraphicBrushItem->GetGraphicLink();
            m_xConnectED->set_text(m_aNewGrfName);
        }
        OUString referer;
        SfxStringItem const * it = rSet.GetItem(SID_REFERER);
        if (it != nullptr) {
            referer = it->GetValue();
        }
        const Graphic* pGrf = pGraphicBrushItem->GetGraphic(referer);
        if( pGrf )
        {
            m_aBmpWin.SetGraphic( *pGrf );
            m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(*pGrf));
        }
    }

    m_xConnectED->save_value();

    m_xMirror->set_sensitive(bEnable);
    m_xAllPagesRB->set_sensitive(bEnableMirrorRB);
    m_xLeftPagesRB->set_sensitive(bEnableMirrorRB);
    m_xRightPagesRB->set_sensitive(bEnableMirrorRB);

    m_xAllPagesRB->save_state();
    m_xLeftPagesRB->save_state();
    m_xRightPagesRB->save_state();
    m_xMirrorHorzBox->save_state();
    m_xMirrorVertBox->save_state();

    m_aBmpWin.MirrorHorz( m_xMirrorVertBox->get_active() );
    m_aBmpWin.MirrorVert( m_xMirrorHorzBox->get_active() );
    m_aBmpWin.Invalidate();
}

bool SwGrfExtPage::FillItemSet( SfxItemSet *rSet )
{
    bool bModified = false;
    if ( m_xMirrorHorzBox->get_state_changed_from_saved() ||
         m_xMirrorVertBox->get_state_changed_from_saved() ||
         m_xAllPagesRB->get_state_changed_from_saved() ||
         m_xLeftPagesRB->get_state_changed_from_saved() ||
         m_xRightPagesRB->get_state_changed_from_saved() )
    {
        bModified = true;

        bool bHori = false;

        if (m_xMirrorHorzBox->get_active() &&
                !m_xLeftPagesRB->get_active())
            bHori = true;

        MirrorGraph eMirror;
        eMirror = m_xMirrorVertBox->get_active() && bHori ?
                    MirrorGraph::Both : bHori ?
                    MirrorGraph::Vertical : m_xMirrorVertBox->get_active() ?
                    MirrorGraph::Horizontal  : MirrorGraph::Dont;

        bool bMirror = !m_xAllPagesRB->get_active();
        SwMirrorGrf aMirror( eMirror );
        aMirror.SetGrfToggle(bMirror );
        rSet->Put( aMirror );
    }

    if (m_aGrfName != m_aNewGrfName || m_xConnectED->get_value_changed_from_saved())
    {
        bModified = true;
        m_aGrfName = m_xConnectED->get_text();
        rSet->Put( SvxBrushItem( m_aGrfName, m_aFilterName, GPOS_LT,
                                SID_ATTR_GRAF_GRAPHIC ));
    }

    // RotGrfFlyFrame: Safe rotation if modified
    if(m_xCtlAngle->IsValueModified())
    {
        rSet->Put(SdrAngleItem(SID_ATTR_TRANSFORM_ANGLE, m_xCtlAngle->GetRotation()));
        bModified = true;
    }

    return bModified;
}

DeactivateRC SwGrfExtPage::DeactivatePage(SfxItemSet *_pSet)
{
    if( _pSet )
        FillItemSet( _pSet );
    return DeactivateRC::LeavePage;
}

IMPL_LINK_NOARG(SwGrfExtPage, BrowseHdl, weld::Button&, void)
{
    if(!m_xGrfDlg)
    {
        m_xGrfDlg.reset(new FileDialogHelper(
                ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW,
                FileDialogFlags::Graphic, GetFrameWeld()));
        m_xGrfDlg->SetTitle(m_xLinkFrame->get_label());
    }
    m_xGrfDlg->SetDisplayDirectory(m_xConnectED->get_text());
    uno::Reference < ui::dialogs::XFilePicker3 > xFP = m_xGrfDlg->GetFilePicker();
    uno::Reference < ui::dialogs::XFilePickerControlAccess > xCtrlAcc(xFP, uno::UNO_QUERY);
    xCtrlAcc->setValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, uno::Any(true) );

    if ( m_xGrfDlg->Execute() != ERRCODE_NONE )
        return;

// remember selected filter
    m_aFilterName = m_xGrfDlg->GetCurrentFilter();
    m_aNewGrfName = INetURLObject::decode( m_xGrfDlg->GetPath(),
                                       INetURLObject::DecodeMechanism::Unambiguous );
    m_xConnectED->set_text(m_aNewGrfName);
    //reset mirrors because maybe a Bitmap was swapped with
    //another type of graphic that cannot be mirrored.
    m_xMirrorVertBox->set_active(false);
    m_xMirrorHorzBox->set_active(false);
    m_xAllPagesRB->set_sensitive(false);
    m_xLeftPagesRB->set_sensitive(false);
    m_xRightPagesRB->set_sensitive(false);
    m_aBmpWin.MirrorHorz(false);
    m_aBmpWin.MirrorVert(false);

    Graphic aGraphic;
    (void)GraphicFilter::LoadGraphic(m_xGrfDlg->GetPath(), OUString(), aGraphic);
    m_aBmpWin.SetGraphic(aGraphic);
    m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(aGraphic));

    bool bEnable = GraphicType::Bitmap      == aGraphic.GetType() ||
                        GraphicType::GdiMetafile == aGraphic.GetType();
    m_xMirrorVertBox->set_sensitive(bEnable);
    m_xMirrorHorzBox->set_sensitive(bEnable);
    m_xAllPagesRB->set_sensitive(bEnable);
    m_xLeftPagesRB->set_sensitive(bEnable);
    m_xRightPagesRB->set_sensitive(bEnable);

}

IMPL_LINK_NOARG(SwGrfExtPage, MirrorHdl, weld::Toggleable&, void)
{
    bool bEnable = m_xMirrorHorzBox->get_active();

    m_aBmpWin.MirrorHorz( m_xMirrorVertBox->get_active() );
    m_aBmpWin.MirrorVert( bEnable );

    m_xAllPagesRB->set_sensitive(bEnable);
    m_xLeftPagesRB->set_sensitive(bEnable);
    m_xRightPagesRB->set_sensitive(bEnable);

    if (!m_xAllPagesRB->get_active() && !m_xLeftPagesRB->get_active() && !m_xRightPagesRB->get_active())
        m_xAllPagesRB->set_active(true);
}

// example window
BmpWindow::BmpWindow()
    : m_bHorz(false)
    , m_bVert(false)
    , m_bGraphic(false)
{
}

void BmpWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
{
    CustomWidgetController::SetDrawingArea(pDrawingArea);
    Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(127 , 66), MapMode(MapUnit::MapAppFont));
    set_size_request(aSize.Width(), aSize.Height());
    SetOutputSizePixel(aSize);
}

void BmpWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    // Setup
    rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
    rRenderContext.Erase();
    // #i119307# the graphic might have transparency, set up white as the color
    // to use when drawing a rectangle under the image
    rRenderContext.SetLineColor(COL_WHITE);
    rRenderContext.SetFillColor(COL_WHITE);

    // Paint
    Point aPntPos;
    Size aPntSz(GetOutputSizePixel());
    Size aGrfSize;
    if (m_bGraphic)
        aGrfSize = ::GetGraphicSizeTwip(m_aGraphic, &rRenderContext);
    //it should show the default bitmap also if no graphic can be found
    if (!aGrfSize.Width() && !aGrfSize.Height())
        aGrfSize = rRenderContext.PixelToLogic(m_aBmp.GetSizePixel());

    tools::Long nRelGrf = aGrfSize.Width() * 100 / aGrfSize.Height();
    tools::Long nRelWin = aPntSz.Width() * 100 / aPntSz.Height();
    if (nRelGrf < nRelWin)
    {
        const tools::Long nWidth = aPntSz.Width();
        // if we use a replacement preview, try to draw at original size
        if (!m_bGraphic && (aGrfSize.Width() <= aPntSz.Width())
                      && (aGrfSize.Height() <= aPntSz.Height()))
        {
            const tools::Long nHeight = aPntSz.Height();
            aPntSz.setWidth( aGrfSize.Width() );
            aPntSz.setHeight( aGrfSize.Height() );
            aPntPos.AdjustY((nHeight - aPntSz.Height()) / 2 );
        }
        else
            aPntSz.setWidth( aPntSz.Height() * nRelGrf /100 );

        aPntPos.AdjustX(nWidth - aPntSz.Width() ) ;
    }

    // #i119307# clear window background, the graphic might have transparency
    rRenderContext.DrawRect(tools::Rectangle(aPntPos, aPntSz));

    if (m_bHorz || m_bVert)
    {
        Bitmap aTmpBmp(m_bGraphic ? m_aGraphic.GetBitmap() : m_aBmp);
        BmpMirrorFlags nMirrorFlags(BmpMirrorFlags::NONE);
        if (m_bHorz)
            nMirrorFlags |= BmpMirrorFlags::Vertical;
        if (m_bVert)
            nMirrorFlags |= BmpMirrorFlags::Horizontal;
        aTmpBmp.Mirror(nMirrorFlags);
        rRenderContext.DrawBitmap(aPntPos, aPntSz, aTmpBmp);
    }
    else if (m_bGraphic)  //draw unmirrored preview graphic
    {
        m_aGraphic.Draw(rRenderContext, aPntPos, aPntSz);
    }
    else    //draw unmirrored stock sample image
    {
        rRenderContext.DrawBitmap(aPntPos, aPntSz, m_aBmp);
    }
}

BmpWindow::~BmpWindow()
{
}

void BmpWindow::SetGraphic(const Graphic& rGraphic)
{
    m_aGraphic = rGraphic;
    Size aSize = m_aGraphic.GetPrefSize();
    m_bGraphic = aSize.Width() && aSize.Height();
    Invalidate();
}

void BmpWindow::SetBitmap(const Bitmap& rBmp)
{
    m_aBmp = rBmp;
    Invalidate();
}

// set URL and ImageMap at frames
SwFrameURLPage::SwFrameURLPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet)
    : SfxTabPage(pPage, pController, u"modules/swriter/ui/frmurlpage.ui"_ustr, u"FrameURLPage"_ustr, &rSet)
    , m_xURLED(m_xBuilder->weld_entry(u"url"_ustr))
    , m_xSearchPB(m_xBuilder->weld_button(u"search"_ustr))
    , m_xNameED(m_xBuilder->weld_entry(u"name"_ustr))
    , m_xFrameCB(m_xBuilder->weld_combo_box(u"frame"_ustr))
    , m_xServerCB(m_xBuilder->weld_check_button(u"server"_ustr))
    , m_xClientCB(m_xBuilder->weld_check_button(u"client"_ustr))
{
    m_xSearchPB->connect_clicked(LINK(this, SwFrameURLPage, InsertFileHdl));
}

SwFrameURLPage::~SwFrameURLPage()
{
}

void SwFrameURLPage::Reset( const SfxItemSet *rSet )
{
    if ( SfxItemState::SET == rSet->GetItemState( SID_DOCFRAME ))
    {
        TargetList aList;
        SfxFrame::GetDefaultTargetList(aList);
        size_t nCount = aList.size();
        for (size_t i = 0; i < nCount; ++i)
        {
            m_xFrameCB->append_text(aList.at(i));
        }
    }

    if ( const SwFormatURL* pFormatURL = rSet->GetItemIfSet( RES_URL ) )
    {
        m_xURLED->set_text(INetURLObject::decode(pFormatURL->GetURL(),
                                           INetURLObject::DecodeMechanism::Unambiguous));
        m_xNameED->set_text(pFormatURL->GetName());

        m_xClientCB->set_sensitive(pFormatURL->GetMap() != nullptr);
        m_xClientCB->set_active(pFormatURL->GetMap() != nullptr);
        m_xServerCB->set_active(pFormatURL->IsServerMap());

        m_xFrameCB->set_entry_text(pFormatURL->GetTargetFrameName());
        m_xFrameCB->save_value();
    }
    else
        m_xClientCB->set_sensitive(false);

    m_xServerCB->save_state();
    m_xClientCB->save_state();
}

bool SwFrameURLPage::FillItemSet(SfxItemSet *rSet)
{
    bool bModified = false;
    const SwFormatURL* pOldURL = GetOldItem(*rSet, RES_URL);
    std::unique_ptr<SwFormatURL> pFormatURL;
    if(pOldURL)
        pFormatURL.reset(pOldURL->Clone());
    else
        pFormatURL.reset(new SwFormatURL());

    {
        const OUString sText = m_xURLED->get_text();

        if( pFormatURL->GetURL() != sText ||
            pFormatURL->GetName() != m_xNameED->get_text() ||
            m_xServerCB->get_active() != pFormatURL->IsServerMap() )
        {
            pFormatURL->SetURL(sText, m_xServerCB->get_active());
            pFormatURL->SetName(m_xNameED->get_text());
            bModified = true;
        }
    }

    if (!m_xClientCB->get_active() && pFormatURL->GetMap() != nullptr)
    {
        pFormatURL->SetMap(nullptr);
        bModified = true;
    }

    if(pFormatURL->GetTargetFrameName() != m_xFrameCB->get_active_text())
    {
        pFormatURL->SetTargetFrameName(m_xFrameCB->get_active_text());
        bModified = true;
    }
    rSet->Put(std::move(pFormatURL));
    return bModified;
}

std::unique_ptr<SfxTabPage> SwFrameURLPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet)
{
    return std::make_unique<SwFrameURLPage>(pPage, pController, *rSet);
}

IMPL_LINK_NOARG(SwFrameURLPage, InsertFileHdl, weld::Button&, void)
{
    FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
                                FileDialogFlags::NONE, GetFrameWeld());
    uno::Reference < ui::dialogs::XFilePicker3 > xFP = aDlgHelper.GetFilePicker();

    try
    {
        const OUString sTemp(m_xURLED->get_text());
        if(!sTemp.isEmpty())
            xFP->setDisplayDirectory(sTemp);
    }
    catch( const uno::Exception& ) {}
    if( aDlgHelper.Execute() == ERRCODE_NONE )
    {
        m_xURLED->set_text(xFP->getSelectedFiles().getConstArray()[0]);
    }
}

SwFrameAddPage::SwFrameAddPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet)
    : SfxTabPage(pPage, pController, u"modules/swriter/ui/frmaddpage.ui"_ustr, u"FrameAddPage"_ustr, &rSet)
    , m_pWrtSh(nullptr)
    , m_bHtmlMode(false)
    , m_bFormat(false)
    , m_bNew(false)
    , m_xNameFrame(m_xBuilder->weld_widget(u"nameframe"_ustr))
    , m_xNameFT(m_xBuilder->weld_label(u"name_label"_ustr))
    , m_xNameED(m_xBuilder->weld_entry(u"name"_ustr))
    , m_xAltNameFT(m_xBuilder->weld_label(u"altname_label"_ustr))
    , m_xAltNameED(m_xBuilder->weld_entry(u"altname"_ustr))
    , m_xDescriptionFT(m_xBuilder->weld_label(u"description_label"_ustr))
    , m_xDescriptionED(m_xBuilder->weld_text_view(u"description"_ustr))
    , m_xDecorativeCB(m_xBuilder->weld_check_button(u"decorative"_ustr))
    , m_xSequenceFrame(m_xBuilder->weld_widget(u"frmSequence"_ustr))
    , m_xPrevLB(m_xBuilder->weld_combo_box(u"prev"_ustr))
    , m_xNextLB(m_xBuilder->weld_combo_box(u"next"_ustr))
    , m_xContentAlignFrame(m_xBuilder->weld_widget(u"contentalign"_ustr))
    , m_xVertAlignLB(m_xBuilder->weld_combo_box(u"vertalign"_ustr))
    , m_xPropertiesFrame(m_xBuilder->weld_widget(u"properties"_ustr))
    , m_xEditInReadonlyCB(m_xBuilder->weld_check_button(u"editinreadonly"_ustr))
    , m_xPrintFrameCB(m_xBuilder->weld_check_button(u"printframe"_ustr))
    , m_xTextFlowFT(m_xBuilder->weld_label(u"textflow_label"_ustr))
    , m_xTextFlowLB(new svx::FrameDirectionListBox(m_xBuilder->weld_combo_box(u"textflow"_ustr)))
{
    m_xTextFlowLB->append(SvxFrameDirection::Horizontal_LR_TB, SvxResId(RID_SVXSTR_FRAMEDIR_LTR));
    m_xTextFlowLB->append(SvxFrameDirection::Horizontal_RL_TB, SvxResId(RID_SVXSTR_FRAMEDIR_RTL));
    m_xTextFlowLB->append(SvxFrameDirection::Vertical_RL_TB, SvxResId(RID_SVXSTR_PAGEDIR_RTL_VERT));
    m_xTextFlowLB->append(SvxFrameDirection::Vertical_LR_TB, SvxResId(RID_SVXSTR_PAGEDIR_LTR_VERT));
    m_xTextFlowLB->append(SvxFrameDirection::Vertical_LR_BT, SvxResId(RID_SVXSTR_PAGEDIR_LTR_BTT_VERT));
    m_xTextFlowLB->append(SvxFrameDirection::Environment, SvxResId(RID_SVXSTR_FRAMEDIR_SUPER));
    m_xDescriptionED->set_size_request(-1, m_xDescriptionED->get_preferred_size().Height());

    m_xDecorativeCB->connect_toggled(LINK(this, SwFrameAddPage, DecorativeHdl));
}

SwFrameAddPage::~SwFrameAddPage()
{
    m_xTextFlowLB.reset();
}

std::unique_ptr<SfxTabPage> SwFrameAddPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet)
{
    return std::make_unique<SwFrameAddPage>(pPage, pController, *rSet);
}

void SwFrameAddPage::Reset(const SfxItemSet *rSet )
{
    sal_uInt16 nHtmlMode = ::GetHtmlMode(static_cast<const SwDocShell*>(SfxObjectShell::Current()));
    m_bHtmlMode = (nHtmlMode & HTMLMODE_ON) != 0;
    if (m_bHtmlMode)
    {
        m_xEditInReadonlyCB->hide();
        m_xPrintFrameCB->hide();
    }
    if (m_sDlgType == "PictureDialog" || m_sDlgType == "ObjectDialog")
    {
        m_xSequenceFrame->hide();
        m_xEditInReadonlyCB->hide();
        if (m_bHtmlMode)
        {
            m_xPropertiesFrame->hide();
        }
        m_xContentAlignFrame->hide();
    }

    if(const SfxStringItem* pNameItem = rSet->GetItemIfSet(FN_SET_FRM_ALT_NAME, false))
    {
        m_xAltNameED->set_text(pNameItem->GetValue());
        m_xAltNameED->save_value();
    }

    if(const SfxStringItem* pDescriptionItem = rSet->GetItemIfSet(FN_UNO_DESCRIPTION, false))
    {
        m_xDescriptionED->set_text(pDescriptionItem->GetValue());
        m_xDescriptionED->save_value();
    }

    if(!m_bFormat)
    {
        // insert graphic - properties
        // bNew is not set, so recognise by selection
        UIName aTmpName1;
        if(const SfxStringItem* pNameItem = rSet->GetItemIfSet(FN_SET_FRM_NAME, false))
        {
            aTmpName1 = UIName(pNameItem->GetValue());
        }

        OSL_ENSURE(m_pWrtSh, "no Shell?");
        if( m_bNew || aTmpName1.isEmpty() )
        {
            if (m_sDlgType == "PictureDialog")
                aTmpName1 = m_pWrtSh->GetUniqueGrfName();
            else if (m_sDlgType == "ObjectDialog")
                aTmpName1 = m_pWrtSh->GetUniqueOLEName();
            else
                aTmpName1 = m_pWrtSh->GetUniqueFrameName();

            m_pWrtSh->SetFlyName(aTmpName1);
        }

        m_xNameED->set_text( aTmpName1.toString() );
        m_xNameED->save_value();
    }
    else
    {
        m_xNameED->set_sensitive( false );
        m_xAltNameED->set_sensitive(false);
        m_xNameFT->set_sensitive( false );
        m_xAltNameFT->set_sensitive(false);
    }
    if (m_sDlgType == "FrameDialog" && m_xAltNameFT->get_visible())
    {
        m_xAltNameFT->hide();
        m_xAltNameED->hide();
    }
    else
    {
        m_xNameED->connect_changed(LINK(this, SwFrameAddPage, EditModifyHdl));
    }

    if (!m_bNew)
    {
        SwFrameFormat* pFormat = m_pWrtSh->GetFlyFrameFormat();

        if (pFormat)
        {
            const SwFormatChain &rChain = pFormat->GetChain();
            const SwFlyFrameFormat* pFlyFormat;
            UIName sNextChain, sPrevChain;
            pFlyFormat = rChain.GetPrev();
            if (pFlyFormat != nullptr)
            {
                sPrevChain = pFlyFormat->GetName();
            }

            pFlyFormat = rChain.GetNext();
            if (pFlyFormat != nullptr)
            {
                sNextChain = pFlyFormat->GetName();
            }
            //determine chainable frames
            std::vector< UIName > aPrevPageFrames;
            std::vector< UIName > aThisPageFrames;
            std::vector< UIName > aNextPageFrames;
            std::vector< UIName > aRemainFrames;
            m_pWrtSh->GetConnectableFrameFormats(*pFormat, sNextChain.toString(), false,
                            aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames );
            for (sal_Int32 nEntry = m_xPrevLB->get_count(); nEntry > 1; nEntry--)
                m_xPrevLB->remove(nEntry - 1);
            lcl_InsertVectors(*m_xPrevLB, aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames);
            if(!sPrevChain.isEmpty())
            {
                if (m_xPrevLB->find_text(sPrevChain.toString()) == -1)
                    m_xPrevLB->insert_text(1, sPrevChain.toString());
                m_xPrevLB->set_active_text(sPrevChain.toString());
            }
            else
                m_xPrevLB->set_active(0);
            aPrevPageFrames.clear();
            aNextPageFrames.clear();
            aThisPageFrames.clear();
            aRemainFrames.clear();

            m_pWrtSh->GetConnectableFrameFormats(*pFormat, sPrevChain.toString(), true,
                            aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames );
            for (sal_Int32 nEntry = m_xNextLB->get_count(); nEntry > 1; nEntry--)
                m_xNextLB->remove(nEntry - 1);
            lcl_InsertVectors(*m_xNextLB, aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames);
            if(!sNextChain.isEmpty())
            {
                if (m_xNextLB->find_text(sNextChain.toString()) == -1)
                    m_xNextLB->insert_text(1, sNextChain.toString());
                m_xNextLB->set_active_text(sNextChain.toString());
            }
            else
                m_xNextLB->set_active(0);
            Link<weld::ComboBox&,void> aLink(LINK(this, SwFrameAddPage, ChainModifyHdl));
            m_xPrevLB->connect_changed(aLink);
            m_xNextLB->connect_changed(aLink);
        }
    }

    const SwFormatEditInReadonly& rEdit = rSet->Get(RES_EDIT_IN_READONLY);
    m_xEditInReadonlyCB->set_active(rEdit.GetValue());
    m_xEditInReadonlyCB->save_state();

    // print
    const SvxPrintItem& rPrt = rSet->Get(RES_PRINT);
    m_xPrintFrameCB->set_active(rPrt.GetValue());
    m_xPrintFrameCB->save_state();

    SfxBoolItem const& rDecorative = rSet->Get(RES_DECORATIVE);
    m_xDecorativeCB->set_active(rDecorative.GetValue());
    m_xDecorativeCB->save_state();

    // textflow
    if( (!m_bHtmlMode || (0 != (nHtmlMode&HTMLMODE_SOME_STYLES)))
        && m_sDlgType != "PictureDialog" && m_sDlgType != "ObjectDialog"
        && SfxItemState::UNKNOWN != rSet->GetItemState( RES_FRAMEDIR ) )
    {
        m_xTextFlowFT->show();
        m_xTextFlowLB->show();

        //vertical text flow is not possible in HTML
        if(m_bHtmlMode)
        {
            m_xTextFlowLB->remove_id(SvxFrameDirection::Vertical_RL_TB);
        }
        SvxFrameDirection nVal = rSet->Get(RES_FRAMEDIR).GetValue();
        m_xTextFlowLB->set_active_id(nVal);
        m_xTextFlowLB->save_value();
    }
    else
    {
        m_xTextFlowFT->hide();
        m_xTextFlowLB->hide();
    }

    // Content alignment
    if ( rSet->GetItemState(RES_TEXT_VERT_ADJUST) > SfxItemState::DEFAULT )
    {
        SdrTextVertAdjust nAdjust = rSet->Get(RES_TEXT_VERT_ADJUST).GetValue();
        sal_Int32 nPos = 0;
        switch(nAdjust)
        {
            case SDRTEXTVERTADJUST_TOP:      nPos = 0;   break;
            case SDRTEXTVERTADJUST_CENTER:
            case SDRTEXTVERTADJUST_BLOCK:    nPos = 1;   break;
            case SDRTEXTVERTADJUST_BOTTOM:   nPos = 2;   break;
        }
        m_xVertAlignLB->set_active(nPos);
    }
    m_xVertAlignLB->save_value();

    DecorativeHdl(*m_xDecorativeCB);
}

bool SwFrameAddPage::FillItemSet(SfxItemSet *rSet)
{
    bool bRet = false;
    if (m_xNameED->get_value_changed_from_saved())
        bRet |= nullptr != rSet->Put(SfxStringItem(FN_SET_FRM_NAME, m_xNameED->get_text()));
    if (m_xAltNameED->get_value_changed_from_saved())
        bRet |= nullptr != rSet->Put(SfxStringItem(FN_SET_FRM_ALT_NAME, m_xAltNameED->get_text()));
    if (m_xDescriptionED->get_value_changed_from_saved())
        bRet |= nullptr != rSet->Put(SfxStringItem(FN_UNO_DESCRIPTION, m_xDescriptionED->get_text()));

    if ( m_xEditInReadonlyCB->get_state_changed_from_saved() )
        bRet |= nullptr != rSet->Put( SwFormatEditInReadonly( RES_EDIT_IN_READONLY, m_xEditInReadonlyCB->get_active()));

    if ( m_xPrintFrameCB->get_state_changed_from_saved() )
        bRet |= nullptr != rSet->Put( SvxPrintItem( RES_PRINT, m_xPrintFrameCB->get_active()));

    if (m_xDecorativeCB->get_state_changed_from_saved())
    {
        bRet |= nullptr != rSet->Put(SfxBoolItem(RES_DECORATIVE, m_xDecorativeCB->get_active()));
    }

    // textflow
    if (m_xTextFlowLB->get_visible() && m_xTextFlowLB->get_value_changed_from_saved())
    {
        SvxFrameDirection eDirection = m_xTextFlowLB->get_active_id();
        bRet |= nullptr != rSet->Put( SvxFrameDirectionItem(eDirection, RES_FRAMEDIR ));
    }
    if(m_pWrtSh)
    {
        const SwFrameFormat* pFormat = m_pWrtSh->GetFlyFrameFormat();
        if (pFormat)
        {
            OUString sCurrentPrevChain, sCurrentNextChain;
            if (m_xPrevLB->get_active())
                sCurrentPrevChain = m_xPrevLB->get_active_text();
            if (m_xNextLB->get_active())
                sCurrentNextChain = m_xNextLB->get_active_text();
            const SwFormatChain &rChain = pFormat->GetChain();
            const SwFlyFrameFormat* pFlyFormat;
            OUString sNextChain, sPrevChain;
            pFlyFormat = rChain.GetPrev();
            if (pFlyFormat != nullptr)
                sPrevChain = pFlyFormat->GetName().toString();

            pFlyFormat = rChain.GetNext();
            if (pFlyFormat != nullptr)
                sNextChain = pFlyFormat->GetName().toString();
            if(sPrevChain != sCurrentPrevChain)
                bRet |= nullptr != rSet->Put(SfxStringItem(FN_PARAM_CHAIN_PREVIOUS, sCurrentPrevChain));
            if(sNextChain != sCurrentNextChain)
                bRet |= nullptr != rSet->Put(SfxStringItem(FN_PARAM_CHAIN_NEXT, sCurrentNextChain));
        }
    }

    if (m_xVertAlignLB->get_value_changed_from_saved())
    {
        SdrTextVertAdjust nAdjust;
        switch (m_xVertAlignLB->get_active())
        {
            default:
            case 0 : nAdjust = SDRTEXTVERTADJUST_TOP; break;
            case 1 : nAdjust = SDRTEXTVERTADJUST_CENTER; break;
            case 2 : nAdjust = SDRTEXTVERTADJUST_BOTTOM; break;
        }
        bRet |= nullptr != rSet->Put(SdrTextVertAdjustItem(nAdjust, RES_TEXT_VERT_ADJUST));
    }

    return bRet;
}

IMPL_LINK_NOARG(SwFrameAddPage, EditModifyHdl, weld::Entry&, void)
{
    bool bEnable = !m_xNameED->get_text().isEmpty();
    m_xAltNameED->set_sensitive(bEnable);
    m_xAltNameFT->set_sensitive(bEnable);
}

IMPL_LINK_NOARG(SwFrameAddPage, DecorativeHdl, weld::Toggleable&, void)
{
    bool const bEnable(!m_xDecorativeCB->get_active());
    m_xAltNameED->set_sensitive(bEnable);
    m_xAltNameFT->set_sensitive(bEnable);
    m_xDescriptionED->set_sensitive(bEnable);
    m_xDescriptionFT->set_sensitive(bEnable);
}

void SwFrameAddPage::SetFormatUsed(bool bFormatUsed)
{
    m_bFormat = bFormatUsed;
    if (m_bFormat)
    {
        m_xNameFrame->hide();
    }
}

IMPL_LINK(SwFrameAddPage, ChainModifyHdl, weld::ComboBox&, rBox, void)
{
    OUString sCurrentPrevChain, sCurrentNextChain;
    if (m_xPrevLB->get_active())
        sCurrentPrevChain = m_xPrevLB->get_active_text();
    if (m_xNextLB->get_active())
        sCurrentNextChain = m_xNextLB->get_active_text();
    SwFrameFormat* pFormat = m_pWrtSh->GetFlyFrameFormat();
    if (!pFormat)
        return;

    bool bNextBox = m_xNextLB.get() == &rBox;
    weld::ComboBox& rChangeLB = bNextBox ? *m_xPrevLB : *m_xNextLB;
    for (sal_Int32 nEntry = rChangeLB.get_count(); nEntry > 1; nEntry--)
        rChangeLB.remove(nEntry - 1);
    //determine chainable frames
    std::vector< UIName > aPrevPageFrames;
    std::vector< UIName > aThisPageFrames;
    std::vector< UIName > aNextPageFrames;
    std::vector< UIName > aRemainFrames;
    m_pWrtSh->GetConnectableFrameFormats(*pFormat, bNextBox ? sCurrentNextChain : sCurrentPrevChain, !bNextBox,
                    aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames );
    lcl_InsertVectors(rChangeLB,
            aPrevPageFrames, aThisPageFrames, aNextPageFrames, aRemainFrames);
    const OUString sToSelect = bNextBox ? sCurrentPrevChain : sCurrentNextChain;
    if (rChangeLB.find_text(sToSelect) != -1)
        rChangeLB.set_active_text(sToSelect);
    else
        rChangeLB.set_active(0);

}

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