diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/uibase/docvw/AnnotationWin2.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/uibase/docvw/AnnotationWin2.cxx')
-rw-r--r-- | sw/source/uibase/docvw/AnnotationWin2.cxx | 1436 |
1 files changed, 1436 insertions, 0 deletions
diff --git a/sw/source/uibase/docvw/AnnotationWin2.cxx b/sw/source/uibase/docvw/AnnotationWin2.cxx new file mode 100644 index 0000000000..a1780f9132 --- /dev/null +++ b/sw/source/uibase/docvw/AnnotationWin2.cxx @@ -0,0 +1,1436 @@ +/* -*- 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 <config_wasm_strip.h> + +#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 "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 <editeng/editund2.hxx> + +#include <svl/undo.hxx> +#include <svl/stritem.hxx> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> + +#include <vcl/decoview.hxx> +#include <vcl/event.hxx> +#include <vcl/gradient.hxx> +#include <vcl/pdfextoutdevdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/ptrstyle.hxx> +#include <vcl/uitest/logger.hxx> +#include <vcl/uitest/eventdescription.hxx> + +#include <edtwin.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <wrtsh.hxx> +#include <doc.hxx> +#include <docstyle.hxx> +#include <docufld.hxx> +#include <swmodule.hxx> + +#include <SwRewriter.hxx> +#include <txtannotationfld.hxx> +#include <ndtxt.hxx> + +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <osl/diagnose.h> +#include <unotools/localedatawrapper.hxx> +#include <unotools/syslocale.hxx> +#include <memory> +#include <comphelper/lok.hxx> + +using namespace sw::sidebarwindows; + +namespace +{ + +void collectUIInformation( const OUString& aevent , const OUString& aID ) +{ + EventDescription aDescription; + aDescription.aID = aID; + aDescription.aParameters = {{"" , ""}}; + aDescription.aAction = aevent; + aDescription.aParent = "MainWindow"; + aDescription.aKeyWord = "SwEditWinUIObject"; + UITestLogger::getInstance().logEvent(aDescription); +} + +} + +namespace sw::annotation { + +#define METABUTTON_WIDTH 16 +#define METABUTTON_HEIGHT 18 +#define POSTIT_MINIMUMSIZE_WITHOUT_META 50 + +void SwAnnotationWin::PaintTile(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + bool bMenuButtonVisible = mxMenuButton->get_visible(); + // No point in showing this button till click on it are not handled. + if (bMenuButtonVisible) + mxMenuButton->hide(); + + // draw left over space + if (Application::GetSettings().GetStyleSettings().GetHighContrastMode()) + rRenderContext.SetFillColor(COL_BLACK); + else + rRenderContext.SetFillColor(mColorDark); + rRenderContext.SetLineColor(); + rRenderContext.DrawRect(rRect); + + m_xContainer->draw(rRenderContext, rRect.TopLeft(), GetSizePixel()); + + const drawinglayer::geometry::ViewInformation2D aViewInformation; + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(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(vcl::PushFlags::NONE); + pProcessor.reset(); + rRenderContext.Push(vcl::PushFlags::NONE); + + if (bMenuButtonVisible) + mxMenuButton->show(); +} + +bool SwAnnotationWin::IsHitWindow(const Point& rPointLogic) +{ + tools::Rectangle aRectangleLogic(EditWin().PixelToLogic(tools::Rectangle(GetPosPixel(),GetSizePixel()))); + return aRectangleLogic.Contains(rPointLogic); +} + +void SwAnnotationWin::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool bClearMark) +{ + mxSidebarTextControl->SetCursorLogicPosition(rPosition, bPoint, bClearMark); +} + +void SwAnnotationWin::DrawForPage(OutputDevice* pDev, const Point& rPt) +{ + // tdf#143511 unclip SysObj so get_extents_relative_to of children + // of the SysObj can provide meaningful results + UnclipVisibleSysObj(); + + vcl::PDFExtOutDevData *const pPDFExtOutDevData( + dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData())); + if (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF()) + { + pPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement, OUString()); + } + + pDev->Push(); + + pDev->SetFillColor(mColorDark); + pDev->SetLineColor(); + + pDev->SetTextColor(mColorAnchor); + vcl::Font aFont = maLabelFont; + aFont.SetFontHeight(aFont.GetFontHeight() * 20); + pDev->SetFont(aFont); + + Size aSz = PixelToLogic(GetSizePixel()); + + pDev->DrawRect(tools::Rectangle(rPt, aSz)); + + if (mxMetadataAuthor->get_visible()) + { + int x, y, width, height; + mxMetadataAuthor->get_extents_relative_to(*m_xContainer, x, y, width, height); + Point aPos(rPt + PixelToLogic(Point(x, y))); + Size aSize(PixelToLogic(Size(width, height))); + + pDev->Push(vcl::PushFlags::CLIPREGION); + pDev->IntersectClipRegion(tools::Rectangle(aPos, aSize)); + pDev->DrawText(aPos, mxMetadataAuthor->get_label()); + pDev->Pop(); + } + + if (mxMetadataDate->get_visible()) + { + int x, y, width, height; + mxMetadataDate->get_extents_relative_to(*m_xContainer, x, y, width, height); + Point aPos(rPt + PixelToLogic(Point(x, y))); + Size aSize(PixelToLogic(Size(width, height))); + + pDev->Push(vcl::PushFlags::CLIPREGION); + pDev->IntersectClipRegion(tools::Rectangle(aPos, aSize)); + pDev->DrawText(aPos, mxMetadataDate->get_label()); + pDev->Pop(); + } + + if (mxMetadataResolved->get_visible()) + { + int x, y, width, height; + mxMetadataResolved->get_extents_relative_to(*m_xContainer, x, y, width, height); + Point aPos(rPt + PixelToLogic(Point(x, y))); + Size aSize(PixelToLogic(Size(width, height))); + + pDev->Push(vcl::PushFlags::CLIPREGION); + pDev->IntersectClipRegion(tools::Rectangle(aPos, aSize)); + pDev->DrawText(aPos, mxMetadataResolved->get_label()); + pDev->Pop(); + } + + mxSidebarTextControl->DrawForPage(pDev, rPt); + + const drawinglayer::geometry::ViewInformation2D aNewViewInfos; + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice( + *pDev, aNewViewInfos )); + + if (mpAnchor) + pProcessor->process(mpAnchor->getOverlayObjectPrimitive2DSequence()); + if (mpTextRangeOverlay) + pProcessor->process(mpTextRangeOverlay->getOverlayObjectPrimitive2DSequence()); + pProcessor.reset(); + + if (mxVScrollbar->get_vpolicy() != VclPolicyType::NEVER) + { + // if there is a scrollbar shown, draw "..." to indicate the comment isn't + // completely shown + int x, y, width, height; + mxMenuButton->get_extents_relative_to(*m_xContainer, x, y, width, height); + Point aPos(rPt + PixelToLogic(Point(x, y))); + pDev->DrawText(aPos, "..."); + } + + pDev->Pop(); + + if (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF()) + { + pPDFExtOutDevData->EndStructureElement(); + } +} + +void SwAnnotationWin::SetPosSizePixelRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + const tools::Long aPageBorder) +{ + mPosSize = tools::Rectangle(Point(nX,nY),Size(nWidth,nHeight)); + mPageBorder = aPageBorder; +} + +void SwAnnotationWin::SetAnchorRect(const SwRect& aAnchorRect) +{ + if (!mAnchorRect.IsEmpty() && mAnchorRect != aAnchorRect) + mbAnchorRectChanged = true; + mAnchorRect = aAnchorRect; +} + +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 tools::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); +} + +void SwAnnotationWin::InitControls() +{ + // window controls for author and date + mxMetadataAuthor = m_xBuilder->weld_label("author"); + mxMetadataAuthor->set_accessible_name( SwResId( STR_ACCESS_ANNOTATION_AUTHOR_NAME ) ); + mxMetadataAuthor->set_direction(AllSettings::GetLayoutRTL()); + + maLabelFont = Application::GetSettings().GetStyleSettings().GetLabelFont(); + maLabelFont.SetFontHeight(8); + + // we should leave this setting alone, but for this we need a better layout algo + // with variable meta size height + mxMetadataAuthor->set_font(maLabelFont); + + mxMetadataDate = m_xBuilder->weld_label("date"); + mxMetadataDate->set_accessible_name( SwResId( STR_ACCESS_ANNOTATION_DATE_NAME ) ); + mxMetadataDate->set_direction(AllSettings::GetLayoutRTL()); + mxMetadataDate->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl)); + + // we should leave this setting alone, but for this we need a better layout algo + // with variable meta size height + mxMetadataDate->set_font(maLabelFont); + + mxMetadataResolved = m_xBuilder->weld_label("resolved"); + mxMetadataResolved->set_accessible_name( SwResId( STR_ACCESS_ANNOTATION_RESOLVED_NAME ) ); + mxMetadataResolved->set_direction(AllSettings::GetLayoutRTL()); + mxMetadataResolved->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl)); + + // we should leave this setting alone, but for this we need a better layout algo + // with variable meta size height + mxMetadataResolved->set_font(maLabelFont); + mxMetadataResolved->set_label(SwResId(STR_ACCESS_ANNOTATION_RESOLVED_NAME)); + + SwDocShell* aShell = mrView.GetDocShell(); + mpOutliner.reset(new Outliner(&aShell->GetPool(),OutlinerMode::TextObject)); + mpOutliner->SetStyleSheetPool(static_cast<SwDocStyleSheetPool*>(aShell->GetStyleSheetPool())->GetEEStyleSheetPool()); + aShell->GetDoc()->SetCalcFieldValueHdl( mpOutliner.get() ); + mpOutliner->SetUpdateLayout( true ); + + mpOutlinerView.reset(new OutlinerView(mpOutliner.get(), nullptr)); + mpOutliner->InsertView(mpOutlinerView.get()); + + //create Scrollbars + mxVScrollbar = m_xBuilder->weld_scrolled_window("scrolledwindow", true); + + mxMenuButton = m_xBuilder->weld_menu_button("menubutton"); + mxMenuButton->set_size_request(METABUTTON_WIDTH, METABUTTON_HEIGHT); + + // actual window which holds the user text + mxSidebarTextControl.reset(new SidebarTextControl(*this, mrView, mrMgr)); + mxSidebarTextControlWin.reset(new weld::CustomWeld(*m_xBuilder, "editview", *mxSidebarTextControl)); + mxSidebarTextControl->SetPointer(PointerStyle::Text); + + Rescale(); + + mpOutlinerView->SetBackgroundColor(COL_TRANSPARENT); + mpOutlinerView->SetOutputArea( PixelToLogic( tools::Rectangle(0,0,1,1) ) ); + + mxVScrollbar->set_direction(false); + mxVScrollbar->connect_vadjustment_changed(LINK(this, SwAnnotationWin, ScrollHdl)); + mxVScrollbar->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl)); + + EEControlBits nCntrl = mpOutliner->GetControlWord(); + // TODO: crash when AUTOCOMPLETE enabled + nCntrl |= EEControlBits::MARKFIELDS | EEControlBits::PASTESPECIAL | EEControlBits::AUTOCORRECT | EEControlBits::USECHARATTRIBS; // | EEControlBits::AUTOCOMPLETE; + // Our stylesheet pool follows closely the core paragraph styles. + // We don't want the rtf import (during paste) to mess with that. + nCntrl &= ~EEControlBits::RTFSTYLESHEETS; + + if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) + { + const SwViewOption* pVOpt = pWrtShell->GetViewOptions(); + if (pVOpt->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(); + + // expand %1 "Author" + OUString aText = mxMenuButton->get_item_label("deleteby"); + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, GetAuthor()); + aText = aRewriter.Apply(aText); + mxMenuButton->set_item_label("deleteby", aText); + + mxMenuButton->set_accessible_name(SwResId(STR_ACCESS_ANNOTATION_BUTTON_NAME)); + mxMenuButton->set_accessible_description(SwResId(STR_ACCESS_ANNOTATION_BUTTON_DESC)); + mxMenuButton->set_tooltip_text(SwResId(STR_ACCESS_ANNOTATION_BUTTON_DESC)); + + mxMenuButton->connect_toggled(LINK(this, SwAnnotationWin, ToggleHdl)); + mxMenuButton->connect_selected(LINK(this, SwAnnotationWin, SelectHdl)); + mxMenuButton->connect_key_press(LINK(this, SwAnnotationWin, KeyInputHdl)); + mxMenuButton->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl)); + + GetOutlinerView()->StartSpeller(mxSidebarTextControl->GetDrawingArea()); + SetPostItText(); + mpOutliner->CompleteOnlineSpelling(); + + mxSidebarTextControl->Show(); + mxMetadataAuthor->show(); + mxMetadataDate->show(); + mxMetadataResolved->set_visible(IsResolved()); + mxVScrollbar->set_vpolicy(VclPolicyType::ALWAYS); +} + +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 = OUString::Concat(sMeta.subView(0, 20)) + "..."; + } + if ( mxMetadataAuthor->get_label() != sMeta ) + { + mxMetadataAuthor->set_label(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 ( mxMetadataDate->get_label() != sMeta ) + { + mxMetadataDate->set_label(sMeta); + } + + std::size_t aIndex = SW_MOD()->InsertRedlineAuthor(GetAuthor()); + SetColor( SwPostItMgr::GetColorDark(aIndex), + SwPostItMgr::GetColorLight(aIndex), + SwPostItMgr::GetColorAnchor(aIndex)); +} + +static Color ColorFromAlphaColor(const sal_uInt8 aTransparency, const Color& aFront, const Color& aBack) +{ + return Color(sal_uInt8(aFront.GetRed() * aTransparency / 255.0 + aBack.GetRed() * (1 - aTransparency / 255.0)), + sal_uInt8(aFront.GetGreen() * aTransparency / 255.0 + aBack.GetGreen() * (1 - aTransparency / 255.0)), + sal_uInt8(aFront.GetBlue() * aTransparency / 255.0 + aBack.GetBlue() * (1 - aTransparency / 255.0))); +} + +void SwAnnotationWin::SetMenuButtonColors() +{ + if (!mxMenuButton) + return; + + mxMenuButton->set_background(mColorDark); + + SwWrtShell* pWrtShell = mrView.GetWrtShellPtr(); + if (!pWrtShell) + return; + const Fraction& rFraction = pWrtShell->GetOut()->GetMapMode().GetScaleY(); + + ScopedVclPtrInstance<VirtualDevice> xVirDev; + Size aSize(tools::Long(METABUTTON_WIDTH * rFraction), + tools::Long(METABUTTON_HEIGHT * rFraction)); + tools::Rectangle aRect(Point(0, 0), aSize); + xVirDev->SetOutputSizePixel(aSize); + + Gradient aGradient(css::awt::GradientStyle_LINEAR, + ColorFromAlphaColor(15, mColorAnchor, mColorDark), + ColorFromAlphaColor(80, mColorAnchor, mColorDark)); + xVirDev->DrawGradient(aRect, aGradient); + + //draw rect around button + xVirDev->SetFillColor(); + xVirDev->SetLineColor(ColorFromAlphaColor(90, mColorAnchor, mColorDark)); + xVirDev->DrawRect(aRect); + + tools::Rectangle aSymbolRect(aRect); + // 25% distance to the left and right button border + const tools::Long nBorderDistanceLeftAndRight = ((aSymbolRect.GetWidth() * 250) + 500) / 1000; + aSymbolRect.AdjustLeft(nBorderDistanceLeftAndRight ); + aSymbolRect.AdjustRight( -nBorderDistanceLeftAndRight ); + // 40% distance to the top button border + const tools::Long nBorderDistanceTop = ((aSymbolRect.GetHeight() * 400) + 500) / 1000; + aSymbolRect.AdjustTop(nBorderDistanceTop ); + // 15% distance to the bottom button border + const tools::Long nBorderDistanceBottom = ((aSymbolRect.GetHeight() * 150) + 500) / 1000; + aSymbolRect.AdjustBottom( -nBorderDistanceBottom ); + DecorationView aDecoView(xVirDev.get()); + aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, GetTextColor(), + DrawSymbolFlags::NONE); + mxMenuButton->set_image(xVirDev); + mxMenuButton->set_size_request(aSize.Width() + 4, aSize.Height() + 4); +} + +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() ); + SetMapMode( aMode ); + mxSidebarTextControl->SetMapMode( aMode ); + + SwWrtShell* pWrtShell = mrView.GetWrtShellPtr(); + if (!pWrtShell) + return; + const Fraction& rFraction = pWrtShell->GetOut()->GetMapMode().GetScaleY(); + + vcl::Font aFont = maLabelFont; + sal_Int32 nHeight = tools::Long(aFont.GetFontHeight() * rFraction); + aFont.SetFontHeight( nHeight ); + + if (mxMetadataAuthor) + mxMetadataAuthor->set_font(aFont); + if (mxMetadataDate) + mxMetadataDate->set_font(aFont); + if (mxMetadataResolved) + mxMetadataResolved->set_font(aFont); + SetMenuButtonColors(); + if (mxVScrollbar) + mxVScrollbar->set_scroll_thickness(GetPrefScrollbarWidth()); +} + +void SwAnnotationWin::SetPosAndSize() +{ + const bool bShowNotes = mrMgr.ShowNotes(); + if (bShowNotes) + { + bool bChange = false; + + if (GetSizePixel() != mPosSize.GetSize()) + { + bChange = true; + SetSizePixel(mPosSize.GetSize()); + + DoResize(); + } + + if (GetPosPixel().X() != mPosSize.Left() || (std::abs(GetPosPixel().Y() - mPosSize.Top()) > 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 (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 != SwNodeOffset(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()->Assign( *pTextNode, pTextAnnotationField->GetStart()+1 ); + pTableCursor->NewTableSelection(); + pTmpCursor = pTableCursor; + } + else + { + SwShellCursor* pCursor = new SwShellCursor( mrView.GetWrtShell(), aStartPos ); + pCursor->SetMark(); + pCursor->GetMark()->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 (bShowNotes && !maAnnotationTextRanges.empty()) + { + if ( mpTextRangeOverlay != nullptr ) + { + mpTextRangeOverlay->setRanges( std::vector(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, + std::vector(maAnnotationTextRanges), + mpAnchor && mpAnchor->getLineSolid() ); + } + } + else + { + mpTextRangeOverlay.reset(); + } +} + +void SwAnnotationWin::DoResize() +{ + tools::Long aHeight = GetSizePixel().Height(); + tools::ULong aWidth = GetSizePixel().Width(); + + aHeight -= GetMetaHeight(); + + mpOutliner->SetPaperSize( PixelToLogic( Size(aWidth, aHeight) ) ) ; + tools::Long aTextHeight = LogicToPixel( mpOutliner->CalcTextSize()).Height(); + + mxMetadataAuthor->show(); + if(IsResolved()) { mxMetadataResolved->show(); } + mxMetadataDate->show(); + + if (aTextHeight > aHeight) + { + const int nThickness = mxVScrollbar->get_scroll_thickness(); + if (nThickness) + { + // we need vertical scrollbars and have to reduce the width + aWidth -= nThickness; + mpOutliner->SetPaperSize(PixelToLogic(Size(aWidth, aHeight))); + } + mxVScrollbar->set_vpolicy(VclPolicyType::ALWAYS); + } + else + { + mxVScrollbar->set_vpolicy(VclPolicyType::NEVER); + } + + tools::Rectangle aOutputArea = PixelToLogic(tools::Rectangle(0, 0, aWidth, aHeight)); + if (mxVScrollbar->get_vpolicy() == VclPolicyType::NEVER) + { + // if we do not have a scrollbar anymore, we want to see the complete text + mpOutlinerView->SetVisArea(aOutputArea); + } + mpOutlinerView->SetOutputArea(aOutputArea); + mpOutlinerView->ShowCursor(true, true); + + // Don't leave an empty area at the bottom if we can move the text down. + tools::Long nMaxVisAreaTop = mpOutliner->GetTextHeight() - aOutputArea.GetHeight(); + if (mpOutlinerView->GetVisArea().Top() > nMaxVisAreaTop) + { + GetOutlinerView()->Scroll(0, mpOutlinerView->GetVisArea().Top() - nMaxVisAreaTop); + } + + int nUpper = mpOutliner->GetTextHeight(); + int nCurrentDocPos = mpOutlinerView->GetVisArea().Top(); + int nStepIncrement = mpOutliner->GetTextHeight() / 10; + int nPageIncrement = PixelToLogic(Size(0,aHeight)).Height() * 8 / 10; + int nPageSize = PixelToLogic(Size(0,aHeight)).Height(); + + /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has + effectively... + + lower = gtk_adjustment_get_lower + upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size + + and requires that upper > lower or the deceleration animation never ends + */ + nPageSize = std::min(nPageSize, nUpper); + + mxVScrollbar->vadjustment_configure(nCurrentDocPos, 0, nUpper, + nStepIncrement, nPageIncrement, nPageSize); +} + +void SwAnnotationWin::SetSizePixel( const Size& rNewSize ) +{ + if (comphelper::LibreOfficeKit::isActive()) + return; + + InterimItemWindow::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() +{ + mxVScrollbar->vadjustment_set_value(mpOutlinerView->GetVisArea().Top()); +} + +void SwAnnotationWin::ResizeIfNecessary(tools::Long aOldHeight, tools::Long aNewHeight) +{ + if (aOldHeight != aNewHeight) + { + //check for lower border or next note + tools::Long aBorder = mrMgr.GetNextBorder(); + if (aBorder != -1) + { + if (aNewHeight > GetMinimumSizeWithoutMeta()) + { + tools::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() ) + return; + + m_xContainer->set_background(mColorDark); + SetMenuButtonColors(); + + mxMetadataAuthor->set_font_color(aColorAnchor); + + mxMetadataDate->set_font_color(aColorAnchor); + + mxMetadataResolved->set_font_color(aColorAnchor); + + mxVScrollbar->customize_scrollbars(mColorLight, + mColorAnchor, + mColorDark); +} + +void SwAnnotationWin::SetSidebarPosition(sw::sidebarwindows::SidebarPosition eSidebarPosition) +{ + meSidebarPosition = eSidebarPosition; +} + +void SwAnnotationWin::SetReadonly(bool bSet) +{ + mbReadonly = bSet; + GetOutlinerView()->SetReadOnly(bSet); +} + +void SwAnnotationWin::GetFocus() +{ + if (mxSidebarTextControl) + mxSidebarTextControl->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); + if (mpTextRangeOverlay && !mpTextRangeOverlay->isVisible()) + mpTextRangeOverlay->setVisible(true); + + collectUIInformation("SHOW",get_id()); +} + +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); + if (mpTextRangeOverlay && mpTextRangeOverlay->isVisible()) + mpTextRangeOverlay->setVisible(false); + collectUIInformation("HIDE",get_id()); +} + +void SwAnnotationWin::ActivatePostIt() +{ + mrMgr.AssureStdModeAtShell(); + + mpOutliner->ClearModifyFlag(); + mpOutliner->GetUndoManager().Clear(); + + CheckMetaText(); + SetViewState(ViewState::EDIT); + + // prevent autoscroll to the old cursor location + // when cursor out of visible area + GetOutlinerView()->ShowCursor(false); + + if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) + mpOutlinerView->GetEditView().SetInsertMode(pWrtShell->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 (!mnDeleteEventId && !IsReadOnlyOrProtected() && mpOutliner->GetEditEngine().GetText().isEmpty()) + { + mnDeleteEventId = 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 aPara(GetOutlinerView()->GetEditView().CreateTextObject()); + mrMgr.RegisterAnswer(&aPara); + } + if (mrMgr.HasActiveSidebarWin()) + mrMgr.SetActiveSidebarWin(nullptr); + SwitchToFieldPos(); + mrView.GetViewFrame().GetDispatcher()->Execute(FN_POSTIT); + + if (nSlot == FN_REPLY) + { + // Get newly created SwPostItField and set its paraIdParent + auto pPostItField = mrMgr.GetLatestPostItField(); + pPostItField->SetParentId(GetTopReplyNote()->GetParaId()); + pPostItField->SetParentPostItId(GetTopReplyNote()->GetPostItField()->GetPostItId()); + pPostItField->SetParentName(GetTopReplyNote()->GetPostItField()->GetName()); + } + break; + } + case FN_DELETE_COMMENT: + //Delete(); // do not kill the parent of our open popup menu + mnDeleteEventId = Application::PostUserEvent( LINK( this, SwAnnotationWin, DeleteHdl), nullptr, true ); + break; + case FN_DELETE_COMMENT_THREAD: + DeleteThread(); + break; + case FN_RESOLVE_NOTE: + ToggleResolved(); + DoResize(); + Invalidate(); + mrMgr.LayoutPostIts(); + break; + case FN_RESOLVE_NOTE_THREAD: + GetTopReplyNote()->SetResolved(!IsThreadResolved()); + 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(); +} + +tools::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, MouseMoveHdl, const MouseEvent&, rMEvt, bool) +{ + if (rMEvt.IsEnterWindow()) + { + mbMouseOver = true; + if ( !HasFocus() ) + { + SetViewState(ViewState::VIEW); + Invalidate(); + } + } + else if (rMEvt.IsLeaveWindow()) + { + mbMouseOver = false; + if ( !HasFocus() ) + { + SetViewState(ViewState::NORMAL); + Invalidate(); + } + } + return false; +} + +bool SwAnnotationWin::SetActiveSidebarWin() +{ + if (mrMgr.GetActiveSidebarWin() == this) + return false; + mrView.GetWrtShell().LockView( true ); + mrMgr.SetActiveSidebarWin(this); + mrView.GetWrtShell().LockView( true ); + + return true; +} + +void SwAnnotationWin::UnsetActiveSidebarWin() +{ + if (mrMgr.GetActiveSidebarWin() != this) + return; + mrView.GetWrtShell().LockView( true ); + mrMgr.SetActiveSidebarWin(nullptr); + mrView.GetWrtShell().LockView( false ); +} + +void SwAnnotationWin::LockView(bool bLock) +{ + mrView.GetWrtShell().LockView( bLock ); +} + +IMPL_LINK(SwAnnotationWin, ScrollHdl, weld::ScrolledWindow&, rScrolledWindow, void) +{ + tools::Long nDiff = GetOutlinerView()->GetEditView().GetVisArea().Top() - rScrolledWindow.vadjustment_get_value(); + GetOutlinerView()->Scroll( 0, nDiff ); +} + +IMPL_LINK_NOARG(SwAnnotationWin, ModifyHdl, LinkParamNone*, void) +{ + mrView.GetDocShell()->SetModified(); +} + +IMPL_LINK_NOARG(SwAnnotationWin, DeleteHdl, void*, void) +{ + mnDeleteEventId = nullptr; + Delete(); +} + +void SwAnnotationWin::ResetAttributes() +{ + mpOutlinerView->RemoveAttribsKeepLanguages(true); + mpOutliner->RemoveFields(); +} + +int SwAnnotationWin::GetPrefScrollbarWidth() const +{ + if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) + { + const Fraction& f(pWrtShell->GetOut()->GetMapMode().GetScaleY()); + return tools::Long(Application::GetSettings().GetStyleSettings().GetScrollBarSize() * f); + } + else + return tools::Long(Application::GetSettings().GetStyleSettings().GetScrollBarSize()); +} + +sal_Int32 SwAnnotationWin::GetMetaHeight() const +{ + const int fields = GetNumFields(); + + sal_Int32 nRequiredHeight = 0; + weld::Label* aLabels[3] = { mxMetadataAuthor.get(), mxMetadataDate.get(), mxMetadataResolved.get() }; + for (int i = 0; i < fields; ++i) + nRequiredHeight += aLabels[i]->get_preferred_size().Height(); + + return nRequiredHeight; +} + +sal_Int32 SwAnnotationWin::GetNumFields() const +{ + return IsResolved() ? 3 : 2; +} + +sal_Int32 SwAnnotationWin::GetMinimumSizeWithMeta() const +{ + return mrMgr.GetMinimumSizeWithMeta(); +} + +sal_Int32 SwAnnotationWin::GetMinimumSizeWithoutMeta() const +{ + if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) + { + const Fraction& f(pWrtShell->GetOut()->GetMapMode().GetScaleY()); + return tools::Long(POSTIT_MINIMUMSIZE_WITHOUT_META * f); + } + else + return tools::Long(POSTIT_MINIMUMSIZE_WITHOUT_META); +} + +void SwAnnotationWin::SetSpellChecking() +{ + if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) + { + const SwViewOption* pVOpt = pWrtShell->GetViewOptions(); + EEControlBits nCntrl = mpOutliner->GetControlWord(); + mpOutliner->SetControlWord(nCntrl & ~EEControlBits::ONLINESPELLING); + if (pVOpt->IsOnlineSpell()) + mpOutliner->SetControlWord(nCntrl | EEControlBits::ONLINESPELLING); + + 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() +{ + for (SwAnnotationWin* pTopNote = this;;) + { + if (!pTopNote->IsFollow()) + return pTopNote; + SwAnnotationWin* pPrev = mrMgr.GetNextPostIt(KEY_PAGEUP, pTopNote); + if (!pPrev) + return pTopNote; + pTopNote = pPrev; + } +} + +void SwAnnotationWin::SwitchToFieldPos() +{ + if ( mrMgr.GetActiveSidebarWin() == this ) + mrMgr.SetActiveSidebarWin(nullptr); + GotoPos(); + sal_uInt32 aCount = MoveCaret(); + if (aCount) + mrView.GetDocShell()->GetWrtShell()->SwCursorShell::Right(aCount, SwCursorSkipMode::Chars); + GrabFocusToDocument(); + collectUIInformation("LEAVE",get_id()); +} + +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 static_cast<bool>(mxVScrollbar); +} + +bool SwAnnotationWin::IsScrollbarVisible() const +{ + return HasScrollbar() && mxVScrollbar->get_vpolicy() == VclPolicyType::ALWAYS; +} + +void SwAnnotationWin::ChangeSidebarItem( SwSidebarItem const & rSidebarItem ) +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + const bool bAnchorChanged = mpAnchorFrame != rSidebarItem.maLayoutInfo.mpAnchorFrame; + if ( bAnchorChanged ) + { + mrMgr.DisconnectSidebarWinFromFrame( *mpAnchorFrame, *this ); + } +#endif + + mrSidebarItem = rSidebarItem; + mpAnchorFrame = mrSidebarItem.maLayoutInfo.mpAnchorFrame; + +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + if (mxSidebarWinAccessible) + mxSidebarWinAccessible->ChangeSidebarItem( mrSidebarItem ); + + if ( bAnchorChanged ) + { + mrMgr.ConnectSidebarWinToFrame( *(mrSidebarItem.maLayoutInfo.mpAnchorFrame), + mrSidebarItem.GetFormatField(), + *this ); + } +#endif +} + +css::uno::Reference< css::accessibility::XAccessible > SwAnnotationWin::CreateAccessible() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + // This is rather dodgy code. Normally in CreateAccessible, if we want a custom + // object, we return a custom object, but we do no override the default toolkit + // window peer. + if (!mxSidebarWinAccessible) + mxSidebarWinAccessible = new SidebarWinAccessible( *this, + mrView.GetWrtShell(), + mrSidebarItem ); +#endif + return mxSidebarWinAccessible; +} + +} // eof of namespace sw::sidebarwindows + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |