Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sd/source/ui/annotations/annotationwindow.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 <editeng/eeitem.hxx>
23
#include <editeng/udlnitem.hxx>
24
#include <editeng/langitem.hxx>
25
#include <editeng/editview.hxx>
26
#include <editeng/editstat.hxx>
27
#include <editeng/outliner.hxx>
28
#include <editeng/editeng.hxx>
29
#include <editeng/outlobj.hxx>
30
#include <editeng/postitem.hxx>
31
#include <editeng/wghtitem.hxx>
32
#include <editeng/crossedoutitem.hxx>
33
#include <editeng/editund2.hxx>
34
#include <officecfg/Office/Common.hxx>
35
#include <svx/svxids.hrc>
36
#include <unotools/useroptions.hxx>
37
38
#include <sfx2/viewfrm.hxx>
39
#include <sfx2/bindings.hxx>
40
#include <sfx2/dispatch.hxx>
41
#include <svl/stritem.hxx>
42
43
#include <vcl/commandevent.hxx>
44
#include <vcl/commandinfoprovider.hxx>
45
#include <vcl/decoview.hxx>
46
#include <vcl/vclenum.hxx>
47
#include <vcl/svapp.hxx>
48
#include <vcl/gradient.hxx>
49
#include <vcl/settings.hxx>
50
#include <vcl/ptrstyle.hxx>
51
#include <vcl/virdev.hxx>
52
53
#include <strings.hrc>
54
#include "annotationwindow.hxx"
55
#include "annotationmanagerimpl.hxx"
56
57
#include <com/sun/star/office/XAnnotation.hpp>
58
#include <DrawDocShell.hxx>
59
#include <ViewShell.hxx>
60
#include <drawdoc.hxx>
61
#include <svx/annotation/TextAPI.hxx>
62
#include <svx/annotation/Annotation.hxx>
63
#include <svx/annotation/ObjectAnnotationData.hxx>
64
#include <svx/svdorect.hxx>
65
#include <sdresid.hxx>
66
67
#include <memory>
68
69
using namespace css;
70
71
0
#define METABUTTON_WIDTH        16
72
0
#define METABUTTON_HEIGHT       18
73
0
#define POSTIT_META_HEIGHT  sal_Int32(30)
74
75
namespace sd {
76
77
void AnnotationTextWindow::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
78
0
{
79
0
    Size aSize = GetOutputSizePixel();
80
81
0
    const bool bHighContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
82
0
    if (!bHighContrast)
83
0
    {
84
0
        rRenderContext.DrawGradient(::tools::Rectangle(Point(0,0), rRenderContext.PixelToLogic(aSize)),
85
0
                                    Gradient(css::awt::GradientStyle_LINEAR, mrContents.maColorLight, mrContents.maColor));
86
0
    }
87
88
0
    DoPaint(rRenderContext, rRect);
89
0
}
90
91
void AnnotationTextWindow::EditViewScrollStateChange()
92
0
{
93
0
    mrContents.SetScrollbar();
94
0
}
95
96
bool AnnotationTextWindow::KeyInput(const KeyEvent& rKeyEvt)
97
0
{
98
0
    const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
99
0
    sal_uInt16 nKey = rKeyCode.GetCode();
100
101
0
    bool bDone = false;
102
103
0
    if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((nKey == KEY_PAGEUP) || (nKey == KEY_PAGEDOWN)))
104
0
    {
105
0
        SfxDispatcher* pDispatcher = mrContents.DocShell()->GetViewShell()->GetViewFrame()->GetDispatcher();
106
0
        if( pDispatcher )
107
0
            pDispatcher->Execute( nKey == KEY_PAGEDOWN ? SID_NEXT_POSTIT : SID_PREVIOUS_POSTIT );
108
0
        bDone = true;
109
0
    }
110
0
    else if (nKey == KEY_INSERT)
111
0
    {
112
0
        if (!rKeyCode.IsMod1() && !rKeyCode.IsMod2())
113
0
            mrContents.ToggleInsMode();
114
0
        bDone = true;
115
0
    }
116
0
    else
117
0
    {
118
0
        ::tools::Long aOldHeight = mrContents.GetPostItTextHeight();
119
120
        /// HACK: need to switch off processing of Undo/Redo in Outliner
121
0
        if ( !( (nKey == KEY_Z || nKey == KEY_Y) && rKeyCode.IsMod1()) )
122
0
        {
123
0
            bool bIsProtected = mrContents.IsProtected();
124
0
            if (!bIsProtected || !EditEngine::DoesKeyChangeText(rKeyEvt) )
125
0
            {
126
0
                if (EditView* pEditView = GetEditView())
127
0
                {
128
0
                    bDone = pEditView->PostKeyEvent(rKeyEvt);
129
0
                    if (!bDone && rKeyEvt.GetKeyCode().IsMod1() && !rKeyEvt.GetKeyCode().IsMod2())
130
0
                    {
131
0
                        if (nKey == KEY_A)
132
0
                        {
133
0
                            EditEngine* pEditEngine = GetEditEngine();
134
0
                            sal_Int32 nPar = pEditEngine->GetParagraphCount();
135
0
                            if (nPar)
136
0
                            {
137
0
                                sal_Int32 nLen = pEditEngine->GetTextLen(nPar - 1);
138
0
                                pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
139
0
                            }
140
0
                            bDone = true;
141
0
                        }
142
0
                    }
143
0
                }
144
0
            }
145
0
        }
146
0
        if (bDone)
147
0
        {
148
0
            mrContents.ResizeIfNecessary(aOldHeight, mrContents.GetPostItTextHeight());
149
0
        }
150
0
    }
151
152
0
    if (bDone)
153
0
        return true;
154
155
0
    return WeldEditView::KeyInput(rKeyEvt);
156
0
}
157
158
AnnotationTextWindow::AnnotationTextWindow(AnnotationWindow& rContents)
159
0
    : mrContents(rContents)
160
0
{
161
0
}
162
163
EditView* AnnotationTextWindow::GetEditView() const
164
0
{
165
0
    OutlinerView* pOutlinerView = mrContents.GetOutlinerView();
166
0
    if (!pOutlinerView)
167
0
        return nullptr;
168
0
    return &pOutlinerView->GetEditView();
169
0
}
170
171
EditEngine* AnnotationTextWindow::GetEditEngine() const
172
0
{
173
0
    OutlinerView* pOutlinerView = mrContents.GetOutlinerView();
174
0
    if (!pOutlinerView)
175
0
        return nullptr;
176
0
    return &pOutlinerView->GetEditView().getEditEngine();
177
0
}
178
179
void AnnotationTextWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
180
0
{
181
0
    Size aSize(0, 0);
182
0
    pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
183
184
0
    SetOutputSizePixel(aSize);
185
186
0
    weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
187
188
0
    EnableRTL(false);
189
190
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
191
0
    Color aBgColor = rStyleSettings.GetWindowColor();
192
193
0
    OutputDevice& rDevice = pDrawingArea->get_ref_device();
194
195
0
    rDevice.SetMapMode(MapMode(MapUnit::Map100thMM));
196
0
    rDevice.SetBackground(aBgColor);
197
198
0
    Size aOutputSize(rDevice.PixelToLogic(aSize));
199
200
0
    EditView* pEditView = GetEditView();
201
0
    pEditView->setEditViewCallbacks(this);
202
203
0
    EditEngine* pEditEngine = GetEditEngine();
204
0
    pEditEngine->SetPaperSize(aOutputSize);
205
0
    pEditEngine->SetRefDevice(&rDevice);
206
207
0
    pEditView->SetOutputArea(::tools::Rectangle(Point(0, 0), aOutputSize));
208
0
    pEditView->SetBackgroundColor(aBgColor);
209
210
0
    pDrawingArea->set_cursor(PointerStyle::Text);
211
212
0
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
213
0
    InitAccessible();
214
0
#endif
215
0
}
216
217
// see SwAnnotationWin in sw for something similar
218
AnnotationWindow::AnnotationWindow(weld::Window* pParent, const ::tools::Rectangle& rRect,
219
                                   DrawDocShell* pDocShell,
220
                                   rtl::Reference<sdr::annotation::Annotation> const& xAnnotation)
221
0
    : mxBuilder(Application::CreateBuilder(pParent, u"modules/simpress/ui/annotation.ui"_ustr))
222
0
    , mxPopover(mxBuilder->weld_popover(u"Annotation"_ustr))
223
0
    , mxContainer(mxBuilder->weld_widget(u"container"_ustr))
224
0
    , mpDocShell(pDocShell)
225
0
    , mpDoc(pDocShell->GetDoc())
226
0
    , mbReadonly(pDocShell->IsReadOnly())
227
0
    , mbProtected(false)
228
0
{
229
0
    mxContainer->set_size_request(320, 240);
230
0
    mxPopover->popup_at_rect(pParent, rRect);
231
232
0
    InitControls();
233
0
    setAnnotation(xAnnotation);
234
0
    FillMenuButton();
235
236
0
    DoResize();
237
238
0
    mxTextControl->GrabFocus();
239
0
}
240
241
AnnotationWindow::~AnnotationWindow()
242
0
{
243
0
}
244
245
void AnnotationWindow::InitControls()
246
0
{
247
    // window control for author and date
248
0
    mxMeta = mxBuilder->weld_label(u"meta"_ustr);
249
0
    mxMeta->set_direction(AllSettings::GetLayoutRTL());
250
251
0
    maLabelFont = Application::GetSettings().GetStyleSettings().GetLabelFont();
252
0
    maLabelFont.SetFontHeight(8);
253
254
    // we should leave this setting alone, but for this we need a better layout algo
255
    // with variable meta size height
256
0
    mxMeta->set_font(maLabelFont);
257
258
0
    mpOutliner.reset( new ::Outliner(GetAnnotationPool(),OutlinerMode::TextObject) );
259
0
    SdDrawDocument::SetCalcFieldValueHdl( mpOutliner.get() );
260
0
    mpOutliner->SetUpdateLayout( true );
261
262
0
    if (OutputDevice* pDev = mpDoc->GetRefDevice())
263
0
        mpOutliner->SetRefDevice( pDev );
264
265
0
    mpOutlinerView.reset(new OutlinerView(*mpOutliner, nullptr));
266
0
    mpOutliner->InsertView(mpOutlinerView.get() );
267
268
    //create Scrollbars
269
0
    mxVScrollbar = mxBuilder->weld_scrolled_window(u"scrolledwindow"_ustr, true);
270
271
    // actual window which holds the user text
272
0
    mxTextControl.reset(new AnnotationTextWindow(*this));
273
0
    mxTextControlWin.reset(new weld::CustomWeld(*mxBuilder, u"editview"_ustr, *mxTextControl));
274
0
    mxTextControl->SetPointer(PointerStyle::Text);
275
276
0
    Rescale();
277
0
    OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
278
279
0
    mxVScrollbar->set_direction(false);
280
0
    mxVScrollbar->connect_vadjustment_value_changed(LINK(this, AnnotationWindow, ScrollHdl));
281
282
0
    mpOutlinerView->SetBackgroundColor(COL_TRANSPARENT);
283
0
    mpOutlinerView->SetOutputArea(rDevice.PixelToLogic(::tools::Rectangle(0, 0, 1, 1)));
284
285
0
    mxMenuButton = mxBuilder->weld_menu_button(u"menubutton"_ustr);
286
0
    if (mbReadonly)
287
0
        mxMenuButton->hide();
288
0
    else
289
0
        mxMenuButton->connect_selected(LINK(this, AnnotationWindow, MenuItemSelectedHdl));
290
291
0
    EEControlBits nCntrl = mpOutliner->GetControlWord();
292
0
    nCntrl |= EEControlBits::PASTESPECIAL | EEControlBits::AUTOCORRECT | EEControlBits::USECHARATTRIBS | EEControlBits::NOCOLORS;
293
0
    mpOutliner->SetControlWord(nCntrl);
294
295
0
    mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
296
0
    mpOutliner->EnableUndo( false );
297
298
0
    mpOutliner->ClearModifyFlag();
299
0
    mpOutliner->GetUndoManager().Clear();
300
0
    mpOutliner->EnableUndo( true );
301
302
0
    SetLanguage(SvxLanguageItem(mpDoc->GetLanguage(EE_CHAR_LANGUAGE), SID_ATTR_LANGUAGE));
303
304
0
    mxTextControl->GrabFocus();
305
0
}
306
307
IMPL_LINK(AnnotationWindow, MenuItemSelectedHdl, const OUString&, rIdent, void)
308
0
{
309
0
    SfxDispatcher* pDispatcher = mpDocShell->GetViewShell()->GetViewFrame()->GetDispatcher();
310
0
    if (!pDispatcher)
311
0
        return;
312
313
0
    uno::Reference<office::XAnnotation> xUnoAnnotation(mxAnnotation);
314
315
0
    if (rIdent == ".uno:ReplyToAnnotation")
316
0
    {
317
318
0
        const SfxUnoAnyItem aItem(SID_REPLYTO_POSTIT, uno::Any(xUnoAnnotation));
319
0
        pDispatcher->ExecuteList(SID_REPLYTO_POSTIT,
320
0
                SfxCallMode::ASYNCHRON, { &aItem });
321
0
    }
322
0
    else if (rIdent == ".uno:DeleteAnnotation")
323
0
    {
324
0
        const SfxUnoAnyItem aItem(SID_DELETE_POSTIT, uno::Any(xUnoAnnotation));
325
0
        pDispatcher->ExecuteList(SID_DELETE_POSTIT, SfxCallMode::ASYNCHRON,
326
0
                { &aItem });
327
0
    }
328
0
    else if (rIdent == ".uno:DeleteAllAnnotationByAuthor")
329
0
    {
330
0
        const SfxStringItem aItem( SID_DELETEALLBYAUTHOR_POSTIT, mxAnnotation->getAuthor() );
331
0
        pDispatcher->ExecuteList( SID_DELETEALLBYAUTHOR_POSTIT,
332
0
                SfxCallMode::ASYNCHRON, { &aItem });
333
0
    }
334
0
    else if (rIdent == ".uno:DeleteAllAnnotation")
335
0
        pDispatcher->Execute( SID_DELETEALL_POSTIT );
336
0
}
337
338
void AnnotationWindow::FillMenuButton()
339
0
{
340
0
    SvtUserOptions aUserOptions;
341
0
    OUString sCurrentAuthor( aUserOptions.GetFullName() );
342
0
    OUString sAuthor( mxAnnotation->getAuthor() );
343
344
0
    OUString aStr(mxMenuButton->get_item_label(u".uno:DeleteAllAnnotationByAuthor"_ustr));
345
0
    OUString aReplace( sAuthor );
346
0
    if( aReplace.isEmpty() )
347
0
        aReplace = SdResId( STR_ANNOTATION_NOAUTHOR );
348
0
    aStr = aStr.replaceFirst("%1", aReplace);
349
0
    mxMenuButton->set_item_label(u".uno:DeleteAllAnnotationByAuthor"_ustr, aStr);
350
351
0
    bool bShowReply = sAuthor != sCurrentAuthor && !mbReadonly;
352
0
    mxMenuButton->set_item_visible(u".uno:ReplyToAnnotation"_ustr, bShowReply);
353
0
    mxMenuButton->set_item_visible(u"separator"_ustr, bShowReply);
354
0
    mxMenuButton->set_item_visible(u".uno:DeleteAnnotation"_ustr, mxAnnotation.is() && !mbReadonly);
355
0
    mxMenuButton->set_item_visible(u".uno:DeleteAllAnnotationByAuthor"_ustr, !mbReadonly);
356
0
    mxMenuButton->set_item_visible(u".uno:DeleteAllAnnotation"_ustr, !mbReadonly);
357
0
}
358
359
void AnnotationWindow::StartEdit()
360
0
{
361
0
    GetOutlinerView()->SetSelection(ESelection::AtEnd());
362
0
    GetOutlinerView()->ShowCursor();
363
0
}
364
365
void AnnotationWindow::SetMapMode(const MapMode& rNewMapMode)
366
0
{
367
0
    OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
368
0
    rDevice.SetMapMode(rNewMapMode);
369
0
}
370
371
void AnnotationWindow::Rescale()
372
0
{
373
0
    MapMode aMode(MapUnit::Map100thMM);
374
0
    aMode.SetOrigin( Point() );
375
0
    mpOutliner->SetRefMapMode( aMode );
376
0
    SetMapMode( aMode );
377
378
0
    if (mxMeta)
379
0
    {
380
0
        vcl::Font aFont = maLabelFont;
381
0
        sal_Int32 nHeight = ::tools::Long(aFont.GetFontHeight() * aMode.GetScaleY());
382
0
        aFont.SetFontHeight( nHeight );
383
0
        mxMeta->set_font(aFont);
384
0
    }
385
0
}
386
387
void AnnotationWindow::DoResize()
388
0
{
389
0
    OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
390
391
0
    ::tools::Long aHeight = mxContainer->get_preferred_size().Height();
392
0
    ::tools::ULong aWidth = mxContainer->get_preferred_size().Width();
393
394
0
    aHeight -= POSTIT_META_HEIGHT;
395
396
0
    mpOutliner->SetPaperSize( rDevice.PixelToLogic( Size(aWidth, aHeight) ) ) ;
397
0
    ::tools::Long aTextHeight = rDevice.LogicToPixel(mpOutliner->CalcTextSize()).Height();
398
399
0
    if( aTextHeight > aHeight )
400
0
    {
401
0
        const int nThickness = mxVScrollbar->get_scroll_thickness();
402
0
        if (nThickness)
403
0
        {
404
            // we need vertical scrollbars and have to reduce the width
405
0
            aWidth -= nThickness;
406
0
            mpOutliner->SetPaperSize(rDevice.PixelToLogic(Size(aWidth, aHeight)));
407
0
        }
408
0
        mxVScrollbar->set_vpolicy(VclPolicyType::ALWAYS);
409
0
    }
410
0
    else
411
0
    {
412
0
        mxVScrollbar->set_vpolicy(VclPolicyType::NEVER);
413
0
    }
414
415
0
    ::tools::Rectangle aOutputArea = rDevice.PixelToLogic(::tools::Rectangle(0, 0, aWidth, aHeight));
416
0
    if (mxVScrollbar->get_vpolicy() == VclPolicyType::NEVER)
417
0
    {
418
        // if we do not have a scrollbar anymore, we want to see the complete text
419
0
        mpOutlinerView->SetVisArea(aOutputArea);
420
0
    }
421
0
    mpOutlinerView->SetOutputArea(aOutputArea);
422
0
    mpOutlinerView->ShowCursor(true, true);
423
424
0
    int nUpper = mpOutliner->GetTextHeight();
425
0
    int nCurrentDocPos = mpOutlinerView->GetVisArea().Top();
426
0
    int nStepIncrement = mpOutliner->GetTextHeight() / 10;
427
0
    int nPageIncrement = rDevice.PixelToLogic(Size(0,aHeight)).Height() * 8 / 10;
428
0
    int nPageSize = rDevice.PixelToLogic(Size(0,aHeight)).Height();
429
430
    /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
431
       effectively...
432
433
       lower = gtk_adjustment_get_lower
434
       upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
435
436
       and requires that upper > lower or the deceleration animation never ends
437
    */
438
0
    nPageSize = std::min(nPageSize, nUpper);
439
440
0
    mxVScrollbar->vadjustment_configure(nCurrentDocPos, nUpper, nStepIncrement, nPageIncrement,
441
0
                                        nPageSize);
442
0
}
443
444
void AnnotationWindow::SetScrollbar()
445
0
{
446
0
    mxVScrollbar->vadjustment_set_value(mpOutlinerView->GetVisArea().Top());
447
0
}
448
449
void AnnotationWindow::ResizeIfNecessary(::tools::Long aOldHeight, ::tools::Long aNewHeight)
450
0
{
451
0
    if (aOldHeight != aNewHeight)
452
0
        DoResize();
453
0
    else
454
0
        SetScrollbar();
455
0
}
456
457
void AnnotationWindow::SetLanguage(const SvxLanguageItem &aNewItem)
458
0
{
459
0
    mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
460
0
    ESelection aOld = GetOutlinerView()->GetSelection();
461
462
0
    GetOutlinerView()->SetSelection(ESelection::All());
463
0
    SfxItemSet aEditAttr(GetOutlinerView()->GetAttribs());
464
0
    aEditAttr.Put(aNewItem);
465
0
    GetOutlinerView()->SetAttribs( aEditAttr );
466
467
0
    GetOutlinerView()->SetSelection(aOld);
468
469
0
    mxTextControl->Invalidate();
470
0
}
471
472
void AnnotationWindow::ToggleInsMode()
473
0
{
474
0
    if( mpOutlinerView )
475
0
    {
476
0
        SfxBindings &rBnd = mpDocShell->GetViewShell()->GetViewFrame()->GetBindings();
477
0
        rBnd.Invalidate(SID_ATTR_INSERT);
478
0
        rBnd.Update(SID_ATTR_INSERT);
479
0
    }
480
0
}
481
482
::tools::Long AnnotationWindow::GetPostItTextHeight()
483
0
{
484
0
    OutputDevice& rDevice = mxTextControl->GetDrawingArea()->get_ref_device();
485
0
    return mpOutliner ? rDevice.LogicToPixel(mpOutliner->CalcTextSize()).Height() : 0;
486
0
}
487
488
IMPL_LINK(AnnotationWindow, ScrollHdl, weld::ScrolledWindow&, rScrolledWindow, void)
489
0
{
490
0
    ::tools::Long nDiff = GetOutlinerView()->GetEditView().GetVisArea().Top() - rScrolledWindow.vadjustment_get_value();
491
0
    GetOutlinerView()->Scroll( 0, nDiff );
492
0
}
493
494
sdr::annotation::TextApiObject* getTextApiObject(const uno::Reference<office::XAnnotation>& xAnnotation)
495
0
{
496
0
    if( xAnnotation.is() )
497
0
    {
498
0
        uno::Reference<text::XText> xText( xAnnotation->getTextRange() );
499
0
        return sdr::annotation::TextApiObject::getImplementation(xText);
500
0
    }
501
0
    return nullptr;
502
0
}
503
504
void AnnotationWindow::setAnnotation(rtl::Reference<sdr::annotation::Annotation> const& xAnnotation)
505
0
{
506
0
    if (xAnnotation == mxAnnotation || !xAnnotation.is())
507
0
        return;
508
509
0
    mxAnnotation = xAnnotation;
510
511
0
    SetColor();
512
513
0
    SvtUserOptions aUserOptions;
514
0
    mbProtected = aUserOptions.GetFullName() != xAnnotation->getAuthor();
515
516
0
    mpOutliner->Clear();
517
0
    auto* pTextApi = getTextApiObject(mxAnnotation);
518
519
0
    if( pTextApi )
520
0
    {
521
0
        std::optional< OutlinerParaObject > pOPO( pTextApi->CreateText() );
522
0
        mpOutliner->SetText(*pOPO);
523
0
    }
524
525
0
    mpOutliner->ClearModifyFlag();
526
0
    mpOutliner->GetUndoManager().Clear();
527
528
//TODO    Invalidate();
529
530
0
    OUString sMeta( xAnnotation->getAuthor() );
531
0
    OUString sDateTime( getAnnotationDateTimeString(xAnnotation) );
532
533
0
    if( !sDateTime.isEmpty() )
534
0
    {
535
0
        if( !sMeta.isEmpty() )
536
0
            sMeta += "\n";
537
538
0
        sMeta += sDateTime;
539
0
    }
540
0
    mxMeta->set_label(sMeta);
541
0
}
542
543
void AnnotationWindow::SetColor()
544
0
{
545
0
    sal_uInt16 nAuthorIdx = mpDoc->GetAnnotationAuthorIndex( mxAnnotation->getAuthor() );
546
547
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
548
0
    const bool bHighContrast = rStyleSettings.GetHighContrastMode();
549
0
    if( bHighContrast )
550
0
    {
551
0
        maColor = rStyleSettings.GetWindowColor();
552
0
        maColorDark = maColor;
553
0
        maColorLight = rStyleSettings.GetWindowTextColor();
554
0
    }
555
0
    else
556
0
    {
557
0
        maColor = AnnotationManagerImpl::GetColor( nAuthorIdx );
558
0
        maColorDark = AnnotationManagerImpl::GetColorDark( nAuthorIdx );
559
0
        maColorLight = AnnotationManagerImpl::GetColorLight( nAuthorIdx );
560
0
    }
561
562
0
    mpOutliner->ForceAutoColor( bHighContrast || officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get() );
563
564
0
    mxPopover->set_background(maColor);
565
0
    mxMenuButton->set_background(maColor);
566
567
0
    ScopedVclPtrInstance<VirtualDevice> xVirDev;
568
0
    xVirDev->SetLineColor();
569
0
    xVirDev->SetFillColor(maColor);
570
571
0
    Size aSize(METABUTTON_WIDTH, METABUTTON_HEIGHT);
572
0
    ::tools::Rectangle aRect(Point(0, 0), aSize);
573
0
    xVirDev->SetOutputSizePixel(aSize);
574
0
    xVirDev->DrawRect(aRect);
575
576
0
    ::tools::Rectangle aSymbolRect(aRect);
577
    // 25% distance to the left and right button border
578
0
    const ::tools::Long nBorderDistanceLeftAndRight = ((aSymbolRect.GetWidth() * 250) + 500) / 1000;
579
0
    aSymbolRect.AdjustLeft(nBorderDistanceLeftAndRight );
580
0
    aSymbolRect.AdjustRight( -nBorderDistanceLeftAndRight );
581
    // 40% distance to the top button border
582
0
    const ::tools::Long nBorderDistanceTop = ((aSymbolRect.GetHeight() * 400) + 500) / 1000;
583
0
    aSymbolRect.AdjustTop(nBorderDistanceTop );
584
    // 15% distance to the bottom button border
585
0
    const ::tools::Long nBorderDistanceBottom = ((aSymbolRect.GetHeight() * 150) + 500) / 1000;
586
0
    aSymbolRect.AdjustBottom( -nBorderDistanceBottom );
587
0
    DecorationView aDecoView(xVirDev.get());
588
0
    aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, COL_BLACK,
589
0
                         DrawSymbolFlags::NONE);
590
0
    mxMenuButton->set_image(xVirDev);
591
0
    mxMenuButton->set_size_request(aSize.Width() + 4, aSize.Height() + 4);
592
593
0
    mxMeta->set_font_color(bHighContrast ? maColorLight : maColorDark);
594
595
0
    mxVScrollbar->customize_scrollbars(maColorLight,
596
0
                                       maColorDark,
597
0
                                       maColor);
598
0
    mxVScrollbar->set_scroll_thickness(GetPrefScrollbarWidth());
599
0
}
600
601
void AnnotationWindow::SaveToDocument()
602
0
{
603
0
    uno::Reference<office::XAnnotation> xAnnotation(mxAnnotation);
604
605
    // write changed text back to annotation
606
0
    if (mpOutliner->IsModified())
607
0
    {
608
0
        auto* pTextApi = getTextApiObject( xAnnotation );
609
610
0
        if( pTextApi )
611
0
        {
612
0
            std::optional<OutlinerParaObject> pOPO = mpOutliner->CreateParaObject();
613
0
            if( pOPO )
614
0
            {
615
0
                if( mpDoc->IsUndoEnabled() )
616
0
                    mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_EDIT ) );
617
618
0
                pTextApi->SetText( *pOPO );
619
0
                pOPO.reset();
620
621
                // set current time to changed annotation
622
0
                xAnnotation->setDateTime( getCurrentDateTime() );
623
624
0
                rtl::Reference<sdr::annotation::Annotation> xSdrAnnotation = dynamic_cast<sdr::annotation::Annotation*>(xAnnotation.get());
625
0
                if (xSdrAnnotation && xSdrAnnotation->getCreationInfo().meType == sdr::annotation::AnnotationType::FreeText)
626
0
                {
627
0
                    SdrObject* pObject = xSdrAnnotation->findAnnotationObject();
628
0
                    SdrRectObj* pRectangleObject = pObject ? dynamic_cast<SdrRectObj*>(pObject) : nullptr;
629
0
                    if (pRectangleObject)
630
0
                    {
631
0
                        OUString aString = xSdrAnnotation->getTextRange()->getString();
632
0
                        pRectangleObject->SetText(aString);
633
0
                    }
634
0
                }
635
636
0
                if( mpDoc->IsUndoEnabled() )
637
0
                    mpDoc->EndUndo();
638
639
0
                mpDocShell->SetModified();
640
0
            }
641
642
0
        }
643
0
    }
644
0
    mpOutliner->ClearModifyFlag();
645
646
0
    mpOutliner->GetUndoManager().Clear();
647
0
}
648
649
bool AnnotationTextWindow::Command(const CommandEvent& rCEvt)
650
0
{
651
0
    if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
652
0
    {
653
0
        if (mrContents.DocShell()->IsReadOnly())
654
0
            return true;
655
656
0
        SfxDispatcher* pDispatcher = mrContents.DocShell()->GetViewShell()->GetViewFrame()->GetDispatcher();
657
0
        if( !pDispatcher )
658
0
            return true;
659
660
0
        if (IsMouseCaptured())
661
0
        {
662
            // so the menu can capture it and the EditView doesn't get the button release and change its
663
            // selection on a successful button click
664
0
            ReleaseMouse();
665
0
        }
666
667
0
        ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
668
0
        weld::Widget* pPopupParent = GetDrawingArea();
669
0
        std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, u"modules/simpress/ui/annotationtagmenu.ui"_ustr));
670
0
        std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"menu"_ustr));
671
672
0
        auto xAnnotation = mrContents.getAnnotation();
673
674
0
        SvtUserOptions aUserOptions;
675
0
        OUString sCurrentAuthor( aUserOptions.GetFullName() );
676
0
        OUString sAuthor( xAnnotation->getAuthor() );
677
678
0
        OUString aStr(xMenu->get_label(u".uno:DeleteAllAnnotationByAuthor"_ustr));
679
0
        OUString aReplace( sAuthor );
680
0
        if( aReplace.isEmpty() )
681
0
            aReplace = SdResId( STR_ANNOTATION_NOAUTHOR );
682
0
        aStr = aStr.replaceFirst("%1", aReplace);
683
0
        xMenu->set_label(u".uno:DeleteAllAnnotationByAuthor"_ustr, aStr);
684
685
0
        bool bShowReply = sAuthor != sCurrentAuthor;
686
0
        xMenu->set_visible(u".uno:ReplyToAnnotation"_ustr, bShowReply);
687
0
        xMenu->set_visible(u"separator"_ustr, bShowReply);
688
0
        xMenu->set_visible(u".uno:DeleteAnnotation"_ustr, xAnnotation.is());
689
0
        xMenu->set_visible(u".uno:DeleteAllAnnotationByAuthor"_ustr, true);
690
0
        xMenu->set_visible(u".uno:DeleteAllAnnotation"_ustr, true);
691
692
0
        int nInsertPos = 2;
693
694
0
        auto xFrame = mrContents.DocShell()->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
695
0
        OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
696
697
0
        bool bEditable = !mrContents.IsProtected();
698
0
        if (bEditable)
699
0
        {
700
0
            SfxItemSet aSet(mrContents.GetOutlinerView()->GetAttribs());
701
702
0
            xMenu->insert(nInsertPos++, u".uno:Bold"_ustr,
703
0
                          vcl::CommandInfoProvider::GetMenuLabelForCommand(
704
0
                              vcl::CommandInfoProvider::GetCommandProperties(u".uno:Bold"_ustr, aModuleName)),
705
0
                          nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(u".uno:Bold"_ustr, xFrame),
706
0
                          TRISTATE_TRUE);
707
708
0
            if ( aSet.GetItemState( EE_CHAR_WEIGHT ) == SfxItemState::SET )
709
0
            {
710
0
                if( aSet.Get( EE_CHAR_WEIGHT ).GetWeight() == WEIGHT_BOLD )
711
0
                    xMenu->set_active(u".uno:Bold"_ustr, true);
712
0
            }
713
714
0
            xMenu->insert(nInsertPos++, u".uno:Italic"_ustr,
715
0
                          vcl::CommandInfoProvider::GetMenuLabelForCommand(
716
0
                              vcl::CommandInfoProvider::GetCommandProperties(u".uno:Italic"_ustr, aModuleName)),
717
0
                          nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(u".uno:Italic"_ustr, xFrame),
718
0
                          TRISTATE_TRUE);
719
720
0
            if ( aSet.GetItemState( EE_CHAR_ITALIC ) == SfxItemState::SET )
721
0
            {
722
0
                if( aSet.Get( EE_CHAR_ITALIC ).GetPosture() != ITALIC_NONE )
723
0
                    xMenu->set_active(u".uno:Italic"_ustr, true);
724
725
0
            }
726
727
0
            xMenu->insert(nInsertPos++, u".uno:Underline"_ustr,
728
0
                          vcl::CommandInfoProvider::GetMenuLabelForCommand(
729
0
                              vcl::CommandInfoProvider::GetCommandProperties(u".uno:Underline"_ustr, aModuleName)),
730
0
                          nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(u".uno:Underline"_ustr, xFrame),
731
0
                          TRISTATE_TRUE);
732
733
0
            if ( aSet.GetItemState( EE_CHAR_UNDERLINE ) == SfxItemState::SET )
734
0
            {
735
0
                if( aSet.Get( EE_CHAR_UNDERLINE ).GetLineStyle() != LINESTYLE_NONE )
736
0
                    xMenu->set_active(u".uno:Underline"_ustr, true);
737
0
            }
738
739
0
            xMenu->insert(nInsertPos++, u".uno:Strikeout"_ustr,
740
0
                          vcl::CommandInfoProvider::GetMenuLabelForCommand(
741
0
                              vcl::CommandInfoProvider::GetCommandProperties(u".uno:Strikeout"_ustr, aModuleName)),
742
0
                          nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(u".uno:Strikeout"_ustr, xFrame),
743
0
                          TRISTATE_TRUE);
744
745
0
            if ( aSet.GetItemState( EE_CHAR_STRIKEOUT ) == SfxItemState::SET )
746
0
            {
747
0
                if( aSet.Get( EE_CHAR_STRIKEOUT ).GetStrikeout() != STRIKEOUT_NONE )
748
0
                    xMenu->set_active(u".uno:Strikeout"_ustr, true);
749
0
            }
750
751
0
            xMenu->insert_separator(nInsertPos++, u"separator2"_ustr);
752
0
        }
753
754
0
        xMenu->insert(nInsertPos++, u".uno:Copy"_ustr,
755
0
                      vcl::CommandInfoProvider::GetMenuLabelForCommand(
756
0
                          vcl::CommandInfoProvider::GetCommandProperties(u".uno:Copy"_ustr, aModuleName)),
757
0
                      nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(u".uno:Copy"_ustr, xFrame),
758
0
                      TRISTATE_INDET);
759
760
0
        xMenu->insert(nInsertPos++, u".uno:Paste"_ustr,
761
0
                      vcl::CommandInfoProvider::GetMenuLabelForCommand(
762
0
                          vcl::CommandInfoProvider::GetCommandProperties(u".uno:Paste"_ustr, aModuleName)),
763
0
                      nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(u".uno:Paste"_ustr, xFrame),
764
0
                      TRISTATE_INDET);
765
766
0
        bool bCanPaste = false;
767
0
        if (bEditable)
768
0
        {
769
0
            TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(GetClipboard()));
770
0
            bCanPaste = aDataHelper.GetFormatCount() != 0;
771
0
        }
772
773
0
        xMenu->insert_separator(nInsertPos++, u"separator3"_ustr);
774
775
0
        xMenu->set_sensitive(u".uno:Copy"_ustr, mrContents.GetOutlinerView()->HasSelection());
776
0
        xMenu->set_sensitive(u".uno:Paste"_ustr, bCanPaste);
777
778
0
        auto sId = xMenu->popup_at_rect(pPopupParent, aRect);
779
780
0
        uno::Reference<office::XAnnotation> xUnoAnnotation(mrContents.getAnnotation());
781
782
0
        if (sId == ".uno:ReplyToAnnotation")
783
0
        {
784
0
            const SfxUnoAnyItem aItem(SID_REPLYTO_POSTIT, uno::Any(xUnoAnnotation));
785
0
            pDispatcher->ExecuteList(SID_REPLYTO_POSTIT,
786
0
                    SfxCallMode::ASYNCHRON, { &aItem });
787
0
        }
788
0
        else if (sId == ".uno:DeleteAnnotation")
789
0
        {
790
0
            const SfxUnoAnyItem aItem(SID_DELETE_POSTIT, uno::Any(xUnoAnnotation));
791
0
            pDispatcher->ExecuteList(SID_DELETE_POSTIT, SfxCallMode::ASYNCHRON,
792
0
                    { &aItem });
793
0
        }
794
0
        else if (sId == ".uno:DeleteAllAnnotationByAuthor")
795
0
        {
796
0
            const SfxStringItem aItem( SID_DELETEALLBYAUTHOR_POSTIT, sAuthor );
797
0
            pDispatcher->ExecuteList( SID_DELETEALLBYAUTHOR_POSTIT,
798
0
                    SfxCallMode::ASYNCHRON, { &aItem });
799
0
        }
800
0
        else if (sId == ".uno:DeleteAllAnnotation")
801
0
            pDispatcher->Execute( SID_DELETEALL_POSTIT );
802
0
        else if (sId == ".uno:Copy")
803
0
        {
804
0
            mrContents.GetOutlinerView()->Copy();
805
0
        }
806
0
        else if (sId == ".uno:Paste")
807
0
        {
808
0
            mrContents.GetOutlinerView()->PasteSpecial();
809
0
            mrContents.DoResize();
810
0
        }
811
0
        else if (!sId.isEmpty())
812
0
        {
813
0
            SfxItemSet aEditAttr(mrContents.GetOutlinerView()->GetAttribs());
814
0
            SfxItemSet aNewAttr(mrContents.GetOutliner()->GetEmptyItemSet());
815
816
0
            if (sId == ".uno:Bold")
817
0
            {
818
0
                FontWeight eFW = aEditAttr.Get( EE_CHAR_WEIGHT ).GetWeight();
819
0
                aNewAttr.Put( SvxWeightItem( eFW == WEIGHT_NORMAL ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
820
0
            }
821
0
            else if (sId == ".uno:Italic")
822
0
            {
823
0
                FontItalic eFI = aEditAttr.Get( EE_CHAR_ITALIC ).GetPosture();
824
0
                aNewAttr.Put( SvxPostureItem( eFI == ITALIC_NORMAL ? ITALIC_NONE : ITALIC_NORMAL, EE_CHAR_ITALIC ) );
825
0
            }
826
0
            else if (sId == ".uno:Underline")
827
0
            {
828
0
                FontLineStyle eFU = aEditAttr. Get( EE_CHAR_UNDERLINE ).GetLineStyle();
829
0
                aNewAttr.Put( SvxUnderlineItem( eFU == LINESTYLE_SINGLE ? LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_UNDERLINE ) );
830
0
            }
831
0
            else if (sId == ".uno:Strikeout")
832
0
            {
833
0
                FontStrikeout eFSO = aEditAttr.Get( EE_CHAR_STRIKEOUT ).GetStrikeout();
834
0
                aNewAttr.Put( SvxCrossedOutItem( eFSO == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT ) );
835
0
            }
836
837
0
            mrContents.GetOutlinerView()->SetAttribs( aNewAttr );
838
0
        }
839
840
0
        return true;
841
0
    }
842
0
    return WeldEditView::Command(rCEvt);
843
0
}
844
845
}
846
847
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */