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