diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/uibase/docvw/AnnotationWin2.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | sw/source/uibase/docvw/AnnotationWin2.cxx | 1624 |
1 files changed, 1624 insertions, 0 deletions
diff --git a/sw/source/uibase/docvw/AnnotationWin2.cxx b/sw/source/uibase/docvw/AnnotationWin2.cxx new file mode 100644 index 000000000..9c3539f2e --- /dev/null +++ b/sw/source/uibase/docvw/AnnotationWin2.cxx @@ -0,0 +1,1624 @@ +/* -*- 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 "SidebarWinAcc.hxx" +#include <PostItMgr.hxx> +#include <AnnotationWin.hxx> +#include <IDocumentUndoRedo.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 <viewopt.hxx> +#include <cmdid.h> + +#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/undo.hxx> +#include <svl/stritem.hxx> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> + +#include <vcl/edit.hxx> +#include <vcl/event.hxx> +#include <vcl/scrbar.hxx> +#include <vcl/svapp.hxx> +#include <vcl/menubtn.hxx> +#include <vcl/settings.hxx> +#include <vcl/ptrstyle.hxx> + +#include <edtwin.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <wrtsh.hxx> +#include <doc.hxx> +#include <swmodule.hxx> + +#include <txtannotationfld.hxx> +#include <ndtxt.hxx> + +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processorfromoutputdevice.hxx> +#include <unotools/localedatawrapper.hxx> +#include <memory> +#include <comphelper/lok.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::annotation { + +#define METABUTTON_WIDTH 16 +#define METABUTTON_HEIGHT 18 +#define METABUTTON_AREA_WIDTH 30 +#define POSTIT_META_FIELD_HEIGHT sal_Int32(15) +#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); + } + + sal_uInt32 boxHeight = mpMetadataAuthor->GetSizePixel().Height() + mpMetadataDate->GetSizePixel().Height(); + boxHeight += IsThreadResolved() ? mpMetadataResolved->GetSizePixel().Height() : 0; + + rRenderContext.SetLineColor(); + tools::Rectangle aRectangle(Point(mpMetadataAuthor->GetPosPixel().X() + mpMetadataAuthor->GetSizePixel().Width(), + mpMetadataAuthor->GetPosPixel().Y()), + Size(GetMetaButtonAreaWidth(), boxHeight)); + + 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, DrawFlags nInFlags) +{ + Size aSz = pDev->PixelToLogic(GetSizePixel()); + + if (mpMetadataAuthor->IsVisible() ) + { + pDev->SetFillColor(mColorDark); + pDev->SetLineColor(); + pDev->DrawRect( tools::Rectangle( rPt, aSz ) ); + } + + if (mpMetadataAuthor->IsVisible()) + { + vcl::Font aOrigFont(mpMetadataAuthor->GetControlFont()); + Point aPos(PixelToLogic(mpMetadataAuthor->GetPosPixel())); + aPos += rPt; + vcl::Font aFont( mpMetadataAuthor->GetSettings().GetStyleSettings().GetFieldFont() ); + mpMetadataAuthor->SetControlFont( aFont ); + mpMetadataAuthor->Draw(pDev, aPos, nInFlags); + mpMetadataAuthor->SetControlFont( aOrigFont ); + } + + if (mpMetadataDate->IsVisible()) + { + vcl::Font aOrigFont(mpMetadataDate->GetControlFont()); + Point aPos(PixelToLogic(mpMetadataDate->GetPosPixel())); + aPos += rPt; + vcl::Font aFont( mpMetadataDate->GetSettings().GetStyleSettings().GetFieldFont() ); + mpMetadataDate->SetControlFont( aFont ); + mpMetadataDate->SetControlFont( aOrigFont ); + } + + if (mpMetadataResolved->IsVisible()) + { + vcl::Font aOrigFont(mpMetadataResolved->GetControlFont()); + Point aPos(PixelToLogic(mpMetadataResolved->GetPosPixel())); + aPos += rPt; + vcl::Font aFont( mpMetadataResolved->GetSettings().GetStyleSettings().GetFieldFont() ); + mpMetadataResolved->SetControlFont( aFont ); + mpMetadataResolved->SetControlFont( aOrigFont ); + } + + Size aOrigSize(mpSidebarTextControl->GetSizePixel()); + mpSidebarTextControl->SetSizePixel(aSz); + mpSidebarTextControl->Draw(pDev, rPt, nInFlags); + mpSidebarTextControl->SetSizePixel(aOrigSize); + + 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()); + + Point aPos(PixelToLogic(mpMenuButton->GetPosPixel())); + aPos += rPt; + + vcl::Font aFont( mpMetadataDate->GetSettings().GetStyleSettings().GetFieldFont() ); + mpMetadataDate->SetControlFont( aFont ); + mpMetadataDate->SetControlBackground( Color(0xFFFFFF) ); + mpMetadataDate->SetText("..."); + aOrigSize = mpMetadataDate->GetSizePixel(); + mpMetadataDate->SetSizePixel(mpMenuButton->GetSizePixel()); + mpMetadataDate->Draw(pDev, aPos, nInFlags); + mpMetadataDate->SetSizePixel(aOrigSize); + + 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(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); + } + + mpMetadataResolved = VclPtr<Edit>::Create( this, 0 ); + mpMetadataResolved->SetAccessibleName( SwResId( STR_ACCESS_ANNOTATION_RESOLVED_NAME ) ); + mpMetadataResolved->EnableRTL(AllSettings::GetLayoutRTL()); + mpMetadataResolved->SetReadOnly(); + mpMetadataResolved->AlwaysDisableInput(true); + mpMetadataResolved->SetCallHandlersOnInputDisabled(true); + mpMetadataResolved->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 = mpMetadataResolved->GetSettings(); + StyleSettings aStyleSettings = aSettings.GetStyleSettings(); + vcl::Font aFont = aStyleSettings.GetFieldFont(); + aFont.SetFontHeight(8); + aStyleSettings.SetFieldFont(aFont); + aSettings.SetStyleSettings(aStyleSettings); + mpMetadataResolved->SetSettings(aSettings); + mpMetadataResolved->SetText( SwResId( STR_ACCESS_ANNOTATION_RESOLVED_NAME ) ); + } + + 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(); + if(IsThreadResolved()) { mpMetadataResolved->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() +{ + // On Android, this method leads to invoke ImpEditEngine::UpdateViews + // which hides the text cursor. Moreover it causes sudden document scroll + // when modifying a commented text. Not clear the root cause, + // anyway skipping this method fixes the problem, and there should be + // no side effect, since the client has disabled annotations rendering. + if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations()) + return; + + 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 ); + } + if ( mpMetadataResolved ) + { + vcl::Font aFont( mpMetadataResolved->GetSettings().GetStyleSettings().GetFieldFont() ); + sal_Int32 nHeight = long(aFont.GetFontHeight() * rFraction); + aFont.SetFontHeight( nHeight ); + mpMetadataResolved->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 (mpShadow && 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 != this && 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); + + if (mrSidebarItem.maLayoutInfo.mPositionFromCommentAnchor) + pTmpCursorForAnnotationTextRange->FillRects(); + + if (bDisableMapMode) + EditWin().EnableMapMode(); + + SwRects* pRects(pTmpCursorForAnnotationTextRange.get()); + for(const 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(); + if(IsThreadResolved()) { mpMetadataResolved->Show(); } + mpMetadataDate->Show(); + mpSidebarTextControl->SetQuickHelpText(OUString()); + unsigned int numFields = GetNumFields(); + 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()/numFields ); + mpMetadataAuthor->setPosSizePixel( 0, + aHeight, + aSizeOfMetadataControls.Width(), + aSizeOfMetadataControls.Height() ); + mpMetadataDate->setPosSizePixel( 0, + aHeight + aSizeOfMetadataControls.Height(), + aSizeOfMetadataControls.Width(), + aSizeOfMetadataControls.Height() ); + if(IsThreadResolved()) { + mpMetadataResolved->setPosSizePixel( 0, + aHeight + aSizeOfMetadataControls.Height()*2, + 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); + } + + { + mpMetadataResolved->SetControlBackground(mColorDark); + AllSettings aSettings = mpMetadataResolved->GetSettings(); + StyleSettings aStyleSettings = aSettings.GetStyleSettings(); + aStyleSettings.SetFieldTextColor(aColorAnchor); + aSettings.SetStyleSettings(aStyleSettings); + mpMetadataResolved->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) +{ + IDocumentUndoRedo& rUndoRedo( + mrView.GetDocShell()->GetDoc()->GetIDocumentUndoRedo()); + const bool bDocUndoEnabled = rUndoRedo.DoesUndo(); + const bool bOutlinerUndoEnabled = mpOutliner->IsUndoEnabled(); + const bool bOutlinerModified = mpOutliner->IsModified(); + const bool bDisableAndRestoreUndoMode = !bDocUndoEnabled && bOutlinerUndoEnabled; + + if (bDisableAndRestoreUndoMode) + { + // doc undo is disabled, but outliner was enabled, turn outliner undo off + // for the duration of this function + mpOutliner->EnableUndo(false); + } + + 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 ); + + if (!mpOutliner->IsUndoEnabled() && !bOutlinerModified) + { + // if undo was disabled (e.g. this is a redo action) and we were + // originally 'unmodified' keep it that way + mpOutliner->ClearModifyFlag(); + } + + 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(); + + // restore original mode + if (bDisableAndRestoreUndoMode) + mpOutliner->EnableUndo(true); + + 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_RESOLVE_NOTE: + GetTopReplyNote()->ToggleResolved(); + mrMgr.UpdateResolvedStatus(GetTopReplyNote()); + DoResize(); + Invalidate(); + mrMgr.LayoutPostIts(); + 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 ) + { + SetActiveSidebarWin(); + mrMgr.MakeVisible( this ); + } +} + +bool SwAnnotationWin::SetActiveSidebarWin() +{ + if (mrMgr.GetActiveSidebarWin() == this) + return false; + const bool bLockView = mrView.GetWrtShell().IsViewLocked(); + mrView.GetWrtShell().LockView( true ); + mrMgr.SetActiveSidebarWin(this); + mrView.GetWrtShell().LockView( bLockView ); + return true; +} + +void SwAnnotationWin::UnsetActiveSidebarWin() +{ + if (mrMgr.GetActiveSidebarWin() != this) + return; + const bool bLockView = mrView.GetWrtShell().IsViewLocked(); + mrView.GetWrtShell().LockView( true ); + mrMgr.SetActiveSidebarWin(nullptr); + mrView.GetWrtShell().LockView( bLockView ); +} + +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() const +{ + return mrView.GetWrtShell().GetViewOptions()->GetZoom() / 10; +} + +sal_Int32 SwAnnotationWin::GetMetaButtonAreaWidth() const +{ + const Fraction& f( GetMapMode().GetScaleX() ); + return long(METABUTTON_AREA_WIDTH * f); +} + +sal_Int32 SwAnnotationWin::GetMetaHeight() +{ + const Fraction& f(mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY()); + const int fields = GetNumFields(); + return long(fields*POSTIT_META_FIELD_HEIGHT*f); +} + +sal_Int32 SwAnnotationWin::GetNumFields() +{ + return IsThreadResolved() ? 3 : 2; +} + +sal_Int32 SwAnnotationWin::GetMinimumSizeWithMeta() const +{ + return mrMgr.GetMinimumSizeWithMeta(); +} + +sal_Int32 SwAnnotationWin::GetMinimumSizeWithoutMeta() const +{ + 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 != this && 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 != this ) && + ( 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 = this; + 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: */ |