Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/sd/source/ui/annotations/annotationmanager.cxx
Line
Count
Source (jump to first uncovered line)
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 <com/sun/star/drawing/XDrawView.hpp>
21
#include <com/sun/star/frame/XController.hpp>
22
#include <com/sun/star/geometry/RealPoint2D.hpp>
23
#include <com/sun/star/text/XText.hpp>
24
#include <com/sun/star/document/XEventBroadcaster.hpp>
25
#include <com/sun/star/office/XAnnotationAccess.hpp>
26
#include <comphelper/lok.hxx>
27
#include <svx/svxids.hrc>
28
#include <svx/svditer.hxx>
29
30
#include <vcl/settings.hxx>
31
#include <vcl/svapp.hxx>
32
#include <vcl/weld.hxx>
33
#include <tools/gen.hxx>
34
35
#include <sal/macros.h>
36
#include <svl/itempool.hxx>
37
#include <svl/intitem.hxx>
38
#include <unotools/localedatawrapper.hxx>
39
#include <unotools/useroptions.hxx>
40
#include <unotools/syslocale.hxx>
41
#include <unotools/saveopt.hxx>
42
43
#include <tools/datetime.hxx>
44
#include <tools/UnitConversion.hxx>
45
#include <comphelper/diagnose_ex.hxx>
46
47
#include <sfx2/viewfrm.hxx>
48
#include <sfx2/bindings.hxx>
49
#include <sfx2/request.hxx>
50
#include <sfx2/dispatch.hxx>
51
52
#include <editeng/editeng.hxx>
53
#include <editeng/eeitem.hxx>
54
#include <editeng/fontitem.hxx>
55
#include <editeng/fhgtitem.hxx>
56
#include <editeng/outlobj.hxx>
57
#include <editeng/postitem.hxx>
58
59
#include <svx/postattr.hxx>
60
61
#include <annotationmanager.hxx>
62
#include "annotationmanagerimpl.hxx"
63
#include "annotationwindow.hxx"
64
#include <strings.hrc>
65
66
#include <Annotation.hxx>
67
#include "AnnotationPopup.hxx"
68
#include <DrawDocShell.hxx>
69
#include <DrawViewShell.hxx>
70
#include <DrawController.hxx>
71
#include <sdresid.hxx>
72
#include <EventMultiplexer.hxx>
73
#include <ViewShellBase.hxx>
74
#include <sdpage.hxx>
75
#include <drawdoc.hxx>
76
#include <svx/annotation/TextAPI.hxx>
77
#include <svx/annotation/AnnotationObject.hxx>
78
#include <svx/annotation/Annotation.hxx>
79
#include <svx/annotation/ObjectAnnotationData.hxx>
80
#include <optsitem.hxx>
81
#include <sdmod.hxx>
82
83
#include <svx/svdobj.hxx>
84
#include <svx/svdocirc.hxx>
85
#include <svx/svdorect.hxx>
86
#include <svx/svdopath.hxx>
87
#include <svx/svdotext.hxx>
88
#include <svx/svdograf.hxx>
89
90
#include <svx/xfillit0.hxx>
91
#include <svx/xflclit.hxx>
92
#include <svx/xlineit0.hxx>
93
#include <svx/xlnclit.hxx>
94
#include <svx/xlnstwit.hxx>
95
#include <svx/xlnwtit.hxx>
96
#include <svx/xfltrit.hxx>
97
#include <svx/xlntrit.hxx>
98
99
#include <cmath>
100
#include <memory>
101
102
using namespace css;
103
104
namespace sd
105
{
106
107
SfxItemPool* GetAnnotationPool()
108
0
{
109
0
    static rtl::Reference<SfxItemPool> s_pAnnotationPool;
110
0
    if( !s_pAnnotationPool )
111
0
    {
112
0
        s_pAnnotationPool = EditEngine::CreatePool();
113
0
        s_pAnnotationPool->SetUserDefaultItem(SvxFontHeightItem(423,100,EE_CHAR_FONTHEIGHT));
114
115
0
        vcl::Font aAppFont( Application::GetSettings().GetStyleSettings().GetAppFont() );
116
0
        s_pAnnotationPool->SetUserDefaultItem(SvxFontItem(aAppFont.GetFamilyTypeMaybeAskConfig(),aAppFont.GetFamilyName(),u""_ustr,PITCH_DONTKNOW,RTL_TEXTENCODING_DONTKNOW,EE_CHAR_FONTINFO));
117
0
    }
118
119
0
    return s_pAnnotationPool.get();
120
0
}
121
122
static SfxBindings* getBindings( ViewShellBase const & rBase )
123
0
{
124
0
    auto pMainViewShell = rBase.GetMainViewShell().get();
125
0
    if( pMainViewShell && pMainViewShell->GetViewFrame() )
126
0
        return &pMainViewShell->GetViewFrame()->GetBindings();
127
128
0
    return nullptr;
129
0
}
130
131
static SfxDispatcher* getDispatcher( ViewShellBase const & rBase )
132
0
{
133
0
    auto pMainViewShell = rBase.GetMainViewShell().get();
134
0
    if( pMainViewShell && pMainViewShell->GetViewFrame() )
135
0
        return pMainViewShell->GetViewFrame()->GetDispatcher();
136
137
0
    return nullptr;
138
0
}
139
140
css::util::DateTime getCurrentDateTime()
141
0
{
142
0
    DateTime aCurrentDate( DateTime::SYSTEM );
143
0
    return css::util::DateTime( 0, aCurrentDate.GetSec(),
144
0
            aCurrentDate.GetMin(), aCurrentDate.GetHour(),
145
0
            aCurrentDate.GetDay(), aCurrentDate.GetMonth(),
146
0
            aCurrentDate.GetYear(), false );
147
0
}
148
149
OUString getAnnotationDateTimeString(const uno::Reference<office::XAnnotation>& xAnnotation)
150
0
{
151
0
    OUString sRet;
152
0
    if( xAnnotation.is() )
153
0
    {
154
0
        const SvtSysLocale aSysLocale;
155
0
        const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
156
157
0
        css::util::DateTime aDateTime( xAnnotation->getDateTime() );
158
159
0
        Date aSysDate( Date::SYSTEM );
160
0
        Date aDate( aDateTime.Day, aDateTime.Month, aDateTime.Year );
161
0
        if (aDate==aSysDate)
162
0
            sRet = SdResId(STR_ANNOTATION_TODAY);
163
0
        else if (aDate == (aSysDate-1))
164
0
            sRet = SdResId(STR_ANNOTATION_YESTERDAY);
165
0
        else if (aDate.IsValidAndGregorian() )
166
0
            sRet = rLocalData.getDate(aDate);
167
168
0
        ::tools::Time aTime( aDateTime );
169
0
        if(aTime.GetTime() != 0)
170
0
            sRet += " "  + rLocalData.getTime( aTime,false );
171
0
    }
172
0
    return sRet;
173
0
}
174
175
AnnotationManagerImpl::AnnotationManagerImpl( ViewShellBase& rViewShellBase )
176
0
: mrBase( rViewShellBase )
177
0
, mpDoc( rViewShellBase.GetDocument() )
178
0
, mbShowAnnotations( true )
179
0
, mnUpdateTagsEvent( nullptr )
180
0
{
181
0
    if (SdOptions* pOptions = SdModule::get()->GetSdOptions(mpDoc->GetDocumentType()))
182
0
        mbShowAnnotations = pOptions->IsShowComments();
183
0
}
Unexecuted instantiation: sd::AnnotationManagerImpl::AnnotationManagerImpl(sd::ViewShellBase&)
Unexecuted instantiation: sd::AnnotationManagerImpl::AnnotationManagerImpl(sd::ViewShellBase&)
184
185
void AnnotationManagerImpl::init()
186
0
{
187
    // get current controller and initialize listeners
188
0
    try
189
0
    {
190
0
        addListener();
191
0
        mxView = mrBase.GetDrawController();
192
0
    }
193
0
    catch (uno::Exception&)
194
0
    {
195
0
        TOOLS_WARN_EXCEPTION( "sd", "sd::AnnotationManagerImpl::AnnotationManagerImpl()" );
196
0
    }
197
198
0
    try
199
0
    {
200
0
        uno::Reference<document::XEventBroadcaster> xModel (mrBase.GetDocShell()->GetModel(), uno::UNO_QUERY_THROW);
201
0
        uno::Reference<document::XEventListener> xListener( this );
202
0
        xModel->addEventListener( xListener );
203
0
    }
204
0
    catch (uno::Exception&)
205
0
    {
206
0
    }
207
0
}
208
209
// WeakComponentImplHelper
210
void AnnotationManagerImpl::disposing (std::unique_lock<std::mutex>&)
211
0
{
212
0
    for (sal_uInt16 i = 0; i < mpDoc->GetPageCount(); i++)
213
0
    {
214
0
        SdrPage* pPage = mpDoc->GetPage(i);
215
0
        SdrObjListIter aIterator(pPage, SdrIterMode::DeepWithGroups);
216
0
        while (aIterator.IsMore())
217
0
        {
218
0
            SdrObject* pObject = aIterator.Next();
219
0
            if (pObject)
220
0
            {
221
0
                auto& xAnnotationData = pObject->getAnnotationData();
222
0
                if (xAnnotationData)
223
0
                    xAnnotationData->closePopup();
224
0
            }
225
0
        }
226
0
    }
227
228
0
    try
229
0
    {
230
0
        uno::Reference<document::XEventBroadcaster> xModel (mrBase.GetDocShell()->GetModel(), uno::UNO_QUERY_THROW);
231
0
        uno::Reference<document::XEventListener> xListener( this );
232
0
        xModel->removeEventListener( xListener );
233
0
    }
234
0
    catch (uno::Exception&)
235
0
    {
236
0
    }
237
238
0
    removeListener();
239
240
0
    if( mnUpdateTagsEvent )
241
0
    {
242
0
        Application::RemoveUserEvent( mnUpdateTagsEvent );
243
0
        mnUpdateTagsEvent = nullptr;
244
0
    }
245
246
0
    mxView.clear();
247
0
    mxCurrentPage.clear();
248
0
}
249
250
// XEventListener
251
void SAL_CALL AnnotationManagerImpl::notifyEvent( const css::document::EventObject& aEvent )
252
0
{
253
0
    if( !(aEvent.EventName == "OnAnnotationInserted" || aEvent.EventName == "OnAnnotationRemoved" || aEvent.EventName == "OnAnnotationChanged") )
254
0
        return;
255
256
    // AnnotationInsertion and modification is not handled here because when
257
    // a new annotation is inserted, it consists of OnAnnotationInserted
258
    // followed by a chain of OnAnnotationChanged (called for setting each
259
    // of the annotation attributes - author, text etc.). This is not what a
260
    // LOK client wants. So only handle removal here as annotation removal
261
    // consists of only one event - 'OnAnnotationRemoved'
262
0
    if ( aEvent.EventName == "OnAnnotationRemoved" )
263
0
    {
264
0
        uno::Reference<office::XAnnotation> xAnnotation( aEvent.Source, uno::UNO_QUERY );
265
0
        if ( auto pAnnotation = dynamic_cast<sd::Annotation*>(xAnnotation.get()) )
266
0
        {
267
0
            LOKCommentNotify(sdr::annotation::CommentNotificationType::Remove, &mrBase, *pAnnotation);
268
0
        }
269
0
    }
270
271
0
    UpdateTags();
272
0
}
273
274
void SAL_CALL AnnotationManagerImpl::disposing( const css::lang::EventObject& /*Source*/ )
275
0
{
276
0
}
277
278
rtl::Reference<sdr::annotation::Annotation> AnnotationManagerImpl::GetAnnotationById(sal_uInt32 nAnnotationId)
279
0
{
280
0
    SdPage* pPage = nullptr;
281
0
    do
282
0
    {
283
0
        pPage = GetNextPage(pPage, true);
284
0
        if( pPage && !pPage->getAnnotations().empty() )
285
0
        {
286
0
            sdr::annotation::AnnotationVector aAnnotations(pPage->getAnnotations());
287
0
            auto iterator = std::find_if(aAnnotations.begin(), aAnnotations.end(),
288
0
                [nAnnotationId](rtl::Reference<sdr::annotation::Annotation> const& xAnnotation)
289
0
                {
290
0
                        return xAnnotation->GetId() == nAnnotationId;
291
0
                });
292
0
            if (iterator != aAnnotations.end())
293
0
                return *iterator;
294
0
        }
295
0
    } while(pPage);
296
297
0
    rtl::Reference<sdr::annotation::Annotation> xAnnotationEmpty;
298
0
    return xAnnotationEmpty;
299
0
}
300
301
void AnnotationManagerImpl::ShowAnnotations( bool bShow )
302
0
{
303
    // enforce show annotations if a new annotation is inserted
304
0
    if( mbShowAnnotations != bShow )
305
0
    {
306
0
        mbShowAnnotations = bShow;
307
308
0
        if (SdOptions* pOptions = SdModule::get()->GetSdOptions(mpDoc->GetDocumentType()))
309
0
            pOptions->SetShowComments( mbShowAnnotations );
310
311
0
        UpdateTags();
312
0
    }
313
0
}
314
315
void AnnotationManagerImpl::ExecuteAnnotation(SfxRequest const & rReq )
316
0
{
317
0
    switch( rReq.GetSlot() )
318
0
    {
319
0
    case SID_INSERT_POSTIT:
320
0
        ExecuteInsertAnnotation( rReq );
321
0
        break;
322
0
    case SID_DELETE_POSTIT:
323
0
    case SID_DELETEALL_POSTIT:
324
0
    case SID_DELETEALLBYAUTHOR_POSTIT:
325
0
        ExecuteDeleteAnnotation( rReq );
326
0
        break;
327
0
    case SID_EDIT_POSTIT:
328
0
        ExecuteEditAnnotation( rReq );
329
0
        break;
330
0
    case SID_PREVIOUS_POSTIT:
331
0
    case SID_NEXT_POSTIT:
332
0
        SelectNextAnnotation( rReq.GetSlot() == SID_NEXT_POSTIT );
333
0
        break;
334
0
    case SID_REPLYTO_POSTIT:
335
0
        ExecuteReplyToAnnotation( rReq );
336
0
        break;
337
0
    case SID_TOGGLE_NOTES:
338
0
        ShowAnnotations( !mbShowAnnotations );
339
0
        break;
340
0
    }
341
0
}
342
343
void AnnotationManagerImpl::ExecuteInsertAnnotation(SfxRequest const & rReq)
344
0
{
345
0
    if (!comphelper::LibreOfficeKit::isActive() || comphelper::LibreOfficeKit::isTiledAnnotations())
346
0
        ShowAnnotations(true);
347
348
0
    const SfxItemSet* pArgs = rReq.GetArgs();
349
0
    OUString sText;
350
0
    if (pArgs)
351
0
    {
352
0
        if (const SfxStringItem* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_TEXT))
353
0
        {
354
0
            sText = pPoolItem->GetValue();
355
0
        }
356
0
    }
357
358
0
    InsertAnnotation(sText);
359
0
}
360
361
void AnnotationManagerImpl::ExecuteDeleteAnnotation(SfxRequest const & rReq)
362
0
{
363
0
    const SfxItemSet* pArgs = rReq.GetArgs();
364
365
0
    switch( rReq.GetSlot() )
366
0
    {
367
0
    case SID_DELETEALL_POSTIT:
368
0
        DeleteAllAnnotations();
369
0
        break;
370
0
    case SID_DELETEALLBYAUTHOR_POSTIT:
371
0
        if( pArgs )
372
0
        {
373
0
            const SfxPoolItem*  pPoolItem = nullptr;
374
0
            if( SfxItemState::SET == pArgs->GetItemState( SID_DELETEALLBYAUTHOR_POSTIT, true, &pPoolItem ) )
375
0
            {
376
0
                OUString sAuthor( static_cast<const SfxStringItem*>( pPoolItem )->GetValue() );
377
0
                DeleteAnnotationsByAuthor( sAuthor );
378
0
            }
379
0
        }
380
0
        break;
381
0
    case SID_DELETE_POSTIT:
382
0
        {
383
0
            rtl::Reference<sdr::annotation::Annotation> xAnnotation;
384
0
            sal_uInt32 nId = 0;
385
0
            if( pArgs )
386
0
            {
387
0
                const SfxPoolItem*  pPoolItem = nullptr;
388
0
                if( SfxItemState::SET == pArgs->GetItemState( SID_DELETE_POSTIT, true, &pPoolItem ) )
389
0
                {
390
0
                    uno::Reference<office::XAnnotation> xTmpAnnotation;
391
0
                    if (static_cast<const SfxUnoAnyItem*>(pPoolItem)->GetValue() >>= xTmpAnnotation)
392
0
                    {
393
0
                        xAnnotation = dynamic_cast<sdr::annotation::Annotation*>(xTmpAnnotation.get());
394
0
                        assert(bool(xAnnotation) == bool(xTmpAnnotation) && "must be of concrete type sd::Annotation");
395
0
                    }
396
0
                }
397
0
                if( SfxItemState::SET == pArgs->GetItemState( SID_ATTR_POSTIT_ID, true, &pPoolItem ) )
398
0
                    nId = static_cast<const SvxPostItIdItem*>(pPoolItem)->GetValue().toUInt32();
399
0
            }
400
401
0
            if (nId != 0)
402
0
                xAnnotation = GetAnnotationById(nId);
403
0
            else if( !xAnnotation.is() )
404
0
                GetSelectedAnnotation(xAnnotation);
405
406
0
            DeleteAnnotation(xAnnotation);
407
0
        }
408
0
        break;
409
0
    }
410
411
0
    UpdateTags();
412
0
}
413
414
void AnnotationManagerImpl::ExecuteEditAnnotation(SfxRequest const & rReq)
415
0
{
416
0
    const SfxItemSet* pArgs = rReq.GetArgs();
417
0
    rtl::Reference<sdr::annotation::Annotation> xAnnotation;
418
0
    OUString sText;
419
0
    sal_Int32 nPositionX = -1;
420
0
    sal_Int32 nPositionY = -1;
421
422
0
    if (!pArgs)
423
0
        return;
424
425
0
    if (mpDoc->IsUndoEnabled())
426
0
        mpDoc->BegUndo(SdResId(STR_ANNOTATION_UNDO_EDIT));
427
428
0
    if (const SvxPostItIdItem* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_ID))
429
0
    {
430
0
        sal_uInt32 nId = pPoolItem->GetValue().toUInt32();
431
0
        xAnnotation = GetAnnotationById(nId);
432
0
    }
433
0
    if (const SfxStringItem* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_TEXT))
434
0
        sText = pPoolItem->GetValue();
435
436
0
    if (const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_POSITION_X))
437
0
        nPositionX = pPoolItem->GetValue();
438
439
0
    if (const SfxInt32Item* pPoolItem = pArgs->GetItemIfSet(SID_ATTR_POSTIT_POSITION_Y))
440
0
        nPositionY = pPoolItem->GetValue();
441
442
0
    if (xAnnotation.is())
443
0
    {
444
0
        auto pSdAnnotation = static_cast<sd::Annotation*>(xAnnotation.get());
445
0
        pSdAnnotation->createChangeUndo();
446
447
0
        SdrObject* pObject = xAnnotation->findAnnotationObject();
448
0
        if (pObject && nPositionX >= 0 && nPositionY >= 0)
449
0
        {
450
0
            double fX = convertTwipToMm100<double>(nPositionX);
451
0
            double fY = convertTwipToMm100<double>(nPositionY);
452
453
0
            ::tools::Long deltaX = std::round(fX - (pSdAnnotation->getPosition().X * 100.0));
454
0
            ::tools::Long deltaY = std::round(fY - (pSdAnnotation->getPosition().Y * 100.0));
455
456
0
            pObject->Move({ deltaX, deltaY });
457
0
        }
458
459
0
        if (!sText.isEmpty())
460
0
        {
461
            // TODO: Not allow other authors to change others' comments ?
462
0
            uno::Reference<text::XText> xText(xAnnotation->getTextRange());
463
0
            xText->setString(sText);
464
0
        }
465
466
0
        LOKCommentNotifyAll(sdr::annotation::CommentNotificationType::Modify, *xAnnotation);
467
0
    }
468
469
0
    if (mpDoc->IsUndoEnabled())
470
0
        mpDoc->EndUndo();
471
472
0
    UpdateTags(true);
473
0
}
474
475
void AnnotationManagerImpl::InsertAnnotation(const OUString& rText)
476
0
{
477
0
    SdPage* pPage = GetCurrentPage();
478
0
    if (!pPage)
479
0
        return;
480
481
0
    if (mpDoc->IsUndoEnabled())
482
0
        mpDoc->BegUndo(SdResId(STR_ANNOTATION_UNDO_INSERT));
483
484
    // find free space for new annotation
485
0
    int y = 0;
486
0
    int x = 0;
487
488
0
    sdr::annotation::AnnotationVector aAnnotations(pPage->getAnnotations());
489
0
    if (!aAnnotations.empty())
490
0
    {
491
0
        const int fPageWidth = pPage->GetSize().Width();
492
0
        const int fWidth = 1000;
493
0
        const int fHeight = 800;
494
495
0
        while (true)
496
0
        {
497
0
            ::tools::Rectangle aNewRect(Point(x, y), Size(fWidth, fHeight));
498
0
            bool bFree = true;
499
500
0
            for (const auto& rxAnnotation : aAnnotations)
501
0
            {
502
0
                geometry::RealPoint2D aRealPoint2D(rxAnnotation->getPosition());
503
0
                Point aPoint(::tools::Long(aRealPoint2D.X * 100.0), ::tools::Long(aRealPoint2D.Y * 100.0));
504
0
                Size aSize(fWidth, fHeight);
505
506
0
                if (aNewRect.Overlaps(::tools::Rectangle(aPoint, aSize)))
507
0
                {
508
0
                    bFree = false;
509
0
                    break;
510
0
                }
511
0
            }
512
513
0
            if (!bFree)
514
0
            {
515
0
                x += fWidth;
516
0
                if (x > fPageWidth)
517
0
                {
518
0
                    x = 0;
519
0
                    y += fHeight;
520
0
                }
521
0
            }
522
0
            else
523
0
            {
524
0
                break;
525
0
            }
526
0
        }
527
0
    }
528
529
0
    rtl::Reference<sdr::annotation::Annotation> xAnnotation = pPage->createAnnotation();
530
531
0
    OUString sAuthor;
532
0
    if (comphelper::LibreOfficeKit::isActive())
533
0
        sAuthor = mrBase.GetMainViewShell()->GetView()->GetAuthor();
534
0
    else
535
0
    {
536
0
        SvtUserOptions aUserOptions;
537
0
        sAuthor = aUserOptions.GetFullName();
538
0
        xAnnotation->setInitials( aUserOptions.GetID() );
539
0
    }
540
541
0
    if (!rText.isEmpty())
542
0
    {
543
0
        uno::Reference<text::XText> xText(xAnnotation->getTextRange());
544
0
        xText->setString(rText);
545
0
    }
546
547
    // set current author to new annotation
548
0
    xAnnotation->setAuthor( sAuthor );
549
    // set current time to new annotation
550
0
    xAnnotation->setDateTime( getCurrentDateTime() );
551
552
    // set position
553
0
    geometry::RealPoint2D aPosition(x / 100.0, y / 100.0);
554
0
    xAnnotation->setPosition(aPosition);
555
0
    xAnnotation->setSize({5.0, 5.0});
556
557
0
    pPage->addAnnotation(xAnnotation, -1);
558
559
0
    if (mpDoc->IsUndoEnabled())
560
0
        mpDoc->EndUndo();
561
562
    // Tell our LOK clients about new comment added
563
0
    LOKCommentNotifyAll(sdr::annotation::CommentNotificationType::Add, *xAnnotation);
564
565
0
    UpdateTags(true);
566
0
    SelectAnnotation(xAnnotation, true);
567
0
}
568
569
void AnnotationManagerImpl::ExecuteReplyToAnnotation( SfxRequest const & rReq )
570
0
{
571
0
    rtl::Reference< sdr::annotation::Annotation> xAnnotation;
572
0
    const SfxItemSet* pArgs = rReq.GetArgs();
573
0
    OUString sReplyText;
574
0
    if( pArgs )
575
0
    {
576
0
        const SfxPoolItem*  pPoolItem = nullptr;
577
0
        if( SfxItemState::SET == pArgs->GetItemState( SID_ATTR_POSTIT_ID, true, &pPoolItem ) )
578
0
        {
579
0
            sal_uInt32 nReplyId = 0; // Id of the comment to reply to
580
0
            nReplyId = static_cast<const SvxPostItIdItem*>(pPoolItem)->GetValue().toUInt32();
581
0
            xAnnotation = GetAnnotationById(nReplyId);
582
0
        }
583
0
        else if( SfxItemState::SET == pArgs->GetItemState( rReq.GetSlot(), true, &pPoolItem ) )
584
0
        {
585
0
            uno::Reference<office::XAnnotation> xTmpAnnotation;
586
0
            if (static_cast<const SfxUnoAnyItem*>(pPoolItem)->GetValue() >>= xTmpAnnotation)
587
0
            {
588
0
                xAnnotation = dynamic_cast<Annotation*>(xTmpAnnotation.get());
589
0
                assert(bool(xAnnotation) == bool(xTmpAnnotation) && "must be of concrete type sd::Annotation");
590
0
            }
591
0
        }
592
593
0
        if( SfxItemState::SET == pArgs->GetItemState( SID_ATTR_POSTIT_TEXT, true, &pPoolItem ) )
594
0
            sReplyText = static_cast<const SvxPostItTextItem*>( pPoolItem )->GetValue();
595
0
    }
596
597
0
    auto* pTextApi = getTextApiObject( xAnnotation );
598
0
    if( !pTextApi )
599
0
        return;
600
601
0
    if (mpDoc->IsUndoEnabled())
602
0
        mpDoc->BegUndo(SdResId(STR_ANNOTATION_REPLY));
603
604
0
    if (xAnnotation)
605
0
    {
606
0
        auto pSdAnnotation = static_cast<sd::Annotation*>(xAnnotation.get());
607
0
        pSdAnnotation->createChangeUndo();
608
0
    }
609
610
0
    ::Outliner aOutliner( GetAnnotationPool(),OutlinerMode::TextObject );
611
612
0
    SdDrawDocument::SetCalcFieldValueHdl( &aOutliner );
613
0
    aOutliner.SetUpdateLayout( true );
614
615
0
    OUString aStr(SdResId(STR_ANNOTATION_REPLY));
616
0
    OUString sAuthor( xAnnotation->getAuthor() );
617
0
    if( sAuthor.isEmpty() )
618
0
        sAuthor = SdResId( STR_ANNOTATION_NOAUTHOR );
619
620
0
    aStr = aStr.replaceFirst("%1", sAuthor) +
621
0
        " (" + getAnnotationDateTimeString( xAnnotation ) + "): \"";
622
623
0
    OUString sQuote( pTextApi->GetText() );
624
625
0
    if( sQuote.isEmpty() )
626
0
        sQuote = "...";
627
0
    aStr += sQuote + "\"\n";
628
629
0
    for( sal_Int32 nIdx = 0; nIdx >= 0; )
630
0
        aOutliner.Insert(aStr.getToken(0, '\n', nIdx), EE_PARA_MAX, -1);
631
632
0
    if( aOutliner.GetParagraphCount() > 1 )
633
0
    {
634
0
        SfxItemSet aAnswerSet( aOutliner.GetEmptyItemSet() );
635
0
        aAnswerSet.Put(SvxPostureItem(ITALIC_NORMAL,EE_CHAR_ITALIC));
636
637
0
        ESelection aSel;
638
0
        aSel.end.nPara = aOutliner.GetParagraphCount() - 2;
639
0
        aSel.end.nIndex = aOutliner.GetText( aOutliner.GetParagraph( aSel.end.nPara ) ).getLength();
640
641
0
        aOutliner.QuickSetAttribs( aAnswerSet, aSel );
642
0
    }
643
644
0
    if (!sReplyText.isEmpty())
645
0
        aOutliner.Insert(sReplyText);
646
647
0
    std::optional< OutlinerParaObject > pOPO( aOutliner.CreateParaObject() );
648
0
    pTextApi->SetText(*pOPO);
649
650
0
    OUString sReplyAuthor;
651
0
    if (comphelper::LibreOfficeKit::isActive())
652
0
        sReplyAuthor = mrBase.GetMainViewShell()->GetView()->GetAuthor();
653
0
    else
654
0
    {
655
0
        SvtUserOptions aUserOptions;
656
0
        sReplyAuthor = aUserOptions.GetFullName();
657
0
        xAnnotation->setInitials( aUserOptions.GetID() );
658
0
    }
659
660
0
    xAnnotation->setAuthor( sReplyAuthor );
661
    // set current time to reply
662
0
    xAnnotation->setDateTime( getCurrentDateTime() );
663
664
    // Tell our LOK clients about this (comment modification)
665
0
    LOKCommentNotifyAll(sdr::annotation::CommentNotificationType::Modify, *xAnnotation);
666
667
0
    if( mpDoc->IsUndoEnabled() )
668
0
        mpDoc->EndUndo();
669
670
0
    UpdateTags(true);
671
0
    SelectAnnotation( xAnnotation, true );
672
0
}
673
674
void AnnotationManagerImpl::DeleteAnnotation(rtl::Reference<sdr::annotation::Annotation> const& xAnnotation )
675
0
{
676
0
    SdPage* pPage = GetCurrentPage();
677
678
0
    if( xAnnotation.is() && pPage )
679
0
    {
680
0
        if( mpDoc->IsUndoEnabled() )
681
0
            mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE ) );
682
683
0
        pPage->removeAnnotation( xAnnotation );
684
685
0
        if( mpDoc->IsUndoEnabled() )
686
0
            mpDoc->EndUndo();
687
0
    }
688
0
}
689
690
void AnnotationManagerImpl::DeleteAnnotationsByAuthor( std::u16string_view sAuthor )
691
0
{
692
0
    if( mpDoc->IsUndoEnabled() )
693
0
        mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE ) );
694
695
0
    SdPage* pPage = nullptr;
696
0
    do
697
0
    {
698
0
        pPage = GetNextPage( pPage, true );
699
700
0
        if( pPage )
701
0
        {
702
0
            std::vector<rtl::Reference<sdr::annotation::Annotation>> aAnnotations(pPage->getAnnotations()); // intentionally copy
703
0
            for (auto const& xAnnotation : aAnnotations)
704
0
            {
705
0
                if( xAnnotation->getAuthor() == sAuthor )
706
0
                {
707
0
                    if( mxSelectedAnnotation == xAnnotation )
708
0
                        mxSelectedAnnotation.clear();
709
0
                    pPage->removeAnnotation( xAnnotation );
710
0
                }
711
0
            }
712
0
        }
713
0
    } while( pPage );
714
715
0
    if( mpDoc->IsUndoEnabled() )
716
0
        mpDoc->EndUndo();
717
0
}
718
719
void AnnotationManagerImpl::DeleteAllAnnotations()
720
0
{
721
0
    if( mpDoc->IsUndoEnabled() )
722
0
        mpDoc->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE ) );
723
724
0
    SdPage* pPage = nullptr;
725
0
    do
726
0
    {
727
0
        pPage = GetNextPage( pPage, true );
728
729
0
        if( pPage && !pPage->getAnnotations().empty() )
730
0
        {
731
0
            std::vector<rtl::Reference<sdr::annotation::Annotation>> aAnnotations(pPage->getAnnotations()); // intentionally copy
732
0
            for( const auto& rxAnnotation : aAnnotations)
733
0
            {
734
0
                pPage->removeAnnotation( rxAnnotation );
735
0
            }
736
0
        }
737
0
    }
738
0
    while( pPage );
739
740
0
    mxSelectedAnnotation.clear();
741
742
0
    if( mpDoc->IsUndoEnabled() )
743
0
        mpDoc->EndUndo();
744
0
}
745
746
void AnnotationManagerImpl::GetAnnotationState(SfxItemSet& rSet)
747
0
{
748
0
    SdPage* pCurrentPage = GetCurrentPage();
749
750
0
    const bool bReadOnly = mrBase.GetDocShell()->IsReadOnly();
751
0
    const bool bWrongPageKind = (pCurrentPage == nullptr) || (pCurrentPage->GetPageKind() != PageKind::Standard);
752
753
0
    const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( GetODFSaneDefaultVersion() );
754
755
0
    if (bReadOnly || bWrongPageKind || (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012))
756
0
        rSet.DisableItem( SID_INSERT_POSTIT );
757
758
0
    rSet.Put(SfxBoolItem(SID_TOGGLE_NOTES, mbShowAnnotations));
759
760
0
    rtl::Reference<sdr::annotation::Annotation> xAnnotation;
761
0
    GetSelectedAnnotation(xAnnotation);
762
763
    // Don't disable these slot in case of LOK, as postit doesn't need to
764
    // selected before doing an operation on it in LOK
765
0
    if( (!xAnnotation.is() && !comphelper::LibreOfficeKit::isActive()) || bReadOnly )
766
0
    {
767
0
        rSet.DisableItem( SID_DELETE_POSTIT );
768
0
        rSet.DisableItem( SID_EDIT_POSTIT );
769
0
    }
770
771
0
    SdPage* pPage = nullptr;
772
773
0
    bool bHasAnnotations = false;
774
0
    do
775
0
    {
776
0
        pPage = GetNextPage( pPage, true );
777
778
0
        if( pPage && !pPage->getAnnotations().empty() )
779
0
            bHasAnnotations = true;
780
0
    }
781
0
    while( pPage && !bHasAnnotations );
782
783
0
    if( !bHasAnnotations || bReadOnly )
784
0
    {
785
0
        rSet.DisableItem( SID_DELETEALL_POSTIT );
786
0
    }
787
788
0
    if( bWrongPageKind || !bHasAnnotations )
789
0
    {
790
0
        rSet.DisableItem( SID_PREVIOUS_POSTIT );
791
0
        rSet.DisableItem( SID_NEXT_POSTIT );
792
0
    }
793
0
}
794
795
void AnnotationManagerImpl::SelectNextAnnotation(bool bForward)
796
0
{
797
0
    ShowAnnotations( true );
798
799
0
    rtl::Reference<sdr::annotation::Annotation> xCurrent;
800
0
    GetSelectedAnnotation(xCurrent);
801
0
    SdPage* pPage = GetCurrentPage();
802
0
    if( !pPage )
803
0
        return;
804
805
0
    sdr::annotation::AnnotationVector const& aAnnotations = pPage->getAnnotations();
806
807
0
    if( bForward )
808
0
    {
809
0
        if( xCurrent.is() )
810
0
        {
811
0
            auto iter = std::find(aAnnotations.begin(), aAnnotations.end(), xCurrent);
812
0
            if (iter != aAnnotations.end())
813
0
            {
814
0
                ++iter;
815
0
                if( iter != aAnnotations.end() )
816
0
                {
817
0
                    SelectAnnotation( *iter );
818
0
                    return;
819
0
                }
820
0
            }
821
0
        }
822
0
        else if( !aAnnotations.empty() )
823
0
        {
824
0
            SelectAnnotation( *(aAnnotations.begin()) );
825
0
            return;
826
0
        }
827
0
    }
828
0
    else
829
0
    {
830
0
        if( xCurrent.is() )
831
0
        {
832
0
            auto iter = std::find(aAnnotations.begin(), aAnnotations.end(), xCurrent);
833
0
            if (iter != aAnnotations.end() && iter != aAnnotations.begin())
834
0
            {
835
0
                --iter;
836
0
                SelectAnnotation( *iter );
837
0
                return;
838
0
            }
839
0
        }
840
0
        else if( !aAnnotations.empty() )
841
0
        {
842
0
            auto iterator = aAnnotations.end();
843
0
            iterator--;
844
0
            SelectAnnotation(*iterator);
845
0
            return;
846
0
        }
847
0
    }
848
849
0
    mxSelectedAnnotation.clear();
850
0
    do
851
0
    {
852
0
        do
853
0
        {
854
0
            pPage = GetNextPage( pPage, bForward );
855
856
0
            if( pPage && !pPage->getAnnotations().empty() )
857
0
            {
858
                // switch to next/previous slide with annotations
859
0
                std::shared_ptr<DrawViewShell> pDrawViewShell(std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
860
0
                if (pDrawViewShell != nullptr)
861
0
                {
862
0
                    pDrawViewShell->ChangeEditMode(pPage->IsMasterPage() ? EditMode::MasterPage : EditMode::Page, false);
863
0
                    pDrawViewShell->SwitchPage((pPage->GetPageNum() - 1) >> 1);
864
865
0
                    SfxDispatcher* pDispatcher = getDispatcher( mrBase );
866
0
                    if( pDispatcher )
867
0
                        pDispatcher->Execute( bForward ? SID_NEXT_POSTIT : SID_PREVIOUS_POSTIT );
868
869
0
                    return;
870
0
                }
871
0
            }
872
0
        }
873
0
        while( pPage );
874
875
        // The question text depends on the search direction.
876
0
        bool bImpress = mpDoc->GetDocumentType() == DocumentType::Impress;
877
0
        TranslateId pStringId;
878
0
        if(bForward)
879
0
            pStringId = bImpress ? STR_ANNOTATION_WRAP_FORWARD : STR_ANNOTATION_WRAP_FORWARD_DRAW;
880
0
        else
881
0
            pStringId = bImpress ? STR_ANNOTATION_WRAP_BACKWARD : STR_ANNOTATION_WRAP_BACKWARD_DRAW;
882
883
        // Pop up question box that asks the user whether to wrap around.
884
        // The dialog is made modal with respect to the whole application.
885
0
        std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
886
0
                                                       VclMessageType::Question, VclButtonsType::YesNo,
887
0
                                                       SdResId(pStringId)));
888
0
        xQueryBox->set_default_response(RET_YES);
889
0
        if (xQueryBox->run() != RET_YES)
890
0
            break;
891
0
    }
892
0
    while( true );
893
0
}
894
895
void AnnotationManagerImpl::SelectAnnotation(rtl::Reference<sdr::annotation::Annotation> const& xAnnotation, bool bEdit)
896
0
{
897
0
    mxSelectedAnnotation = xAnnotation;
898
0
    if (bEdit)
899
0
    {
900
0
        SdrObject* pObject = xAnnotation->findAnnotationObject();
901
0
        if (pObject)
902
0
        {
903
0
            auto& pAnnotationData = pObject->getAnnotationData();
904
0
            if (pAnnotationData)
905
0
                pAnnotationData->openPopup();
906
0
        }
907
0
    }
908
0
}
909
910
void AnnotationManagerImpl::GetSelectedAnnotation( rtl::Reference<sdr::annotation::Annotation>& xAnnotation )
911
0
{
912
0
    xAnnotation = mxSelectedAnnotation;
913
0
}
914
915
void AnnotationManagerImpl::invalidateSlots()
916
0
{
917
0
    SfxBindings* pBindings = getBindings( mrBase );
918
0
    if( pBindings )
919
0
    {
920
0
        pBindings->Invalidate( SID_INSERT_POSTIT );
921
0
        pBindings->Invalidate( SID_DELETE_POSTIT );
922
0
        pBindings->Invalidate( SID_DELETEALL_POSTIT );
923
0
        pBindings->Invalidate( SID_PREVIOUS_POSTIT );
924
0
        pBindings->Invalidate( SID_NEXT_POSTIT );
925
0
        pBindings->Invalidate( SID_UNDO );
926
0
        pBindings->Invalidate( SID_REDO );
927
0
    }
928
0
}
929
930
void AnnotationManagerImpl::onSelectionChanged()
931
0
{
932
0
    if (!mxView.is() || !mrBase.GetDrawView())
933
0
        return;
934
935
0
    rtl::Reference<SdPage> xPage = mrBase.GetMainViewShell()->getCurrentPage();
936
0
    if (xPage != mxCurrentPage)
937
0
    {
938
0
        mxCurrentPage = std::move(xPage);
939
0
        UpdateTags(true);
940
0
    }
941
0
}
942
943
void AnnotationManagerImpl::UpdateTags(bool bSynchron)
944
0
{
945
0
    SyncAnnotationObjects();
946
947
0
    invalidateSlots();
948
949
0
    if (bSynchron)
950
0
    {
951
0
        if (mnUpdateTagsEvent)
952
0
            Application::RemoveUserEvent(mnUpdateTagsEvent);
953
954
0
        UpdateTagsHdl(nullptr);
955
0
    }
956
0
    else
957
0
    {
958
0
        if (!mnUpdateTagsEvent && mxView.is())
959
0
            mnUpdateTagsEvent = Application::PostUserEvent(LINK(this, AnnotationManagerImpl, UpdateTagsHdl));
960
0
    }
961
0
}
962
963
IMPL_LINK_NOARG(AnnotationManagerImpl, UpdateTagsHdl, void*, void)
964
0
{
965
0
    mnUpdateTagsEvent  = nullptr;
966
0
    SyncAnnotationObjects();
967
968
0
    if (mrBase.GetDrawView())
969
0
        static_cast<::sd::View*>(mrBase.GetDrawView())->updateHandles();
970
971
0
    invalidateSlots();
972
0
}
973
974
namespace
975
{
976
977
void applyAnnotationCommon(SdrObject& rObject, rtl::Reference<sdr::annotation::Annotation> const& xAnnotation)
978
0
{
979
0
    rObject.setAsAnnotationObject();
980
0
    auto& xAnnotationData = rObject.getAnnotationData();
981
0
    xAnnotationData->mpAnnotationPopup.reset(new AnnotationPopup(xAnnotation));
982
0
    xAnnotationData->mxAnnotation = xAnnotation;
983
0
    rObject.SetPrintable(false);
984
0
}
985
986
void applyAnnotationProperties(SdrObject& rObject, sdr::annotation::CreationInfo const& rInfo)
987
0
{
988
0
    if (rInfo.mbColor)
989
0
    {
990
0
        rObject.SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
991
0
        rObject.SetMergedItem(XLineColorItem(OUString(), rInfo.maColor));
992
0
        sal_uInt16 nTransparence = 100.0 - (rInfo.maColor.GetAlpha() / 255.0) * 100.0;
993
0
        rObject.SetMergedItem(XLineTransparenceItem(nTransparence));
994
0
    }
995
0
    rObject.SetMergedItem(XLineWidthItem(rInfo.mnWidth));
996
997
0
    if (rInfo.mbFillColor)
998
0
    {
999
0
        rObject.SetMergedItem(XFillStyleItem(drawing::FillStyle_SOLID));
1000
0
        rObject.SetMergedItem(XFillColorItem(OUString(), rInfo.maFillColor));
1001
0
        sal_uInt16 nTransparence = 100.0 - (rInfo.maFillColor.GetAlpha() / 255.0) * 100.0;
1002
0
        rObject.SetMergedItem(XFillTransparenceItem(nTransparence));
1003
0
    }
1004
0
}
1005
1006
}
1007
1008
void AnnotationManagerImpl::SyncAnnotationObjects()
1009
0
{
1010
0
    if (!mxCurrentPage.is() || !mpDoc)
1011
0
        return;
1012
1013
0
    std::shared_ptr<DrawViewShell> pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell());
1014
1015
0
    if (!pDrawViewShell)
1016
0
        return;
1017
1018
0
    auto* pView = pDrawViewShell->GetView();
1019
0
    if (!pView)
1020
0
        return;
1021
1022
0
    if (!pView->GetSdrPageView())
1023
0
        return;
1024
1025
0
    auto& rModel = pView->getSdrModelFromSdrView();
1026
1027
0
    sal_Int32 nIndex = 1;
1028
0
    bool bAnnotatonInserted = false;
1029
0
    for (auto const& xAnnotation : mxCurrentPage->getAnnotations())
1030
0
    {
1031
0
        SdrObject* pObject = xAnnotation->findAnnotationObject();
1032
1033
0
        if (pObject)
1034
0
        {
1035
0
            nIndex++;
1036
0
            pObject->SetVisible(mbShowAnnotations);
1037
0
            continue;
1038
0
        }
1039
1040
0
        if (!bAnnotatonInserted && mpDoc->IsUndoEnabled())
1041
0
            mpDoc->BegUndo(SdResId(STR_ANNOTATION_UNDO_INSERT));
1042
1043
0
        bAnnotatonInserted = true;
1044
1045
0
        auto const& rInfo = xAnnotation->getCreationInfo();
1046
1047
0
        auto aRealPoint2D = xAnnotation->getPosition();
1048
0
        Point aPosition(::tools::Long(aRealPoint2D.X * 100.0), ::tools::Long(aRealPoint2D.Y * 100.0));
1049
1050
0
        auto aRealSize2D = xAnnotation->getSize();
1051
0
        Size aSize(::tools::Long(aRealSize2D.Width * 100.0), ::tools::Long(aRealSize2D.Height * 100.0));
1052
        // If the size is not set, set it to a default value so it is non-zero
1053
0
        if (aSize.getWidth() == 0 || aSize.getHeight() == 0)
1054
0
             aSize = Size(500, 500);
1055
1056
0
        ::tools::Rectangle aRectangle(aPosition, aSize);
1057
1058
0
        rtl::Reference<SdrObject> pNewObject;
1059
1060
0
        if (rInfo.meType == sdr::annotation::AnnotationType::None)
1061
0
        {
1062
0
            sal_uInt16 nAuthorIndex = mpDoc->GetAnnotationAuthorIndex(xAnnotation->getAuthor());
1063
1064
0
            sdr::annotation::AnnotationViewData aAnnotationViewData
1065
0
            {
1066
0
                .nIndex = nIndex,
1067
0
                .nAuthorIndex = nAuthorIndex
1068
0
            };
1069
1070
0
            rtl::Reference<sdr::annotation::AnnotationObject> pAnnotationObject = new sdr::annotation::AnnotationObject(rModel, aRectangle, aAnnotationViewData);
1071
0
            pNewObject = pAnnotationObject;
1072
1073
0
            applyAnnotationCommon(*pNewObject, xAnnotation);
1074
1075
0
            pAnnotationObject->ApplyAnnotationName();
1076
0
        }
1077
0
        else if (rInfo.meType == sdr::annotation::AnnotationType::FreeText)
1078
0
        {
1079
0
            rtl::Reference<SdrRectObj> pRectangleObject = new SdrRectObj(rModel, aRectangle, SdrObjKind::Text);
1080
0
            pNewObject = pRectangleObject;
1081
1082
0
            applyAnnotationCommon(*pNewObject, xAnnotation);
1083
0
            applyAnnotationProperties(*pNewObject, rInfo);
1084
1085
0
            OUString aString = xAnnotation->getTextRange()->getString();
1086
0
            pRectangleObject->SetText(aString);
1087
0
        }
1088
0
        else if (rInfo.meType == sdr::annotation::AnnotationType::Square)
1089
0
        {
1090
0
            pNewObject = new SdrRectObj(rModel, aRectangle);
1091
1092
0
            applyAnnotationCommon(*pNewObject, xAnnotation);
1093
0
            applyAnnotationProperties(*pNewObject, rInfo);
1094
0
        }
1095
0
        else if (rInfo.meType == sdr::annotation::AnnotationType::Circle)
1096
0
        {
1097
0
            pNewObject = new SdrCircObj(rModel, SdrCircKind::Full, aRectangle);
1098
1099
0
            applyAnnotationCommon(*pNewObject, xAnnotation);
1100
0
            applyAnnotationProperties(*pNewObject, rInfo);
1101
0
        }
1102
0
        else if (rInfo.meType == sdr::annotation::AnnotationType::Stamp)
1103
0
        {
1104
0
            rtl::Reference<SdrGrafObj> pGrafObject = new SdrGrafObj(rModel, Graphic(rInfo.maBitmapEx), aRectangle);
1105
0
            pNewObject = pGrafObject;
1106
1107
0
            applyAnnotationCommon(*pNewObject, xAnnotation);
1108
1109
0
            pGrafObject->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
1110
0
            pGrafObject->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
1111
0
        }
1112
0
        else
1113
0
        {
1114
0
            SdrObjKind ekind = SdrObjKind::Polygon;
1115
1116
0
            switch (rInfo.meType)
1117
0
            {
1118
0
                case sdr::annotation::AnnotationType::Polygon:
1119
0
                    ekind = SdrObjKind::Polygon;
1120
0
                    break;
1121
0
                case sdr::annotation::AnnotationType::Line:
1122
0
                    ekind = SdrObjKind::PolyLine;
1123
0
                    break;
1124
0
                case sdr::annotation::AnnotationType::Ink:
1125
0
                    ekind = SdrObjKind::FreehandLine;
1126
0
                    break;
1127
0
                default:
1128
0
                    break;
1129
0
            }
1130
1131
0
            basegfx::B2DPolyPolygon aPolyPolygon;
1132
0
            for (auto const& rPolygon : rInfo.maPolygons)
1133
0
                aPolyPolygon.append(rPolygon);
1134
1135
0
            pNewObject = new SdrPathObj(rModel, ekind, std::move(aPolyPolygon));
1136
1137
0
            applyAnnotationCommon(*pNewObject, xAnnotation);
1138
0
            applyAnnotationProperties(*pNewObject, rInfo);
1139
0
        }
1140
1141
0
        pNewObject->SetRelativePos(aRectangle.TopLeft());
1142
0
        pNewObject->SetVisible(mbShowAnnotations);
1143
1144
0
        pView->InsertObjectAtView(pNewObject.get(), *pView->GetSdrPageView());
1145
1146
0
        nIndex++;
1147
0
    }
1148
1149
0
    if (bAnnotatonInserted && mpDoc->IsUndoEnabled())
1150
0
        mpDoc->EndUndo();
1151
0
}
1152
1153
void AnnotationManagerImpl::addListener()
1154
0
{
1155
0
    Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,AnnotationManagerImpl,EventMultiplexerListener) );
1156
0
    mrBase.GetEventMultiplexer()->AddEventListener(aLink);
1157
0
}
1158
1159
void AnnotationManagerImpl::removeListener()
1160
0
{
1161
0
    Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,AnnotationManagerImpl,EventMultiplexerListener) );
1162
0
    mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
1163
0
}
1164
1165
IMPL_LINK(AnnotationManagerImpl,EventMultiplexerListener,
1166
    tools::EventMultiplexerEvent&, rEvent, void)
1167
0
{
1168
0
    switch (rEvent.meEventId)
1169
0
    {
1170
0
        case EventMultiplexerEventId::CurrentPageChanged:
1171
0
        case EventMultiplexerEventId::EditViewSelection:
1172
0
            onSelectionChanged();
1173
0
            break;
1174
1175
0
        case EventMultiplexerEventId::MainViewRemoved:
1176
0
            mxView.clear();
1177
0
            onSelectionChanged();
1178
0
            break;
1179
1180
0
        case EventMultiplexerEventId::MainViewAdded:
1181
0
            mxView = mrBase.GetDrawController();
1182
0
            onSelectionChanged();
1183
0
            break;
1184
1185
0
        default: break;
1186
0
    }
1187
0
}
1188
1189
// TODO: Update colors on notification via DrawViewShell::ConfigurationChanged()
1190
Color AnnotationManagerImpl::GetColor(sal_uInt16 aAuthorIndex)
1191
0
{
1192
0
    if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1193
0
    {
1194
0
        svtools::ColorConfig aColorConfig;
1195
0
        switch (aAuthorIndex % 9)
1196
0
        {
1197
0
            case 0: return aColorConfig.GetColorValue(svtools::AUTHOR1).nColor;
1198
0
            case 1: return aColorConfig.GetColorValue(svtools::AUTHOR2).nColor;
1199
0
            case 2: return aColorConfig.GetColorValue(svtools::AUTHOR3).nColor;
1200
0
            case 3: return aColorConfig.GetColorValue(svtools::AUTHOR4).nColor;
1201
0
            case 4: return aColorConfig.GetColorValue(svtools::AUTHOR5).nColor;
1202
0
            case 5: return aColorConfig.GetColorValue(svtools::AUTHOR6).nColor;
1203
0
            case 6: return aColorConfig.GetColorValue(svtools::AUTHOR7).nColor;
1204
0
            case 7: return aColorConfig.GetColorValue(svtools::AUTHOR8).nColor;
1205
0
            case 8: return aColorConfig.GetColorValue(svtools::AUTHOR9).nColor;
1206
0
        }
1207
0
    }
1208
1209
0
    return COL_WHITE;
1210
0
}
1211
1212
Color AnnotationManagerImpl::GetColorLight(sal_uInt16 aAuthorIndex)
1213
0
{
1214
0
    Color aColor = GetColor(aAuthorIndex);
1215
0
    if (MiscSettings::GetUseDarkMode())
1216
0
        aColor.IncreaseLuminance(30);
1217
0
    else
1218
0
        aColor.DecreaseLuminance(30);
1219
0
    return aColor;
1220
0
}
1221
1222
Color AnnotationManagerImpl::GetColorDark(sal_uInt16 aAuthorIndex)
1223
0
{
1224
0
    Color aColor = GetColor(aAuthorIndex);;
1225
0
    if (MiscSettings::GetUseDarkMode())
1226
0
        aColor.DecreaseLuminance(80);
1227
0
    else
1228
0
        aColor.IncreaseLuminance(80);
1229
0
    return aColor;
1230
0
}
1231
1232
SdPage* AnnotationManagerImpl::GetNextPage( SdPage const * pPage, bool bForward )
1233
0
{
1234
0
    if( pPage == nullptr )
1235
0
    {
1236
0
        if (bForward)
1237
0
            return mpDoc->GetSdPage(0, PageKind::Standard ); // first page
1238
0
        else
1239
0
            return mpDoc->GetMasterSdPage( mpDoc->GetMasterSdPageCount(PageKind::Standard) - 1, PageKind::Standard ); // last page
1240
0
    }
1241
1242
0
    sal_uInt16 nPageNum = static_cast<sal_uInt16>((pPage->GetPageNum() - 1) >> 1);
1243
1244
    // first all non master pages
1245
0
    if( !pPage->IsMasterPage() )
1246
0
    {
1247
0
        if( bForward )
1248
0
        {
1249
0
            if( nPageNum >= mpDoc->GetSdPageCount(PageKind::Standard)-1 )
1250
0
            {
1251
                // we reached end of draw pages, start with master pages (skip handout master for draw)
1252
0
                return mpDoc->GetMasterSdPage( (mpDoc->GetDocumentType() == DocumentType::Impress) ? 0 : 1, PageKind::Standard );
1253
0
            }
1254
0
            nPageNum++;
1255
0
        }
1256
0
        else
1257
0
        {
1258
0
            if( nPageNum == 0 )
1259
0
                return nullptr; // we are already on the first draw page, finished
1260
1261
0
            nPageNum--;
1262
0
        }
1263
0
        return mpDoc->GetSdPage(nPageNum, PageKind::Standard);
1264
0
    }
1265
0
    else
1266
0
    {
1267
0
        if( bForward )
1268
0
        {
1269
0
            if( nPageNum >= mpDoc->GetMasterSdPageCount(PageKind::Standard)-1 )
1270
0
            {
1271
0
                return nullptr;   // we reached the end, there is nothing more to see here
1272
0
            }
1273
0
            nPageNum++;
1274
0
        }
1275
0
        else
1276
0
        {
1277
0
            if( nPageNum == (mpDoc->GetDocumentType() == DocumentType::Impress ? 0 : 1) )
1278
0
            {
1279
                // we reached beginning of master pages, start with end if pages
1280
0
                return mpDoc->GetSdPage( mpDoc->GetSdPageCount(PageKind::Standard)-1, PageKind::Standard );
1281
0
            }
1282
1283
0
            nPageNum--;
1284
0
        }
1285
0
        return mpDoc->GetMasterSdPage(nPageNum,PageKind::Standard);
1286
0
    }
1287
0
}
1288
1289
SdPage* AnnotationManagerImpl::GetCurrentPage()
1290
0
{
1291
0
    if (auto pMainViewShell = mrBase.GetMainViewShell().get())
1292
0
        return pMainViewShell->getCurrentPage();
1293
0
    return nullptr;
1294
0
}
1295
1296
AnnotationManager::AnnotationManager( ViewShellBase& rViewShellBase )
1297
0
: mxImpl( new AnnotationManagerImpl( rViewShellBase ) )
1298
0
{
1299
0
    mxImpl->init();
1300
0
}
1301
1302
AnnotationManager::~AnnotationManager()
1303
0
{
1304
0
    mxImpl->dispose();
1305
0
}
1306
1307
void AnnotationManager::ExecuteAnnotation(SfxRequest const & rRequest)
1308
0
{
1309
0
    mxImpl->ExecuteAnnotation( rRequest );
1310
0
}
1311
1312
void AnnotationManager::GetAnnotationState(SfxItemSet& rItemSet)
1313
0
{
1314
0
    mxImpl->GetAnnotationState(rItemSet);
1315
0
}
1316
1317
void AnnotationManager::SelectAnnotation(rtl::Reference<sdr::annotation::Annotation> const& xAnnotation, bool bEdit)
1318
0
{
1319
0
    mxImpl->SelectAnnotation(xAnnotation, bEdit);
1320
0
}
1321
1322
} // end sd
1323
1324
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */