    /* -*- 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 <sal/config.h>

    #include <cstddef>
    #include <cstdlib>

    #include "SidebarWinAcc.hxx"
    #include <PostItMgr.hxx>
    #include <AnnotationWin.hxx>
    #include <basegfx/range/b2drange.hxx>
    #include "SidebarTxtControl.hxx"
    #include "SidebarScrollBar.hxx"
    #include "AnchorOverlayObject.hxx"
    #include "ShadowOverlayObject.hxx"
    #include "OverlayRanges.hxx"

    #include <strings.hrc>
    #include <app.hrc>

    #include <viewopt.hxx>
    #include <cmdid.h>

    #include <editeng/editobj.hxx>
    #include <editeng/fontitem.hxx>
    #include <editeng/fhgtitem.hxx>
    #include <editeng/langitem.hxx>
    #include <editeng/editview.hxx>
    #include <editeng/outliner.hxx>
    #include <editeng/editeng.hxx>
    #include <editeng/eeitem.hxx>
    #include <editeng/outlobj.hxx>

    #include <svl/zforlist.hxx>
    #include <svl/undo.hxx>
    #include <svl/stritem.hxx>

    #include <sfx2/viewfrm.hxx>
    #include <sfx2/bindings.hxx>
    #include <sfx2/dispatch.hxx>

    #include <vcl/scrbar.hxx>
    #include <vcl/svapp.hxx>
    #include <vcl/menubtn.hxx>
    #include <vcl/settings.hxx>

    #include <edtwin.hxx>
    #include <view.hxx>
    #include <docsh.hxx>
    #include <wrtsh.hxx>
    #include <doc.hxx>
    #include <swmodule.hxx>
    #include <langhelper.hxx>

    #include <txtannotationfld.hxx>
    #include <ndtxt.hxx>

    #include <sw_primitivetypes2d.hxx>
    #include <drawinglayer/processor2d/baseprocessor2d.hxx>
    #include <drawinglayer/primitive2d/primitivetools2d.hxx>
    #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
    #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
    #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
    #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
    #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
    #include <memory>
    #include <comphelper/lok.hxx>
    #include <IDocumentDrawModelAccess.hxx>
    #include <drawdoc.hxx>

    using namespace sw::sidebarwindows;

    namespace
    {

    /// Translate absolute <-> relative twips: LOK wants absolute coordinates as output and gives absolute coordinates as input.
    void lcl_translateTwips(vcl::Window const & rParent, vcl::Window& rChild, MouseEvent* pMouseEvent)
    {
        // Set map mode, so that callback payloads will contain absolute coordinates instead of relative ones.
        Point aOffset(rChild.GetOutOffXPixel() - rParent.GetOutOffXPixel(), rChild.GetOutOffYPixel() - rParent.GetOutOffYPixel());
        if (!rChild.IsMapModeEnabled())
        {
            MapMode aMapMode(rChild.GetMapMode());
            aMapMode.SetMapUnit(MapUnit::MapTwip);
            aMapMode.SetScaleX(rParent.GetMapMode().GetScaleX());
            aMapMode.SetScaleY(rParent.GetMapMode().GetScaleY());
            rChild.SetMapMode(aMapMode);
            rChild.EnableMapMode();
        }
        aOffset = rChild.PixelToLogic(aOffset);
        MapMode aMapMode(rChild.GetMapMode());
        aMapMode.SetOrigin(aOffset);
        aMapMode.SetMapUnit(rParent.GetMapMode().GetMapUnit());
        rChild.SetMapMode(aMapMode);
        rChild.EnableMapMode(false);

        if (pMouseEvent)
        {
            // Set event coordinates, so they contain relative coordinates instead of absolute ones.
            Point aPos = pMouseEvent->GetPosPixel();
            aPos.Move(-aOffset.getX(), -aOffset.getY());
            MouseEvent aMouseEvent(aPos, pMouseEvent->GetClicks(), pMouseEvent->GetMode(), pMouseEvent->GetButtons(), pMouseEvent->GetModifier());
            *pMouseEvent = aMouseEvent;
        }
    }

    /// Decide which one from the children of rParent should get rMouseEvent.
    vcl::Window* lcl_getHitWindow(sw::annotation::SwAnnotationWin& rParent, const MouseEvent& rMouseEvent)
    {
        vcl::Window* pRet = nullptr;

        rParent.EditWin().Push(PushFlags::MAPMODE);
        rParent.EditWin().EnableMapMode();
        for (sal_Int16 i = rParent.GetChildCount() - 1; i >= 0; --i)
        {
            vcl::Window* pChild = rParent.GetChild(i);

            Point aPosition(rParent.GetPosPixel());
            aPosition.Move(pChild->GetPosPixel().getX(), pChild->GetPosPixel().getY());
            Size aSize(rParent.GetSizePixel());
            tools::Rectangle aRectangleLogic(rParent.EditWin().PixelToLogic(aPosition), rParent.EditWin().PixelToLogic(aSize));
            if (aRectangleLogic.IsInside(rMouseEvent.GetPosPixel()))
            {
                pRet = pChild;
                break;
            }
        }
        rParent.EditWin().Pop();
        return pRet;
    }

    }

    namespace sw { namespace annotation {

    #define METABUTTON_WIDTH        16
    #define METABUTTON_HEIGHT       18
    #define METABUTTON_AREA_WIDTH   30
    #define POSTIT_META_HEIGHT  sal_Int32(30)
    #define POSTIT_MINIMUMSIZE_WITHOUT_META     50

    void SwAnnotationWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
    {
        Window::Paint(rRenderContext, rRect);

        if (mpMetadataAuthor->IsVisible())
        {
            //draw left over space
            if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
            {
                rRenderContext.SetFillColor(COL_BLACK);
            }
            else
            {
                rRenderContext.SetFillColor(mColorDark);
            }

            rRenderContext.SetLineColor();
            tools::Rectangle aRectangle(Point(mpMetadataAuthor->GetPosPixel().X() + mpMetadataAuthor->GetSizePixel().Width(),
                                       mpMetadataAuthor->GetPosPixel().Y()),
                                 Size(GetMetaButtonAreaWidth(),
                                      mpMetadataAuthor->GetSizePixel().Height() + mpMetadataDate->GetSizePixel().Height()));

            if (comphelper::LibreOfficeKit::isActive())
                aRectangle = rRect;
            else
                aRectangle = PixelToLogic(aRectangle);
            rRenderContext.DrawRect(aRectangle);
        }
    }

    void SwAnnotationWin::PaintTile(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
    {
        Paint(rRenderContext, rRect);

        for (sal_uInt16 i = 0; i < GetChildCount(); ++i)
        {
            vcl::Window* pChild = GetChild(i);

            // No point in showing this button till click on it are not handled.
            if (pChild == mpMenuButton.get())
                continue;

            if (!pChild->IsVisible())
                continue;

            rRenderContext.Push(PushFlags::MAPMODE);
            Point aOffset(PixelToLogic(pChild->GetPosPixel()));
            MapMode aMapMode(rRenderContext.GetMapMode());
            aMapMode.SetOrigin(aMapMode.GetOrigin() + aOffset);
            rRenderContext.SetMapMode(aMapMode);

            bool bPopChild = false;
            if (pChild->GetMapMode().GetMapUnit() != rRenderContext.GetMapMode().GetMapUnit())
            {
                // This is needed for the scrollbar that has its map unit in pixels.
                pChild->Push(PushFlags::MAPMODE);
                bPopChild = true;
                pChild->EnableMapMode();
                aMapMode = pChild->GetMapMode();
                aMapMode.SetMapUnit(rRenderContext.GetMapMode().GetMapUnit());
                aMapMode.SetScaleX(rRenderContext.GetMapMode().GetScaleX());
                aMapMode.SetScaleY(rRenderContext.GetMapMode().GetScaleY());
                pChild->SetMapMode(aMapMode);
            }

            pChild->Paint(rRenderContext, rRect);

            if (bPopChild)
                pChild->Pop();
            rRenderContext.Pop();
        }

        const drawinglayer::geometry::ViewInformation2D aViewInformation;
        std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext, aViewInformation));

        // drawinglayer sets the map mode to pixels, not needed here.
        rRenderContext.Pop();
        // Work in document-global twips.
        rRenderContext.Pop();
        if (mpAnchor)
            pProcessor->process(mpAnchor->getOverlayObjectPrimitive2DSequence());
        if (mpTextRangeOverlay)
            pProcessor->process(mpTextRangeOverlay->getOverlayObjectPrimitive2DSequence());

        rRenderContext.Push(PushFlags::NONE);
        pProcessor.reset();
        rRenderContext.Push(PushFlags::NONE);
    }

    bool SwAnnotationWin::IsHitWindow(const Point& rPointLogic)
    {
        tools::Rectangle aRectangleLogic(EditWin().PixelToLogic(GetPosPixel()), EditWin().PixelToLogic(GetSizePixel()));
        return aRectangleLogic.IsInside(rPointLogic);
    }

    void SwAnnotationWin::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool bClearMark)
    {
        mpSidebarTextControl->Push(PushFlags::MAPMODE);
        MouseEvent aMouseEvent(rPosition);
        lcl_translateTwips(EditWin(), *mpSidebarTextControl, &aMouseEvent);
        Point aPosition(aMouseEvent.GetPosPixel());

        EditView& rEditView = GetOutlinerView()->GetEditView();
        rEditView.SetCursorLogicPosition(aPosition, bPoint, bClearMark);

        mpSidebarTextControl->Pop();
    }

    void SwAnnotationWin::Draw(OutputDevice* pDev, const Point& rPt, const Size& rSz, DrawFlags nInFlags)
    {
        if (mpMetadataAuthor->IsVisible() )
        {
            pDev->SetFillColor(mColorDark);
            pDev->SetLineColor();
            pDev->DrawRect( tools::Rectangle( rPt, rSz ) );
        }

        if (mpMetadataAuthor->IsVisible())
        {
            vcl::Font aOrigFont(mpMetadataAuthor->GetControlFont());
            Size aSize(PixelToLogic(mpMetadataAuthor->GetSizePixel()));
            Point aPos(PixelToLogic(mpMetadataAuthor->GetPosPixel()));
            aPos += rPt;
            vcl::Font aFont( mpMetadataAuthor->GetSettings().GetStyleSettings().GetFieldFont() );
            mpMetadataAuthor->SetControlFont( aFont );
            mpMetadataAuthor->Draw(pDev, aPos, aSize, nInFlags);
            mpMetadataAuthor->SetControlFont( aOrigFont );
        }

        if (mpMetadataDate->IsVisible())
        {
            vcl::Font aOrigFont(mpMetadataDate->GetControlFont());
            Size aSize(PixelToLogic(mpMetadataDate->GetSizePixel()));
            Point aPos(PixelToLogic(mpMetadataDate->GetPosPixel()));
            aPos += rPt;
            vcl::Font aFont( mpMetadataDate->GetSettings().GetStyleSettings().GetFieldFont() );
            mpMetadataDate->SetControlFont( aFont );
            mpMetadataDate->Draw(pDev, aPos, aSize, nInFlags);
            mpMetadataDate->SetControlFont( aOrigFont );
        }

        mpSidebarTextControl->Draw(pDev, rPt, rSz, nInFlags);

        const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
        std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
            drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
                *pDev, aNewViewInfos ));

        if (mpAnchor)
            pProcessor->process(mpAnchor->getOverlayObjectPrimitive2DSequence());
        if (mpTextRangeOverlay)
            pProcessor->process(mpTextRangeOverlay->getOverlayObjectPrimitive2DSequence());
        pProcessor.reset();

        if (!mpVScrollbar->IsVisible())
            return;

        vcl::Font aOrigFont(mpMetadataDate->GetControlFont());
        Color aOrigBg( mpMetadataDate->GetControlBackground() );
        OUString sOrigText(mpMetadataDate->GetText());

        Size aSize(PixelToLogic(mpMenuButton->GetSizePixel()));
        Point aPos(PixelToLogic(mpMenuButton->GetPosPixel()));
        aPos += rPt;

        vcl::Font aFont( mpMetadataDate->GetSettings().GetStyleSettings().GetFieldFont() );
        mpMetadataDate->SetControlFont( aFont );
        mpMetadataDate->SetControlBackground( Color(0xFFFFFF) );
        mpMetadataDate->SetText("...");
        mpMetadataDate->Draw(pDev, aPos, aSize, nInFlags);

        mpMetadataDate->SetText(sOrigText);
        mpMetadataDate->SetControlFont( aOrigFont );
        mpMetadataDate->SetControlBackground( aOrigBg );

    }

    void SwAnnotationWin::KeyInput(const KeyEvent& rKeyEvent)
    {
        if (mpSidebarTextControl)
        {
            mpSidebarTextControl->Push(PushFlags::MAPMODE);
            lcl_translateTwips(EditWin(), *mpSidebarTextControl, nullptr);

            mpSidebarTextControl->KeyInput(rKeyEvent);

            mpSidebarTextControl->Pop();
        }
    }

    void SwAnnotationWin::MouseMove(const MouseEvent& rMouseEvent)
    {
        if (vcl::Window* pHit = lcl_getHitWindow(*this, rMouseEvent))
        {
            pHit->Push(PushFlags::MAPMODE);
            MouseEvent aMouseEvent(rMouseEvent);
            lcl_translateTwips(EditWin(), *pHit, &aMouseEvent);

            pHit->MouseMove(aMouseEvent);

            pHit->Pop();
        }
    }

    void SwAnnotationWin::MouseButtonDown(const MouseEvent& rMouseEvent)
    {
        if (vcl::Window* pHit = lcl_getHitWindow(*this, rMouseEvent))
        {
            pHit->Push(PushFlags::MAPMODE);
            MouseEvent aMouseEvent(rMouseEvent);
            lcl_translateTwips(EditWin(), *pHit, &aMouseEvent);

            pHit->MouseButtonDown(aMouseEvent);

            pHit->Pop();
        }
    }

    void SwAnnotationWin::MouseButtonUp(const MouseEvent& rMouseEvent)
    {
        if (vcl::Window* pHit = lcl_getHitWindow(*this, rMouseEvent))
        {
            pHit->Push(PushFlags::MAPMODE);
            MouseEvent aMouseEvent(rMouseEvent);
            lcl_translateTwips(EditWin(), *pHit, &aMouseEvent);

            pHit->MouseButtonUp(aMouseEvent);

            pHit->Pop();
        }
    }

    void SwAnnotationWin::SetPosSizePixelRect(long nX, long nY, long nWidth, long nHeight,
                                           const SwRect& aAnchorRect, const long aPageBorder)
    {
        mPosSize = tools::Rectangle(Point(nX,nY),Size(nWidth,nHeight));
        if (!mAnchorRect.IsEmpty() && mAnchorRect != aAnchorRect)
            mbAnchorRectChanged = true;
        mAnchorRect = aAnchorRect;
        mPageBorder = aPageBorder;
    }

    void SwAnnotationWin::SetSize( const Size& rNewSize )
    {
        mPosSize.SetSize(rNewSize);
    }

    void SwAnnotationWin::SetVirtualPosSize( const Point& aPoint, const Size& aSize)
    {
        mPosSize = tools::Rectangle(aPoint,aSize);
    }

    void SwAnnotationWin::TranslateTopPosition(const long aAmount)
    {
        mPosSize.Move(0,aAmount);
    }

    void SwAnnotationWin::ShowAnchorOnly(const Point &aPoint)
    {
        HideNote();
        SetPosAndSize();
        if (mpAnchor)
        {
            mpAnchor->SetSixthPosition(basegfx::B2DPoint(aPoint.X(),aPoint.Y()));
            mpAnchor->SetSeventhPosition(basegfx::B2DPoint(aPoint.X(),aPoint.Y()));
            mpAnchor->SetAnchorState(AnchorState::All);
            mpAnchor->setVisible(true);
        }
        if (mpShadow)
            mpShadow->setVisible(false);
    }

    SfxItemSet SwAnnotationWin::DefaultItem()
    {
        SfxItemSet aItem( mrView.GetDocShell()->GetPool() );
        aItem.Put(SvxFontHeightItem(200,100,EE_CHAR_FONTHEIGHT));
        return aItem;
    }

    void SwAnnotationWin::InitControls()
    {
        AddEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );

        // actual window which holds the user text
        mpSidebarTextControl = VclPtr<SidebarTextControl>::Create( *this,
                                                     WB_NODIALOGCONTROL,
                                                     mrView, mrMgr );
        mpSidebarTextControl->SetPointer(Pointer(PointerStyle::Text));

        // window controls for author and date
        mpMetadataAuthor = VclPtr<Edit>::Create( this, 0 );
        mpMetadataAuthor->SetAccessibleName( SwResId( STR_ACCESS_ANNOTATION_AUTHOR_NAME ) );
        mpMetadataAuthor->EnableRTL(AllSettings::GetLayoutRTL());
        mpMetadataAuthor->SetReadOnly();
        mpMetadataAuthor->AlwaysDisableInput(true);
        mpMetadataAuthor->SetCallHandlersOnInputDisabled(true);
        mpMetadataAuthor->AddEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
        // we should leave this setting alone, but for this we need a better layout algo
        // with variable meta size height
        {
            AllSettings aSettings = mpMetadataAuthor->GetSettings();
            StyleSettings aStyleSettings = aSettings.GetStyleSettings();
            vcl::Font aFont = aStyleSettings.GetFieldFont();
            aFont.SetFontHeight(8);
            aStyleSettings.SetFieldFont(aFont);
            aSettings.SetStyleSettings(aStyleSettings);
            mpMetadataAuthor->SetSettings(aSettings);
        }

        mpMetadataDate = VclPtr<Edit>::Create( this, 0 );
        mpMetadataDate->SetAccessibleName( SwResId( STR_ACCESS_ANNOTATION_DATE_NAME ) );
        mpMetadataDate->EnableRTL(AllSettings::GetLayoutRTL());
        mpMetadataDate->SetReadOnly();
        mpMetadataDate->AlwaysDisableInput(true);
        mpMetadataDate->SetCallHandlersOnInputDisabled(true);
        mpMetadataDate->AddEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
        // we should leave this setting alone, but for this we need a better layout algo
        // with variable meta size height
        {
            AllSettings aSettings = mpMetadataDate->GetSettings();
            StyleSettings aStyleSettings = aSettings.GetStyleSettings();
            vcl::Font aFont = aStyleSettings.GetFieldFont();
            aFont.SetFontHeight(8);
            aStyleSettings.SetFieldFont(aFont);
            aSettings.SetStyleSettings(aStyleSettings);
            mpMetadataDate->SetSettings(aSettings);
        }

        SwDocShell* aShell = mrView.GetDocShell();
        mpOutliner.reset(new Outliner(&aShell->GetPool(),OutlinerMode::TextObject));
        aShell->GetDoc()->SetCalcFieldValueHdl( mpOutliner.get() );
        mpOutliner->SetUpdateMode( true );
        Rescale();

        mpSidebarTextControl->EnableRTL( false );
        mpOutlinerView.reset(new OutlinerView ( mpOutliner.get(), mpSidebarTextControl ));
        mpOutlinerView->SetBackgroundColor(COL_TRANSPARENT);
        mpOutliner->InsertView(mpOutlinerView.get() );
        mpOutlinerView->SetOutputArea( PixelToLogic( tools::Rectangle(0,0,1,1) ) );

        mpOutlinerView->SetAttribs(DefaultItem());

        if (comphelper::LibreOfficeKit::isActive())
        {
            // If there is a callback already registered, inform the new outliner view about it.
            mpOutlinerView->RegisterViewShell(&mrView);
        }

        //create Scrollbars
        mpVScrollbar = VclPtr<SidebarScrollBar>::Create(*this, WB_3DLOOK |WB_VSCROLL|WB_DRAG, mrView);
        mpVScrollbar->EnableNativeWidget(false);
        mpVScrollbar->EnableRTL( false );
        mpVScrollbar->SetScrollHdl(LINK(this, SwAnnotationWin, ScrollHdl));
        mpVScrollbar->EnableDrag();
        mpVScrollbar->AddEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );

        const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
        EEControlBits nCntrl = mpOutliner->GetControlWord();
        // TODO: crash when AUTOCOMPLETE enabled
        nCntrl |= EEControlBits::MARKFIELDS | EEControlBits::PASTESPECIAL | EEControlBits::AUTOCORRECT | EEControlBits::USECHARATTRIBS; // | EEControlBits::AUTOCOMPLETE;
        if (SwViewOption::IsFieldShadings())
            nCntrl |= EEControlBits::MARKFIELDS;
        else
            nCntrl &= ~EEControlBits::MARKFIELDS;
        if (pVOpt->IsOnlineSpell())
            nCntrl |= EEControlBits::ONLINESPELLING;
        else
            nCntrl &= ~EEControlBits::ONLINESPELLING;
        mpOutliner->SetControlWord(nCntrl);

        std::size_t aIndex = SW_MOD()->InsertRedlineAuthor(GetAuthor());
        SetColor( SwPostItMgr::GetColorDark(aIndex),
                  SwPostItMgr::GetColorLight(aIndex),
                  SwPostItMgr::GetColorAnchor(aIndex));

        CheckMetaText();

        mpMenuButton = CreateMenuButton();

        SetLanguage(GetLanguage());
        GetOutlinerView()->StartSpeller();
        SetPostItText();
        mpOutliner->CompleteOnlineSpelling();

        mpSidebarTextControl->Show();
        mpMetadataAuthor->Show();
        mpMetadataDate->Show();
        mpVScrollbar->Show();
    }

    void SwAnnotationWin::CheckMetaText()
    {
        const SvtSysLocale aSysLocale;
        const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
        OUString sMeta = GetAuthor();
        if (sMeta.isEmpty())
        {
            sMeta = SwResId(STR_NOAUTHOR);
        }
        else if (sMeta.getLength() > 23)
        {
            sMeta = sMeta.copy(0, 20) + "...";
        }
        if ( mpMetadataAuthor->GetText() != sMeta )
        {
            mpMetadataAuthor->SetText(sMeta);
        }

        Date aDate = GetDate();
        if (aDate.IsValidAndGregorian() )
        {
            sMeta = rLocalData.getDate(aDate);
        }
        else
        {
            sMeta = SwResId(STR_NODATE);
        }
        if (GetTime().GetTime()!=0)
        {
            sMeta += " " + rLocalData.getTime( GetTime(),false );
        }
        if ( mpMetadataDate->GetText() != sMeta )
        {
            mpMetadataDate->SetText(sMeta);
        }
    }

    void SwAnnotationWin::Rescale()
    {
        MapMode aMode = GetParent()->GetMapMode();
        aMode.SetOrigin( Point() );
        mpOutliner->SetRefMapMode( aMode );
        SetMapMode( aMode );
        mpSidebarTextControl->SetMapMode( aMode );
        const Fraction& rFraction = mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY();
        if ( mpMetadataAuthor )
        {
            vcl::Font aFont( mpMetadataAuthor->GetSettings().GetStyleSettings().GetFieldFont() );
            sal_Int32 nHeight = long(aFont.GetFontHeight() * rFraction);
            aFont.SetFontHeight( nHeight );
            mpMetadataAuthor->SetControlFont( aFont );
        }
        if ( mpMetadataDate )
        {
            vcl::Font aFont( mpMetadataDate->GetSettings().GetStyleSettings().GetFieldFont() );
            sal_Int32 nHeight = long(aFont.GetFontHeight() * rFraction);
            aFont.SetFontHeight( nHeight );
            mpMetadataDate->SetControlFont( aFont );
        }
    }

    void SwAnnotationWin::SetPosAndSize()
    {
        bool bChange = false;

        if (GetSizePixel() != mPosSize.GetSize())
        {
            bChange = true;
            SetSizePixel(mPosSize.GetSize());

            if (comphelper::LibreOfficeKit::isActive())
            {
                // Position is not yet set at VCL level, but the map mode should
                // contain the right origin to emit the correct cursor position.
                mpSidebarTextControl->Push(PushFlags::MAPMODE);
                Point aOffset(mPosSize.Left(), mPosSize.Top());
                aOffset = PixelToLogic(aOffset);
                MapMode aMapMode(mpSidebarTextControl->GetMapMode());
                aMapMode.SetOrigin(aOffset);
                mpSidebarTextControl->SetMapMode(aMapMode);
                mpSidebarTextControl->EnableMapMode(false);
            }

            DoResize();

            if (comphelper::LibreOfficeKit::isActive())
                mpSidebarTextControl->Pop();
        }

        if (GetPosPixel().X() != mPosSize.TopLeft().X() || (std::abs(GetPosPixel().Y() - mPosSize.TopLeft().Y()) > 5) )
        {
            bChange = true;
            SetPosPixel(mPosSize.TopLeft());

            Point aLineStart;
            Point aLineEnd ;
            switch ( meSidebarPosition )
            {
                case sw::sidebarwindows::SidebarPosition::LEFT:
                {
                    aLineStart = EditWin().PixelToLogic( Point(GetPosPixel().X()+GetSizePixel().Width(),GetPosPixel().Y()-1) );
                    aLineEnd = EditWin().PixelToLogic( Point(GetPosPixel().X(),GetPosPixel().Y()-1) );
                }
                break;
                case sw::sidebarwindows::SidebarPosition::RIGHT:
                {
                    aLineStart = EditWin().PixelToLogic( Point(GetPosPixel().X(),GetPosPixel().Y()-1) );
                    aLineEnd = EditWin().PixelToLogic( Point(GetPosPixel().X()+GetSizePixel().Width(),GetPosPixel().Y()-1) );
                }
                break;
                default:
                    OSL_FAIL( "<SwAnnotationWin::SetPosAndSize()> - unexpected position of sidebar" );
                break;
            }

            // LOK has map mode disabled, and we still want to perform pixel ->
            // twips conversion for the size of the line above the note.
            if (comphelper::LibreOfficeKit::isActive() && !EditWin().IsMapModeEnabled())
            {
                EditWin().EnableMapMode();
                Size aSize(aLineEnd.getX() - aLineStart.getX(), aLineEnd.getY() - aLineStart.getY());
                aSize = EditWin().PixelToLogic(aSize);
                aLineEnd = aLineStart;
                aLineEnd.Move(aSize.getWidth(), aSize.getHeight());
                EditWin().EnableMapMode(false);
            }

            if (mpAnchor)
            {
                mpAnchor->SetAllPosition( basegfx::B2DPoint( mAnchorRect.Left() , mAnchorRect.Bottom() - 5* 15),
                                          basegfx::B2DPoint( mAnchorRect.Left()-5*15 , mAnchorRect.Bottom()+5*15),
                                          basegfx::B2DPoint( mAnchorRect.Left()+5*15 , mAnchorRect.Bottom()+5*15),
                                          basegfx::B2DPoint( mAnchorRect.Left(), mAnchorRect.Bottom()+2*15),
                                          basegfx::B2DPoint( mPageBorder ,mAnchorRect.Bottom()+2*15),
                                          basegfx::B2DPoint( aLineStart.X(),aLineStart.Y()),
                                          basegfx::B2DPoint( aLineEnd.X(),aLineEnd.Y()));
            }
            else
            {
                mpAnchor = AnchorOverlayObject::CreateAnchorOverlayObject( mrView,
                                                                           mAnchorRect,
                                                                           mPageBorder,
                                                                           aLineStart,
                                                                           aLineEnd,
                                                                           mColorAnchor );
                if ( mpAnchor )
                {
                    mpAnchor->setVisible(true);
                    mpAnchor->SetAnchorState(AnchorState::Tri);
                    if (HasChildPathFocus())
                    {
                        mpAnchor->setLineSolid(true);
                    }
                }
            }
        }
        else
        {
            if ( mpAnchor &&
                 ( mpAnchor->getBasePosition() != basegfx::B2DPoint( mAnchorRect.Left() , mAnchorRect.Bottom()-5*15) ) )
            {
                mpAnchor->SetTriPosition( basegfx::B2DPoint( mAnchorRect.Left() , mAnchorRect.Bottom() - 5* 15),
                                          basegfx::B2DPoint( mAnchorRect.Left()-5*15 , mAnchorRect.Bottom()+5*15),
                                          basegfx::B2DPoint( mAnchorRect.Left()+5*15 , mAnchorRect.Bottom()+5*15),
                                          basegfx::B2DPoint( mAnchorRect.Left(), mAnchorRect.Bottom()+2*15),
                                          basegfx::B2DPoint( mPageBorder , mAnchorRect.Bottom()+2*15));
            }
        }

        if (bChange)
        {
            Point aStart = EditWin().PixelToLogic(GetPosPixel()+Point(0,GetSizePixel().Height()));
            Point aEnd = EditWin().PixelToLogic(GetPosPixel()+Point(GetSizePixel().Width()-1,GetSizePixel().Height()));
            mpShadow->SetPosition(basegfx::B2DPoint(aStart.X(),aStart.Y()), basegfx::B2DPoint(aEnd.X(),aEnd.Y()));
        }

        if (mrMgr.ShowNotes())
        {
            if (IsFollow() && !HasChildPathFocus())
            {
                // #i111964#
                if ( mpAnchor )
                {
                    mpAnchor->SetAnchorState(AnchorState::End);
                }
            }
            else
            {
                // #i111964#
                if ( mpAnchor )
                {
                    mpAnchor->SetAnchorState(AnchorState::All);
                }
                SwAnnotationWin* pWin = GetTopReplyNote();
                // #i111964#
                if ( pWin && pWin->Anchor() )
                {
                    pWin->Anchor()->SetAnchorState(AnchorState::End);
                }
            }
        }

        // text range overlay
        maAnnotationTextRanges.clear();
        if ( mrSidebarItem.maLayoutInfo.mnStartNodeIdx != 0
             && mrSidebarItem.maLayoutInfo.mnStartContent != -1 )
        {
            const SwTextAnnotationField* pTextAnnotationField =
                dynamic_cast< const SwTextAnnotationField* >( mrSidebarItem.GetFormatField().GetTextField() );
            SwTextNode* pTextNode = pTextAnnotationField ? pTextAnnotationField->GetpTextNode() : nullptr;
            SwContentNode* pContentNd = nullptr;
            if (pTextNode)
            {
                SwNodes& rNds = pTextNode->GetDoc()->GetNodes();
                pContentNd = rNds[mrSidebarItem.maLayoutInfo.mnStartNodeIdx]->GetContentNode();
            }
            if (pContentNd)
            {
                SwPosition aStartPos( *pContentNd, mrSidebarItem.maLayoutInfo.mnStartContent );
                SwShellCursor* pTmpCursor = nullptr;
                const bool bTableCursorNeeded = pTextNode->FindTableBoxStartNode() != pContentNd->FindTableBoxStartNode();
                if ( bTableCursorNeeded )
                {
                    SwShellTableCursor* pTableCursor = new SwShellTableCursor( mrView.GetWrtShell(), aStartPos );
                    pTableCursor->SetMark();
                    pTableCursor->GetMark()->nNode = *pTextNode;
                    pTableCursor->GetMark()->nContent.Assign( pTextNode, pTextAnnotationField->GetStart()+1 );
                    pTableCursor->NewTableSelection();
                    pTmpCursor = pTableCursor;
                }
                else
                {
                    SwShellCursor* pCursor = new SwShellCursor( mrView.GetWrtShell(), aStartPos );
                    pCursor->SetMark();
                    pCursor->GetMark()->nNode = *pTextNode;
                    pCursor->GetMark()->nContent.Assign( pTextNode, pTextAnnotationField->GetStart()+1 );
                    pTmpCursor = pCursor;
                }
                std::unique_ptr<SwShellCursor> pTmpCursorForAnnotationTextRange( pTmpCursor );

                // For annotation text range rectangles to be calculated correctly,
                // we need the map mode disabled
                bool bDisableMapMode = comphelper::LibreOfficeKit::isActive() && EditWin().IsMapModeEnabled();
                if (bDisableMapMode)
                    EditWin().EnableMapMode(false);

                pTmpCursorForAnnotationTextRange->FillRects();

                if (bDisableMapMode)
                    EditWin().EnableMapMode();

                SwRects* pRects(pTmpCursorForAnnotationTextRange.get());
                for(SwRect & rNextRect : *pRects)
                {
                    const tools::Rectangle aPntRect(rNextRect.SVRect());
                    maAnnotationTextRanges.emplace_back(
                        aPntRect.Left(), aPntRect.Top(),
                        aPntRect.Right() + 1, aPntRect.Bottom() + 1);
                }
            }
        }

        if (mrMgr.ShowNotes() && !maAnnotationTextRanges.empty())
        {
            if ( mpTextRangeOverlay != nullptr )
            {
                mpTextRangeOverlay->setRanges( maAnnotationTextRanges );
                if ( mpAnchor != nullptr && mpAnchor->getLineSolid() )
                {
                    mpTextRangeOverlay->ShowSolidBorder();
                }
                else
                {
                    mpTextRangeOverlay->HideSolidBorder();
                }
            }
            else if (!IsFollow())
            {
                // This window is not a reply, then draw its range overlay.
                mpTextRangeOverlay =
                    sw::overlay::OverlayRanges::CreateOverlayRange(
                        mrView,
                        mColorAnchor,
                        maAnnotationTextRanges,
                        mpAnchor && mpAnchor->getLineSolid() );
            }
        }
        else
        {
            mpTextRangeOverlay.reset();
        }
    }

    void SwAnnotationWin::DoResize()
    {
        long aTextHeight    =  LogicToPixel( mpOutliner->CalcTextSize()).Height();
        long aHeight        =  GetSizePixel().Height();
        unsigned long aWidth    =  GetSizePixel().Width();

        aHeight -= GetMetaHeight();
        mpMetadataAuthor->Show();
        mpMetadataDate->Show();
        mpSidebarTextControl->SetQuickHelpText(OUString());

        if (aTextHeight > aHeight)
        {   // we need vertical scrollbars and have to reduce the width
            aWidth -= GetScrollbarWidth();
            mpVScrollbar->Show();
        }
        else
        {
            mpVScrollbar->Hide();
        }

        {
            const Size aSizeOfMetadataControls( GetSizePixel().Width() - GetMetaButtonAreaWidth(),
                                                GetMetaHeight()/2 );
            mpMetadataAuthor->setPosSizePixel( 0,
                                               aHeight,
                                               aSizeOfMetadataControls.Width(),
                                               aSizeOfMetadataControls.Height() );
            mpMetadataDate->setPosSizePixel( 0,
                                             aHeight + aSizeOfMetadataControls.Height(),
                                             aSizeOfMetadataControls.Width(),
                                             aSizeOfMetadataControls.Height() );
        }

        mpOutliner->SetPaperSize( PixelToLogic( Size(aWidth,aHeight) ) ) ;
        if (!mpVScrollbar->IsVisible())
        {   // if we do not have a scrollbar anymore, we want to see the complete text
            mpOutlinerView->SetVisArea( PixelToLogic( tools::Rectangle(0,0,aWidth,aHeight) ) );
        }
        mpOutlinerView->SetOutputArea( PixelToLogic( tools::Rectangle(0,0,aWidth,aHeight) ) );

        if (!AllSettings::GetLayoutRTL())
        {
            mpSidebarTextControl->setPosSizePixel(0, 0, aWidth, aHeight);
            mpVScrollbar->setPosSizePixel( aWidth, 0, GetScrollbarWidth(), aHeight);
        }
        else
        {
            mpSidebarTextControl->setPosSizePixel( ( aTextHeight > aHeight ? GetScrollbarWidth() : 0 ), 0,
                                          aWidth, aHeight);
            mpVScrollbar->setPosSizePixel( 0, 0, GetScrollbarWidth(), aHeight);
        }

        mpVScrollbar->SetVisibleSize( PixelToLogic(Size(0,aHeight)).Height() );
        mpVScrollbar->SetPageSize( PixelToLogic(Size(0,aHeight)).Height() * 8 / 10 );
        mpVScrollbar->SetLineSize( mpOutliner->GetTextHeight() / 10 );
        SetScrollbar();
        mpVScrollbar->SetRange( Range(0, mpOutliner->GetTextHeight()));

        //calculate rects for meta- button
        const Fraction& fx( GetMapMode().GetScaleX() );
        const Fraction& fy( GetMapMode().GetScaleY() );

        const Point aPos( mpMetadataAuthor->GetPosPixel());
        mpMenuButton->setPosSizePixel( long(aPos.X()+GetSizePixel().Width()-(METABUTTON_WIDTH+10)*fx),
                                       long(aPos.Y()+5*fy),
                                       long(METABUTTON_WIDTH*fx),
                                       long(METABUTTON_HEIGHT*fy) );
    }

    void SwAnnotationWin::SetSizePixel( const Size& rNewSize )
    {
        Window::SetSizePixel(rNewSize);

        if (mpShadow)
        {
            Point aStart = EditWin().PixelToLogic(GetPosPixel()+Point(0,GetSizePixel().Height()));
            Point aEnd = EditWin().PixelToLogic(GetPosPixel()+Point(GetSizePixel().Width()-1,GetSizePixel().Height()));
            mpShadow->SetPosition(basegfx::B2DPoint(aStart.X(),aStart.Y()), basegfx::B2DPoint(aEnd.X(),aEnd.Y()));
        }
    }

    void SwAnnotationWin::SetScrollbar()
    {
        mpVScrollbar->SetThumbPos(mpOutlinerView->GetVisArea().Top());
    }

    void SwAnnotationWin::ResizeIfNecessary(long aOldHeight, long aNewHeight)
    {
        if (aOldHeight != aNewHeight)
        {
            //check for lower border or next note
            long aBorder = mrMgr.GetNextBorder();
            if (aBorder != -1)
            {
                if (aNewHeight > GetMinimumSizeWithoutMeta())
                {
                    long aNewLowerValue = GetPosPixel().Y() + aNewHeight + GetMetaHeight();
                    if (aNewLowerValue < aBorder)
                        SetSizePixel(Size(GetSizePixel().Width(),aNewHeight+GetMetaHeight()));
                    else
                        SetSizePixel(Size(GetSizePixel().Width(),aBorder - GetPosPixel().Y()));
                    DoResize();
                    Invalidate();
                }
                else
                {
                    if (GetSizePixel().Height() != GetMinimumSizeWithoutMeta() + GetMetaHeight())
                        SetSizePixel(Size(GetSizePixel().Width(),GetMinimumSizeWithoutMeta() + GetMetaHeight()));
                    DoResize();
                    Invalidate();
                }
            }
            else
            {
                DoResize();
                Invalidate();
            }
        }
        else
        {
            SetScrollbar();
        }
    }

    void SwAnnotationWin::SetColor(Color aColorDark,Color aColorLight, Color aColorAnchor)
    {
        mColorDark =  aColorDark;
        mColorLight = aColorLight;
        mColorAnchor = aColorAnchor;

        if ( !Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
        {
            {
                mpMetadataAuthor->SetControlBackground(mColorDark);
                AllSettings aSettings = mpMetadataAuthor->GetSettings();
                StyleSettings aStyleSettings = aSettings.GetStyleSettings();
                aStyleSettings.SetFieldTextColor(aColorAnchor);
                aSettings.SetStyleSettings(aStyleSettings);
                mpMetadataAuthor->SetSettings(aSettings);
            }

            {
                mpMetadataDate->SetControlBackground(mColorDark);
                AllSettings aSettings = mpMetadataDate->GetSettings();
                StyleSettings aStyleSettings = aSettings.GetStyleSettings();
                aStyleSettings.SetFieldTextColor(aColorAnchor);
                aSettings.SetStyleSettings(aStyleSettings);
                mpMetadataDate->SetSettings(aSettings);
            }

            AllSettings aSettings2 = mpVScrollbar->GetSettings();
            StyleSettings aStyleSettings2 = aSettings2.GetStyleSettings();
            aStyleSettings2.SetButtonTextColor(Color(0,0,0));
            aStyleSettings2.SetCheckedColor(mColorLight); // background
            aStyleSettings2.SetShadowColor(mColorAnchor);
            aStyleSettings2.SetFaceColor(mColorDark);
            aSettings2.SetStyleSettings(aStyleSettings2);
            mpVScrollbar->SetSettings(aSettings2);
        }
    }

    void SwAnnotationWin::SetSidebarPosition(sw::sidebarwindows::SidebarPosition eSidebarPosition)
    {
        meSidebarPosition = eSidebarPosition;
    }

    void SwAnnotationWin::SetReadonly(bool bSet)
    {
        mbReadonly = bSet;
        GetOutlinerView()->SetReadOnly(bSet);
    }

    void SwAnnotationWin::SetLanguage(const SvxLanguageItem& rNewItem)
    {
        Link<LinkParamNone*,void> aLink = mpOutliner->GetModifyHdl();
        mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
        ESelection aOld = GetOutlinerView()->GetSelection();

        ESelection aNewSelection( 0, 0, mpOutliner->GetParagraphCount()-1, EE_TEXTPOS_ALL );
        GetOutlinerView()->SetSelection( aNewSelection );
        SfxItemSet aEditAttr(GetOutlinerView()->GetAttribs());
        aEditAttr.Put(rNewItem);
        GetOutlinerView()->SetAttribs( aEditAttr );

        GetOutlinerView()->SetSelection(aOld);
        mpOutliner->SetModifyHdl( aLink );

        const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
        EEControlBits nCntrl = mpOutliner->GetControlWord();
        // turn off
        nCntrl &= ~EEControlBits::ONLINESPELLING;
        mpOutliner->SetControlWord(nCntrl);

        //turn back on
        if (pVOpt->IsOnlineSpell())
            nCntrl |= EEControlBits::ONLINESPELLING;
        else
            nCntrl &= ~EEControlBits::ONLINESPELLING;
        mpOutliner->SetControlWord(nCntrl);

        mpOutliner->CompleteOnlineSpelling();
        Invalidate();
    }

    void SwAnnotationWin::GetFocus()
    {
        if (mpSidebarTextControl)
            mpSidebarTextControl->GrabFocus();
    }

    void SwAnnotationWin::LoseFocus()
    {
    }

    void SwAnnotationWin::ShowNote()
    {
        SetPosAndSize();
        if (!IsVisible())
            Window::Show();
        if (mpShadow && !mpShadow->isVisible())
            mpShadow->setVisible(true);
        if (mpAnchor && !mpAnchor->isVisible())
            mpAnchor->setVisible(true);

        // Invalidate.
        InvalidateControl();
    }

    void SwAnnotationWin::HideNote()
    {
        if (IsVisible())
            Window::Hide();
        if (mpAnchor)
        {
            if (mrMgr.IsShowAnchor())
                mpAnchor->SetAnchorState(AnchorState::Tri);
            else
                mpAnchor->setVisible(false);
        }
        if (mpShadow && mpShadow->isVisible())
            mpShadow->setVisible(false);
    }

    void SwAnnotationWin::InvalidateControl()
    {
        // Invalidate.
        mpSidebarTextControl->Push(PushFlags::MAPMODE);
        lcl_translateTwips(EditWin(), *mpSidebarTextControl, nullptr);
        mpSidebarTextControl->Invalidate();
        mpSidebarTextControl->Pop();
    }

    void SwAnnotationWin::ActivatePostIt()
    {
        mrMgr.AssureStdModeAtShell();

        mpOutliner->ClearModifyFlag();
        mpOutliner->GetUndoManager().Clear();

        CheckMetaText();
        SetViewState(ViewState::EDIT);
        GetOutlinerView()->ShowCursor();

        mpOutlinerView->GetEditView().SetInsertMode(mrView.GetWrtShellPtr()->IsInsMode());

        if ( !Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
            GetOutlinerView()->SetBackgroundColor(mColorDark);

        //tdf#119130 only have the active postit as a dialog control in which pressing
        //ctrl+tab cycles between text and button so we don't waste time searching
        //thousands of SwAnnotationWins
        SetStyle(GetStyle() | WB_DIALOGCONTROL);
    }

    void SwAnnotationWin::DeactivatePostIt()
    {
        //tdf#119130 only have the active postit as a dialog control in which pressing
        //ctrl+tab cycles between text and button so we don't waste time searching
        //thousands of SwAnnotationWins
        SetStyle(GetStyle() & ~WB_DIALOGCONTROL);

        // remove selection, #i87073#
        if (GetOutlinerView()->GetEditView().HasSelection())
        {
            ESelection aSelection = GetOutlinerView()->GetEditView().GetSelection();
            aSelection.nEndPara = aSelection.nStartPara;
            aSelection.nEndPos = aSelection.nStartPos;
            GetOutlinerView()->GetEditView().SetSelection(aSelection);
        }

        mpOutliner->CompleteOnlineSpelling();

        SetViewState(ViewState::NORMAL);
        // Make sure this view doesn't emit LOK callbacks during the update, as the
        // sidebar window's SidebarTextControl doesn't have a valid twip offset
        // (map mode origin) during that operation.
        bool bTiledPainting = comphelper::LibreOfficeKit::isTiledPainting();
        comphelper::LibreOfficeKit::setTiledPainting(true);
        // write the visible text back into the SwField
        UpdateData();
        comphelper::LibreOfficeKit::setTiledPainting(bTiledPainting);

        if ( !Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
            GetOutlinerView()->SetBackgroundColor(COL_TRANSPARENT);

        if ( !IsProtected() && mpOutliner->GetEditEngine().GetText().isEmpty() )
        {
            mnEventId = Application::PostUserEvent( LINK( this, SwAnnotationWin, DeleteHdl), nullptr, true );
        }
    }

    void SwAnnotationWin::ToggleInsMode()
    {
        if (!mrView.GetWrtShell().IsRedlineOn())
        {
            //change outliner
            mpOutlinerView->GetEditView().SetInsertMode(!mpOutlinerView->GetEditView().IsInsertMode());
            //change document
            mrView.GetWrtShell().ToggleInsMode();
            //update statusbar
            SfxBindings &rBnd = mrView.GetViewFrame()->GetBindings();
            rBnd.Invalidate(SID_ATTR_INSERT);
            rBnd.Update(SID_ATTR_INSERT);
        }
    }

    void SwAnnotationWin::ExecuteCommand(sal_uInt16 nSlot)
    {
        mrMgr.AssureStdModeAtShell();

        switch (nSlot)
        {
            case FN_POSTIT:
            case FN_REPLY:
            {
                // if this note is empty, it will be deleted once losing the focus, so no reply, but only a new note
                // will be created
                if (!mpOutliner->GetEditEngine().GetText().isEmpty())
                {
                    OutlinerParaObject* pPara = new OutlinerParaObject(*GetOutlinerView()->GetEditView().CreateTextObject());
                    mrMgr.RegisterAnswer(pPara);
                }
                if (mrMgr.HasActiveSidebarWin())
                    mrMgr.SetActiveSidebarWin(nullptr);
                SwitchToFieldPos();
                mrView.GetViewFrame()->GetDispatcher()->Execute(FN_POSTIT);
                break;
            }
            case FN_DELETE_COMMENT:

                //Delete(); // do not kill the parent of our open popup menu
                mnEventId = Application::PostUserEvent( LINK( this, SwAnnotationWin, DeleteHdl), nullptr, true );
                break;
            case FN_FORMAT_ALL_NOTES:
            case FN_DELETE_ALL_NOTES:
            case FN_HIDE_ALL_NOTES:
                // not possible as slot as this would require that "this" is the active postit
                mrView.GetViewFrame()->GetBindings().Execute( nSlot, nullptr, SfxCallMode::ASYNCHRON );
                break;
            case FN_DELETE_NOTE_AUTHOR:
            case FN_HIDE_NOTE_AUTHOR:
            {
                // not possible as slot as this would require that "this" is the active postit
                SfxStringItem aItem( nSlot, GetAuthor() );
                const SfxPoolItem* aItems[2];
                aItems[0] = &aItem;
                aItems[1] = nullptr;
                mrView.GetViewFrame()->GetBindings().Execute( nSlot, aItems, SfxCallMode::ASYNCHRON );
            }
                break;
            default:
                mrView.GetViewFrame()->GetBindings().Execute( nSlot );
                break;
        }
    }

    SwEditWin&  SwAnnotationWin::EditWin()
    {
        return mrView.GetEditWin();
    }

    long SwAnnotationWin::GetPostItTextHeight()
    {
        return mpOutliner ? LogicToPixel(mpOutliner->CalcTextSize()).Height() : 0;
    }

    void SwAnnotationWin::SwitchToPostIt(sal_uInt16 aDirection)
    {
        SwAnnotationWin* pPostIt = mrMgr.GetNextPostIt(aDirection, this);
        if (pPostIt)
            pPostIt->GrabFocus();
    }

    IMPL_LINK( SwAnnotationWin, WindowEventListener, VclWindowEvent&, rEvent, void )
    {
        if ( rEvent.GetId() == VclEventId::WindowMouseMove )
        {
            MouseEvent* pMouseEvt = static_cast<MouseEvent*>(rEvent.GetData());
            if ( pMouseEvt->IsEnterWindow() )
            {
                mbMouseOver = true;
                if ( !HasFocus() )
                {
                    SetViewState(ViewState::VIEW);
                    Invalidate();
                }
            }
            else if ( pMouseEvt->IsLeaveWindow())
            {
                mbMouseOver = false;
                if ( !HasFocus() )
                {
                    SetViewState(ViewState::NORMAL);
                    Invalidate();
                }
            }
        }
        else if ( rEvent.GetId() == VclEventId::WindowActivate &&
                  rEvent.GetWindow() == mpSidebarTextControl )
        {
            const bool bLockView = mrView.GetWrtShell().IsViewLocked();
            mrView.GetWrtShell().LockView( true );
            mrMgr.SetActiveSidebarWin( this );
            mrView.GetWrtShell().LockView( bLockView );
            mrMgr.MakeVisible( this );
        }
    }

    IMPL_LINK(SwAnnotationWin, ScrollHdl, ScrollBar*, pScroll, void)
    {
        long nDiff = GetOutlinerView()->GetEditView().GetVisArea().Top() - pScroll->GetThumbPos();
        GetOutlinerView()->Scroll( 0, nDiff );
    }

    IMPL_LINK_NOARG(SwAnnotationWin, ModifyHdl, LinkParamNone*, void)
    {
        mrView.GetDocShell()->SetModified();
    }

    IMPL_LINK_NOARG(SwAnnotationWin, DeleteHdl, void*, void)
    {
        mnEventId = nullptr;
        Delete();
    }

    void SwAnnotationWin::ResetAttributes()
    {
        mpOutlinerView->RemoveAttribsKeepLanguages(true);
        mpOutliner->RemoveFields();
        mpOutlinerView->SetAttribs(DefaultItem());
    }

    sal_Int32 SwAnnotationWin::GetScrollbarWidth()
    {
        return mrView.GetWrtShell().GetViewOptions()->GetZoom() / 10;
    }

    sal_Int32 SwAnnotationWin::GetMetaButtonAreaWidth()
    {
        const Fraction& f( GetMapMode().GetScaleX() );
        return long(METABUTTON_AREA_WIDTH * f);
    }

    sal_Int32 SwAnnotationWin::GetMetaHeight()
    {
        const Fraction& f(mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY());
        return long(POSTIT_META_HEIGHT * f);
    }

    sal_Int32 SwAnnotationWin::GetMinimumSizeWithMeta()
    {
        return mrMgr.GetMinimumSizeWithMeta();
    }

    sal_Int32 SwAnnotationWin::GetMinimumSizeWithoutMeta()
    {
        const Fraction& f(mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY());
        return long(POSTIT_MINIMUMSIZE_WITHOUT_META * f);
    }

    void SwAnnotationWin::SetSpellChecking()
    {
        const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
        EEControlBits nCntrl = mpOutliner->GetControlWord();
        if (pVOpt->IsOnlineSpell())
            nCntrl |= EEControlBits::ONLINESPELLING;
        else
            nCntrl &= ~EEControlBits::ONLINESPELLING;
        mpOutliner->SetControlWord(nCntrl);

        mpOutliner->CompleteOnlineSpelling();
        Invalidate();
    }

    void SwAnnotationWin::SetViewState(ViewState bViewState)
    {
        switch (bViewState)
        {
            case ViewState::EDIT:
            {
                if (mpAnchor)
                {
                    mpAnchor->SetAnchorState(AnchorState::All);
                    SwAnnotationWin* pWin = GetTopReplyNote();
                    // #i111964#
                    if ( pWin && pWin->Anchor() )
                    {
                        pWin->Anchor()->SetAnchorState(AnchorState::End);
                    }
                    mpAnchor->setLineSolid(true);
                    if ( mpTextRangeOverlay != nullptr )
                    {
                        mpTextRangeOverlay->ShowSolidBorder();
                    }
                }
                if (mpShadow)
                    mpShadow->SetShadowState(SS_EDIT);
                break;
            }
            case ViewState::VIEW:
            {
                if (mpAnchor)
                {
                    mpAnchor->setLineSolid(true);
                    if ( mpTextRangeOverlay != nullptr )
                    {
                        mpTextRangeOverlay->ShowSolidBorder();
                    }
                }
                if (mpShadow)
                    mpShadow->SetShadowState(SS_VIEW);
                break;
            }
            case ViewState::NORMAL:
            {
                if (mpAnchor)
                {
                    if (IsFollow())
                    {
                        // if there is no visible parent note, we want to see the complete anchor ??
                        //if (IsAnyStackParentVisible())
                        mpAnchor->SetAnchorState(AnchorState::End);
                        SwAnnotationWin* pTopWinSelf = GetTopReplyNote();
                        SwAnnotationWin* pTopWinActive = mrMgr.HasActiveSidebarWin()
                                                      ? mrMgr.GetActiveSidebarWin()->GetTopReplyNote()
                                                      : nullptr;
                        // #i111964#
                        if ( pTopWinSelf && ( pTopWinSelf != pTopWinActive ) &&
                             pTopWinSelf->Anchor() )
                        {
                            if ( pTopWinSelf != mrMgr.GetActiveSidebarWin() )
                            {
                                pTopWinSelf->Anchor()->setLineSolid(false);
                                if ( pTopWinSelf->TextRange() != nullptr )
                                {
                                    pTopWinSelf->TextRange()->HideSolidBorder();
                                }
                            }
                            pTopWinSelf->Anchor()->SetAnchorState(AnchorState::All);
                        }
                    }
                    mpAnchor->setLineSolid(false);
                    if ( mpTextRangeOverlay != nullptr )
                    {
                        mpTextRangeOverlay->HideSolidBorder();
                    }
                }
                if ( mpShadow )
                {
                    mpShadow->SetShadowState(SS_NORMAL);
                }
                break;
            }
        }
    }

    SwAnnotationWin* SwAnnotationWin::GetTopReplyNote()
    {
        SwAnnotationWin* pTopNote = nullptr;
        SwAnnotationWin* pSidebarWin = IsFollow() ? mrMgr.GetNextPostIt(KEY_PAGEUP, this) : nullptr;
        while (pSidebarWin)
        {
            pTopNote = pSidebarWin;
            pSidebarWin = pSidebarWin->IsFollow() ? mrMgr.GetNextPostIt(KEY_PAGEUP, pSidebarWin) : nullptr;
        }
        return pTopNote;
    }

    void SwAnnotationWin::SwitchToFieldPos()
    {
        if ( mrMgr.GetActiveSidebarWin() == this )
                mrMgr.SetActiveSidebarWin(nullptr);
        GotoPos();
        sal_uInt32 aCount = MoveCaret();
        if (aCount)
            mrView.GetDocShell()->GetWrtShell()->SwCursorShell::Right(aCount, 0);
        GrabFocusToDocument();
    }

    void SwAnnotationWin::SetChangeTracking( const SwPostItHelper::SwLayoutStatus aLayoutStatus,
                                          const Color& aChangeColor )
    {
        if ( (mLayoutStatus != aLayoutStatus) ||
             (mChangeColor != aChangeColor) )
        {
            mLayoutStatus = aLayoutStatus;
            mChangeColor = aChangeColor;
            Invalidate();
        }
    }

    bool SwAnnotationWin::HasScrollbar() const
    {
        return mpVScrollbar != nullptr;
    }

    bool SwAnnotationWin::IsScrollbarVisible() const
    {
        return HasScrollbar() && mpVScrollbar->IsVisible();
    }

    void SwAnnotationWin::ChangeSidebarItem( SwSidebarItem const & rSidebarItem )
    {
        const bool bAnchorChanged = mpAnchorFrame != rSidebarItem.maLayoutInfo.mpAnchorFrame;
        if ( bAnchorChanged )
        {
            mrMgr.DisconnectSidebarWinFromFrame( *(mpAnchorFrame), *this );
        }

        mrSidebarItem = rSidebarItem;
        mpAnchorFrame = mrSidebarItem.maLayoutInfo.mpAnchorFrame;

        if ( GetWindowPeer() )
        {
            SidebarWinAccessible* pAcc =
                            static_cast<SidebarWinAccessible*>( GetWindowPeer() );
            OSL_ENSURE( dynamic_cast<SidebarWinAccessible*>( GetWindowPeer() ),
                    "<SwAnnotationWin::ChangeSidebarItem(..)> - unexpected type of window peer -> crash possible!" );
            pAcc->ChangeSidebarItem( mrSidebarItem );
        }

        if ( bAnchorChanged )
        {
            mrMgr.ConnectSidebarWinToFrame( *(mrSidebarItem.maLayoutInfo.mpAnchorFrame),
                                          mrSidebarItem.GetFormatField(),
                                          *this );
        }
    }

    css::uno::Reference< css::accessibility::XAccessible > SwAnnotationWin::CreateAccessible()
    {
        SidebarWinAccessible* pAcc( new SidebarWinAccessible( *this,
                                                              mrView.GetWrtShell(),
                                                              mrSidebarItem ) );
        css::uno::Reference< css::awt::XWindowPeer > xWinPeer( pAcc );
        SetWindowPeer( xWinPeer, pAcc );

        css::uno::Reference< css::accessibility::XAccessible > xAcc( xWinPeer, css::uno::UNO_QUERY );
        return xAcc;
    }

    } } // eof of namespace sw::sidebarwindows

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

↑ V522 There might be dereferencing of a potential null pointer 'pTextAnnotationField'.