Coverage Report

Created: 2026-10-14 09:33

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