Coverage Report

Created: 2026-08-14 10:22

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