1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <cstddef>
23 
24 #include "SidebarWinAcc.hxx"
25 #include <PostItMgr.hxx>
26 #include <AnnotationWin.hxx>
27 #include <IDocumentUndoRedo.hxx>
28 #include <basegfx/range/b2drange.hxx>
29 #include "SidebarTxtControl.hxx"
30 #include "AnchorOverlayObject.hxx"
31 #include "ShadowOverlayObject.hxx"
32 #include "OverlayRanges.hxx"
33 
34 #include <strings.hrc>
35 
36 #include <viewopt.hxx>
37 #include <cmdid.h>
38 
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/langitem.hxx>
41 #include <editeng/editview.hxx>
42 #include <editeng/outliner.hxx>
43 #include <editeng/editeng.hxx>
44 #include <editeng/eeitem.hxx>
45 #include <editeng/outlobj.hxx>
46 
47 #include <svl/undo.hxx>
48 #include <svl/stritem.hxx>
49 
50 #include <sfx2/viewfrm.hxx>
51 #include <sfx2/bindings.hxx>
52 #include <sfx2/dispatch.hxx>
53 
54 #include <vcl/decoview.hxx>
55 #include <vcl/event.hxx>
56 #include <vcl/gradient.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/settings.hxx>
59 #include <vcl/ptrstyle.hxx>
60 #include <vcl/uitest/logger.hxx>
61 #include <vcl/uitest/eventdescription.hxx>
62 
63 #include <edtwin.hxx>
64 #include <view.hxx>
65 #include <docsh.hxx>
66 #include <wrtsh.hxx>
67 #include <doc.hxx>
68 #include <swmodule.hxx>
69 
70 #include <SwRewriter.hxx>
71 #include <txtannotationfld.hxx>
72 #include <ndtxt.hxx>
73 
74 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
75 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
76 #include <unotools/localedatawrapper.hxx>
77 #include <unotools/syslocale.hxx>
78 #include <memory>
79 #include <comphelper/lok.hxx>
80 
81 using namespace sw::sidebarwindows;
82 
83 namespace
84 {
85 
collectUIInformation(const OUString & aevent,const OUString & aID)86 void collectUIInformation( const OUString& aevent , const OUString& aID )
87 {
88     EventDescription aDescription;
89     aDescription.aID =  aID;
90     aDescription.aParameters = {{"" ,  ""}};
91     aDescription.aAction = aevent;
92     aDescription.aParent = "MainWindow";
93     aDescription.aKeyWord = "SwEditWinUIObject";
94     UITestLogger::getInstance().logEvent(aDescription);
95 }
96 
97 }
98 
99 namespace sw::annotation {
100 
101 #define METABUTTON_WIDTH        16
102 #define METABUTTON_HEIGHT       18
103 #define POSTIT_META_FIELD_HEIGHT  sal_Int32(15)
104 #define POSTIT_MINIMUMSIZE_WITHOUT_META     50
105 
PaintTile(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)106 void SwAnnotationWin::PaintTile(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
107 {
108     bool bMenuButtonVisible = mxMenuButton->get_visible();
109     // No point in showing this button till click on it are not handled.
110     if (bMenuButtonVisible)
111         mxMenuButton->hide();
112 
113     // draw left over space
114     if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
115         rRenderContext.SetFillColor(COL_BLACK);
116     else
117         rRenderContext.SetFillColor(mColorDark);
118     rRenderContext.SetLineColor();
119     rRenderContext.DrawRect(rRect);
120 
121     m_xContainer->draw(rRenderContext, rRect.TopLeft(), GetSizePixel());
122 
123     const drawinglayer::geometry::ViewInformation2D aViewInformation;
124     std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext, aViewInformation));
125 
126     // drawinglayer sets the map mode to pixels, not needed here.
127     rRenderContext.Pop();
128     // Work in document-global twips.
129     rRenderContext.Pop();
130     if (mpAnchor)
131         pProcessor->process(mpAnchor->getOverlayObjectPrimitive2DSequence());
132     if (mpTextRangeOverlay)
133         pProcessor->process(mpTextRangeOverlay->getOverlayObjectPrimitive2DSequence());
134 
135     rRenderContext.Push(PushFlags::NONE);
136     pProcessor.reset();
137     rRenderContext.Push(PushFlags::NONE);
138 
139     if (bMenuButtonVisible)
140         mxMenuButton->show();
141 }
142 
IsHitWindow(const Point & rPointLogic)143 bool SwAnnotationWin::IsHitWindow(const Point& rPointLogic)
144 {
145     tools::Rectangle aRectangleLogic(EditWin().PixelToLogic(GetPosPixel()), EditWin().PixelToLogic(GetSizePixel()));
146     return aRectangleLogic.IsInside(rPointLogic);
147 }
148 
SetCursorLogicPosition(const Point & rPosition,bool bPoint,bool bClearMark)149 void SwAnnotationWin::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool bClearMark)
150 {
151     mxSidebarTextControl->SetCursorLogicPosition(rPosition, bPoint, bClearMark);
152 }
153 
DrawForPage(OutputDevice * pDev,const Point & rPt)154 void SwAnnotationWin::DrawForPage(OutputDevice* pDev, const Point& rPt)
155 {
156     // tdf#143511 unclip SysObj so get_extents_relative_to of children
157     // of the SysObj can provide meaningful results
158     UnclipVisibleSysObj();
159 
160     pDev->Push();
161 
162     pDev->SetFillColor(mColorDark);
163     pDev->SetLineColor();
164 
165     pDev->SetTextColor(mColorAnchor);
166     vcl::Font aFont = maLabelFont;
167     aFont.SetFontHeight(aFont.GetFontHeight() * 20);
168     pDev->SetFont(aFont);
169 
170     Size aSz = PixelToLogic(GetSizePixel());
171 
172     pDev->DrawRect(tools::Rectangle(rPt, aSz));
173 
174     if (mxMetadataAuthor->get_visible())
175     {
176         int x, y, width, height;
177         mxMetadataAuthor->get_extents_relative_to(*m_xContainer, x, y, width, height);
178         Point aPos(rPt + PixelToLogic(Point(x, y)));
179         Size aSize(PixelToLogic(Size(width, height)));
180 
181         pDev->Push(PushFlags::CLIPREGION);
182         pDev->IntersectClipRegion(tools::Rectangle(aPos, aSize));
183         pDev->DrawText(aPos, mxMetadataAuthor->get_label());
184         pDev->Pop();
185     }
186 
187 //    m_xContainer->draw(*pDev, rPt, GetSizePixel());
188 
189     if (mxMetadataDate->get_visible())
190     {
191         int x, y, width, height;
192         mxMetadataDate->get_extents_relative_to(*m_xContainer, x, y, width, height);
193         Point aPos(rPt + PixelToLogic(Point(x, y)));
194         Size aSize(PixelToLogic(Size(width, height)));
195 
196         pDev->Push(PushFlags::CLIPREGION);
197         pDev->IntersectClipRegion(tools::Rectangle(aPos, aSize));
198         pDev->DrawText(aPos, mxMetadataDate->get_label());
199         pDev->Pop();
200     }
201 
202     if (mxMetadataResolved->get_visible())
203     {
204         int x, y, width, height;
205         mxMetadataResolved->get_extents_relative_to(*m_xContainer, x, y, width, height);
206         Point aPos(rPt + PixelToLogic(Point(x, y)));
207         Size aSize(PixelToLogic(Size(width, height)));
208 
209         pDev->Push(PushFlags::CLIPREGION);
210         pDev->IntersectClipRegion(tools::Rectangle(aPos, aSize));
211         pDev->DrawText(aPos, mxMetadataResolved->get_label());
212         pDev->Pop();
213     }
214 
215     mxSidebarTextControl->DrawForPage(pDev, rPt);
216 
217     const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
218     std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
219         drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
220             *pDev, aNewViewInfos ));
221 
222     if (mpAnchor)
223         pProcessor->process(mpAnchor->getOverlayObjectPrimitive2DSequence());
224     if (mpTextRangeOverlay)
225         pProcessor->process(mpTextRangeOverlay->getOverlayObjectPrimitive2DSequence());
226     pProcessor.reset();
227 
228     if (mxVScrollbar->get_vpolicy() != VclPolicyType::NEVER)
229     {
230         // if there is a scrollbar shown, draw "..." to indicate the comment isn't
231         // completely shown
232         int x, y, width, height;
233         mxMenuButton->get_extents_relative_to(*m_xContainer, x, y, width, height);
234         Point aPos(rPt + PixelToLogic(Point(x, y)));
235         pDev->DrawText(aPos, "...");
236     }
237 
238     pDev->Pop();
239 }
240 
SetPosSizePixelRect(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight,const SwRect & aAnchorRect,const tools::Long aPageBorder)241 void SwAnnotationWin::SetPosSizePixelRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
242                                        const SwRect& aAnchorRect, const tools::Long aPageBorder)
243 {
244     mPosSize = tools::Rectangle(Point(nX,nY),Size(nWidth,nHeight));
245     if (!mAnchorRect.IsEmpty() && mAnchorRect != aAnchorRect)
246         mbAnchorRectChanged = true;
247     mAnchorRect = aAnchorRect;
248     mPageBorder = aPageBorder;
249 }
250 
SetSize(const Size & rNewSize)251 void SwAnnotationWin::SetSize( const Size& rNewSize )
252 {
253     mPosSize.SetSize(rNewSize);
254 }
255 
SetVirtualPosSize(const Point & aPoint,const Size & aSize)256 void SwAnnotationWin::SetVirtualPosSize( const Point& aPoint, const Size& aSize)
257 {
258     mPosSize = tools::Rectangle(aPoint,aSize);
259 }
260 
TranslateTopPosition(const tools::Long aAmount)261 void SwAnnotationWin::TranslateTopPosition(const tools::Long aAmount)
262 {
263     mPosSize.Move(0,aAmount);
264 }
265 
ShowAnchorOnly(const Point & aPoint)266 void SwAnnotationWin::ShowAnchorOnly(const Point &aPoint)
267 {
268     HideNote();
269     SetPosAndSize();
270     if (mpAnchor)
271     {
272         mpAnchor->SetSixthPosition(basegfx::B2DPoint(aPoint.X(),aPoint.Y()));
273         mpAnchor->SetSeventhPosition(basegfx::B2DPoint(aPoint.X(),aPoint.Y()));
274         mpAnchor->SetAnchorState(AnchorState::All);
275         mpAnchor->setVisible(true);
276     }
277     if (mpShadow)
278         mpShadow->setVisible(false);
279 }
280 
DefaultItem()281 SfxItemSet SwAnnotationWin::DefaultItem()
282 {
283     SfxItemSet aItem( mrView.GetDocShell()->GetPool() );
284     aItem.Put(SvxFontHeightItem(200,100,EE_CHAR_FONTHEIGHT));
285     return aItem;
286 }
287 
InitControls()288 void SwAnnotationWin::InitControls()
289 {
290     // window controls for author and date
291     mxMetadataAuthor = m_xBuilder->weld_label("author");
292     mxMetadataAuthor->set_accessible_name( SwResId( STR_ACCESS_ANNOTATION_AUTHOR_NAME ) );
293     mxMetadataAuthor->set_direction(AllSettings::GetLayoutRTL());
294 
295     maLabelFont = Application::GetSettings().GetStyleSettings().GetLabelFont();
296     maLabelFont.SetFontHeight(8);
297 
298     // we should leave this setting alone, but for this we need a better layout algo
299     // with variable meta size height
300     mxMetadataAuthor->set_font(maLabelFont);
301 
302     mxMetadataDate = m_xBuilder->weld_label("date");
303     mxMetadataDate->set_accessible_name( SwResId( STR_ACCESS_ANNOTATION_DATE_NAME ) );
304     mxMetadataDate->set_direction(AllSettings::GetLayoutRTL());
305     mxMetadataDate->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl));
306 
307     // we should leave this setting alone, but for this we need a better layout algo
308     // with variable meta size height
309     mxMetadataDate->set_font(maLabelFont);
310 
311     mxMetadataResolved = m_xBuilder->weld_label("resolved");
312     mxMetadataResolved->set_accessible_name( SwResId( STR_ACCESS_ANNOTATION_RESOLVED_NAME ) );
313     mxMetadataResolved->set_direction(AllSettings::GetLayoutRTL());
314     mxMetadataResolved->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl));
315 
316     // we should leave this setting alone, but for this we need a better layout algo
317     // with variable meta size height
318     mxMetadataResolved->set_font(maLabelFont);
319     mxMetadataResolved->set_label(SwResId(STR_ACCESS_ANNOTATION_RESOLVED_NAME));
320 
321     SwDocShell* aShell = mrView.GetDocShell();
322     mpOutliner.reset(new Outliner(&aShell->GetPool(),OutlinerMode::TextObject));
323     aShell->GetDoc()->SetCalcFieldValueHdl( mpOutliner.get() );
324     mpOutliner->SetUpdateMode( true );
325 
326     mpOutlinerView.reset(new OutlinerView(mpOutliner.get(), nullptr));
327     mpOutliner->InsertView(mpOutlinerView.get());
328 
329     //create Scrollbars
330     mxVScrollbar = m_xBuilder->weld_scrolled_window("scrolledwindow", true);
331 
332     mxMenuButton = m_xBuilder->weld_menu_button("menubutton");
333     mxMenuButton->set_size_request(METABUTTON_WIDTH, METABUTTON_HEIGHT);
334 
335     // actual window which holds the user text
336     mxSidebarTextControl.reset(new SidebarTextControl(*this, mrView, mrMgr));
337     mxSidebarTextControlWin.reset(new weld::CustomWeld(*m_xBuilder, "editview", *mxSidebarTextControl));
338     mxSidebarTextControl->SetPointer(PointerStyle::Text);
339 
340     Rescale();
341 
342     mpOutlinerView->SetBackgroundColor(COL_TRANSPARENT);
343     mpOutlinerView->SetOutputArea( PixelToLogic( tools::Rectangle(0,0,1,1) ) );
344 
345     mpOutlinerView->SetAttribs(DefaultItem());
346 
347     mxVScrollbar->set_direction(false);
348     mxVScrollbar->connect_vadjustment_changed(LINK(this, SwAnnotationWin, ScrollHdl));
349     mxVScrollbar->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl));
350 
351     const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
352     EEControlBits nCntrl = mpOutliner->GetControlWord();
353     // TODO: crash when AUTOCOMPLETE enabled
354     nCntrl |= EEControlBits::MARKFIELDS | EEControlBits::PASTESPECIAL | EEControlBits::AUTOCORRECT | EEControlBits::USECHARATTRIBS; // | EEControlBits::AUTOCOMPLETE;
355     if (SwViewOption::IsFieldShadings())
356         nCntrl |= EEControlBits::MARKFIELDS;
357     else
358         nCntrl &= ~EEControlBits::MARKFIELDS;
359     if (pVOpt->IsOnlineSpell())
360         nCntrl |= EEControlBits::ONLINESPELLING;
361     else
362         nCntrl &= ~EEControlBits::ONLINESPELLING;
363     mpOutliner->SetControlWord(nCntrl);
364 
365     std::size_t aIndex = SW_MOD()->InsertRedlineAuthor(GetAuthor());
366     SetColor( SwPostItMgr::GetColorDark(aIndex),
367               SwPostItMgr::GetColorLight(aIndex),
368               SwPostItMgr::GetColorAnchor(aIndex));
369 
370     CheckMetaText();
371 
372     // expand %1 "Author"
373     OUString aText = mxMenuButton->get_item_label("deleteby");
374     SwRewriter aRewriter;
375     aRewriter.AddRule(UndoArg1, GetAuthor());
376     aText = aRewriter.Apply(aText);
377     mxMenuButton->set_item_label("deleteby", aText);
378 
379     mxMenuButton->set_accessible_name(SwResId(STR_ACCESS_ANNOTATION_BUTTON_NAME));
380     mxMenuButton->set_accessible_description(SwResId(STR_ACCESS_ANNOTATION_BUTTON_DESC));
381     mxMenuButton->set_tooltip_text(SwResId(STR_ACCESS_ANNOTATION_BUTTON_DESC));
382 
383     mxMenuButton->connect_toggled(LINK(this, SwAnnotationWin, ToggleHdl));
384     mxMenuButton->connect_selected(LINK(this, SwAnnotationWin, SelectHdl));
385     mxMenuButton->connect_key_press(LINK(this, SwAnnotationWin, KeyInputHdl));
386     mxMenuButton->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl));
387 
388     SetLanguage(GetLanguage());
389     GetOutlinerView()->StartSpeller(mxSidebarTextControl->GetDrawingArea());
390     SetPostItText();
391     mpOutliner->CompleteOnlineSpelling();
392 
393     mxSidebarTextControl->Show();
394     mxMetadataAuthor->show();
395     mxMetadataDate->show();
396     mxMetadataResolved->set_visible(IsResolved());
397     mxVScrollbar->set_vpolicy(VclPolicyType::ALWAYS);
398 }
399 
CheckMetaText()400 void SwAnnotationWin::CheckMetaText()
401 {
402     const SvtSysLocale aSysLocale;
403     const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
404     OUString sMeta = GetAuthor();
405     if (sMeta.isEmpty())
406     {
407         sMeta = SwResId(STR_NOAUTHOR);
408     }
409     else if (sMeta.getLength() > 23)
410     {
411         sMeta = OUString::Concat(sMeta.subView(0, 20)) + "...";
412     }
413     if ( mxMetadataAuthor->get_label() != sMeta )
414     {
415         mxMetadataAuthor->set_label(sMeta);
416     }
417 
418     Date aDate = GetDate();
419     if (aDate.IsValidAndGregorian() )
420     {
421         sMeta = rLocalData.getDate(aDate);
422     }
423     else
424     {
425         sMeta = SwResId(STR_NODATE);
426     }
427     if (GetTime().GetTime()!=0)
428     {
429         sMeta += " " + rLocalData.getTime( GetTime(),false );
430     }
431     if ( mxMetadataDate->get_label() != sMeta )
432     {
433         mxMetadataDate->set_label(sMeta);
434     }
435 
436     std::size_t aIndex = SW_MOD()->InsertRedlineAuthor(GetAuthor());
437     SetColor( SwPostItMgr::GetColorDark(aIndex),
438               SwPostItMgr::GetColorLight(aIndex),
439               SwPostItMgr::GetColorAnchor(aIndex));
440 }
441 
ColorFromAlphaColor(const sal_uInt8 aTransparency,const Color & aFront,const Color & aBack)442 static Color ColorFromAlphaColor(const sal_uInt8 aTransparency, const Color& aFront, const Color& aBack)
443 {
444     return Color(sal_uInt8(aFront.GetRed()   * aTransparency / 255.0 + aBack.GetRed()   * (1 - aTransparency / 255.0)),
445                  sal_uInt8(aFront.GetGreen() * aTransparency / 255.0 + aBack.GetGreen() * (1 - aTransparency / 255.0)),
446                  sal_uInt8(aFront.GetBlue()  * aTransparency / 255.0 + aBack.GetBlue()  * (1 - aTransparency / 255.0)));
447 }
448 
SetMenuButtonColors()449 void SwAnnotationWin::SetMenuButtonColors()
450 {
451     if (!mxMenuButton)
452         return;
453 
454     mxMenuButton->set_background(mColorDark);
455 
456     const Fraction& rFraction = mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY();
457 
458     ScopedVclPtrInstance<VirtualDevice> xVirDev;
459     Size aSize(tools::Long(METABUTTON_WIDTH * rFraction),
460                tools::Long(METABUTTON_HEIGHT * rFraction));
461     tools::Rectangle aRect(Point(0, 0), aSize);
462     xVirDev->SetOutputSizePixel(aSize);
463 
464     Gradient aGradient(GradientStyle::Linear,
465                              ColorFromAlphaColor(15, mColorAnchor, mColorDark),
466                              ColorFromAlphaColor(80, mColorAnchor, mColorDark));
467     xVirDev->DrawGradient(aRect, aGradient);
468 
469     //draw rect around button
470     xVirDev->SetFillColor();
471     xVirDev->SetLineColor(ColorFromAlphaColor(90, mColorAnchor, mColorDark));
472     xVirDev->DrawRect(aRect);
473 
474     tools::Rectangle aSymbolRect(aRect);
475     // 25% distance to the left and right button border
476     const tools::Long nBorderDistanceLeftAndRight = ((aSymbolRect.GetWidth() * 250) + 500) / 1000;
477     aSymbolRect.AdjustLeft(nBorderDistanceLeftAndRight );
478     aSymbolRect.AdjustRight( -nBorderDistanceLeftAndRight );
479     // 40% distance to the top button border
480     const tools::Long nBorderDistanceTop = ((aSymbolRect.GetHeight() * 400) + 500) / 1000;
481     aSymbolRect.AdjustTop(nBorderDistanceTop );
482     // 15% distance to the bottom button border
483     const tools::Long nBorderDistanceBottom = ((aSymbolRect.GetHeight() * 150) + 500) / 1000;
484     aSymbolRect.AdjustBottom( -nBorderDistanceBottom );
485     DecorationView aDecoView(xVirDev.get());
486     aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, GetTextColor(),
487                          DrawSymbolFlags::NONE);
488     mxMenuButton->set_image(xVirDev);
489     mxMenuButton->set_size_request(aSize.Width() + 4, aSize.Height() + 4);
490 }
491 
Rescale()492 void SwAnnotationWin::Rescale()
493 {
494     // On Android, this method leads to invoke ImpEditEngine::UpdateViews
495     // which hides the text cursor. Moreover it causes sudden document scroll
496     // when modifying a commented text. Not clear the root cause,
497     // anyway skipping this method fixes the problem, and there should be
498     // no side effect, since the client has disabled annotations rendering.
499     if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
500         return;
501 
502     MapMode aMode = GetParent()->GetMapMode();
503     aMode.SetOrigin( Point() );
504     mpOutliner->SetRefMapMode( aMode );
505     SetMapMode( aMode );
506     mxSidebarTextControl->SetMapMode( aMode );
507     const Fraction& rFraction = mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY();
508 
509     vcl::Font aFont = maLabelFont;
510     sal_Int32 nHeight = tools::Long(aFont.GetFontHeight() * rFraction);
511     aFont.SetFontHeight( nHeight );
512 
513     if (mxMetadataAuthor)
514         mxMetadataAuthor->set_font(aFont);
515     if (mxMetadataDate)
516         mxMetadataDate->set_font(aFont);
517     if (mxMetadataResolved)
518         mxMetadataResolved->set_font(aFont);
519     SetMenuButtonColors();
520     if (mxVScrollbar)
521         mxVScrollbar->set_scroll_thickness(GetPrefScrollbarWidth());
522 }
523 
SetPosAndSize()524 void SwAnnotationWin::SetPosAndSize()
525 {
526     bool bChange = false;
527 
528     if (GetSizePixel() != mPosSize.GetSize())
529     {
530         bChange = true;
531         SetSizePixel(mPosSize.GetSize());
532 
533         DoResize();
534     }
535 
536     if (GetPosPixel().X() != mPosSize.Left() || (std::abs(GetPosPixel().Y() - mPosSize.Top()) > 5) )
537     {
538         bChange = true;
539         SetPosPixel(mPosSize.TopLeft());
540 
541         Point aLineStart;
542         Point aLineEnd ;
543         switch ( meSidebarPosition )
544         {
545             case sw::sidebarwindows::SidebarPosition::LEFT:
546             {
547                 aLineStart = EditWin().PixelToLogic( Point(GetPosPixel().X()+GetSizePixel().Width(),GetPosPixel().Y()-1) );
548                 aLineEnd = EditWin().PixelToLogic( Point(GetPosPixel().X(),GetPosPixel().Y()-1) );
549             }
550             break;
551             case sw::sidebarwindows::SidebarPosition::RIGHT:
552             {
553                 aLineStart = EditWin().PixelToLogic( Point(GetPosPixel().X(),GetPosPixel().Y()-1) );
554                 aLineEnd = EditWin().PixelToLogic( Point(GetPosPixel().X()+GetSizePixel().Width(),GetPosPixel().Y()-1) );
555             }
556             break;
557             default:
558                 OSL_FAIL( "<SwAnnotationWin::SetPosAndSize()> - unexpected position of sidebar" );
559             break;
560         }
561 
562         // LOK has map mode disabled, and we still want to perform pixel ->
563         // twips conversion for the size of the line above the note.
564         if (comphelper::LibreOfficeKit::isActive() && !EditWin().IsMapModeEnabled())
565         {
566             EditWin().EnableMapMode();
567             Size aSize(aLineEnd.getX() - aLineStart.getX(), aLineEnd.getY() - aLineStart.getY());
568             aSize = EditWin().PixelToLogic(aSize);
569             aLineEnd = aLineStart;
570             aLineEnd.Move(aSize.getWidth(), aSize.getHeight());
571             EditWin().EnableMapMode(false);
572         }
573 
574         if (mpAnchor)
575         {
576             mpAnchor->SetAllPosition( basegfx::B2DPoint( mAnchorRect.Left() , mAnchorRect.Bottom() - 5* 15),
577                                       basegfx::B2DPoint( mAnchorRect.Left()-5*15 , mAnchorRect.Bottom()+5*15),
578                                       basegfx::B2DPoint( mAnchorRect.Left()+5*15 , mAnchorRect.Bottom()+5*15),
579                                       basegfx::B2DPoint( mAnchorRect.Left(), mAnchorRect.Bottom()+2*15),
580                                       basegfx::B2DPoint( mPageBorder ,mAnchorRect.Bottom()+2*15),
581                                       basegfx::B2DPoint( aLineStart.X(),aLineStart.Y()),
582                                       basegfx::B2DPoint( aLineEnd.X(),aLineEnd.Y()));
583         }
584         else
585         {
586             mpAnchor = AnchorOverlayObject::CreateAnchorOverlayObject( mrView,
587                                                                        mAnchorRect,
588                                                                        mPageBorder,
589                                                                        aLineStart,
590                                                                        aLineEnd,
591                                                                        mColorAnchor );
592             if ( mpAnchor )
593             {
594                 mpAnchor->setVisible(true);
595                 mpAnchor->SetAnchorState(AnchorState::Tri);
596                 if (HasChildPathFocus())
597                 {
598                     mpAnchor->setLineSolid(true);
599                 }
600             }
601         }
602     }
603     else
604     {
605         if ( mpAnchor &&
606              ( mpAnchor->getBasePosition() != basegfx::B2DPoint( mAnchorRect.Left() , mAnchorRect.Bottom()-5*15) ) )
607         {
608             mpAnchor->SetTriPosition( basegfx::B2DPoint( mAnchorRect.Left() , mAnchorRect.Bottom() - 5* 15),
609                                       basegfx::B2DPoint( mAnchorRect.Left()-5*15 , mAnchorRect.Bottom()+5*15),
610                                       basegfx::B2DPoint( mAnchorRect.Left()+5*15 , mAnchorRect.Bottom()+5*15),
611                                       basegfx::B2DPoint( mAnchorRect.Left(), mAnchorRect.Bottom()+2*15),
612                                       basegfx::B2DPoint( mPageBorder , mAnchorRect.Bottom()+2*15));
613         }
614     }
615 
616     if (mpShadow && bChange)
617     {
618         Point aStart = EditWin().PixelToLogic(GetPosPixel()+Point(0,GetSizePixel().Height()));
619         Point aEnd = EditWin().PixelToLogic(GetPosPixel()+Point(GetSizePixel().Width()-1,GetSizePixel().Height()));
620         mpShadow->SetPosition(basegfx::B2DPoint(aStart.X(),aStart.Y()), basegfx::B2DPoint(aEnd.X(),aEnd.Y()));
621     }
622 
623     if (mrMgr.ShowNotes())
624     {
625         if (IsFollow() && !HasChildPathFocus())
626         {
627             // #i111964#
628             if ( mpAnchor )
629             {
630                 mpAnchor->SetAnchorState(AnchorState::End);
631             }
632         }
633         else
634         {
635             // #i111964#
636             if ( mpAnchor )
637             {
638                 mpAnchor->SetAnchorState(AnchorState::All);
639             }
640             SwAnnotationWin* pWin = GetTopReplyNote();
641             // #i111964#
642             if ( pWin != this && pWin->Anchor() )
643             {
644                 pWin->Anchor()->SetAnchorState(AnchorState::End);
645             }
646         }
647     }
648 
649 
650     // text range overlay
651     maAnnotationTextRanges.clear();
652     if ( mrSidebarItem.maLayoutInfo.mnStartNodeIdx != 0
653          && mrSidebarItem.maLayoutInfo.mnStartContent != -1 )
654     {
655         const SwTextAnnotationField* pTextAnnotationField =
656             dynamic_cast< const SwTextAnnotationField* >( mrSidebarItem.GetFormatField().GetTextField() );
657         SwTextNode* pTextNode = pTextAnnotationField ? pTextAnnotationField->GetpTextNode() : nullptr;
658         SwContentNode* pContentNd = nullptr;
659         if (pTextNode)
660         {
661             SwNodes& rNds = pTextNode->GetDoc().GetNodes();
662             pContentNd = rNds[mrSidebarItem.maLayoutInfo.mnStartNodeIdx]->GetContentNode();
663         }
664         if (pContentNd)
665         {
666             SwPosition aStartPos( *pContentNd, mrSidebarItem.maLayoutInfo.mnStartContent );
667             SwShellCursor* pTmpCursor = nullptr;
668             const bool bTableCursorNeeded = pTextNode->FindTableBoxStartNode() != pContentNd->FindTableBoxStartNode();
669             if ( bTableCursorNeeded )
670             {
671                 SwShellTableCursor* pTableCursor = new SwShellTableCursor( mrView.GetWrtShell(), aStartPos );
672                 pTableCursor->SetMark();
673                 pTableCursor->GetMark()->nNode = *pTextNode;
674                 pTableCursor->GetMark()->nContent.Assign( pTextNode, pTextAnnotationField->GetStart()+1 );
675                 pTableCursor->NewTableSelection();
676                 pTmpCursor = pTableCursor;
677             }
678             else
679             {
680                 SwShellCursor* pCursor = new SwShellCursor( mrView.GetWrtShell(), aStartPos );
681                 pCursor->SetMark();
682                 pCursor->GetMark()->nNode = *pTextNode;
683                 pCursor->GetMark()->nContent.Assign( pTextNode, pTextAnnotationField->GetStart()+1 );
684                 pTmpCursor = pCursor;
685             }
686             std::unique_ptr<SwShellCursor> pTmpCursorForAnnotationTextRange( pTmpCursor );
687 
688             // For annotation text range rectangles to be calculated correctly,
689             // we need the map mode disabled
690             bool bDisableMapMode = comphelper::LibreOfficeKit::isActive() && EditWin().IsMapModeEnabled();
691             if (bDisableMapMode)
692                 EditWin().EnableMapMode(false);
693 
694             if (mrSidebarItem.maLayoutInfo.mPositionFromCommentAnchor)
695                 pTmpCursorForAnnotationTextRange->FillRects();
696 
697             if (bDisableMapMode)
698                 EditWin().EnableMapMode();
699 
700             SwRects* pRects(pTmpCursorForAnnotationTextRange.get());
701             for(const SwRect & rNextRect : *pRects)
702             {
703                 const tools::Rectangle aPntRect(rNextRect.SVRect());
704                 maAnnotationTextRanges.emplace_back(
705                     aPntRect.Left(), aPntRect.Top(),
706                     aPntRect.Right() + 1, aPntRect.Bottom() + 1);
707             }
708         }
709     }
710 
711     if (mrMgr.ShowNotes() && !maAnnotationTextRanges.empty())
712     {
713         if ( mpTextRangeOverlay != nullptr )
714         {
715             mpTextRangeOverlay->setRanges( maAnnotationTextRanges );
716             if ( mpAnchor != nullptr && mpAnchor->getLineSolid() )
717             {
718                 mpTextRangeOverlay->ShowSolidBorder();
719             }
720             else
721             {
722                 mpTextRangeOverlay->HideSolidBorder();
723             }
724         }
725         else if (!IsFollow())
726         {
727             // This window is not a reply, then draw its range overlay.
728             mpTextRangeOverlay =
729                 sw::overlay::OverlayRanges::CreateOverlayRange(
730                     mrView,
731                     mColorAnchor,
732                     maAnnotationTextRanges,
733                     mpAnchor && mpAnchor->getLineSolid() );
734         }
735     }
736     else
737     {
738         mpTextRangeOverlay.reset();
739     }
740 }
741 
DoResize()742 void SwAnnotationWin::DoResize()
743 {
744     tools::Long aHeight = GetSizePixel().Height();
745     tools::ULong aWidth = GetSizePixel().Width();
746 
747     aHeight -= GetMetaHeight();
748 
749     mpOutliner->SetPaperSize( PixelToLogic( Size(aWidth, aHeight) ) ) ;
750     tools::Long aTextHeight = LogicToPixel( mpOutliner->CalcTextSize()).Height();
751 
752     mxMetadataAuthor->show();
753     if(IsResolved()) { mxMetadataResolved->show(); }
754     mxMetadataDate->show();
755 
756     if (aTextHeight > aHeight)
757     {
758         const int nThickness = mxVScrollbar->get_scroll_thickness();
759         if (nThickness)
760         {
761             // we need vertical scrollbars and have to reduce the width
762             aWidth -= nThickness;
763             mpOutliner->SetPaperSize(PixelToLogic(Size(aWidth, aHeight)));
764         }
765         mxVScrollbar->set_vpolicy(VclPolicyType::ALWAYS);
766     }
767     else
768     {
769         mxVScrollbar->set_vpolicy(VclPolicyType::NEVER);
770     }
771 
772     tools::Rectangle aOutputArea = PixelToLogic(tools::Rectangle(0, 0, aWidth, aHeight));
773     if (mxVScrollbar->get_vpolicy() == VclPolicyType::NEVER)
774     {
775         // if we do not have a scrollbar anymore, we want to see the complete text
776         mpOutlinerView->SetVisArea(aOutputArea);
777     }
778     mpOutlinerView->SetOutputArea(aOutputArea);
779     mpOutlinerView->ShowCursor(true, true);
780 
781     // Don't leave an empty area at the bottom if we can move the text down.
782     tools::Long nMaxVisAreaTop = mpOutliner->GetTextHeight() - aOutputArea.GetHeight();
783     if (mpOutlinerView->GetVisArea().Top() > nMaxVisAreaTop)
784     {
785         GetOutlinerView()->Scroll(0, mpOutlinerView->GetVisArea().Top() - nMaxVisAreaTop);
786     }
787 
788     int nUpper = mpOutliner->GetTextHeight();
789     int nCurrentDocPos = mpOutlinerView->GetVisArea().Top();
790     int nStepIncrement = mpOutliner->GetTextHeight() / 10;
791     int nPageIncrement = PixelToLogic(Size(0,aHeight)).Height() * 8 / 10;
792     int nPageSize = PixelToLogic(Size(0,aHeight)).Height();
793 
794     /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
795        effectively...
796 
797        lower = gtk_adjustment_get_lower
798        upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
799 
800        and requires that upper > lower or the deceleration animation never ends
801     */
802     nPageSize = std::min(nPageSize, nUpper);
803 
804     mxVScrollbar->vadjustment_configure(nCurrentDocPos, 0, nUpper,
805                                         nStepIncrement, nPageIncrement, nPageSize);
806 }
807 
SetSizePixel(const Size & rNewSize)808 void SwAnnotationWin::SetSizePixel( const Size& rNewSize )
809 {
810     InterimItemWindow::SetSizePixel(rNewSize);
811 
812     if (mpShadow)
813     {
814         Point aStart = EditWin().PixelToLogic(GetPosPixel()+Point(0,GetSizePixel().Height()));
815         Point aEnd = EditWin().PixelToLogic(GetPosPixel()+Point(GetSizePixel().Width()-1,GetSizePixel().Height()));
816         mpShadow->SetPosition(basegfx::B2DPoint(aStart.X(),aStart.Y()), basegfx::B2DPoint(aEnd.X(),aEnd.Y()));
817     }
818 }
819 
SetScrollbar()820 void SwAnnotationWin::SetScrollbar()
821 {
822     mxVScrollbar->vadjustment_set_value(mpOutlinerView->GetVisArea().Top());
823 }
824 
ResizeIfNecessary(tools::Long aOldHeight,tools::Long aNewHeight)825 void SwAnnotationWin::ResizeIfNecessary(tools::Long aOldHeight, tools::Long aNewHeight)
826 {
827     if (aOldHeight != aNewHeight)
828     {
829         //check for lower border or next note
830         tools::Long aBorder = mrMgr.GetNextBorder();
831         if (aBorder != -1)
832         {
833             if (aNewHeight > GetMinimumSizeWithoutMeta())
834             {
835                 tools::Long aNewLowerValue = GetPosPixel().Y() + aNewHeight + GetMetaHeight();
836                 if (aNewLowerValue < aBorder)
837                     SetSizePixel(Size(GetSizePixel().Width(),aNewHeight+GetMetaHeight()));
838                 else
839                     SetSizePixel(Size(GetSizePixel().Width(),aBorder - GetPosPixel().Y()));
840                 DoResize();
841                 Invalidate();
842             }
843             else
844             {
845                 if (GetSizePixel().Height() != GetMinimumSizeWithoutMeta() + GetMetaHeight())
846                     SetSizePixel(Size(GetSizePixel().Width(),GetMinimumSizeWithoutMeta() + GetMetaHeight()));
847                 DoResize();
848                 Invalidate();
849             }
850         }
851         else
852         {
853             DoResize();
854             Invalidate();
855         }
856     }
857     else
858     {
859         SetScrollbar();
860     }
861 }
862 
SetColor(Color aColorDark,Color aColorLight,Color aColorAnchor)863 void SwAnnotationWin::SetColor(Color aColorDark,Color aColorLight, Color aColorAnchor)
864 {
865     mColorDark =  aColorDark;
866     mColorLight = aColorLight;
867     mColorAnchor = aColorAnchor;
868 
869     if ( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
870         return;
871 
872     m_xContainer->set_background(mColorDark);
873     SetMenuButtonColors();
874 
875     mxMetadataAuthor->set_font_color(aColorAnchor);
876 
877     mxMetadataDate->set_font_color(aColorAnchor);
878 
879     mxMetadataResolved->set_font_color(aColorAnchor);
880 
881     mxVScrollbar->customize_scrollbars(mColorLight,
882                                        mColorAnchor,
883                                        mColorDark);
884 }
885 
SetSidebarPosition(sw::sidebarwindows::SidebarPosition eSidebarPosition)886 void SwAnnotationWin::SetSidebarPosition(sw::sidebarwindows::SidebarPosition eSidebarPosition)
887 {
888     meSidebarPosition = eSidebarPosition;
889 }
890 
SetReadonly(bool bSet)891 void SwAnnotationWin::SetReadonly(bool bSet)
892 {
893     mbReadonly = bSet;
894     GetOutlinerView()->SetReadOnly(bSet);
895 }
896 
SetLanguage(const SvxLanguageItem & rNewItem)897 void SwAnnotationWin::SetLanguage(const SvxLanguageItem& rNewItem)
898 {
899     IDocumentUndoRedo& rUndoRedo(
900         mrView.GetDocShell()->GetDoc()->GetIDocumentUndoRedo());
901     const bool bDocUndoEnabled = rUndoRedo.DoesUndo();
902     const bool bOutlinerUndoEnabled = mpOutliner->IsUndoEnabled();
903     const bool bOutlinerModified = mpOutliner->IsModified();
904     const bool bDisableAndRestoreUndoMode = !bDocUndoEnabled && bOutlinerUndoEnabled;
905 
906     if (bDisableAndRestoreUndoMode)
907     {
908         // doc undo is disabled, but outliner was enabled, turn outliner undo off
909         // for the duration of this function
910         mpOutliner->EnableUndo(false);
911     }
912 
913     Link<LinkParamNone*,void> aLink = mpOutliner->GetModifyHdl();
914     mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
915     ESelection aOld = GetOutlinerView()->GetSelection();
916 
917     ESelection aNewSelection( 0, 0, mpOutliner->GetParagraphCount()-1, EE_TEXTPOS_ALL );
918     GetOutlinerView()->SetSelection( aNewSelection );
919     SfxItemSet aEditAttr(GetOutlinerView()->GetAttribs());
920     aEditAttr.Put(rNewItem);
921     GetOutlinerView()->SetAttribs( aEditAttr );
922 
923     if (!mpOutliner->IsUndoEnabled() && !bOutlinerModified)
924     {
925         // if undo was disabled (e.g. this is a redo action) and we were
926         // originally 'unmodified' keep it that way
927         mpOutliner->ClearModifyFlag();
928     }
929 
930     GetOutlinerView()->SetSelection(aOld);
931     mpOutliner->SetModifyHdl( aLink );
932 
933     const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
934     EEControlBits nCntrl = mpOutliner->GetControlWord();
935     // turn off
936     nCntrl &= ~EEControlBits::ONLINESPELLING;
937     mpOutliner->SetControlWord(nCntrl);
938 
939     //turn back on
940     if (pVOpt->IsOnlineSpell())
941         nCntrl |= EEControlBits::ONLINESPELLING;
942     else
943         nCntrl &= ~EEControlBits::ONLINESPELLING;
944     mpOutliner->SetControlWord(nCntrl);
945 
946     mpOutliner->CompleteOnlineSpelling();
947 
948     // restore original mode
949     if (bDisableAndRestoreUndoMode)
950         mpOutliner->EnableUndo(true);
951 
952     Invalidate();
953 }
954 
GetFocus()955 void SwAnnotationWin::GetFocus()
956 {
957     if (mxSidebarTextControl)
958         mxSidebarTextControl->GrabFocus();
959 }
960 
LoseFocus()961 void SwAnnotationWin::LoseFocus()
962 {
963 }
964 
ShowNote()965 void SwAnnotationWin::ShowNote()
966 {
967     SetPosAndSize();
968     if (!IsVisible())
969         Window::Show();
970     if (mpShadow && !mpShadow->isVisible())
971         mpShadow->setVisible(true);
972     if (mpAnchor && !mpAnchor->isVisible())
973         mpAnchor->setVisible(true);
974     if (mpTextRangeOverlay && !mpTextRangeOverlay->isVisible())
975         mpTextRangeOverlay->setVisible(true);
976 
977     collectUIInformation("SHOW",get_id());
978 }
979 
HideNote()980 void SwAnnotationWin::HideNote()
981 {
982     if (IsVisible())
983         Window::Hide();
984     if (mpAnchor)
985     {
986         if (mrMgr.IsShowAnchor())
987             mpAnchor->SetAnchorState(AnchorState::Tri);
988         else
989             mpAnchor->setVisible(false);
990     }
991     if (mpShadow && mpShadow->isVisible())
992         mpShadow->setVisible(false);
993     if (mpTextRangeOverlay && mpTextRangeOverlay->isVisible())
994         mpTextRangeOverlay->setVisible(false);
995     collectUIInformation("HIDE",get_id());
996 }
997 
ActivatePostIt()998 void SwAnnotationWin::ActivatePostIt()
999 {
1000     mrMgr.AssureStdModeAtShell();
1001 
1002     mpOutliner->ClearModifyFlag();
1003     mpOutliner->GetUndoManager().Clear();
1004 
1005     CheckMetaText();
1006     SetViewState(ViewState::EDIT);
1007     GetOutlinerView()->ShowCursor();
1008 
1009     mpOutlinerView->GetEditView().SetInsertMode(mrView.GetWrtShellPtr()->IsInsMode());
1010 
1011     if ( !Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1012         GetOutlinerView()->SetBackgroundColor(mColorDark);
1013 
1014     //tdf#119130 only have the active postit as a dialog control in which pressing
1015     //ctrl+tab cycles between text and button so we don't waste time searching
1016     //thousands of SwAnnotationWins
1017     SetStyle(GetStyle() | WB_DIALOGCONTROL);
1018 }
1019 
DeactivatePostIt()1020 void SwAnnotationWin::DeactivatePostIt()
1021 {
1022     //tdf#119130 only have the active postit as a dialog control in which pressing
1023     //ctrl+tab cycles between text and button so we don't waste time searching
1024     //thousands of SwAnnotationWins
1025     SetStyle(GetStyle() & ~WB_DIALOGCONTROL);
1026 
1027     // remove selection, #i87073#
1028     if (GetOutlinerView()->GetEditView().HasSelection())
1029     {
1030         ESelection aSelection = GetOutlinerView()->GetEditView().GetSelection();
1031         aSelection.nEndPara = aSelection.nStartPara;
1032         aSelection.nEndPos = aSelection.nStartPos;
1033         GetOutlinerView()->GetEditView().SetSelection(aSelection);
1034     }
1035 
1036     mpOutliner->CompleteOnlineSpelling();
1037 
1038     SetViewState(ViewState::NORMAL);
1039     // Make sure this view doesn't emit LOK callbacks during the update, as the
1040     // sidebar window's SidebarTextControl doesn't have a valid twip offset
1041     // (map mode origin) during that operation.
1042     bool bTiledPainting = comphelper::LibreOfficeKit::isTiledPainting();
1043     comphelper::LibreOfficeKit::setTiledPainting(true);
1044     // write the visible text back into the SwField
1045     UpdateData();
1046     comphelper::LibreOfficeKit::setTiledPainting(bTiledPainting);
1047 
1048     if ( !Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1049         GetOutlinerView()->SetBackgroundColor(COL_TRANSPARENT);
1050 
1051     if (!mnEventId && !IsProtected() && mpOutliner->GetEditEngine().GetText().isEmpty())
1052     {
1053         mnEventId = Application::PostUserEvent( LINK( this, SwAnnotationWin, DeleteHdl), nullptr, true );
1054     }
1055 }
1056 
ToggleInsMode()1057 void SwAnnotationWin::ToggleInsMode()
1058 {
1059     if (!mrView.GetWrtShell().IsRedlineOn())
1060     {
1061         //change outliner
1062         mpOutlinerView->GetEditView().SetInsertMode(!mpOutlinerView->GetEditView().IsInsertMode());
1063         //change document
1064         mrView.GetWrtShell().ToggleInsMode();
1065         //update statusbar
1066         SfxBindings &rBnd = mrView.GetViewFrame()->GetBindings();
1067         rBnd.Invalidate(SID_ATTR_INSERT);
1068         rBnd.Update(SID_ATTR_INSERT);
1069     }
1070 }
1071 
ExecuteCommand(sal_uInt16 nSlot)1072 void SwAnnotationWin::ExecuteCommand(sal_uInt16 nSlot)
1073 {
1074     mrMgr.AssureStdModeAtShell();
1075 
1076     switch (nSlot)
1077     {
1078         case FN_POSTIT:
1079         case FN_REPLY:
1080         {
1081             // if this note is empty, it will be deleted once losing the focus, so no reply, but only a new note
1082             // will be created
1083             if (!mpOutliner->GetEditEngine().GetText().isEmpty())
1084             {
1085                 OutlinerParaObject* pPara = new OutlinerParaObject(GetOutlinerView()->GetEditView().CreateTextObject());
1086                 mrMgr.RegisterAnswer(pPara);
1087             }
1088             if (mrMgr.HasActiveSidebarWin())
1089                 mrMgr.SetActiveSidebarWin(nullptr);
1090             SwitchToFieldPos();
1091             mrView.GetViewFrame()->GetDispatcher()->Execute(FN_POSTIT);
1092             break;
1093         }
1094         case FN_DELETE_COMMENT:
1095             //Delete(); // do not kill the parent of our open popup menu
1096             mnEventId = Application::PostUserEvent( LINK( this, SwAnnotationWin, DeleteHdl), nullptr, true );
1097             break;
1098         case FN_DELETE_COMMENT_THREAD:
1099             DeleteThread();
1100             break;
1101         case FN_RESOLVE_NOTE:
1102             ToggleResolved();
1103             DoResize();
1104             Invalidate();
1105             mrMgr.LayoutPostIts();
1106             break;
1107         case FN_RESOLVE_NOTE_THREAD:
1108             GetTopReplyNote()->SetResolved(!IsThreadResolved());
1109             mrMgr.UpdateResolvedStatus(GetTopReplyNote());
1110             DoResize();
1111             Invalidate();
1112             mrMgr.LayoutPostIts();
1113             break;
1114         case FN_FORMAT_ALL_NOTES:
1115         case FN_DELETE_ALL_NOTES:
1116         case FN_HIDE_ALL_NOTES:
1117             // not possible as slot as this would require that "this" is the active postit
1118             mrView.GetViewFrame()->GetBindings().Execute( nSlot, nullptr, SfxCallMode::ASYNCHRON );
1119             break;
1120         case FN_DELETE_NOTE_AUTHOR:
1121         case FN_HIDE_NOTE_AUTHOR:
1122         {
1123             // not possible as slot as this would require that "this" is the active postit
1124             SfxStringItem aItem( nSlot, GetAuthor() );
1125             const SfxPoolItem* aItems[2];
1126             aItems[0] = &aItem;
1127             aItems[1] = nullptr;
1128             mrView.GetViewFrame()->GetBindings().Execute( nSlot, aItems, SfxCallMode::ASYNCHRON );
1129         }
1130             break;
1131         default:
1132             mrView.GetViewFrame()->GetBindings().Execute( nSlot );
1133             break;
1134     }
1135 }
1136 
EditWin()1137 SwEditWin&  SwAnnotationWin::EditWin()
1138 {
1139     return mrView.GetEditWin();
1140 }
1141 
GetPostItTextHeight()1142 tools::Long SwAnnotationWin::GetPostItTextHeight()
1143 {
1144     return mpOutliner ? LogicToPixel(mpOutliner->CalcTextSize()).Height() : 0;
1145 }
1146 
SwitchToPostIt(sal_uInt16 aDirection)1147 void SwAnnotationWin::SwitchToPostIt(sal_uInt16 aDirection)
1148 {
1149     SwAnnotationWin* pPostIt = mrMgr.GetNextPostIt(aDirection, this);
1150     if (pPostIt)
1151         pPostIt->GrabFocus();
1152 }
1153 
IMPL_LINK(SwAnnotationWin,MouseMoveHdl,const MouseEvent &,rMEvt,bool)1154 IMPL_LINK(SwAnnotationWin, MouseMoveHdl, const MouseEvent&, rMEvt, bool)
1155 {
1156     if (rMEvt.IsEnterWindow())
1157     {
1158         mbMouseOver = true;
1159         if ( !HasFocus() )
1160         {
1161             SetViewState(ViewState::VIEW);
1162             Invalidate();
1163         }
1164     }
1165     else if (rMEvt.IsLeaveWindow())
1166     {
1167         mbMouseOver = false;
1168         if ( !HasFocus() )
1169         {
1170             SetViewState(ViewState::NORMAL);
1171             Invalidate();
1172         }
1173     }
1174     return false;
1175 }
1176 
SetActiveSidebarWin()1177 bool SwAnnotationWin::SetActiveSidebarWin()
1178 {
1179     if (mrMgr.GetActiveSidebarWin() == this)
1180         return false;
1181     const bool bLockView = mrView.GetWrtShell().IsViewLocked();
1182     mrView.GetWrtShell().LockView( true );
1183     mrMgr.SetActiveSidebarWin(this);
1184     mrView.GetWrtShell().LockView( bLockView );
1185     return true;
1186 }
1187 
UnsetActiveSidebarWin()1188 void SwAnnotationWin::UnsetActiveSidebarWin()
1189 {
1190     if (mrMgr.GetActiveSidebarWin() != this)
1191         return;
1192     const bool bLockView = mrView.GetWrtShell().IsViewLocked();
1193     mrView.GetWrtShell().LockView( true );
1194     mrMgr.SetActiveSidebarWin(nullptr);
1195     mrView.GetWrtShell().LockView( bLockView );
1196 }
1197 
IMPL_LINK(SwAnnotationWin,ScrollHdl,weld::ScrolledWindow &,rScrolledWindow,void)1198 IMPL_LINK(SwAnnotationWin, ScrollHdl, weld::ScrolledWindow&, rScrolledWindow, void)
1199 {
1200     tools::Long nDiff = GetOutlinerView()->GetEditView().GetVisArea().Top() - rScrolledWindow.vadjustment_get_value();
1201     GetOutlinerView()->Scroll( 0, nDiff );
1202 }
1203 
IMPL_LINK_NOARG(SwAnnotationWin,ModifyHdl,LinkParamNone *,void)1204 IMPL_LINK_NOARG(SwAnnotationWin, ModifyHdl, LinkParamNone*, void)
1205 {
1206     mrView.GetDocShell()->SetModified();
1207 }
1208 
IMPL_LINK_NOARG(SwAnnotationWin,DeleteHdl,void *,void)1209 IMPL_LINK_NOARG(SwAnnotationWin, DeleteHdl, void*, void)
1210 {
1211     mnEventId = nullptr;
1212     Delete();
1213 }
1214 
ResetAttributes()1215 void SwAnnotationWin::ResetAttributes()
1216 {
1217     mpOutlinerView->RemoveAttribsKeepLanguages(true);
1218     mpOutliner->RemoveFields();
1219     mpOutlinerView->SetAttribs(DefaultItem());
1220 }
1221 
GetPrefScrollbarWidth() const1222 int SwAnnotationWin::GetPrefScrollbarWidth() const
1223 {
1224     const Fraction& f(mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY());
1225     return tools::Long(Application::GetSettings().GetStyleSettings().GetScrollBarSize() * f);
1226 }
1227 
GetMetaHeight() const1228 sal_Int32 SwAnnotationWin::GetMetaHeight() const
1229 {
1230     const int fields = GetNumFields();
1231 
1232     const Fraction& f(mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY());
1233     sal_Int32 nClassicHeight(fields * POSTIT_META_FIELD_HEIGHT * f);
1234 
1235     sal_Int32 nRequiredHeight = 0;
1236     weld::Label* aLabels[3] = { mxMetadataAuthor.get(), mxMetadataDate.get(), mxMetadataResolved.get() };
1237     for (int i = 0; i < fields; ++i)
1238         nRequiredHeight += aLabels[i]->get_preferred_size().Height();
1239 
1240     return std::max(nClassicHeight, nRequiredHeight);
1241 }
1242 
GetNumFields() const1243 sal_Int32 SwAnnotationWin::GetNumFields() const
1244 {
1245     return IsResolved() ? 3 : 2;
1246 }
1247 
GetMinimumSizeWithMeta() const1248 sal_Int32 SwAnnotationWin::GetMinimumSizeWithMeta() const
1249 {
1250     return mrMgr.GetMinimumSizeWithMeta();
1251 }
1252 
GetMinimumSizeWithoutMeta() const1253 sal_Int32 SwAnnotationWin::GetMinimumSizeWithoutMeta() const
1254 {
1255     const Fraction& f(mrView.GetWrtShellPtr()->GetOut()->GetMapMode().GetScaleY());
1256     return tools::Long(POSTIT_MINIMUMSIZE_WITHOUT_META * f);
1257 }
1258 
SetSpellChecking()1259 void SwAnnotationWin::SetSpellChecking()
1260 {
1261     const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
1262     EEControlBits nCntrl = mpOutliner->GetControlWord();
1263     if (pVOpt->IsOnlineSpell())
1264         nCntrl |= EEControlBits::ONLINESPELLING;
1265     else
1266         nCntrl &= ~EEControlBits::ONLINESPELLING;
1267     mpOutliner->SetControlWord(nCntrl);
1268 
1269     mpOutliner->CompleteOnlineSpelling();
1270     Invalidate();
1271 }
1272 
SetViewState(ViewState bViewState)1273 void SwAnnotationWin::SetViewState(ViewState bViewState)
1274 {
1275     switch (bViewState)
1276     {
1277         case ViewState::EDIT:
1278         {
1279             if (mpAnchor)
1280             {
1281                 mpAnchor->SetAnchorState(AnchorState::All);
1282                 SwAnnotationWin* pWin = GetTopReplyNote();
1283                 // #i111964#
1284                 if ( pWin != this && pWin->Anchor() )
1285                 {
1286                     pWin->Anchor()->SetAnchorState(AnchorState::End);
1287                 }
1288                 mpAnchor->setLineSolid(true);
1289                 if ( mpTextRangeOverlay != nullptr )
1290                 {
1291                     mpTextRangeOverlay->ShowSolidBorder();
1292                 }
1293             }
1294             if (mpShadow)
1295                 mpShadow->SetShadowState(SS_EDIT);
1296             break;
1297         }
1298         case ViewState::VIEW:
1299         {
1300             if (mpAnchor)
1301             {
1302                 mpAnchor->setLineSolid(true);
1303                 if ( mpTextRangeOverlay != nullptr )
1304                 {
1305                     mpTextRangeOverlay->ShowSolidBorder();
1306                 }
1307             }
1308             if (mpShadow)
1309                 mpShadow->SetShadowState(SS_VIEW);
1310             break;
1311         }
1312         case ViewState::NORMAL:
1313         {
1314             if (mpAnchor)
1315             {
1316                 if (IsFollow())
1317                 {
1318                     // if there is no visible parent note, we want to see the complete anchor ??
1319                     //if (IsAnyStackParentVisible())
1320                     mpAnchor->SetAnchorState(AnchorState::End);
1321                     SwAnnotationWin* pTopWinSelf = GetTopReplyNote();
1322                     SwAnnotationWin* pTopWinActive = mrMgr.HasActiveSidebarWin()
1323                                                   ? mrMgr.GetActiveSidebarWin()->GetTopReplyNote()
1324                                                   : nullptr;
1325                     // #i111964#
1326                     if ( ( pTopWinSelf != this ) &&
1327                          ( pTopWinSelf != pTopWinActive ) &&
1328                          pTopWinSelf->Anchor() )
1329                     {
1330                         if ( pTopWinSelf != mrMgr.GetActiveSidebarWin() )
1331                         {
1332                             pTopWinSelf->Anchor()->setLineSolid(false);
1333                             if ( pTopWinSelf->TextRange() != nullptr )
1334                             {
1335                                 pTopWinSelf->TextRange()->HideSolidBorder();
1336                             }
1337                         }
1338                         pTopWinSelf->Anchor()->SetAnchorState(AnchorState::All);
1339                     }
1340                 }
1341                 mpAnchor->setLineSolid(false);
1342                 if ( mpTextRangeOverlay != nullptr )
1343                 {
1344                     mpTextRangeOverlay->HideSolidBorder();
1345                 }
1346             }
1347             if ( mpShadow )
1348             {
1349                 mpShadow->SetShadowState(SS_NORMAL);
1350             }
1351             break;
1352         }
1353     }
1354 }
1355 
GetTopReplyNote()1356 SwAnnotationWin* SwAnnotationWin::GetTopReplyNote()
1357 {
1358     SwAnnotationWin* pTopNote = this;
1359     SwAnnotationWin* pSidebarWin = IsFollow() ? mrMgr.GetNextPostIt(KEY_PAGEUP, this) : nullptr;
1360     while (pSidebarWin)
1361     {
1362         pTopNote = pSidebarWin;
1363         pSidebarWin = pSidebarWin->IsFollow() ? mrMgr.GetNextPostIt(KEY_PAGEUP, pSidebarWin) : nullptr;
1364     }
1365     return pTopNote;
1366 }
1367 
SwitchToFieldPos()1368 void SwAnnotationWin::SwitchToFieldPos()
1369 {
1370     if ( mrMgr.GetActiveSidebarWin() == this )
1371             mrMgr.SetActiveSidebarWin(nullptr);
1372     GotoPos();
1373     sal_uInt32 aCount = MoveCaret();
1374     if (aCount)
1375         mrView.GetDocShell()->GetWrtShell()->SwCursorShell::Right(aCount, 0);
1376     GrabFocusToDocument();
1377     collectUIInformation("LEAVE",get_id());
1378 }
1379 
SetChangeTracking(const SwPostItHelper::SwLayoutStatus aLayoutStatus,const Color & aChangeColor)1380 void SwAnnotationWin::SetChangeTracking( const SwPostItHelper::SwLayoutStatus aLayoutStatus,
1381                                       const Color& aChangeColor )
1382 {
1383     if ( (mLayoutStatus != aLayoutStatus) ||
1384          (mChangeColor != aChangeColor) )
1385     {
1386         mLayoutStatus = aLayoutStatus;
1387         mChangeColor = aChangeColor;
1388         Invalidate();
1389     }
1390 }
1391 
HasScrollbar() const1392 bool SwAnnotationWin::HasScrollbar() const
1393 {
1394     return static_cast<bool>(mxVScrollbar);
1395 }
1396 
IsScrollbarVisible() const1397 bool SwAnnotationWin::IsScrollbarVisible() const
1398 {
1399     return HasScrollbar() && mxVScrollbar->get_vpolicy() == VclPolicyType::ALWAYS;
1400 }
1401 
ChangeSidebarItem(SwSidebarItem const & rSidebarItem)1402 void SwAnnotationWin::ChangeSidebarItem( SwSidebarItem const & rSidebarItem )
1403 {
1404     const bool bAnchorChanged = mpAnchorFrame != rSidebarItem.maLayoutInfo.mpAnchorFrame;
1405     if ( bAnchorChanged )
1406     {
1407         mrMgr.DisconnectSidebarWinFromFrame( *mpAnchorFrame, *this );
1408     }
1409 
1410     mrSidebarItem = rSidebarItem;
1411     mpAnchorFrame = mrSidebarItem.maLayoutInfo.mpAnchorFrame;
1412 
1413     if (mxSidebarWinAccessible)
1414         mxSidebarWinAccessible->ChangeSidebarItem( mrSidebarItem );
1415 
1416     if ( bAnchorChanged )
1417     {
1418         mrMgr.ConnectSidebarWinToFrame( *(mrSidebarItem.maLayoutInfo.mpAnchorFrame),
1419                                       mrSidebarItem.GetFormatField(),
1420                                       *this );
1421     }
1422 }
1423 
CreateAccessible()1424 css::uno::Reference< css::accessibility::XAccessible > SwAnnotationWin::CreateAccessible()
1425 {
1426     // This is rather dodgy code. Normally in CreateAccessible, if we want a custom
1427     // object, we return a custom object, but we do no override the default toolkit
1428     // window peer.
1429     if (!mxSidebarWinAccessible)
1430         mxSidebarWinAccessible = new SidebarWinAccessible( *this,
1431                                                           mrView.GetWrtShell(),
1432                                                           mrSidebarItem );
1433     return mxSidebarWinAccessible;
1434 }
1435 
1436 } // eof of namespace sw::sidebarwindows
1437 
1438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1439