Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdmrkv.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
21
#include <svx/svdmrkv.hxx>
22
#include <svx/svdview.hxx>
23
#include <svx/svdpagv.hxx>
24
#include <svx/svdpage.hxx>
25
#include <svx/svdotable.hxx>
26
#include <svx/svdomedia.hxx>
27
#include <svx/svdogrp.hxx>
28
#include <svx/diagram/DiagramHelper_svx.hxx>
29
30
#include <osl/diagnose.h>
31
#include <osl/thread.h>
32
#include <rtl/strbuf.hxx>
33
#include <tools/debug.hxx>
34
#include <svx/svdoole2.hxx>
35
#include <svx/xfillit0.hxx>
36
#include <svx/xflgrit.hxx>
37
#include "gradtrns.hxx"
38
#include <svx/xflftrit.hxx>
39
#include <svx/dialmgr.hxx>
40
#include <svx/strings.hrc>
41
#include <svx/svdundo.hxx>
42
#include <svx/svdopath.hxx>
43
#include <svx/scene3d.hxx>
44
#include <svx/svdovirt.hxx>
45
#include <sdr/overlay/overlayrollingrectangle.hxx>
46
#include <svx/sdr/overlay/overlaypolypolygon.hxx>
47
#include <svx/sdr/contact/displayinfo.hxx>
48
#include <svx/sdr/contact/objectcontact.hxx>
49
#include <svx/sdr/overlay/overlaymanager.hxx>
50
#include <svx/sdr/overlay/overlayselection.hxx>
51
#include <svx/sdr/contact/viewcontact.hxx>
52
#include <svx/sdr/contact/viewobjectcontact.hxx>
53
#include <svx/sdrpaintwindow.hxx>
54
#include <svx/sdrpagewindow.hxx>
55
#include <svx/sdrhittesthelper.hxx>
56
#include <vcl/uitest/logger.hxx>
57
#include <vcl/uitest/eventdescription.hxx>
58
#include <vcl/window.hxx>
59
#include <o3tl/string_view.hxx>
60
#include <basegfx/polygon/b2dpolygontools.hxx>
61
62
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
63
#include <comphelper/lok.hxx>
64
#include <sfx2/lokhelper.hxx>
65
#include <sfx2/lokcomponenthelpers.hxx>
66
#include <sfx2/viewsh.hxx>
67
#include <sfx2/objsh.hxx>
68
#include <svtools/optionsdrawinglayer.hxx>
69
70
#include <drawinglayer/processor2d/textextractor2d.hxx>
71
#include <svl/cryptosign.hxx>
72
73
#include <array>
74
75
#include <com/sun/star/frame/XController.hpp>
76
#include <com/sun/star/view/XSelectionSupplier.hpp>
77
78
#include <boost/property_tree/json_parser.hpp>
79
80
#include <com/sun/star/lang/XServiceInfo.hpp>
81
#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
82
83
using namespace com::sun::star;
84
85
// Migrate Marking of Objects, Points and GluePoints
86
87
class ImplMarkingOverlay
88
{
89
    // The OverlayObjects
90
    sdr::overlay::OverlayObjectList               maObjects;
91
92
    // The remembered second position in logical coordinates
93
    basegfx::B2DPoint                               maSecondPosition;
94
95
    // A flag to remember if the action is for unmarking.
96
    bool                                            mbUnmarking : 1;
97
98
public:
99
    ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking);
100
101
    // The OverlayObjects are cleared using the destructor of OverlayObjectList.
102
    // That destructor calls clear() at the list which removes all objects from the
103
    // OverlayManager and deletes them.
104
105
    void SetSecondPosition(const basegfx::B2DPoint& rNewPosition);
106
0
    bool IsUnmarking() const { return mbUnmarking; }
107
};
108
109
ImplMarkingOverlay::ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking)
110
0
:   maSecondPosition(rStartPos),
111
0
    mbUnmarking(bUnmarking)
112
0
{
113
0
    if (comphelper::LibreOfficeKit::isActive())
114
0
        return; // We do client-side object manipulation with the Kit API
115
116
0
    for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
117
0
    {
118
0
        SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
119
0
        const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
120
121
0
        if (xTargetOverlay.is())
122
0
        {
123
0
            std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(new sdr::overlay::OverlayRollingRectangleStriped(
124
0
                rStartPos, rStartPos, false));
125
0
            xTargetOverlay->add(*pNew);
126
0
            maObjects.append(std::move(pNew));
127
0
        }
128
0
    }
129
0
}
130
131
void ImplMarkingOverlay::SetSecondPosition(const basegfx::B2DPoint& rNewPosition)
132
0
{
133
0
    if(rNewPosition != maSecondPosition)
134
0
    {
135
        // apply to OverlayObjects
136
0
        for(sal_uInt32 a(0); a < maObjects.count(); a++)
137
0
        {
138
0
            sdr::overlay::OverlayRollingRectangleStriped& rCandidate = static_cast< sdr::overlay::OverlayRollingRectangleStriped&>(maObjects.getOverlayObject(a));
139
0
            rCandidate.setSecondPosition(rNewPosition);
140
0
        }
141
142
        // remember new position
143
0
        maSecondPosition = rNewPosition;
144
0
    }
145
0
}
146
147
class MarkingSelectionOverlay
148
{
149
    sdr::overlay::OverlayObjectList maObjects;
150
public:
151
    MarkingSelectionOverlay(const SdrPaintView& rView, basegfx::B2DRectangle const& rSelection)
152
0
    {
153
0
        if (comphelper::LibreOfficeKit::isActive())
154
0
            return; // We do client-side object manipulation with the Kit API
155
156
0
        for (sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
157
0
        {
158
0
            SdrPaintWindow* pPaintWindow = rView.GetPaintWindow(a);
159
0
            const rtl::Reference<sdr::overlay::OverlayManager>& xTargetOverlay = pPaintWindow->GetOverlayManager();
160
161
0
            if (xTargetOverlay.is())
162
0
            {
163
0
                basegfx::B2DPolyPolygon aPolyPoly(basegfx::utils::createPolygonFromRect(rSelection));
164
0
                auto pNew = std::make_unique<sdr::overlay::OverlayPolyPolygon>(aPolyPoly, COL_GRAY, 0, COL_TRANSPARENT);
165
0
                xTargetOverlay->add(*pNew);
166
0
                maObjects.append(std::move(pNew));
167
0
            }
168
0
        }
169
0
    }
170
};
171
172
class MarkingSubSelectionOverlay
173
{
174
    sdr::overlay::OverlayObjectList maObjects;
175
176
public:
177
    MarkingSubSelectionOverlay(const SdrPaintView& rView, std::vector<basegfx::B2DRectangle> const & rSelections)
178
0
    {
179
0
        if (comphelper::LibreOfficeKit::isActive())
180
0
            return; // We do client-side object manipulation with the Kit API
181
182
0
        for (sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
183
0
        {
184
0
            SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
185
0
            const rtl::Reference<sdr::overlay::OverlayManager>& xTargetOverlay = pCandidate->GetOverlayManager();
186
187
0
            if (xTargetOverlay.is())
188
0
            {
189
0
                const Color aHighlightColor = SvtOptionsDrawinglayer::getHilightColor();
190
191
0
                std::unique_ptr<sdr::overlay::OverlaySelection> pNew =
192
0
                    std::make_unique<sdr::overlay::OverlaySelection>(
193
0
                        sdr::overlay::OverlayType::Transparent,
194
0
                        aHighlightColor, std::vector(rSelections), false);
195
196
0
                xTargetOverlay->add(*pNew);
197
0
                maObjects.append(std::move(pNew));
198
0
            }
199
0
        }
200
0
    }
201
};
202
203
SdrMarkView::SdrMarkView(SdrModel& rSdrModel, OutputDevice* pOut)
204
320k
    : SdrSnapView(rSdrModel, pOut)
205
320k
    , mpMarkedObj(nullptr)
206
320k
    , mpMarkedPV(nullptr)
207
320k
    , maHdlList(this)
208
320k
    , meDragMode(SdrDragMode::Move)
209
320k
    , meEditMode(SdrViewEditMode::Edit)
210
320k
    , meEditMode0(SdrViewEditMode::Edit)
211
320k
    , mbDesignMode(false)
212
320k
    , mbForceFrameHandles(false)
213
320k
    , mbPlusHdlAlways(false)
214
320k
    , mbInsPolyPoint(false)
215
320k
    , mbMarkedObjRectDirty(false)
216
320k
    , mbMrkPntDirty(false)
217
320k
    , mbMarkedPointsRectsDirty(false)
218
320k
    , mbMarkHandlesHidden(false)
219
320k
    , mbNegativeX(false)
220
320k
{
221
222
320k
    BrkMarkObj();
223
320k
    BrkMarkPoints();
224
320k
    BrkMarkGluePoints();
225
226
320k
    StartListening(rSdrModel);
227
320k
}
228
229
SdrMarkView::~SdrMarkView()
230
320k
{
231
    // Migrate selections
232
320k
    BrkMarkObj();
233
320k
    BrkMarkPoints();
234
320k
    BrkMarkGluePoints();
235
320k
}
236
237
void SdrMarkView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
238
425M
{
239
425M
    if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
240
425M
    {
241
425M
        const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
242
425M
        SdrHintKind eKind=pSdrHint->GetKind();
243
425M
        if (eKind==SdrHintKind::ObjectChange || eKind==SdrHintKind::ObjectInserted || eKind==SdrHintKind::ObjectRemoved)
244
105M
        {
245
105M
            mbMarkedObjRectDirty=true;
246
105M
            mbMarkedPointsRectsDirty=true;
247
105M
        }
248
425M
    }
249
425M
    SdrSnapView::Notify(rBC,rHint);
250
425M
}
251
252
void SdrMarkView::ModelHasChanged()
253
0
{
254
0
    SdrPaintView::ModelHasChanged();
255
0
    GetMarkedObjectListWriteAccess().SetNameDirty();
256
0
    mbMarkedObjRectDirty=true;
257
0
    mbMarkedPointsRectsDirty=true;
258
    // Example: Obj is selected and maMarkedObjectList is sorted.
259
    // In another View 2, the ObjOrder is changed (e. g. MovToTop())
260
    // Then we need to re-sort MarkList.
261
0
    GetMarkedObjectListWriteAccess().SetUnsorted();
262
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
263
0
    rMarkList.ForceSort();
264
0
    mbMrkPntDirty=true;
265
0
    UndirtyMrkPnt();
266
0
    SdrView* pV=static_cast<SdrView*>(this);
267
0
    if (!pV->IsDragObj() && !pV->IsInsObjPoint()) {
268
0
        AdjustMarkHdl();
269
0
    }
270
271
0
    if (comphelper::LibreOfficeKit::isActive())
272
0
        modelHasChangedLOKit();
273
0
}
274
275
void SdrMarkView::modelHasChangedLOKit()
276
0
{
277
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
278
0
    if (rMarkList.GetMarkCount() <= 0)
279
0
        return;
280
281
    //TODO: Is MarkedObjRect valid at this point?
282
0
    tools::Rectangle aSelection(GetMarkedObjRect());
283
0
    tools::Rectangle* pResultSelection;
284
0
    if (aSelection.IsEmpty())
285
0
        pResultSelection = nullptr;
286
0
    else
287
0
    {
288
0
        sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
289
0
        if (nTotalPaintWindows == 1)
290
0
        {
291
0
            const OutputDevice* pOut = this->GetFirstOutputDevice();
292
0
            const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr;
293
0
            if (pWin && pWin->IsChart())
294
0
            {
295
0
                if (SfxViewShell* pViewShell = GetSfxViewShell())
296
0
                {
297
0
                    const vcl::Window* pViewShellWindow = pViewShell->GetEditWindowForActiveOLEObj();
298
0
                    if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
299
0
                    {
300
0
                        Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
301
0
                        Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
302
0
                        aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
303
0
                    }
304
0
                }
305
0
            }
306
0
        }
307
308
        // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
309
0
        if (mpMarkedPV)
310
0
        {
311
0
            if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
312
0
            {
313
0
                if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
314
0
                    aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
315
0
            }
316
0
        }
317
318
0
        pResultSelection = &aSelection;
319
320
0
        if (mbNegativeX)
321
0
        {
322
            // Convert to positive X doc-coordinates
323
0
            tools::Long nTmp = aSelection.Left();
324
0
            aSelection.SetLeft(-aSelection.Right());
325
0
            aSelection.SetRight(-nTmp);
326
0
        }
327
0
    }
328
329
0
    if (SfxViewShell* pViewShell = GetSfxViewShell())
330
0
        SfxLokHelper::notifyInvalidation(pViewShell, pResultSelection);
331
0
}
332
333
bool SdrMarkView::IsAction() const
334
0
{
335
0
    return SdrSnapView::IsAction() || IsMarkObj() || IsMarkPoints() || IsMarkGluePoints();
336
0
}
337
338
void SdrMarkView::MovAction(const Point& rPnt)
339
0
{
340
0
    SdrSnapView::MovAction(rPnt);
341
342
0
    if(IsMarkObj())
343
0
    {
344
0
        MovMarkObj(rPnt);
345
0
    }
346
0
    else if(IsMarkPoints())
347
0
    {
348
0
        MovMarkPoints(rPnt);
349
0
    }
350
0
    else if(IsMarkGluePoints())
351
0
    {
352
0
        MovMarkGluePoints(rPnt);
353
0
    }
354
0
}
355
356
void SdrMarkView::EndAction()
357
0
{
358
0
    if(IsMarkObj())
359
0
    {
360
0
        EndMarkObj();
361
0
    }
362
0
    else if(IsMarkPoints())
363
0
    {
364
0
        EndMarkPoints();
365
0
    }
366
0
    else if(IsMarkGluePoints())
367
0
    {
368
0
        EndMarkGluePoints();
369
0
    }
370
371
0
    SdrSnapView::EndAction();
372
0
}
373
374
void SdrMarkView::BckAction()
375
0
{
376
0
    SdrSnapView::BckAction();
377
0
    BrkMarkObj();
378
0
    BrkMarkPoints();
379
0
    BrkMarkGluePoints();
380
0
}
381
382
void SdrMarkView::BrkAction()
383
58.4k
{
384
58.4k
    SdrSnapView::BrkAction();
385
58.4k
    BrkMarkObj();
386
58.4k
    BrkMarkPoints();
387
58.4k
    BrkMarkGluePoints();
388
58.4k
}
389
390
void SdrMarkView::TakeActionRect(tools::Rectangle& rRect) const
391
0
{
392
0
    if(IsMarkObj() || IsMarkPoints() || IsMarkGluePoints())
393
0
    {
394
0
        rRect = tools::Rectangle(maDragStat.GetStart(), maDragStat.GetNow());
395
0
    }
396
0
    else
397
0
    {
398
0
        SdrSnapView::TakeActionRect(rRect);
399
0
    }
400
0
}
401
402
403
void SdrMarkView::ClearPageView()
404
0
{
405
0
    UnmarkAllObj();
406
0
    SdrSnapView::ClearPageView();
407
0
}
408
409
void SdrMarkView::HideSdrPage()
410
58.3k
{
411
58.3k
    bool bMrkChg(false);
412
413
58.3k
    SdrPageView* pPageView = GetSdrPageView();
414
58.3k
    if (pPageView)
415
58.3k
    {
416
        // break all creation actions when hiding page (#75081#)
417
58.3k
        BrkAction();
418
419
        // Discard all selections on this page
420
58.3k
        bMrkChg = GetMarkedObjectListWriteAccess().DeletePageView(*pPageView);
421
58.3k
    }
422
423
58.3k
    SdrSnapView::HideSdrPage();
424
425
58.3k
    if(bMrkChg)
426
0
    {
427
0
        MarkListHasChanged();
428
0
        AdjustMarkHdl();
429
0
    }
430
58.3k
}
431
432
433
void SdrMarkView::BegMarkObj(const Point& rPnt, bool bUnmark)
434
0
{
435
0
    BrkAction();
436
437
0
    DBG_ASSERT(!mpMarkObjOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkObjOverlay (!)");
438
439
0
    basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
440
0
    mpMarkObjOverlay.reset(new ImplMarkingOverlay(*this, aStartPos, bUnmark));
441
442
0
    maDragStat.Reset(rPnt);
443
0
    maDragStat.NextPoint();
444
0
    maDragStat.SetMinMove(mnMinMovLog);
445
0
}
446
447
void SdrMarkView::MovMarkObj(const Point& rPnt)
448
0
{
449
0
    if(IsMarkObj() && maDragStat.CheckMinMoved(rPnt))
450
0
    {
451
0
        maDragStat.NextMove(rPnt);
452
0
        DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
453
0
        basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
454
0
        mpMarkObjOverlay->SetSecondPosition(aNewPos);
455
0
    }
456
0
}
457
458
bool SdrMarkView::EndMarkObj()
459
0
{
460
0
    bool bRetval(false);
461
462
0
    if(IsMarkObj())
463
0
    {
464
0
        if(maDragStat.IsMinMoved())
465
0
        {
466
0
            tools::Rectangle aRect(maDragStat.GetStart(), maDragStat.GetNow());
467
0
            aRect.Normalize();
468
0
            MarkObj(aRect, mpMarkObjOverlay->IsUnmarking());
469
0
            bRetval = true;
470
0
        }
471
472
        // cleanup
473
0
        BrkMarkObj();
474
0
    }
475
476
0
    return bRetval;
477
0
}
478
479
void SdrMarkView::BrkMarkObj()
480
699k
{
481
699k
    if(IsMarkObj())
482
0
    {
483
0
        DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
484
0
        mpMarkObjOverlay.reset();
485
0
    }
486
699k
}
487
488
489
bool SdrMarkView::BegMarkPoints(const Point& rPnt, bool bUnmark)
490
0
{
491
0
    if(HasMarkablePoints())
492
0
    {
493
0
        BrkAction();
494
495
0
        DBG_ASSERT(!mpMarkPointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkPointsOverlay (!)");
496
0
        basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
497
0
        mpMarkPointsOverlay.reset(new ImplMarkingOverlay(*this, aStartPos, bUnmark));
498
499
0
        maDragStat.Reset(rPnt);
500
0
        maDragStat.NextPoint();
501
0
        maDragStat.SetMinMove(mnMinMovLog);
502
503
0
        return true;
504
0
    }
505
506
0
    return false;
507
0
}
508
509
void SdrMarkView::MovMarkPoints(const Point& rPnt)
510
0
{
511
0
    if(IsMarkPoints() && maDragStat.CheckMinMoved(rPnt))
512
0
    {
513
0
        maDragStat.NextMove(rPnt);
514
515
0
        DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
516
0
        basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
517
0
        mpMarkPointsOverlay->SetSecondPosition(aNewPos);
518
0
    }
519
0
}
520
521
bool SdrMarkView::EndMarkPoints()
522
0
{
523
0
    bool bRetval(false);
524
525
0
    if(IsMarkPoints())
526
0
    {
527
0
        if(maDragStat.IsMinMoved())
528
0
        {
529
0
            tools::Rectangle aRect(maDragStat.GetStart(), maDragStat.GetNow());
530
0
            aRect.Normalize();
531
0
            MarkPoints(&aRect, mpMarkPointsOverlay->IsUnmarking());
532
533
0
            bRetval = true;
534
0
        }
535
536
        // cleanup
537
0
        BrkMarkPoints();
538
0
    }
539
540
0
    return bRetval;
541
0
}
542
543
void SdrMarkView::BrkMarkPoints()
544
699k
{
545
699k
    if(IsMarkPoints())
546
0
    {
547
0
        DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
548
0
        mpMarkPointsOverlay.reset();
549
0
    }
550
699k
}
551
552
553
bool SdrMarkView::BegMarkGluePoints(const Point& rPnt, bool bUnmark)
554
0
{
555
0
    if(HasMarkableGluePoints())
556
0
    {
557
0
        BrkAction();
558
559
0
        DBG_ASSERT(!mpMarkGluePointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkGluePointsOverlay (!)");
560
561
0
        basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
562
0
        mpMarkGluePointsOverlay.reset(new ImplMarkingOverlay(*this, aStartPos, bUnmark));
563
0
        maDragStat.Reset(rPnt);
564
0
        maDragStat.NextPoint();
565
0
        maDragStat.SetMinMove(mnMinMovLog);
566
567
0
        return true;
568
0
    }
569
570
0
    return false;
571
0
}
572
573
void SdrMarkView::MovMarkGluePoints(const Point& rPnt)
574
0
{
575
0
    if(IsMarkGluePoints() && maDragStat.CheckMinMoved(rPnt))
576
0
    {
577
0
        maDragStat.NextMove(rPnt);
578
579
0
        DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
580
0
        basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
581
0
        mpMarkGluePointsOverlay->SetSecondPosition(aNewPos);
582
0
    }
583
0
}
584
585
void SdrMarkView::EndMarkGluePoints()
586
0
{
587
0
    if(IsMarkGluePoints())
588
0
    {
589
0
        if(maDragStat.IsMinMoved())
590
0
        {
591
0
            tools::Rectangle aRect(maDragStat.GetStart(),maDragStat.GetNow());
592
0
            aRect.Normalize();
593
0
            MarkGluePoints(&aRect, mpMarkGluePointsOverlay->IsUnmarking());
594
0
        }
595
596
        // cleanup
597
0
        BrkMarkGluePoints();
598
0
    }
599
0
}
600
601
void SdrMarkView::BrkMarkGluePoints()
602
699k
{
603
699k
    if(IsMarkGluePoints())
604
0
    {
605
0
        DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
606
0
        mpMarkGluePointsOverlay.reset();
607
0
    }
608
699k
}
609
610
bool SdrMarkView::MarkableObjectsExceed( int n ) const
611
0
{
612
0
    SdrPageView* pPV = GetSdrPageView();
613
0
    if (!pPV)
614
0
        return false;
615
616
0
    SdrObjList* pOL=pPV->GetObjList();
617
0
    for (const rtl::Reference<SdrObject>& pObj : *pOL)
618
0
        if (IsObjMarkable(pObj.get(),pPV) && --n<0)
619
0
            return true;
620
621
0
    return false;
622
0
}
623
624
void SdrMarkView::hideMarkHandles()
625
536
{
626
536
    if(!mbMarkHandlesHidden)
627
536
    {
628
536
        mbMarkHandlesHidden = true;
629
536
        AdjustMarkHdl();
630
536
    }
631
536
}
632
633
void SdrMarkView::showMarkHandles()
634
4.47k
{
635
4.47k
    if(mbMarkHandlesHidden)
636
536
    {
637
536
        mbMarkHandlesHidden = false;
638
536
        AdjustMarkHdl();
639
536
    }
640
4.47k
}
641
642
bool SdrMarkView::ImpIsFrameHandles() const
643
367k
{
644
367k
    const SdrMarkList& rMarkList = GetMarkedObjectList();
645
367k
    const size_t nMarkCount=rMarkList.GetMarkCount();
646
367k
    bool bFrmHdl=nMarkCount>static_cast<size_t>(mnFrameHandlesLimit) || mbForceFrameHandles;
647
367k
    bool bStdDrag=meDragMode==SdrDragMode::Move;
648
367k
    if (nMarkCount==1 && bStdDrag && bFrmHdl)
649
0
    {
650
0
        const SdrObject* pObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
651
0
        if (pObj && pObj->GetObjInventor()==SdrInventor::Default)
652
0
        {
653
0
            SdrObjKind nIdent=pObj->GetObjIdentifier();
654
0
            if (nIdent==SdrObjKind::Line || nIdent==SdrObjKind::Edge || nIdent==SdrObjKind::Caption || nIdent==SdrObjKind::Measure || nIdent==SdrObjKind::CustomShape || nIdent==SdrObjKind::Table )
655
0
            {
656
0
                bFrmHdl=false;
657
0
            }
658
0
        }
659
0
    }
660
367k
    if (!bStdDrag && !bFrmHdl) {
661
        // all other drag modes only with FrameHandles
662
0
        bFrmHdl=true;
663
0
        if (meDragMode==SdrDragMode::Rotate) {
664
            // when rotating, use ObjOwn drag, if there's at least 1 PolyObj
665
0
            for (size_t nMarkNum=0; nMarkNum<nMarkCount && bFrmHdl; ++nMarkNum) {
666
0
                const SdrMark* pM=rMarkList.GetMark(nMarkNum);
667
0
                const SdrObject* pObj=pM->GetMarkedSdrObj();
668
0
                bFrmHdl=!pObj->IsPolyObj();
669
0
            }
670
0
        }
671
0
    }
672
367k
    if (!bFrmHdl) {
673
        // FrameHandles, if at least 1 Obj can't do SpecialDrag
674
67.8k
        for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bFrmHdl; ++nMarkNum) {
675
0
            const SdrMark* pM=rMarkList.GetMark(nMarkNum);
676
0
            const SdrObject* pObj=pM->GetMarkedSdrObj();
677
0
            bFrmHdl=!pObj->hasSpecialDrag();
678
0
        }
679
67.8k
    }
680
681
    // no FrameHdl for crop
682
367k
    if(bFrmHdl && SdrDragMode::Crop == meDragMode)
683
0
    {
684
0
        bFrmHdl = false;
685
0
    }
686
687
367k
    return bFrmHdl;
688
367k
}
689
690
namespace
691
{
692
std::u16string_view lcl_getDragMethodServiceName( std::u16string_view rCID )
693
0
{
694
0
    std::u16string_view aRet;
695
696
0
    size_t nIndexStart = rCID.find( u"DragMethod=" );
697
0
    if( nIndexStart != std::u16string_view::npos )
698
0
    {
699
0
        nIndexStart = rCID.find( '=', nIndexStart );
700
0
        if( nIndexStart != std::u16string_view::npos )
701
0
        {
702
0
            nIndexStart++;
703
0
            size_t nNextSlash = rCID.find( '/', nIndexStart );
704
0
            if( nNextSlash != std::u16string_view::npos )
705
0
            {
706
0
                sal_Int32 nIndexEnd = nNextSlash;
707
0
                size_t nNextColon = rCID.find( ':', nIndexStart );
708
0
                if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash )
709
0
                    nIndexEnd = nNextColon;
710
0
                aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart);
711
0
            }
712
0
        }
713
0
    }
714
0
    return aRet;
715
0
}
716
717
std::u16string_view lcl_getDragParameterString( std::u16string_view rCID )
718
0
{
719
0
    std::u16string_view aRet;
720
721
0
    size_t nIndexStart = rCID.find( u"DragParameter=" );
722
0
    if( nIndexStart != std::u16string_view::npos )
723
0
    {
724
0
        nIndexStart = rCID.find( '=', nIndexStart );
725
0
        if( nIndexStart != std::u16string_view::npos )
726
0
        {
727
0
            nIndexStart++;
728
0
            size_t nNextSlash = rCID.find( '/', nIndexStart );
729
0
            if( nNextSlash != std::u16string_view::npos )
730
0
            {
731
0
                sal_Int32 nIndexEnd = nNextSlash;
732
0
                size_t nNextColon = rCID.find( ':', nIndexStart );
733
0
                if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash )
734
0
                    nIndexEnd = nNextColon;
735
0
                aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart);
736
0
            }
737
0
        }
738
0
    }
739
0
    return aRet;
740
0
}
741
742
bool lcl_isStarMath(SdrObject* pO)
743
0
{
744
0
    auto xUnoShape = pO->getUnoShape();
745
746
0
    if (xUnoShape.is())
747
0
    {
748
0
        auto xServiceInfo = xUnoShape.query<lang::XServiceInfo>();
749
750
0
        if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextEmbeddedObject"))
751
0
        {
752
0
            auto xUnoShapeProperties =  xUnoShape.query<beans::XPropertySet>();
753
0
            if (xUnoShapeProperties.is())
754
0
            {
755
0
                auto xModelInfo = xUnoShapeProperties->getPropertyValue("Model").query<lang::XServiceInfo>();
756
0
                if (xModelInfo.is())
757
0
                    return xModelInfo->supportsService("com.sun.star.formula.FormulaProperties");
758
0
            }
759
0
        }
760
0
    }
761
762
0
    return false;
763
0
}
764
765
} // anonymous namespace
766
767
bool SdrMarkView::dumpGluePointsToJSON(boost::property_tree::ptree& rTree)
768
0
{
769
0
    bool result = false;
770
0
    tools::Long nSignX = mbNegativeX ? -1 : 1;
771
0
    if (OutputDevice* pOutDev = mpMarkedPV ? mpMarkedPV->GetView().GetFirstOutputDevice() : nullptr)
772
0
    {
773
0
        bool bConvertUnit = false;
774
0
        if (pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
775
0
            bConvertUnit = true;
776
0
        const SdrObjList* pOL = mpMarkedPV->GetObjList();
777
0
        if (!pOL)
778
0
            return false;
779
0
        boost::property_tree::ptree elements;
780
0
        const SdrMarkList& rMarkList = GetMarkedObjectList();
781
0
        for (const rtl::Reference<SdrObject>& pObj : *pOL)
782
0
        {
783
0
            if (!pObj)
784
0
                continue;
785
0
            if (pObj == rMarkList.GetMark(0)->GetMarkedSdrObj())
786
0
                continue;
787
0
            const SdrGluePointList* pGPL = pObj->GetGluePointList();
788
0
            bool VertexObject = !(pGPL && pGPL->GetCount());
789
0
            const size_t count = !VertexObject ? pGPL->GetCount() : 4;
790
0
            boost::property_tree::ptree object;
791
0
            boost::property_tree::ptree points;
792
0
            for (size_t i = 0; i < count; ++i)
793
0
            {
794
0
                boost::property_tree::ptree node;
795
0
                boost::property_tree::ptree point;
796
0
                const SdrGluePoint aGP = !VertexObject ? (*pGPL)[i] : pObj->GetVertexGluePoint(i);
797
0
                Point rPoint = aGP.GetAbsolutePos(*pObj);
798
0
                if (bConvertUnit)
799
0
                {
800
0
                    rPoint = o3tl::convert(rPoint, o3tl::Length::mm100, o3tl::Length::twip);
801
0
                }
802
0
                point.put("x", nSignX * rPoint.getX());
803
0
                point.put("y", rPoint.getY());
804
0
                node.add_child("point", point);
805
0
                points.push_back(std::make_pair("", node));
806
0
            }
807
0
            basegfx::B2DVector aGridOffset(0.0, 0.0);
808
0
            Point objLogicRectTopLeft = pObj->GetLogicRect().TopLeft();
809
0
            if(getPossibleGridOffsetForPosition(aGridOffset, basegfx::B2DPoint(objLogicRectTopLeft.X(), objLogicRectTopLeft.Y()), GetSdrPageView()))
810
0
            {
811
0
                Point p(aGridOffset.getX(), aGridOffset.getY());
812
0
                if (bConvertUnit)
813
0
                {
814
0
                    p = o3tl::convert(p, o3tl::Length::mm100, o3tl::Length::twip);
815
0
                }
816
0
                boost::property_tree::ptree gridOffset;
817
0
                gridOffset.put("x", nSignX * p.getX());
818
0
                gridOffset.put("y", p.getY());
819
0
                object.add_child("gridoffset", gridOffset);
820
0
            }
821
0
            object.put("ordnum", pObj->GetOrdNum());
822
0
            object.add_child("gluepoints", points);
823
0
            elements.push_back(std::make_pair("", object));
824
0
            result = true;
825
0
        }
826
0
        rTree.add_child("shapes", elements);
827
0
    }
828
0
    return result;
829
0
}
830
831
namespace
832
{
833
    class TextBoundsExtractor final : public drawinglayer::processor2d::TextExtractor2D
834
    {
835
    private:
836
        basegfx::B2DRange maTextRange;
837
        void processTextPrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate) override
838
0
        {
839
0
            maTextRange.expand(rCandidate.getB2DRange(getViewInformation2D()));
840
0
        }
841
    public:
842
        explicit TextBoundsExtractor(const drawinglayer::geometry::ViewInformation2D& rViewInformation)
843
0
            : drawinglayer::processor2d::TextExtractor2D(rViewInformation)
844
0
        {
845
0
        }
846
847
        const basegfx::B2DRange & getTextBounds(const sdr::contact::ViewObjectContact &rVOC, const sdr::contact::DisplayInfo &raDisplayInfo)
848
0
        {
849
0
            this->process(rVOC.getPrimitive2DSequence(raDisplayInfo));
850
0
            return maTextRange;
851
0
        }
852
    };
853
}
854
855
OString SdrMarkView::CreateInnerTextRectString() const
856
0
{
857
0
    if (!mpMarkedObj)
858
0
        return OString();
859
860
0
    SdrPageView* pPageView = GetSdrPageView();
861
0
    const sdr::contact::ViewObjectContact& rVOC = mpMarkedObj->GetViewContact().GetViewObjectContact(
862
0
        pPageView->GetPageWindow(0)->GetObjectContact());
863
864
0
    sdr::contact::DisplayInfo aDisplayInfo;
865
0
    TextBoundsExtractor aTextBoundsExtractor(rVOC.GetObjectContact().getViewInformation2D());
866
0
    basegfx::B2DRange aRange = aTextBoundsExtractor.getTextBounds(rVOC, aDisplayInfo);
867
0
    if (!aRange.isEmpty()) {
868
0
        tools::Rectangle rect(aRange.getMinX(), aRange.getMinY(), aRange.getMaxX(), aRange.getMaxY());
869
0
        tools::Rectangle aRangeTWIP = o3tl::convert(rect, o3tl::Length::mm100, o3tl::Length::twip);
870
0
        OString innerTextInfo = "\"innerTextRect\":[" +
871
0
            OString::number(aRangeTWIP.getX()) + "," +
872
0
            OString::number(aRangeTWIP.getY()) + "," +
873
0
            OString::number(aRangeTWIP.GetWidth()) + "," +
874
0
            OString::number(aRangeTWIP.GetHeight()) + "]";
875
0
        return innerTextInfo;
876
0
    }
877
878
0
    return OString();
879
0
}
880
881
void SdrMarkView::SetInnerTextAreaForLOKit() const
882
0
{
883
0
    if (!comphelper::LibreOfficeKit::isActive())
884
0
        return;
885
0
    SfxViewShell* pViewShell = GetSfxViewShell();
886
0
    OString sRectString = CreateInnerTextRectString();
887
0
    if (pViewShell && !sRectString.isEmpty())
888
0
        pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SHAPE_INNER_TEXT, sRectString);
889
0
}
890
891
void SdrMarkView::SetMarkHandlesForLOKit(tools::Rectangle const & rRect, const SfxViewShell* pOtherShell)
892
0
{
893
0
    SfxViewShell* pViewShell = GetSfxViewShell();
894
895
0
    tools::Rectangle aSelection(rRect);
896
0
    tools::Long nSignX = mbNegativeX ? -1 : 1;
897
0
    bool bIsChart = false;
898
0
    Point addLogicOffset(0, 0);
899
0
    bool convertMapMode = false;
900
0
    if (!rRect.IsEmpty())
901
0
    {
902
0
        sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
903
0
        if (nTotalPaintWindows == 1)
904
0
        {
905
0
            const OutputDevice* pOut = this->GetFirstOutputDevice();
906
0
            const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr;
907
0
            if (pWin && pWin->IsChart())
908
0
            {
909
0
                bIsChart = true;
910
0
                const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
911
0
                if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
912
0
                {
913
0
                    Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
914
0
                    if (mbNegativeX && AllSettings::GetLayoutRTL())
915
0
                    {
916
                        // mbNegativeX is set only for Calc in RTL mode.
917
                        // If global RTL flag is set, vcl-window X offset of chart window is
918
                        // mirrored w.r.t parent window rectangle. This needs to be reverted.
919
0
                        aOffsetPx.setX(pViewShellWindow->GetOutOffXPixel() + pViewShellWindow->GetSizePixel().Width()
920
0
                            - pWin->GetOutOffXPixel() - pWin->GetSizePixel().Width());
921
0
                    }
922
0
                    Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
923
0
                    addLogicOffset = aLogicOffset;
924
0
                    aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
925
0
                }
926
0
            }
927
0
        }
928
0
    }
929
930
0
    if (!aSelection.IsEmpty())
931
0
    {
932
        // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
933
0
        if (mpMarkedPV)
934
0
        {
935
0
            if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
936
0
            {
937
0
                if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
938
0
                {
939
0
                    aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
940
0
                    convertMapMode = true;
941
0
                }
942
0
            }
943
0
        }
944
945
        // hide the text selection too
946
0
        if (pViewShell)
947
0
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, ""_ostr);
948
0
    }
949
950
0
    {
951
0
        OStringBuffer aExtraInfo;
952
0
        OString sSelectionText;
953
0
        OString sSelectionTextView;
954
0
        boost::property_tree::ptree aTableJsonTree;
955
0
        boost::property_tree::ptree aGluePointsTree;
956
0
        const bool bMediaObj = (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == SdrObjKind::Media);
957
0
        bool bTableSelection = false;
958
0
        bool bConnectorSelection = false;
959
960
0
        if (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == SdrObjKind::Table)
961
0
        {
962
0
            auto& rTableObject = dynamic_cast<sdr::table::SdrTableObj&>(*mpMarkedObj);
963
0
            bTableSelection = rTableObject.createTableEdgesJson(aTableJsonTree);
964
0
        }
965
0
        if (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == SdrObjKind::Edge)
966
0
        {
967
0
            bConnectorSelection = dumpGluePointsToJSON(aGluePointsTree);
968
0
        }
969
970
0
        SdrPageView* pPageView = GetSdrPageView();
971
972
0
        const SdrMarkList& rMarkList = GetMarkedObjectList();
973
0
        if (rMarkList.GetMarkCount())
974
0
        {
975
0
            SdrMark* pM = rMarkList.GetMark(0);
976
0
            SdrObject* pO = pM->GetMarkedSdrObj();
977
0
            Degree100 nRotAngle = pO->GetRotateAngle();
978
            // true if we are dealing with a RotGrfFlyFrame
979
            // (SwVirtFlyDrawObj with a SwGrfNode)
980
0
            bool bWriterGraphic = pO->HasLimitedRotation();
981
982
0
            OString handleArrayStr;
983
984
0
            aExtraInfo.append("{\"id\":\""
985
0
                + OString::number(reinterpret_cast<sal_IntPtr>(pO))
986
0
                + "\",\"type\":"
987
0
                + OString::number(static_cast<sal_Int32>(pO->GetObjIdentifier()))
988
0
                + ",\"OrdNum\":" + OString::number(pO->GetOrdNum())
989
0
                );
990
991
0
            aExtraInfo.append(", \"isMathObject\": " + OString::boolean(lcl_isStarMath(pO)));
992
0
            aExtraInfo.append(", \"isDiagram\": " + OString::boolean(pO->isDiagram()));
993
994
0
            if (mpMarkedObj && !pOtherShell)
995
0
            {
996
0
                OString innerTextInfo = CreateInnerTextRectString();
997
0
                if (!innerTextInfo.isEmpty())
998
0
                    aExtraInfo.append("," + innerTextInfo);
999
0
            }
1000
1001
            // In core, the gridOffset is calculated based on the LogicRect's TopLeft coordinate
1002
            // In online, we have the SnapRect and we calculate it based on its TopLeft coordinate
1003
            // SnapRect's TopLeft and LogicRect's TopLeft match unless there is rotation
1004
            // but the rotation is not applied to the LogicRect. Therefore,
1005
            // what we calculate in online does not match with the core in case of the rotation.
1006
            // Here we can send the correct gridOffset in the selection callback, this way
1007
            // whether the shape is rotated or not, we will always have the correct gridOffset
1008
            // Note that the gridOffset is calculated from the first selected obj
1009
0
            basegfx::B2DVector aGridOffset(0.0, 0.0);
1010
0
            if(getPossibleGridOffsetForSdrObject(aGridOffset, rMarkList.GetMark(0)->GetMarkedSdrObj(), pPageView))
1011
0
            {
1012
0
                Point p(aGridOffset.getX(), aGridOffset.getY());
1013
0
                if (convertMapMode)
1014
0
                    p = o3tl::convert(p, o3tl::Length::mm100, o3tl::Length::twip);
1015
0
                aExtraInfo.append(",\"gridOffsetX\":"
1016
0
                    + OString::number(nSignX * p.getX())
1017
0
                    + ",\"gridOffsetY\":"
1018
0
                    + OString::number(p.getY()));
1019
0
            }
1020
1021
0
            if (meDragMode == SdrDragMode::Crop)
1022
0
                aExtraInfo.append(", \"isCropMode\": true");
1023
1024
0
            if (bWriterGraphic)
1025
0
            {
1026
0
                aExtraInfo.append(", \"isWriterGraphic\": true");
1027
0
            }
1028
0
            else if (bIsChart)
1029
0
            {
1030
0
                LokChartHelper aChartHelper(pViewShell);
1031
0
                css::uno::Reference<css::frame::XController>& xChartController = aChartHelper.GetXController();
1032
0
                css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier( xChartController, uno::UNO_QUERY);
1033
0
                if (xSelectionSupplier.is())
1034
0
                {
1035
0
                    uno::Any aSel = xSelectionSupplier->getSelection();
1036
0
                    OUString aValue;
1037
0
                    if (aSel >>= aValue)
1038
0
                    {
1039
0
                        OString aObjectCID(aValue.getStr(), aValue.getLength(), osl_getThreadTextEncoding());
1040
0
                        const std::vector<OString> aProps{"Draggable"_ostr, "Resizable"_ostr, "Rotatable"_ostr};
1041
0
                        for (const auto& rProp: aProps)
1042
0
                        {
1043
0
                            sal_Int32 nPos = aObjectCID.indexOf(rProp);
1044
0
                            if (nPos == -1) continue;
1045
0
                            nPos += rProp.getLength() + 1; // '='
1046
0
                            if (aExtraInfo.getLength() > 2) // != "{ "
1047
0
                                aExtraInfo.append(", ");
1048
0
                            aExtraInfo.append("\"is" + rProp + "\": "
1049
0
                                + OString::boolean(aObjectCID[nPos] == '1'));
1050
0
                        }
1051
1052
0
                        std::u16string_view sDragMethod = lcl_getDragMethodServiceName(aValue);
1053
0
                        if (sDragMethod == u"PieSegmentDragging")
1054
0
                        {
1055
                            // old initial offset inside the CID returned by xSelectionSupplier->getSelection()
1056
                            // after a pie segment dragging; using SdrObject::GetName for getting a CID with the updated offset
1057
0
                            aValue = pO->GetName();
1058
0
                            std::u16string_view sDragParameters = lcl_getDragParameterString(aValue);
1059
0
                            if (!sDragParameters.empty())
1060
0
                            {
1061
0
                                aExtraInfo.append(", \"dragInfo\": { "
1062
0
                                    "\"dragMethod\": \""
1063
0
                                    + OUString(sDragMethod).toUtf8()
1064
0
                                    + "\"");
1065
1066
0
                                sal_Int32 nStartIndex = 0;
1067
0
                                std::array<int, 5> aDragParameters;
1068
0
                                for (auto& rParam : aDragParameters)
1069
0
                                {
1070
0
                                    std::u16string_view sParam = o3tl::getToken(sDragParameters, 0, ',', nStartIndex);
1071
0
                                    if (sParam.empty())
1072
0
                                        break;
1073
0
                                    rParam = o3tl::toInt32(sParam);
1074
0
                                }
1075
1076
                                // initial offset in %
1077
0
                                if (aDragParameters[0] < 0)
1078
0
                                    aDragParameters[0] = 0;
1079
0
                                else if (aDragParameters[0] > 100)
1080
0
                                    aDragParameters[0] = 100;
1081
1082
0
                                aExtraInfo.append(", \"initialOffset\": "
1083
0
                                    + OString::number(static_cast<sal_Int32>(aDragParameters[0])));
1084
1085
                                // drag direction constraint
1086
0
                                Point aMinPos(aDragParameters[1], aDragParameters[2]);
1087
0
                                Point aMaxPos(aDragParameters[3], aDragParameters[4]);
1088
0
                                Point aDragDirection = aMaxPos - aMinPos;
1089
0
                                aDragDirection = o3tl::convert(aDragDirection, o3tl::Length::mm100, o3tl::Length::twip);
1090
1091
0
                                aExtraInfo.append(", \"dragDirection\": ["
1092
0
                                    + aDragDirection.toString()
1093
0
                                    + "]");
1094
1095
                                // polygon approximating the pie segment or donut segment
1096
0
                                if (pViewShell && pO->GetObjIdentifier() == SdrObjKind::PathFill)
1097
0
                                {
1098
0
                                    const basegfx::B2DPolyPolygon aPolyPolygon(pO->TakeXorPoly());
1099
0
                                    if (aPolyPolygon.count() == 1)
1100
0
                                    {
1101
0
                                        const basegfx::B2DPolygon& aPolygon = aPolyPolygon.getB2DPolygon(0);
1102
0
                                        if (sal_uInt32 nPolySize = aPolygon.count())
1103
0
                                        {
1104
0
                                            const OutputDevice* pOut = this->GetFirstOutputDevice();
1105
0
                                            const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr;
1106
0
                                            const vcl::Window* pViewShellWindow = pViewShell->GetEditWindowForActiveOLEObj();
1107
0
                                            if (pWin && pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
1108
0
                                            {
1109
                                                // in the following code escaping sequences used inside raw literal strings
1110
                                                // are for making them understandable by the JSON parser
1111
1112
0
                                                Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
1113
0
                                                Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
1114
0
                                                OStringBuffer sPolygonElem("<polygon points=\\\"");
1115
0
                                                for (sal_uInt32 nIndex = 0; nIndex < nPolySize; ++nIndex)
1116
0
                                                {
1117
0
                                                    const basegfx::B2DPoint aB2Point = aPolygon.getB2DPoint(nIndex);
1118
0
                                                    Point aPoint(aB2Point.getX(), aB2Point.getY());
1119
0
                                                    aPoint.Move(aLogicOffset.getX(), aLogicOffset.getY());
1120
0
                                                    if (mbNegativeX)
1121
0
                                                        aPoint.setX(-aPoint.X());
1122
0
                                                    if (nIndex > 0)
1123
0
                                                        sPolygonElem.append(" ");
1124
0
                                                    sPolygonElem.append(aPoint.toString());
1125
0
                                                }
1126
0
                                                sPolygonElem.append(R"elem(\" style=\"stroke: none; fill: rgb(114,159,207); fill-opacity: 0.8\"/>)elem");
1127
1128
0
                                                OString sSVGElem = R"elem(<svg version=\"1.2\" width=\")elem" +
1129
0
                                                    OString::number(aSelection.GetWidth() / 100.0) +
1130
0
                                                    R"elem(mm\" height=\")elem" +
1131
0
                                                    OString::number(aSelection.GetHeight() / 100.0) +
1132
0
                                                    R"elem(mm\" viewBox=\")elem" +
1133
0
                                                    aSelection.toString() +
1134
0
                                                    R"elem(\" preserveAspectRatio=\"xMidYMid\" xmlns=\"http://www.w3.org/2000/svg\">)elem";
1135
1136
0
                                                aExtraInfo.append(", \"svg\": \""
1137
0
                                                    + sSVGElem
1138
0
                                                    + "\\n  "
1139
0
                                                    + sPolygonElem
1140
0
                                                    + "\\n</svg>"
1141
0
                                                    "\""); // svg
1142
0
                                            }
1143
0
                                        }
1144
0
                                    }
1145
0
                                }
1146
0
                                aExtraInfo.append("}"); // dragInfo
1147
0
                            }
1148
0
                        }
1149
0
                    }
1150
0
                }
1151
0
            }
1152
0
            else
1153
0
            {
1154
0
                SfxObjectShell* pObjectShell = pViewShell ? pViewShell->GetObjectShell() : nullptr;
1155
0
                if (pObjectShell && pObjectShell->IsSignPDF() && pViewShell && pViewShell->GetSignPDFCertificate().Is())
1156
0
                {
1157
                    // Expose the info that this is the special signature widget that is OK to
1158
                    // move/resize.
1159
0
                    aExtraInfo.append(", \"isSignature\": true");
1160
0
                }
1161
0
            }
1162
0
            if (!bTableSelection && !pOtherShell && maHdlList.GetHdlCount())
1163
0
            {
1164
0
                boost::property_tree::ptree responseJSON;
1165
0
                boost::property_tree::ptree others;
1166
0
                boost::property_tree::ptree anchor;
1167
0
                boost::property_tree::ptree rectangle;
1168
0
                boost::property_tree::ptree poly;
1169
0
                boost::property_tree::ptree custom;
1170
0
                boost::property_tree::ptree nodes;
1171
0
                for (size_t i = 0; i < maHdlList.GetHdlCount(); i++)
1172
0
                {
1173
0
                    SdrHdl *pHdl = maHdlList.GetHdl(i);
1174
0
                    boost::property_tree::ptree child;
1175
0
                    boost::property_tree::ptree point;
1176
0
                    sal_Int32 kind = static_cast<sal_Int32>(pHdl->GetKind());
1177
0
                    child.put("id", pHdl->GetObjHdlNum());
1178
0
                    child.put("kind", kind);
1179
0
                    child.put("pointer", static_cast<sal_Int32>(pHdl->GetPointer()));
1180
0
                    Point pHdlPos = pHdl->GetPos();
1181
0
                    pHdlPos.Move(addLogicOffset.getX(), addLogicOffset.getY());
1182
0
                    if (convertMapMode)
1183
0
                    {
1184
0
                        pHdlPos = o3tl::convert(pHdlPos, o3tl::Length::mm100, o3tl::Length::twip);
1185
0
                    }
1186
0
                    point.put("x", pHdlPos.getX());
1187
0
                    point.put("y", pHdlPos.getY());
1188
0
                    child.add_child("point", point);
1189
0
                    const auto node = std::make_pair("", child);
1190
0
                    boost::property_tree::ptree* selectedNode = nullptr;
1191
0
                    if (kind >= static_cast<sal_Int32>(SdrHdlKind::UpperLeft) && kind <= static_cast<sal_Int32>(SdrHdlKind::LowerRight))
1192
0
                    {
1193
0
                        selectedNode = &rectangle;
1194
0
                    }
1195
0
                    else if (kind == static_cast<sal_Int32>(SdrHdlKind::Poly))
1196
0
                    {
1197
0
                        selectedNode = &poly;
1198
0
                    }
1199
0
                    else if (kind == static_cast<sal_Int32>(SdrHdlKind::CustomShape1))
1200
0
                    {
1201
0
                        selectedNode = &custom;
1202
0
                    }
1203
0
                    else if (kind == static_cast<sal_Int32>(SdrHdlKind::Anchor) || kind == static_cast<sal_Int32>(SdrHdlKind::Anchor_TR))
1204
0
                    {
1205
0
                        if (getSdrModelFromSdrView().IsWriter())
1206
0
                            selectedNode = &anchor;
1207
0
                        else
1208
                            // put it to others as we don't render them except in writer
1209
0
                            selectedNode = &others;
1210
0
                    }
1211
0
                    else
1212
0
                    {
1213
0
                        selectedNode = &others;
1214
0
                    }
1215
0
                    std::string sKind = std::to_string(kind);
1216
0
                    boost::optional< boost::property_tree::ptree& > kindNode = selectedNode->get_child_optional(sKind);
1217
0
                    if (!kindNode)
1218
0
                    {
1219
0
                        boost::property_tree::ptree newChild;
1220
0
                        newChild.push_back(node);
1221
0
                        selectedNode->add_child(sKind, newChild);
1222
0
                    }
1223
0
                    else
1224
0
                        kindNode.get().push_back(node);
1225
0
                }
1226
0
                nodes.add_child("rectangle", rectangle);
1227
0
                nodes.add_child("poly", poly);
1228
0
                nodes.add_child("custom", custom);
1229
0
                nodes.add_child("anchor", anchor);
1230
0
                nodes.add_child("others", others);
1231
0
                responseJSON.add_child("kinds", nodes);
1232
0
                std::stringstream aStream;
1233
0
                boost::property_tree::write_json(aStream, responseJSON, /*pretty=*/ false);
1234
0
                handleArrayStr = OString::Concat(", \"handles\":") + aStream.str().c_str();
1235
0
                if (bConnectorSelection)
1236
0
                {
1237
0
                    aStream.str("");
1238
0
                    boost::property_tree::write_json(aStream, aGluePointsTree, /*pretty=*/ false);
1239
0
                    handleArrayStr += OString::Concat(", \"GluePoints\":") + aStream.str().c_str();
1240
0
                }
1241
0
            }
1242
1243
0
            if (mbNegativeX)
1244
0
            {
1245
0
                tools::Rectangle aNegatedRect(aSelection);
1246
0
                aNegatedRect.SetLeft(-aNegatedRect.Left());
1247
0
                aNegatedRect.SetRight(-aNegatedRect.Right());
1248
0
                aNegatedRect.Normalize();
1249
0
                sSelectionText = aNegatedRect.toString() +
1250
0
                    ", " + OString::number(nRotAngle.get());
1251
0
            }
1252
0
            else
1253
0
            {
1254
0
                sSelectionText = aSelection.toString() +
1255
0
                    ", " + OString::number(nRotAngle.get());
1256
0
            }
1257
1258
0
            if (!aExtraInfo.isEmpty())
1259
0
            {
1260
0
                sSelectionTextView = sSelectionText + ", " + aExtraInfo + "}";
1261
1262
0
                if (bMediaObj && pOtherShell == nullptr)
1263
0
                {
1264
                    // Add the URL only if we have a Media Object and
1265
                    // we are the selecting view.
1266
0
                    SdrMediaObj* mediaObj = dynamic_cast<SdrMediaObj*>(mpMarkedObj);
1267
0
                    if (mediaObj)
1268
0
                        aExtraInfo.append(", \"url\": \"" + mediaObj->getTempURL().toUtf8() + "\"");
1269
0
                }
1270
1271
0
                SdrPage *pPage = pPageView ? pPageView->GetPage(): nullptr;
1272
1273
0
                if (pPage && getSdrModelFromSdrView().IsImpress())
1274
0
                {
1275
                    // Send all objects' rectangles along with the selected object's information.
1276
                    // Other rectangles can be used for aligning the selected object referencing the others.
1277
                    // Replace curly braces with empty string in order to merge it with the resulting string.
1278
0
                    OString objectRectangles = SdrObjList::GetObjectRectangles(*pPage).replaceAll("{"_ostr, ""_ostr).replaceAll("}"_ostr, ""_ostr);
1279
0
                    aExtraInfo.append(", \"ObjectRectangles\": "_ostr + objectRectangles);
1280
0
                }
1281
1282
0
                sSelectionText += ", " + aExtraInfo + handleArrayStr + "}";
1283
0
            }
1284
0
        }
1285
1286
0
        if (sSelectionText.isEmpty())
1287
0
        {
1288
0
            sSelectionText = "EMPTY"_ostr;
1289
0
            sSelectionTextView = "EMPTY"_ostr;
1290
0
            if (!pOtherShell && pViewShell)
1291
0
                pViewShell->NotifyOtherViews(LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection"_ostr, OString());
1292
0
        }
1293
1294
0
        if (bTableSelection)
1295
0
        {
1296
0
            boost::property_tree::ptree aTableRectangle;
1297
0
            aTableRectangle.put("x", aSelection.Left());
1298
0
            aTableRectangle.put("y", aSelection.Top());
1299
0
            aTableRectangle.put("width", aSelection.GetWidth());
1300
0
            aTableRectangle.put("height", aSelection.GetHeight());
1301
0
            aTableJsonTree.push_back(std::make_pair("rectangle", aTableRectangle));
1302
1303
0
            std::stringstream aStream;
1304
0
            boost::property_tree::write_json(aStream, aTableJsonTree);
1305
0
            if (pViewShell)
1306
0
                pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED, OString(aStream.str()));
1307
0
        }
1308
0
        else if (!getSdrModelFromSdrView().IsWriter() && pViewShell)
1309
0
        {
1310
0
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED, "{}"_ostr);
1311
0
        }
1312
1313
0
        if (pOtherShell)
1314
0
        {
1315
            // Another shell wants to know about our existing
1316
            // selection.
1317
0
            if (pViewShell != pOtherShell)
1318
0
                SfxLokHelper::notifyOtherView(*pViewShell, pOtherShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionTextView);
1319
0
        }
1320
0
        else if (pViewShell)
1321
0
        {
1322
            // We have a new selection, so both pViewShell and the
1323
            // other views want to know about it.
1324
0
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, sSelectionText);
1325
1326
0
            SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionTextView);
1327
0
        }
1328
0
    }
1329
0
}
1330
1331
void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
1332
236k
{
1333
    // remember old focus handle values to search for it again
1334
236k
    const SdrHdl* pSaveOldFocusHdl = maHdlList.GetFocusHdl();
1335
236k
    bool bSaveOldFocus(false);
1336
236k
    sal_uInt32 nSavePolyNum(0), nSavePointNum(0);
1337
236k
    SdrHdlKind eSaveKind(SdrHdlKind::Move);
1338
236k
    SdrObject* pSaveObj = nullptr;
1339
1340
236k
    mpMarkingSubSelectionOverlay.reset();
1341
236k
    mpMarkingSelectionOverlay.reset();
1342
1343
236k
    if(pSaveOldFocusHdl
1344
0
        && pSaveOldFocusHdl->GetObj()
1345
0
        && dynamic_cast<const SdrPathObj*>(pSaveOldFocusHdl->GetObj()) != nullptr
1346
0
        && (pSaveOldFocusHdl->GetKind() == SdrHdlKind::Poly || pSaveOldFocusHdl->GetKind() == SdrHdlKind::BezierWeight))
1347
0
    {
1348
0
        bSaveOldFocus = true;
1349
0
        nSavePolyNum = pSaveOldFocusHdl->GetPolyNum();
1350
0
        nSavePointNum = pSaveOldFocusHdl->GetPointNum();
1351
0
        pSaveObj = pSaveOldFocusHdl->GetObj();
1352
0
        eSaveKind = pSaveOldFocusHdl->GetKind();
1353
0
    }
1354
1355
    // delete/clear all handles. This will always be done, even with areMarkHandlesHidden()
1356
236k
    maHdlList.Clear();
1357
236k
    maHdlList.SetRotateShear(meDragMode==SdrDragMode::Rotate);
1358
236k
    maHdlList.SetDistortShear(meDragMode==SdrDragMode::Shear);
1359
236k
    mpMarkedObj=nullptr;
1360
236k
    mpMarkedPV=nullptr;
1361
1362
    // are handles enabled at all? Create only then
1363
236k
    if(areMarkHandlesHidden())
1364
568
        return;
1365
1366
    // There can be multiple mark views, but we're only interested in the one that has a window associated.
1367
236k
    const bool bTiledRendering = comphelper::LibreOfficeKit::isActive() && GetFirstOutputDevice() && GetFirstOutputDevice()->GetOutDevType() == OUTDEV_WINDOW;
1368
1369
236k
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1370
236k
    const size_t nMarkCount=rMarkList.GetMarkCount();
1371
236k
    bool bStdDrag=meDragMode==SdrDragMode::Move;
1372
236k
    bool bSingleTextObjMark=false;
1373
236k
    bool bLimitedRotation(false);
1374
1375
236k
    if (nMarkCount==1)
1376
0
    {
1377
0
        mpMarkedObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
1378
1379
0
        if(nullptr != mpMarkedObj)
1380
0
        {
1381
0
            bSingleTextObjMark =
1382
0
                DynCastSdrTextObj( mpMarkedObj) !=  nullptr &&
1383
0
                static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame();
1384
1385
            // RotGrfFlyFrame: we may have limited rotation
1386
0
            bLimitedRotation = SdrDragMode::Rotate == meDragMode && mpMarkedObj->HasLimitedRotation();
1387
0
        }
1388
0
    }
1389
1390
236k
    bool bFrmHdl=ImpIsFrameHandles();
1391
1392
236k
    if (nMarkCount>0)
1393
0
    {
1394
0
        mpMarkedPV=rMarkList.GetMark(0)->GetPageView();
1395
1396
0
        for (size_t nMarkNum=0; nMarkNum<nMarkCount && (mpMarkedPV!=nullptr || !bFrmHdl); ++nMarkNum)
1397
0
        {
1398
0
            const SdrMark* pM=rMarkList.GetMark(nMarkNum);
1399
1400
0
            if (mpMarkedPV!=pM->GetPageView())
1401
0
            {
1402
0
                mpMarkedPV=nullptr;
1403
0
            }
1404
0
        }
1405
0
    }
1406
1407
236k
    tools::Rectangle aRect(GetMarkedObjRect());
1408
1409
236k
    if (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == SdrObjKind::Annotation)
1410
0
    {
1411
0
        basegfx::B2DRectangle aB2DRect(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
1412
0
        mpMarkingSelectionOverlay = std::make_unique<MarkingSelectionOverlay>(*this, aB2DRect);
1413
1414
0
        return;
1415
1416
0
    }
1417
1418
236k
    SfxViewShell* pViewShell = GetSfxViewShell();
1419
1420
    // check if text edit or ole is active and handles need to be suppressed. This may be the case
1421
    // when a single object is selected
1422
    // Using a strict return statement is okay here; no handles means *no* handles.
1423
236k
    if (mpMarkedObj)
1424
0
    {
1425
        // formerly #i33755#: If TextEdit is active the EditEngine will directly paint
1426
        // to the window, so suppress Overlay and handles completely; a text frame for
1427
        // the active text edit will be painted by the repaint mechanism in
1428
        // SdrObjEditView::ImpPaintOutlinerView in this case. This needs to be reworked
1429
        // in the future
1430
        // Also formerly #122142#: Pretty much the same for SdrCaptionObj's in calc.
1431
0
        if(static_cast<SdrView*>(this)->IsTextEdit())
1432
0
        {
1433
0
            const SdrTextObj* pSdrTextObj = DynCastSdrTextObj(mpMarkedObj);
1434
1435
0
            if (pSdrTextObj && pSdrTextObj->IsInEditMode())
1436
0
            {
1437
0
                if (!bTiledRendering)
1438
0
                    return;
1439
0
            }
1440
0
        }
1441
1442
        // formerly #i118524#: if inplace activated OLE is selected, suppress handles
1443
0
        const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(mpMarkedObj);
1444
1445
0
        if(pSdrOle2Obj && (pSdrOle2Obj->isInplaceActive() || pSdrOle2Obj->isUiActive()))
1446
0
        {
1447
0
            return;
1448
0
        }
1449
1450
0
        if (!maSubSelectionList.empty())
1451
0
        {
1452
0
            mpMarkingSubSelectionOverlay = std::make_unique<MarkingSubSelectionOverlay>(*this, maSubSelectionList);
1453
0
        }
1454
0
    }
1455
1456
236k
    if (bFrmHdl)
1457
233k
    {
1458
233k
        if(!aRect.IsEmpty())
1459
0
        {
1460
            // otherwise nothing is found
1461
0
            const size_t nSiz0(maHdlList.GetHdlCount());
1462
0
            SdrObject* pSubSelection(nullptr);
1463
1464
0
            if( bSingleTextObjMark )
1465
0
            {
1466
0
                mpMarkedObj->AddToHdlList(maHdlList);
1467
0
            }
1468
0
            else
1469
0
            {
1470
                // caution! mpMarkedObj and pSubSelection are and may only be set for
1471
                // single object selection
1472
0
                if (nullptr != mpMarkedObj)
1473
0
                    pSubSelection = mpMarkedObj->getDiagramSubSelection();
1474
1475
                // use SubSelection not for BGShape, in that case use SdrObjGroup to
1476
                // allow group actions on it
1477
0
                if(nullptr != pSubSelection)
1478
0
                {
1479
0
                    if (pSubSelection->isDiagramBackgroundShape())
1480
0
                        pSubSelection = nullptr;
1481
0
                    else
1482
0
                        aRect = pSubSelection->GetSnapRect();
1483
0
                }
1484
1485
0
                const bool bWdt0(aRect.Left() == aRect.Right());
1486
0
                const bool bHgt0(aRect.Top() == aRect.Bottom());
1487
1488
0
                if (bWdt0 && bHgt0)
1489
0
                {
1490
0
                    maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
1491
0
                }
1492
0
                else if (!bStdDrag && (bWdt0 || bHgt0))
1493
0
                {
1494
0
                    maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
1495
0
                    maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
1496
0
                }
1497
0
                else
1498
0
                {
1499
0
                    if (!bWdt0 && !bHgt0)
1500
0
                    {
1501
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
1502
0
                    }
1503
1504
0
                    if (!bLimitedRotation && !bHgt0)
1505
0
                    {
1506
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopCenter(), SdrHdlKind::Upper));
1507
0
                    }
1508
1509
0
                    if (!bWdt0 && !bHgt0)
1510
0
                    {
1511
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopRight(), SdrHdlKind::UpperRight));
1512
0
                    }
1513
1514
0
                    if (!bLimitedRotation && !bWdt0)
1515
0
                    {
1516
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.LeftCenter(), SdrHdlKind::Left ));
1517
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.RightCenter(), SdrHdlKind::Right));
1518
0
                    }
1519
1520
0
                    if (!bWdt0 && !bHgt0)
1521
0
                    {
1522
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomLeft(), SdrHdlKind::LowerLeft));
1523
0
                    }
1524
1525
0
                    if (!bLimitedRotation && !bHgt0)
1526
0
                    {
1527
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomCenter(), SdrHdlKind::Lower));
1528
0
                    }
1529
1530
0
                    if (!bWdt0 && !bHgt0)
1531
0
                    {
1532
0
                        maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
1533
0
                    }
1534
0
                }
1535
0
            }
1536
1537
            // Diagram selection visualization support
1538
            // Caution: CppunitTest_sd_tiledrendering shows that mpMarkedObj *can* actually be nullptr (!)
1539
0
            if(nullptr != mpMarkedObj && mpMarkedObj->isDiagram())
1540
0
            {
1541
0
                mpMarkedObj->AddToHdlList(maHdlList);
1542
0
            }
1543
1544
0
            const size_t nSiz1(maHdlList.GetHdlCount());
1545
1546
            // moved setting the missing parameters at SdrHdl here from the
1547
            // single loop above (bSingleTextObjMark), this was missing all
1548
            // the time. Setting SdrObject is now required to correctly get
1549
            // the View-Dependent evtl. GridOffset adapted
1550
0
            for (size_t i=nSiz0; i<nSiz1; ++i)
1551
0
            {
1552
0
                SdrHdl* pHdl=maHdlList.GetHdl(i);
1553
0
                pHdl->SetObj(nullptr != pSubSelection ? pSubSelection : mpMarkedObj);
1554
0
                pHdl->SetPageView(mpMarkedPV);
1555
0
                pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
1556
0
            }
1557
0
        }
1558
233k
    }
1559
2.45k
    else
1560
2.45k
    {
1561
2.45k
        bool bDone(false);
1562
1563
        // moved crop handling to non-frame part and the handle creation to SdrGrafObj
1564
2.45k
        if(1 == nMarkCount && mpMarkedObj && SdrDragMode::Crop == meDragMode)
1565
0
        {
1566
            // Default addCropHandles from SdrObject does nothing. When pMarkedObj is SdrGrafObj, previous
1567
            // behaviour occurs (code in svx/source/svdraw/svdograf.cxx). When pMarkedObj is SwVirtFlyDrawObj
1568
            // writer takes the responsibility of adding handles (code in sw/source/core/draw/dflyobj.cxx)
1569
0
            const size_t nSiz0(maHdlList.GetHdlCount());
1570
0
            mpMarkedObj->addCropHandles(maHdlList);
1571
0
            const size_t nSiz1(maHdlList.GetHdlCount());
1572
1573
            // Was missing: Set infos at SdrCropHdl
1574
0
            for (size_t i=nSiz0; i<nSiz1; ++i)
1575
0
            {
1576
0
                SdrHdl* pHdl=maHdlList.GetHdl(i);
1577
0
                pHdl->SetObj(mpMarkedObj);
1578
0
                pHdl->SetPageView(mpMarkedPV);
1579
0
                pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
1580
0
            }
1581
1582
0
            bDone = true;
1583
0
        }
1584
1585
2.45k
        if(!bDone)
1586
2.45k
        {
1587
2.45k
            for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1588
0
            {
1589
0
                const SdrMark* pM=rMarkList.GetMark(nMarkNum);
1590
0
                SdrObject* pObj=pM->GetMarkedSdrObj();
1591
0
                SdrPageView* pPV=pM->GetPageView();
1592
0
                const size_t nSiz0=maHdlList.GetHdlCount();
1593
0
                pObj->AddToHdlList(maHdlList);
1594
0
                const size_t nSiz1=maHdlList.GetHdlCount();
1595
0
                bool bPoly=pObj->IsPolyObj();
1596
0
                const SdrUShortCont& rMrkPnts = pM->GetMarkedPoints();
1597
0
                for (size_t i=nSiz0; i<nSiz1; ++i)
1598
0
                {
1599
0
                    SdrHdl* pHdl=maHdlList.GetHdl(i);
1600
0
                    pHdl->SetObj(pObj);
1601
0
                    pHdl->SetPageView(pPV);
1602
0
                    pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
1603
1604
0
                    if (bPoly)
1605
0
                    {
1606
0
                        bool bSelected= rMrkPnts.contains( sal_uInt16(i-nSiz0) );
1607
0
                        pHdl->SetSelected(bSelected);
1608
0
                        if (mbPlusHdlAlways || bSelected)
1609
0
                        {
1610
0
                            SdrHdlList plusList(nullptr);
1611
0
                            pObj->AddToPlusHdlList(plusList, *pHdl);
1612
0
                            sal_uInt32 nPlusHdlCnt=plusList.GetHdlCount();
1613
0
                            for (sal_uInt32 nPlusNum=0; nPlusNum<nPlusHdlCnt; nPlusNum++)
1614
0
                            {
1615
0
                                SdrHdl* pPlusHdl=plusList.GetHdl(nPlusNum);
1616
0
                                pPlusHdl->SetObj(pObj);
1617
0
                                pPlusHdl->SetPageView(pPV);
1618
0
                                pPlusHdl->SetPlusHdl(true);
1619
0
                            }
1620
0
                            plusList.MoveTo(maHdlList);
1621
0
                        }
1622
0
                    }
1623
0
                }
1624
0
            }
1625
2.45k
        }
1626
2.45k
    }
1627
1628
    // GluePoint handles
1629
236k
    for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1630
0
    {
1631
0
        const SdrMark* pM=rMarkList.GetMark(nMarkNum);
1632
0
        SdrObject* pObj=pM->GetMarkedSdrObj();
1633
0
        const SdrGluePointList* pGPL=pObj->GetGluePointList();
1634
0
        if (!pGPL)
1635
0
            continue;
1636
1637
0
        SdrPageView* pPV=pM->GetPageView();
1638
0
        const SdrUShortCont& rMrkGlue=pM->GetMarkedGluePoints();
1639
0
        for (sal_uInt16 nId : rMrkGlue)
1640
0
        {
1641
            //nNum changed to nNumGP because already used in for loop
1642
0
            sal_uInt16 nNumGP=pGPL->FindGluePoint(nId);
1643
0
            if (nNumGP!=SDRGLUEPOINT_NOTFOUND)
1644
0
            {
1645
0
                const SdrGluePoint& rGP=(*pGPL)[nNumGP];
1646
0
                Point aPos(rGP.GetAbsolutePos(*pObj));
1647
0
                std::unique_ptr<SdrHdl> pGlueHdl(new SdrHdl(aPos,SdrHdlKind::Glue));
1648
0
                pGlueHdl->SetObj(pObj);
1649
0
                pGlueHdl->SetPageView(pPV);
1650
0
                pGlueHdl->SetObjHdlNum(nId);
1651
0
                maHdlList.AddHdl(std::move(pGlueHdl));
1652
0
            }
1653
0
        }
1654
0
    }
1655
1656
    // rotation point/axis of reflection
1657
236k
    if(!bLimitedRotation)
1658
236k
    {
1659
236k
        AddDragModeHdl(meDragMode);
1660
236k
    }
1661
1662
    // sort handles
1663
236k
    maHdlList.Sort();
1664
1665
    // add custom handles (used by other apps, e.g. AnchorPos)
1666
236k
    AddCustomHdl();
1667
1668
    // moved it here to access all the handles for callback.
1669
236k
    if (bTiledRendering && pViewShell)
1670
0
    {
1671
0
        SetMarkHandlesForLOKit(aRect, pOtherShell);
1672
0
    }
1673
1674
    // try to restore focus handle index from remembered values
1675
236k
    if(!bSaveOldFocus)
1676
236k
        return;
1677
1678
0
    for(size_t a = 0; a < maHdlList.GetHdlCount(); ++a)
1679
0
    {
1680
0
        SdrHdl* pCandidate = maHdlList.GetHdl(a);
1681
1682
0
        if(pCandidate->GetObj()
1683
0
            && pCandidate->GetObj() == pSaveObj
1684
0
            && pCandidate->GetKind() == eSaveKind
1685
0
            && pCandidate->GetPolyNum() == nSavePolyNum
1686
0
            && pCandidate->GetPointNum() == nSavePointNum)
1687
0
        {
1688
0
            maHdlList.SetFocusHdl(pCandidate);
1689
0
            break;
1690
0
        }
1691
0
    }
1692
0
}
1693
1694
void SdrMarkView::AddCustomHdl()
1695
11.9k
{
1696
    // add custom handles (used by other apps, e.g. AnchorPos)
1697
11.9k
}
1698
1699
void SdrMarkView::SetDragMode(SdrDragMode eMode)
1700
0
{
1701
0
    SdrDragMode eMode0=meDragMode;
1702
0
    meDragMode=eMode;
1703
0
    if (meDragMode==SdrDragMode::Resize) meDragMode=SdrDragMode::Move;
1704
0
    if (meDragMode!=eMode0) {
1705
0
        ForceRefToMarked();
1706
0
        SetMarkHandles(nullptr);
1707
0
        {
1708
0
            const SdrMarkList& rMarkList = GetMarkedObjectList();
1709
0
            if (rMarkList.GetMarkCount() != 0) MarkListHasChanged();
1710
0
        }
1711
0
    }
1712
0
}
1713
1714
void SdrMarkView::AddDragModeHdl(SdrDragMode eMode)
1715
236k
{
1716
236k
    switch(eMode)
1717
236k
    {
1718
0
        case SdrDragMode::Rotate:
1719
0
        {
1720
            // add rotation center
1721
0
            maHdlList.AddHdl(std::make_unique<SdrHdl>(maRef1, SdrHdlKind::Ref1));
1722
0
            break;
1723
0
        }
1724
0
        case SdrDragMode::Mirror:
1725
0
        {
1726
            // add axis of reflection
1727
0
            std::unique_ptr<SdrHdl> pHdl3(new SdrHdl(maRef2, SdrHdlKind::Ref2));
1728
0
            std::unique_ptr<SdrHdl> pHdl2(new SdrHdl(maRef1, SdrHdlKind::Ref1));
1729
0
            std::unique_ptr<SdrHdl> pHdl1(new SdrHdlLine(*pHdl2, *pHdl3, SdrHdlKind::MirrorAxis));
1730
1731
0
            pHdl1->SetObjHdlNum(1); // for sorting
1732
0
            pHdl2->SetObjHdlNum(2); // for sorting
1733
0
            pHdl3->SetObjHdlNum(3); // for sorting
1734
1735
0
            maHdlList.AddHdl(std::move(pHdl1)); // line comes first, so it is the last in HitTest
1736
0
            maHdlList.AddHdl(std::move(pHdl2));
1737
0
            maHdlList.AddHdl(std::move(pHdl3));
1738
1739
0
            break;
1740
0
        }
1741
0
        case SdrDragMode::Transparence:
1742
0
        {
1743
            // add interactive transparency handle
1744
0
            const SdrMarkList& rMarkList = GetMarkedObjectList();
1745
0
            const size_t nMarkCount = rMarkList.GetMarkCount();
1746
0
            if(nMarkCount == 1)
1747
0
            {
1748
0
                SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
1749
0
                SdrModel& rModel = GetModel();
1750
0
                const SfxItemSet& rSet = pObj->GetMergedItemSet();
1751
1752
0
                if(SfxItemState::SET != rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE, false))
1753
0
                {
1754
                    // add this item, it's not yet there
1755
0
                    XFillFloatTransparenceItem aNewItem(rSet.Get(XATTR_FILLFLOATTRANSPARENCE));
1756
0
                    basegfx::BGradient aGrad = aNewItem.GetGradientValue();
1757
1758
0
                    aNewItem.SetEnabled(true);
1759
0
                    aGrad.SetStartIntens(100);
1760
0
                    aGrad.SetEndIntens(100);
1761
0
                    aNewItem.SetGradientValue(aGrad);
1762
1763
                    // add undo to allow user to take back this step
1764
0
                    if (rModel.IsUndoEnabled())
1765
0
                    {
1766
0
                        rModel.BegUndo(SvxResId(SIP_XA_FILLTRANSPARENCE));
1767
0
                        rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
1768
0
                        rModel.EndUndo();
1769
0
                    }
1770
1771
0
                    SfxItemSet aNewSet(rModel.GetItemPool());
1772
0
                    aNewSet.Put(aNewItem);
1773
0
                    pObj->SetMergedItemSetAndBroadcast(aNewSet);
1774
0
                }
1775
1776
                // set values and transform to vector set
1777
0
                GradTransVector aGradTransVector;
1778
0
                GradTransGradient aGradTransGradient;
1779
1780
0
                aGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
1781
0
                GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, pObj);
1782
1783
                // build handles
1784
0
                const Point aTmpPos1(basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getX()), basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getY()));
1785
0
                const Point aTmpPos2(basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getX()), basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getY()));
1786
0
                std::unique_ptr<SdrHdlColor> pColHdl1(new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, SDR_HANDLE_COLOR_SIZE_NORMAL, true));
1787
0
                std::unique_ptr<SdrHdlColor> pColHdl2(new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, SDR_HANDLE_COLOR_SIZE_NORMAL, true));
1788
0
                std::unique_ptr<SdrHdlGradient> pGradHdl(new SdrHdlGradient(aTmpPos1, aTmpPos2, false));
1789
0
                DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Could not get all necessary handles!");
1790
1791
                // link them
1792
0
                pGradHdl->SetColorHandles(pColHdl1.get(), pColHdl2.get());
1793
0
                pGradHdl->SetObj(pObj);
1794
0
                pColHdl1->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1795
0
                pColHdl2->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1796
1797
                // insert them
1798
0
                maHdlList.AddHdl(std::move(pColHdl1));
1799
0
                maHdlList.AddHdl(std::move(pColHdl2));
1800
0
                maHdlList.AddHdl(std::move(pGradHdl));
1801
0
            }
1802
0
            break;
1803
0
        }
1804
0
        case SdrDragMode::Gradient:
1805
0
        {
1806
            // add interactive gradient handle
1807
0
            const SdrMarkList& rMarkList = GetMarkedObjectList();
1808
0
            const size_t nMarkCount = rMarkList.GetMarkCount();
1809
0
            if(nMarkCount == 1)
1810
0
            {
1811
0
                SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
1812
0
                const SfxItemSet& rSet = pObj->GetMergedItemSet();
1813
0
                drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
1814
1815
0
                if(eFillStyle == drawing::FillStyle_GRADIENT)
1816
0
                {
1817
                    // set values and transform to vector set
1818
0
                    GradTransVector aGradTransVector;
1819
0
                    GradTransGradient aGradTransGradient;
1820
0
                    Size aHdlSize(15, 15);
1821
1822
0
                    aGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
1823
0
                    GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, pObj);
1824
1825
                    // build handles
1826
0
                    const Point aTmpPos1(basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getX()), basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getY()));
1827
0
                    const Point aTmpPos2(basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getX()), basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getY()));
1828
0
                    std::unique_ptr<SdrHdlColor> pColHdl1(new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, aHdlSize, false));
1829
0
                    std::unique_ptr<SdrHdlColor> pColHdl2(new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, aHdlSize, false));
1830
0
                    std::unique_ptr<SdrHdlGradient> pGradHdl(new SdrHdlGradient(aTmpPos1, aTmpPos2, true));
1831
0
                    DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Could not get all necessary handles!");
1832
1833
                    // link them
1834
0
                    pGradHdl->SetColorHandles(pColHdl1.get(), pColHdl2.get());
1835
0
                    pGradHdl->SetObj(pObj);
1836
0
                    pColHdl1->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1837
0
                    pColHdl2->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
1838
1839
                    // insert them
1840
0
                    maHdlList.AddHdl(std::move(pColHdl1));
1841
0
                    maHdlList.AddHdl(std::move(pColHdl2));
1842
0
                    maHdlList.AddHdl(std::move(pGradHdl));
1843
0
                }
1844
0
            }
1845
0
            break;
1846
0
        }
1847
0
        case SdrDragMode::Crop:
1848
0
        {
1849
            // TODO
1850
0
            break;
1851
0
        }
1852
236k
        default: break;
1853
236k
    }
1854
236k
}
1855
1856
/** handle mouse over effects for handles */
1857
bool SdrMarkView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
1858
0
{
1859
0
    if(maHdlList.GetHdlCount())
1860
0
    {
1861
0
        SdrHdl* pMouseOverHdl = nullptr;
1862
0
        if( !rMEvt.IsLeaveWindow() && pWin )
1863
0
        {
1864
0
            Point aMDPos( pWin->PixelToLogic( rMEvt.GetPosPixel() ) );
1865
0
            pMouseOverHdl = PickHandle(aMDPos);
1866
0
        }
1867
1868
        // notify last mouse over handle that he lost the mouse
1869
0
        const size_t nHdlCount = maHdlList.GetHdlCount();
1870
1871
0
        for(size_t nHdl = 0; nHdl < nHdlCount; ++nHdl)
1872
0
        {
1873
0
            SdrHdl* pCurrentHdl = GetHdl(nHdl);
1874
0
            if( pCurrentHdl->mbMouseOver )
1875
0
            {
1876
0
                if( pCurrentHdl != pMouseOverHdl )
1877
0
                {
1878
0
                    pCurrentHdl->mbMouseOver = false;
1879
0
                    pCurrentHdl->onMouseLeave();
1880
0
                }
1881
0
                break;
1882
0
            }
1883
0
        }
1884
1885
        // notify current mouse over handle
1886
0
        if( pMouseOverHdl )
1887
0
        {
1888
0
            pMouseOverHdl->mbMouseOver = true;
1889
0
            pMouseOverHdl->onMouseEnter(rMEvt);
1890
0
        }
1891
0
    }
1892
0
    return SdrSnapView::MouseMove(rMEvt, pWin);
1893
0
}
1894
1895
bool SdrMarkView::RequestHelp(const HelpEvent& rHEvt)
1896
0
{
1897
0
    if (maHdlList.GetHdlCount())
1898
0
    {
1899
0
        const size_t nHdlCount = maHdlList.GetHdlCount();
1900
1901
0
        for (size_t nHdl = 0; nHdl < nHdlCount; ++nHdl)
1902
0
        {
1903
0
            SdrHdl* pCurrentHdl = GetHdl(nHdl);
1904
0
            if (pCurrentHdl->mbMouseOver)
1905
0
            {
1906
0
                pCurrentHdl->onHelpRequest();
1907
0
                return true;
1908
0
            }
1909
0
        }
1910
0
    }
1911
0
    return SdrSnapView::RequestHelp(rHEvt);
1912
0
}
1913
1914
void SdrMarkView::ForceRefToMarked()
1915
0
{
1916
0
    switch(meDragMode)
1917
0
    {
1918
0
        case SdrDragMode::Rotate:
1919
0
        {
1920
0
            tools::Rectangle aR(GetMarkedObjRect());
1921
0
            maRef1 = aR.Center();
1922
1923
0
            break;
1924
0
        }
1925
1926
0
        case SdrDragMode::Mirror:
1927
0
        {
1928
            // first calculate the length of the axis of reflection
1929
0
            tools::Long nOutMin=0;
1930
0
            tools::Long nOutMax=0;
1931
0
            tools::Long nMinLen=0;
1932
0
            tools::Long nObjDst=0;
1933
0
            tools::Long nOutHgt=0;
1934
0
            OutputDevice* pOut=GetFirstOutputDevice();
1935
0
            if (pOut!=nullptr) {
1936
                // minimum length: 50 pixels
1937
0
                nMinLen=pOut->PixelToLogic(Size(0,50)).Height();
1938
                // 20 pixels distance to the Obj for the reference point
1939
0
                nObjDst=pOut->PixelToLogic(Size(0,20)).Height();
1940
                // MinY/MaxY
1941
                // margin = minimum length = 10 pixels
1942
0
                tools::Long nDst=pOut->PixelToLogic(Size(0,10)).Height();
1943
0
                nOutMin=-pOut->GetMapMode().GetOrigin().Y();
1944
0
                nOutMax=pOut->GetOutputSize().Height()-1+nOutMin;
1945
0
                nOutMin+=nDst;
1946
0
                nOutMax-=nDst;
1947
                // absolute minimum length, however, is 10 pixels
1948
0
                if (nOutMax-nOutMin<nDst) {
1949
0
                    nOutMin+=nOutMax+1;
1950
0
                    nOutMin/=2;
1951
0
                    nOutMin-=(nDst+1)/2;
1952
0
                    nOutMax=nOutMin+nDst;
1953
0
                }
1954
0
                nOutHgt=nOutMax-nOutMin;
1955
                // otherwise minimum length = 1/4 OutHgt
1956
0
                tools::Long nTemp=nOutHgt/4;
1957
0
                if (nTemp>nMinLen) nMinLen=nTemp;
1958
0
            }
1959
1960
0
            tools::Rectangle aR(GetMarkedObjBoundRect());
1961
0
            Point aCenter(aR.Center());
1962
0
            tools::Long nMarkHgt=aR.GetHeight()-1;
1963
0
            tools::Long nHgt=nMarkHgt+nObjDst*2;       // 20 pixels overlapping above and below
1964
0
            if (nHgt<nMinLen) nHgt=nMinLen;     // minimum length 50 pixels or 1/4 OutHgt, respectively
1965
1966
0
            tools::Long nY1=aCenter.Y()-(nHgt+1)/2;
1967
0
            tools::Long nY2=nY1+nHgt;
1968
1969
0
            if (pOut!=nullptr && nMinLen>nOutHgt) nMinLen=nOutHgt; // TODO: maybe shorten this a little
1970
1971
0
            if (pOut!=nullptr) { // now move completely into the visible area
1972
0
                if (nY1<nOutMin) {
1973
0
                    nY1=nOutMin;
1974
0
                    if (nY2<nY1+nMinLen) nY2=nY1+nMinLen;
1975
0
                }
1976
0
                if (nY2>nOutMax) {
1977
0
                    nY2=nOutMax;
1978
0
                    if (nY1>nY2-nMinLen) nY1=nY2-nMinLen;
1979
0
                }
1980
0
            }
1981
1982
0
            maRef1.setX(aCenter.X() );
1983
0
            maRef1.setY(nY1 );
1984
0
            maRef2.setX(aCenter.X() );
1985
0
            maRef2.setY(nY2 );
1986
1987
0
            break;
1988
0
        }
1989
1990
0
        case SdrDragMode::Transparence:
1991
0
        case SdrDragMode::Gradient:
1992
0
        case SdrDragMode::Crop:
1993
0
        {
1994
0
            tools::Rectangle aRect(GetMarkedObjBoundRect());
1995
0
            maRef1 = aRect.TopLeft();
1996
0
            maRef2 = aRect.BottomRight();
1997
0
            break;
1998
0
        }
1999
0
        default: break;
2000
0
    }
2001
0
}
2002
2003
void SdrMarkView::SetRef1(const Point& rPt)
2004
0
{
2005
0
    if(meDragMode == SdrDragMode::Rotate || meDragMode == SdrDragMode::Mirror)
2006
0
    {
2007
0
        maRef1 = rPt;
2008
0
        SdrHdl* pH = maHdlList.GetHdl(SdrHdlKind::Ref1);
2009
0
        if(pH)
2010
0
            pH->SetPos(rPt);
2011
0
    }
2012
0
}
2013
2014
void SdrMarkView::SetRef2(const Point& rPt)
2015
0
{
2016
0
    if(meDragMode == SdrDragMode::Mirror)
2017
0
    {
2018
0
        maRef2 = rPt;
2019
0
        SdrHdl* pH = maHdlList.GetHdl(SdrHdlKind::Ref2);
2020
0
        if(pH)
2021
0
            pH->SetPos(rPt);
2022
0
    }
2023
0
}
2024
2025
SfxViewShell* SdrMarkView::GetSfxViewShell() const
2026
11.9k
{
2027
11.9k
    return SfxViewShell::Current();
2028
11.9k
}
2029
2030
void SdrMarkView::CheckMarked()
2031
236k
{
2032
236k
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2033
236k
    for (size_t nm=rMarkList.GetMarkCount(); nm>0;) {
2034
0
        --nm;
2035
0
        SdrMark* pM = rMarkList.GetMark(nm);
2036
0
        SdrObject* pObj = pM->GetMarkedSdrObj();
2037
0
        SdrPageView* pPV = pM->GetPageView();
2038
0
        bool bRaus = !pObj || !pPV->IsObjMarkable(pObj);
2039
0
        if (bRaus)
2040
0
        {
2041
0
            GetMarkedObjectListWriteAccess().DeleteMark(nm);
2042
0
        }
2043
0
        else
2044
0
        {
2045
0
            if (!IsGluePointEditMode()) { // selected gluepoints only in GlueEditMode
2046
0
                SdrUShortCont& rPts = pM->GetMarkedGluePoints();
2047
0
                rPts.clear();
2048
0
            }
2049
0
        }
2050
0
    }
2051
2052
    // at least reset the remembered BoundRect to prevent handle
2053
    // generation if bForceFrameHandles is TRUE.
2054
236k
    mbMarkedObjRectDirty = true;
2055
236k
}
2056
2057
void SdrMarkView::SetMarkRects()
2058
236k
{
2059
236k
    SdrPageView* pPV = GetSdrPageView();
2060
2061
236k
    if(pPV)
2062
171k
    {
2063
171k
        const SdrMarkList& rMarkList = GetMarkedObjectList();
2064
171k
        pPV->SetHasMarkedObj(rMarkList.TakeSnapRect(pPV, pPV->MarkSnap()));
2065
171k
        rMarkList.TakeBoundRect(pPV, pPV->MarkBound());
2066
171k
    }
2067
236k
}
2068
2069
void SdrMarkView::SetFrameHandles(bool bOn)
2070
65.7k
{
2071
65.7k
    if (bOn!=mbForceFrameHandles) {
2072
65.4k
        bool bOld=ImpIsFrameHandles();
2073
65.4k
        mbForceFrameHandles=bOn;
2074
65.4k
        bool bNew=ImpIsFrameHandles();
2075
65.4k
        if (bNew!=bOld) {
2076
65.4k
            AdjustMarkHdl();
2077
65.4k
            MarkListHasChanged();
2078
65.4k
        }
2079
65.4k
    }
2080
65.7k
}
2081
2082
void SdrMarkView::SetEditMode(SdrViewEditMode eMode)
2083
0
{
2084
0
    if (eMode==meEditMode)        return;
2085
2086
0
    bool bGlue0=meEditMode==SdrViewEditMode::GluePointEdit;
2087
0
    bool bEdge0=static_cast<SdrCreateView*>(this)->IsEdgeTool();
2088
0
    meEditMode0=meEditMode;
2089
0
    meEditMode=eMode;
2090
0
    bool bGlue1=meEditMode==SdrViewEditMode::GluePointEdit;
2091
0
    bool bEdge1=static_cast<SdrCreateView*>(this)->IsEdgeTool();
2092
    // avoid flickering when switching between GlueEdit and EdgeTool
2093
0
    if (bGlue1 && !bGlue0) ImpSetGlueVisible2(bGlue1);
2094
0
    if (bEdge1!=bEdge0) ImpSetGlueVisible3(bEdge1);
2095
0
    if (!bGlue1 && bGlue0) ImpSetGlueVisible2(bGlue1);
2096
0
    if (bGlue0 && !bGlue1) UnmarkAllGluePoints();
2097
0
}
2098
2099
2100
bool SdrMarkView::IsObjMarkable(SdrObject const * pObj, SdrPageView const * pPV) const
2101
32
{
2102
32
    if (pObj)
2103
32
    {
2104
32
        if (pObj->IsMarkProtect() ||
2105
32
            (!mbDesignMode && pObj->IsUnoObj()))
2106
0
        {
2107
            // object not selectable or
2108
            // SdrUnoObj not in DesignMode
2109
0
            return false;
2110
0
        }
2111
32
    }
2112
32
    return pPV==nullptr || pPV->IsObjMarkable(pObj);
2113
32
}
2114
2115
bool SdrMarkView::IsMarkedObjHit(const Point& rPnt, short nTol) const
2116
0
{
2117
0
    bool bRet=false;
2118
0
    nTol=ImpGetHitTolLogic(nTol,nullptr);
2119
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2120
0
    for (size_t nm=0; nm<rMarkList.GetMarkCount() && !bRet; ++nm) {
2121
0
        SdrMark* pM=rMarkList.GetMark(nm);
2122
0
        SdrObject* pObj(pM->GetMarkedSdrObj());
2123
2124
        // access possible SubSelection
2125
0
        if (nullptr != pObj)
2126
0
            pObj = pObj->getDiagramSubSelection();
2127
2128
0
        bRet = nullptr != CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pObj,pM->GetPageView(),SdrSearchOptions::NONE,nullptr);
2129
0
    }
2130
0
    return bRet;
2131
0
}
2132
2133
SdrHdl* SdrMarkView::PickHandle(const Point& rPnt) const
2134
0
{
2135
0
    if (mbSomeObjChgdFlag) { // recalculate handles, if necessary
2136
0
        FlushComeBackTimer();
2137
0
    }
2138
0
    return maHdlList.IsHdlListHit(rPnt);
2139
0
}
2140
2141
bool SdrMarkView::MarkObj(const Point& rPnt, short nTol, bool bToggle, bool bDeep)
2142
0
{
2143
0
    SdrPageView* pPV;
2144
0
    nTol=ImpGetHitTolLogic(nTol,nullptr);
2145
0
    SdrSearchOptions nOptions=SdrSearchOptions::PICKMARKABLE;
2146
0
    if (bDeep) nOptions=nOptions|SdrSearchOptions::DEEP;
2147
0
    SdrObject* pObj = PickObj(rPnt, static_cast<sal_uInt16>(nTol), pPV, nOptions);
2148
2149
0
    if (pObj)
2150
0
    {
2151
0
        const std::shared_ptr< svx::diagram::DiagramHelper_svx >& rDiagramHelper(pObj->getDiagramHelper());
2152
0
        if (rDiagramHelper)
2153
0
        {
2154
0
            if (pObj->isDiagram() && !bDeep)
2155
0
            {
2156
                // Click on Diagram, look again but deep to get possibly an object
2157
                // inside the SdrObjGroup associated with it
2158
0
                SdrObject* pCandidate = PickObj(rPnt, static_cast<sal_uInt16>(nTol), pPV, nOptions|SdrSearchOptions::DEEP);
2159
2160
0
                if (pCandidate && !pCandidate->isDiagram())
2161
0
                    rDiagramHelper->markDirectDiagramSubSelection(*pCandidate);
2162
0
            }
2163
0
            else
2164
0
            {
2165
0
                rDiagramHelper->markDirectDiagramSubSelection(*pObj);
2166
0
                pObj = rDiagramHelper->getAssociatedRootShape();
2167
0
            }
2168
0
        }
2169
0
    }
2170
2171
0
    if (pObj)
2172
0
    {
2173
0
        bool bUnmark=bToggle && IsObjMarked(pObj);
2174
0
        MarkObj(pObj,pPV,bUnmark);
2175
0
    }
2176
0
    return pObj != nullptr;
2177
0
}
2178
2179
bool SdrMarkView::MarkNextObj(bool bPrev)
2180
0
{
2181
0
    SdrPageView* pPageView = GetSdrPageView();
2182
2183
0
    if(!pPageView)
2184
0
    {
2185
0
        return false;
2186
0
    }
2187
2188
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2189
0
    rMarkList.ForceSort();
2190
0
    const size_t nMarkCount(rMarkList.GetMarkCount());
2191
0
    size_t nChgMarkNum(SAL_MAX_SIZE); // number of the MarkEntry we want to replace
2192
0
    SdrObject* pMarkObj(nullptr);
2193
2194
0
    if (1 == nMarkCount)
2195
0
    {
2196
0
        SdrMark* pM(rMarkList.GetMark(0));
2197
0
        if (nullptr != pM)
2198
0
        {
2199
0
            SdrObject* pCandidate(pM->GetMarkedSdrObj());
2200
2201
0
            if (nullptr != pCandidate)
2202
0
            {
2203
0
                const std::shared_ptr< svx::diagram::DiagramHelper_svx >& rDiagramHelper(pCandidate->getDiagramHelper());
2204
2205
0
                if (rDiagramHelper)
2206
0
                {
2207
0
                    if (rDiagramHelper->markNextDiagramSubSelection(bPrev))
2208
0
                        pMarkObj=pCandidate;
2209
0
                }
2210
0
            }
2211
0
        }
2212
0
    }
2213
2214
0
    if (nullptr == pMarkObj)
2215
0
    {
2216
0
        size_t nSearchObjNum = bPrev ? 0 : SAL_MAX_SIZE;
2217
0
        if (nMarkCount!=0) {
2218
0
            nChgMarkNum=bPrev ? 0 : nMarkCount-1;
2219
0
            SdrMark* pM=rMarkList.GetMark(nChgMarkNum);
2220
0
            assert(pM != nullptr);
2221
0
            if (pM->GetMarkedSdrObj() != nullptr)
2222
0
                nSearchObjNum = pM->GetMarkedSdrObj()->GetNavigationPosition();
2223
0
        }
2224
2225
0
        SdrObjList* pSearchObjList=pPageView->GetObjList();
2226
0
        const size_t nObjCount = pSearchObjList->GetObjCount();
2227
0
        if (nObjCount!=0) {
2228
0
            if (nSearchObjNum>nObjCount) nSearchObjNum=nObjCount;
2229
0
            while (pMarkObj==nullptr && ((!bPrev && nSearchObjNum>0) || (bPrev && nSearchObjNum<nObjCount)))
2230
0
            {
2231
0
                if (!bPrev)
2232
0
                    nSearchObjNum--;
2233
0
                SdrObject* pSearchObj = pSearchObjList->GetObjectForNavigationPosition(nSearchObjNum);
2234
0
                if (IsObjMarkable(pSearchObj,pPageView))
2235
0
                {
2236
0
                    if (rMarkList.FindObject(pSearchObj)==SAL_MAX_SIZE)
2237
0
                    {
2238
0
                        pMarkObj=pSearchObj;
2239
0
                    }
2240
0
                }
2241
0
                if (bPrev) nSearchObjNum++;
2242
0
            }
2243
2244
0
            if (nullptr != pMarkObj && pMarkObj->IsGroupObject() && pMarkObj->isDiagram())
2245
0
            {
2246
                // newly selected by keyboard, reset old sub selection
2247
0
                const std::shared_ptr< svx::diagram::DiagramHelper_svx >& rDiagramHelper(pMarkObj->getDiagramHelper());
2248
0
                if (rDiagramHelper)
2249
0
                    rDiagramHelper->initSelectionByKeyboard(bPrev);
2250
0
            }
2251
0
        }
2252
0
    }
2253
2254
0
    if(!pMarkObj)
2255
0
    {
2256
0
        return false;
2257
0
    }
2258
2259
0
    if (nChgMarkNum!=SAL_MAX_SIZE)
2260
0
    {
2261
0
        GetMarkedObjectListWriteAccess().DeleteMark(nChgMarkNum);
2262
0
    }
2263
0
    MarkObj(pMarkObj,pPageView); // also calls MarkListHasChanged(), AdjustMarkHdl()
2264
0
    return true;
2265
0
}
2266
2267
bool SdrMarkView::MarkNextObj(const Point& rPnt, short nTol, bool bPrev)
2268
0
{
2269
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2270
0
    rMarkList.ForceSort();
2271
0
    nTol=ImpGetHitTolLogic(nTol,nullptr);
2272
0
    SdrMark* pTopMarkHit=nullptr;
2273
0
    SdrMark* pBtmMarkHit=nullptr;
2274
0
    size_t nTopMarkHit=0;
2275
0
    size_t nBtmMarkHit=0;
2276
    // find topmost of the selected objects that is hit by rPnt
2277
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
2278
0
    for (size_t nm=nMarkCount; nm>0 && pTopMarkHit==nullptr;) {
2279
0
        --nm;
2280
0
        SdrMark* pM=rMarkList.GetMark(nm);
2281
0
        if(CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),SdrSearchOptions::NONE,nullptr))
2282
0
        {
2283
0
            pTopMarkHit=pM;
2284
0
            nTopMarkHit=nm;
2285
0
        }
2286
0
    }
2287
    // nothing found, in this case, just select an object
2288
0
    if (pTopMarkHit==nullptr) return MarkObj(rPnt,sal_uInt16(nTol));
2289
2290
0
    SdrObject* pTopObjHit=pTopMarkHit->GetMarkedSdrObj();
2291
0
    SdrObjList* pObjList=pTopObjHit->getParentSdrObjListFromSdrObject();
2292
0
    SdrPageView* pPV=pTopMarkHit->GetPageView();
2293
    // find lowermost of the selected objects that is hit by rPnt
2294
    // and is placed on the same PageView as pTopMarkHit
2295
0
    for (size_t nm=0; nm<nMarkCount && pBtmMarkHit==nullptr; ++nm) {
2296
0
        SdrMark* pM=rMarkList.GetMark(nm);
2297
0
        SdrPageView* pPV2=pM->GetPageView();
2298
0
        if (pPV2==pPV && CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pPV2,SdrSearchOptions::NONE,nullptr))
2299
0
        {
2300
0
            pBtmMarkHit=pM;
2301
0
            nBtmMarkHit=nm;
2302
0
        }
2303
0
    }
2304
0
    if (pBtmMarkHit==nullptr) { pBtmMarkHit=pTopMarkHit; nBtmMarkHit=nTopMarkHit; }
2305
0
    SdrObject* pBtmObjHit=pBtmMarkHit->GetMarkedSdrObj();
2306
0
    const size_t nObjCount = pObjList->GetObjCount();
2307
2308
0
    size_t nSearchBeg(0);
2309
0
    E3dScene* pScene(nullptr);
2310
0
    SdrObject* pObjHit(bPrev ? pBtmObjHit : pTopObjHit);
2311
0
    bool bRemap =
2312
0
        nullptr != dynamic_cast< const E3dCompoundObject* >(pObjHit);
2313
0
    if (bRemap)
2314
0
    {
2315
0
        pScene = DynCastE3dScene(pObjHit->getParentSdrObjectFromSdrObject());
2316
0
        bRemap = nullptr != pScene;
2317
0
    }
2318
2319
0
    if(bPrev)
2320
0
    {
2321
0
        sal_uInt32 nOrdNumBtm(pBtmObjHit->GetOrdNum());
2322
2323
0
        if(bRemap)
2324
0
        {
2325
0
            nOrdNumBtm = pScene->RemapOrdNum(nOrdNumBtm);
2326
0
        }
2327
2328
0
        nSearchBeg = nOrdNumBtm + 1;
2329
0
    }
2330
0
    else
2331
0
    {
2332
0
        sal_uInt32 nOrdNumTop(pTopObjHit->GetOrdNum());
2333
2334
0
        if(bRemap)
2335
0
        {
2336
0
            nOrdNumTop = pScene->RemapOrdNum(nOrdNumTop);
2337
0
        }
2338
2339
0
        nSearchBeg = nOrdNumTop;
2340
0
    }
2341
2342
0
    size_t no=nSearchBeg;
2343
0
    SdrObject* pFndObj=nullptr;
2344
0
    while (pFndObj==nullptr && ((!bPrev && no>0) || (bPrev && no<nObjCount))) {
2345
0
        if (!bPrev) no--;
2346
0
        SdrObject* pObj;
2347
2348
0
        if(bRemap)
2349
0
        {
2350
0
            pObj = pObjList->GetObj(pScene->RemapOrdNum(no));
2351
0
        }
2352
0
        else
2353
0
        {
2354
0
            pObj = pObjList->GetObj(no);
2355
0
        }
2356
2357
0
        if (CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr))
2358
0
        {
2359
0
            if (rMarkList.FindObject(pObj)==SAL_MAX_SIZE) {
2360
0
                pFndObj=pObj;
2361
0
            } else {
2362
                // TODO: for performance reasons set on to Top or Btm, if necessary
2363
0
            }
2364
0
        }
2365
0
        if (bPrev) no++;
2366
0
    }
2367
0
    if (pFndObj!=nullptr)
2368
0
    {
2369
0
        GetMarkedObjectListWriteAccess().DeleteMark(bPrev?nBtmMarkHit:nTopMarkHit);
2370
0
        GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pFndObj,pPV));
2371
0
        MarkListHasChanged();
2372
0
        AdjustMarkHdl();
2373
0
    }
2374
0
    return pFndObj!=nullptr;
2375
0
}
2376
2377
void SdrMarkView::MarkObj(const tools::Rectangle& rRect, bool bUnmark)
2378
0
{
2379
0
    bool bFnd=false;
2380
0
    tools::Rectangle aR(rRect);
2381
0
    SdrObjList* pObjList;
2382
0
    BrkAction();
2383
0
    SdrPageView* pPV = GetSdrPageView();
2384
2385
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2386
0
    if(pPV)
2387
0
    {
2388
0
        pObjList=pPV->GetObjList();
2389
0
        tools::Rectangle aFrm1(aR);
2390
0
        for (const rtl::Reference<SdrObject>& pObj : *pObjList) {
2391
0
            tools::Rectangle aRect(pObj->GetCurrentBoundRect());
2392
0
            if (aFrm1.Contains(aRect)) {
2393
0
                if (!bUnmark) {
2394
0
                    if (IsObjMarkable(pObj.get(),pPV))
2395
0
                    {
2396
0
                        GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj.get(),pPV));
2397
0
                        bFnd=true;
2398
0
                    }
2399
0
                } else {
2400
0
                    const size_t nPos=rMarkList.FindObject(pObj.get());
2401
0
                    if (nPos!=SAL_MAX_SIZE)
2402
0
                    {
2403
0
                        GetMarkedObjectListWriteAccess().DeleteMark(nPos);
2404
0
                        bFnd=true;
2405
0
                    }
2406
0
                }
2407
0
            }
2408
0
        }
2409
0
    }
2410
0
    if (bFnd) {
2411
0
        rMarkList.ForceSort();
2412
0
        MarkListHasChanged();
2413
0
        AdjustMarkHdl();
2414
0
    }
2415
0
}
2416
2417
namespace {
2418
2419
void collectUIInformation(const SdrObject* pObj)
2420
0
{
2421
0
    EventDescription aDescription;
2422
0
    aDescription.aAction = "SELECT";
2423
0
    aDescription.aParent = "MainWindow";
2424
0
    aDescription.aKeyWord = "CurrentApp";
2425
2426
0
    if (!pObj->GetName().isEmpty())
2427
0
        aDescription.aParameters = {{"OBJECT", pObj->GetName()}};
2428
0
    else
2429
0
        aDescription.aParameters = {{"OBJECT", "Unnamed_Obj_" + OUString::number(pObj->GetOrdNum())}};
2430
2431
0
    UITestLogger::getInstance().logEvent(aDescription);
2432
0
}
2433
2434
}
2435
2436
 void SdrMarkView::MarkObj(SdrObject* pObj, SdrPageView* pPV, bool bUnmark, bool bDoNoSetMarkHdl,
2437
                          std::vector<basegfx::B2DRectangle> && rSubSelections)
2438
32
{
2439
32
    if (!(pObj!=nullptr && pPV!=nullptr && IsObjMarkable(pObj, pPV)))
2440
0
        return;
2441
2442
32
    BrkAction();
2443
32
    if (!bUnmark)
2444
0
    {
2445
0
        GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
2446
0
        collectUIInformation(pObj);
2447
0
    }
2448
32
    else
2449
32
    {
2450
32
        const SdrMarkList& rMarkList = GetMarkedObjectList();
2451
32
        const size_t nPos=rMarkList.FindObject(pObj);
2452
32
        if (nPos!=SAL_MAX_SIZE)
2453
0
        {
2454
0
            GetMarkedObjectListWriteAccess().DeleteMark(nPos);
2455
0
        }
2456
32
    }
2457
2458
32
    maSubSelectionList = std::move(rSubSelections);
2459
2460
32
    if (!bDoNoSetMarkHdl) {
2461
32
        MarkListHasChanged();
2462
32
        AdjustMarkHdl();
2463
32
    }
2464
32
}
2465
2466
bool SdrMarkView::IsObjMarked(SdrObject const * pObj) const
2467
0
{
2468
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2469
0
    return rMarkList.FindObject(pObj)!=SAL_MAX_SIZE;
2470
0
}
2471
2472
sal_uInt16 SdrMarkView::GetMarkHdlSizePixel() const
2473
55.9k
{
2474
55.9k
    return maHdlList.GetHdlSize()*2+1;
2475
55.9k
}
2476
2477
void SdrMarkView::SetMarkHdlSizePixel(sal_uInt16 nSiz)
2478
64.1k
{
2479
64.1k
    if (nSiz<3) nSiz=3;
2480
64.1k
    nSiz/=2;
2481
64.1k
    if (nSiz!=maHdlList.GetHdlSize()) {
2482
55.9k
        maHdlList.SetHdlSize(nSiz);
2483
55.9k
    }
2484
64.1k
}
2485
2486
bool SdrMarkView::getPossibleGridOffsetForSdrObject(
2487
    basegfx::B2DVector& rOffset,
2488
    const SdrObject* pObj,
2489
    const SdrPageView* pPV) const
2490
0
{
2491
0
    if(nullptr == pObj || nullptr == pPV)
2492
0
    {
2493
0
        return false;
2494
0
    }
2495
2496
0
    const OutputDevice* pOutputDevice(GetFirstOutputDevice());
2497
2498
0
    if(nullptr == pOutputDevice)
2499
0
    {
2500
0
        return false;
2501
0
    }
2502
2503
0
    const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));
2504
2505
0
    if(nullptr == pSdrPageWindow)
2506
0
    {
2507
0
        return false;
2508
0
    }
2509
2510
0
    const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());
2511
2512
0
    if(!rObjectContact.supportsGridOffsets())
2513
0
    {
2514
0
        return false;
2515
0
    }
2516
2517
0
    const sdr::contact::ViewObjectContact& rVOC(pObj->GetViewContact().GetViewObjectContact(
2518
0
        const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
2519
2520
0
    rOffset = rVOC.getGridOffset();
2521
2522
0
    return !rOffset.equalZero();
2523
0
}
2524
2525
bool SdrMarkView::getPossibleGridOffsetForPosition(
2526
    basegfx::B2DVector& rOffset,
2527
    const basegfx::B2DPoint& rPoint,
2528
    const SdrPageView* pPV) const
2529
0
{
2530
0
    if(nullptr == pPV)
2531
0
    {
2532
0
        return false;
2533
0
    }
2534
2535
0
    const OutputDevice* pOutputDevice(GetFirstOutputDevice());
2536
2537
0
    if(nullptr == pOutputDevice)
2538
0
    {
2539
0
        return false;
2540
0
    }
2541
2542
0
    const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));
2543
2544
0
    if(nullptr == pSdrPageWindow)
2545
0
    {
2546
0
        return false;
2547
0
    }
2548
2549
0
    const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());
2550
2551
0
    if(!rObjectContact.supportsGridOffsets())
2552
0
    {
2553
0
        return false;
2554
0
    }
2555
2556
0
    rObjectContact.calculateGridOffsetForB2DRange(rOffset, basegfx::B2DRange(rPoint));
2557
2558
0
    return !rOffset.equalZero();
2559
0
}
2560
2561
SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
2562
0
{
2563
0
    assert(pObj);
2564
0
    if(((nOptions & SdrSearchOptions::IMPISMASTER) && pObj->IsNotVisibleAsMaster()) || (!pObj->IsVisible()))
2565
0
    {
2566
0
        return nullptr;
2567
0
    }
2568
2569
0
    const bool bCheckIfMarkable(nOptions & SdrSearchOptions::TESTMARKABLE);
2570
0
    const bool bDeep(nOptions & SdrSearchOptions::DEEP);
2571
0
    const bool bOLE(DynCastSdrOle2Obj(pObj) !=  nullptr);
2572
0
    auto pTextObj = DynCastSdrTextObj( pObj);
2573
0
    const bool bTXT(pTextObj && pTextObj->IsTextFrame());
2574
0
    SdrObject* pRet=nullptr;
2575
0
    tools::Rectangle aRect(pObj->GetCurrentBoundRect());
2576
2577
    // add possible GridOffset to up-to-now view-independent BoundRect data
2578
0
    basegfx::B2DVector aGridOffset(0.0, 0.0);
2579
0
    if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, pPV))
2580
0
    {
2581
0
        aRect += Point(
2582
0
            basegfx::fround<tools::Long>(aGridOffset.getX()),
2583
0
            basegfx::fround<tools::Long>(aGridOffset.getY()));
2584
0
    }
2585
2586
0
    double nTol2(nTol);
2587
2588
    // double tolerance for OLE, text frames and objects in
2589
    // active text edit
2590
0
    if(bOLE || bTXT || pObj==static_cast<const SdrObjEditView*>(this)->GetTextEditObject())
2591
0
    {
2592
0
        nTol2*=2;
2593
0
    }
2594
2595
0
    aRect.expand(nTol2); // add 1 tolerance for all objects
2596
2597
0
    if (aRect.Contains(rPnt))
2598
0
    {
2599
0
        if (!bCheckIfMarkable || IsObjMarkable(pObj,pPV))
2600
0
        {
2601
0
            SdrObjList* pOL=pObj->GetSubList();
2602
2603
0
            if (pOL!=nullptr && pOL->GetObjCount()!=0)
2604
0
            {
2605
0
                SdrObject* pTmpObj;
2606
                // adjustment hit point for virtual objects
2607
0
                Point aPnt( rPnt );
2608
2609
0
                if ( auto pVirtObj = dynamic_cast<const SdrVirtObj*>( pObj) )
2610
0
                {
2611
0
                    Point aOffset = pVirtObj->GetOffset();
2612
0
                    aPnt.Move( -aOffset.X(), -aOffset.Y() );
2613
0
                }
2614
2615
0
                pRet=CheckSingleSdrObjectHit(aPnt,nTol,pOL,pPV,nOptions,pMVisLay,pTmpObj);
2616
0
            }
2617
0
            else
2618
0
            {
2619
0
                if(!pMVisLay || pMVisLay->IsSet(pObj->GetLayer()))
2620
0
                {
2621
0
                    pRet = SdrObjectPrimitiveHit(*pObj, rPnt, {nTol2, nTol2}, *pPV, &pPV->GetVisibleLayers(), false);
2622
0
                }
2623
0
            }
2624
0
        }
2625
0
    }
2626
2627
0
    if (!bDeep && pRet!=nullptr)
2628
0
    {
2629
0
        pRet=pObj;
2630
0
    }
2631
2632
0
    return pRet;
2633
0
}
2634
2635
SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj) const
2636
0
{
2637
0
    return (*this).CheckSingleSdrObjectHit(rPnt,nTol,pOL,pPV,nOptions,pMVisLay,rpRootObj,nullptr);
2638
0
}
2639
SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj,const SdrMarkList * pMarkList) const
2640
0
{
2641
0
    SdrObject* pRet=nullptr;
2642
0
    rpRootObj=nullptr;
2643
0
    if (!pOL)
2644
0
        return nullptr;
2645
0
    const E3dScene* pRemapScene = DynCastE3dScene(pOL->getSdrObjectFromSdrObjList());
2646
0
    const size_t nObjCount(pOL->GetObjCount());
2647
0
    size_t nObjNum(nObjCount);
2648
2649
0
    while (pRet==nullptr && nObjNum>0)
2650
0
    {
2651
0
        nObjNum--;
2652
0
        SdrObject* pObj;
2653
2654
0
        if(pRemapScene)
2655
0
        {
2656
0
            pObj = pOL->GetObj(pRemapScene->RemapOrdNum(nObjNum));
2657
0
        }
2658
0
        else
2659
0
        {
2660
0
            pObj = pOL->GetObj(nObjNum);
2661
0
        }
2662
0
        if (nOptions & SdrSearchOptions::BEFOREMARK)
2663
0
        {
2664
0
            if (pMarkList!=nullptr)
2665
0
            {
2666
0
                if ((*pMarkList).FindObject(pObj)!=SAL_MAX_SIZE)
2667
0
                {
2668
0
                    return nullptr;
2669
0
                }
2670
0
            }
2671
0
        }
2672
0
        pRet=CheckSingleSdrObjectHit(rPnt,nTol,pObj,pPV,nOptions,pMVisLay);
2673
0
        if (pRet!=nullptr) rpRootObj=pObj;
2674
0
    }
2675
0
    return pRet;
2676
0
}
2677
2678
SdrObject* SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions) const
2679
0
{
2680
0
    return PickObj(rPnt, nTol, rpPV, nOptions, nullptr);
2681
0
}
2682
2683
SdrObject* SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions, SdrObject** ppRootObj, bool* pbHitPassDirect) const
2684
0
{ // TODO: lacks a Pass2,Pass3
2685
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2686
0
    rMarkList.ForceSort();
2687
0
    if (ppRootObj!=nullptr) *ppRootObj=nullptr;
2688
0
    if (pbHitPassDirect!=nullptr) *pbHitPassDirect=true;
2689
0
    SdrObject* pRet = nullptr;
2690
0
    rpPV=nullptr;
2691
0
    bool bMarked(nOptions & SdrSearchOptions::MARKED);
2692
0
    bool bMasters=!bMarked && bool(nOptions & SdrSearchOptions::ALSOONMASTER);
2693
    // nOptions & SdrSearchOptions::NEXT: n.i.
2694
    // nOptions & SdrSearchOptions::PASS2BOUND: n.i.
2695
    // nOptions & SdrSearchOptions::PASS3NEAREST// n.i.
2696
0
    if (nTol<0) nTol=ImpGetHitTolLogic(nTol,nullptr);
2697
0
    SdrObject* pObj=nullptr;
2698
0
    SdrObject* pHitObj=nullptr;
2699
0
    SdrPageView* pPV=nullptr;
2700
0
    if (static_cast<const SdrObjEditView*>(this)->IsTextEditFrameHit(rPnt)) {
2701
0
        pObj=static_cast<const SdrObjEditView*>(this)->GetTextEditObject();
2702
0
        pHitObj=pObj;
2703
0
        pPV=static_cast<const SdrObjEditView*>(this)->GetTextEditPageView();
2704
0
    }
2705
0
    if (bMarked) {
2706
0
        const size_t nMrkCnt=rMarkList.GetMarkCount();
2707
0
        size_t nMrkNum=nMrkCnt;
2708
0
        while (pHitObj==nullptr && nMrkNum>0) {
2709
0
            nMrkNum--;
2710
0
            SdrMark* pM=rMarkList.GetMark(nMrkNum);
2711
0
            pObj=pM->GetMarkedSdrObj();
2712
0
            pPV=pM->GetPageView();
2713
0
            pHitObj=CheckSingleSdrObjectHit(rPnt,nTol,pObj,pPV,nOptions,nullptr);
2714
0
        }
2715
0
    }
2716
0
    else
2717
0
    {
2718
0
        pPV = GetSdrPageView();
2719
2720
0
        if(pPV)
2721
0
        {
2722
0
            SdrPage* pPage=pPV->GetPage();
2723
0
            sal_uInt16 nPgCount=1;
2724
2725
0
            if(bMasters && pPage->TRG_HasMasterPage())
2726
0
            {
2727
0
                nPgCount++;
2728
0
            }
2729
0
            bool bWholePage(nOptions & SdrSearchOptions::WHOLEPAGE);
2730
0
            bool bExtraPassForWholePage=bWholePage && pPage!=pPV->GetObjList();
2731
0
            if (bExtraPassForWholePage) nPgCount++; // First search in AktObjList, then on the entire page
2732
0
            sal_uInt16 nPgNum=nPgCount;
2733
0
            while (pHitObj==nullptr && nPgNum>0) {
2734
0
                SdrSearchOptions nTmpOptions=nOptions;
2735
0
                nPgNum--;
2736
0
                const SdrLayerIDSet* pMVisLay=nullptr;
2737
0
                SdrObjList* pObjList=nullptr;
2738
0
                if (pbHitPassDirect!=nullptr) *pbHitPassDirect = true;
2739
0
                if (nPgNum>=nPgCount-1 || (bExtraPassForWholePage && nPgNum>=nPgCount-2))
2740
0
                {
2741
0
                    pObjList=pPV->GetObjList();
2742
0
                    if (bExtraPassForWholePage && nPgNum==nPgCount-2) {
2743
0
                        pObjList=pPage;
2744
0
                        if (pbHitPassDirect!=nullptr) *pbHitPassDirect = false;
2745
0
                    }
2746
0
                }
2747
0
                else
2748
0
                {
2749
                    // otherwise MasterPage
2750
0
                    SdrPage& rMasterPage = pPage->TRG_GetMasterPage();
2751
0
                    pMVisLay = &pPage->TRG_GetMasterPageVisibleLayers();
2752
0
                    pObjList = &rMasterPage;
2753
2754
0
                    if (pbHitPassDirect!=nullptr) *pbHitPassDirect = false;
2755
0
                    nTmpOptions=nTmpOptions | SdrSearchOptions::IMPISMASTER;
2756
0
                }
2757
0
                pHitObj=CheckSingleSdrObjectHit(rPnt,nTol,pObjList,pPV,nTmpOptions,pMVisLay,pObj,&rMarkList);
2758
0
            }
2759
0
        }
2760
0
    }
2761
0
    if (pHitObj!=nullptr) {
2762
0
        if (ppRootObj!=nullptr) *ppRootObj=pObj;
2763
0
        if (nOptions & SdrSearchOptions::DEEP) pObj=pHitObj;
2764
0
        if (nOptions & SdrSearchOptions::TESTTEXTEDIT) {
2765
0
            assert(pPV);
2766
0
            if (!pObj->HasTextEdit() || pPV->GetLockedLayers().IsSet(pObj->GetLayer())) {
2767
0
                pObj=nullptr;
2768
0
            }
2769
0
        }
2770
0
        if (pObj!=nullptr && (nOptions & SdrSearchOptions::TESTMACRO)) {
2771
0
            assert(pPV);
2772
0
            SdrObjMacroHitRec aHitRec;
2773
0
            aHitRec.aPos=rPnt;
2774
0
            aHitRec.nTol=nTol;
2775
0
            aHitRec.pVisiLayer=&pPV->GetVisibleLayers();
2776
0
            aHitRec.pPageView=pPV;
2777
0
            if (!pObj->HasMacro() || !pObj->IsMacroHit(aHitRec)) pObj=nullptr;
2778
0
        }
2779
0
        if (pObj!=nullptr) {
2780
0
            pRet=pObj;
2781
0
            rpPV=pPV;
2782
0
        }
2783
0
    }
2784
0
    return pRet;
2785
0
}
2786
2787
bool SdrMarkView::PickMarkedObj(const Point& rPnt, SdrObject*& rpObj, SdrPageView*& rpPV, SdrSearchOptions nOptions) const
2788
0
{
2789
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2790
0
    rMarkList.ForceSort();
2791
0
    const bool bBoundCheckOn2ndPass(nOptions & SdrSearchOptions::PASS2BOUND);
2792
0
    rpObj=nullptr;
2793
0
    rpPV=nullptr;
2794
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
2795
0
    for (size_t nMarkNum=nMarkCount; nMarkNum>0;) {
2796
0
        --nMarkNum;
2797
0
        SdrMark* pM=rMarkList.GetMark(nMarkNum);
2798
0
        SdrPageView* pPV=pM->GetPageView();
2799
0
        SdrObject* pObj=pM->GetMarkedSdrObj();
2800
0
        if (CheckSingleSdrObjectHit(rPnt,mnHitTolLog,pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr)) {
2801
0
            rpObj=pObj;
2802
0
            rpPV=pPV;
2803
0
            return true;
2804
0
        }
2805
0
    }
2806
0
    if (bBoundCheckOn2ndPass) {
2807
0
        for (size_t nMarkNum=nMarkCount; nMarkNum>0;) {
2808
0
            --nMarkNum;
2809
0
            SdrMark* pM=rMarkList.GetMark(nMarkNum);
2810
0
            SdrPageView* pPV=pM->GetPageView();
2811
0
            SdrObject* pObj=pM->GetMarkedSdrObj();
2812
0
            tools::Rectangle aRect(pObj->GetCurrentBoundRect());
2813
0
            aRect.AdjustLeft( -mnHitTolLog );
2814
0
            aRect.AdjustTop( -mnHitTolLog );
2815
0
            aRect.AdjustRight(mnHitTolLog );
2816
0
            aRect.AdjustBottom(mnHitTolLog );
2817
0
            if (aRect.Contains(rPnt)) {
2818
0
                rpObj=pObj;
2819
0
                rpPV=pPV;
2820
0
                return true;
2821
0
            }
2822
0
        }
2823
0
    }
2824
0
    return false;
2825
0
}
2826
2827
2828
void SdrMarkView::UnmarkAllObj(SdrPageView const * pPV)
2829
2.51k
{
2830
2.51k
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2831
2.51k
    if (rMarkList.GetMarkCount()==0)
2832
2.51k
        return;
2833
2834
0
    BrkAction();
2835
0
    if (pPV!=nullptr)
2836
0
    {
2837
0
        GetMarkedObjectListWriteAccess().DeletePageView(*pPV);
2838
0
    }
2839
0
    else
2840
0
    {
2841
0
        GetMarkedObjectListWriteAccess().Clear();
2842
0
    }
2843
0
    mpMarkedObj=nullptr;
2844
0
    mpMarkedPV=nullptr;
2845
0
    MarkListHasChanged();
2846
0
    AdjustMarkHdl();
2847
0
}
2848
2849
void SdrMarkView::MarkAllObj(SdrPageView* pPV)
2850
0
{
2851
0
    BrkAction();
2852
2853
0
    if(!pPV)
2854
0
    {
2855
0
        pPV = GetSdrPageView();
2856
0
    }
2857
2858
    // #i69171# pPV may still be NULL if there is no SDrPageView (!), e.g. when inserting
2859
    // other files
2860
0
    if(pPV)
2861
0
    {
2862
0
        const bool bMarkChg(GetMarkedObjectListWriteAccess().InsertPageView(*pPV));
2863
2864
0
        if(bMarkChg)
2865
0
        {
2866
0
            MarkListHasChanged();
2867
0
        }
2868
0
    }
2869
2870
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2871
0
    if(rMarkList.GetMarkCount())
2872
0
    {
2873
0
        AdjustMarkHdl();
2874
0
    }
2875
0
}
2876
2877
void SdrMarkView::AdjustMarkHdl(SfxViewShell* pOtherShell)
2878
236k
{
2879
236k
    CheckMarked();
2880
236k
    SetMarkRects();
2881
236k
    SetMarkHandles(pOtherShell);
2882
236k
}
2883
2884
// BoundRect in model coordinates, no GridOffset added
2885
tools::Rectangle SdrMarkView::GetMarkedObjBoundRect() const
2886
0
{
2887
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2888
0
    tools::Rectangle aRect;
2889
0
    for (size_t nm=0; nm<rMarkList.GetMarkCount(); ++nm) {
2890
0
        SdrMark* pM=rMarkList.GetMark(nm);
2891
0
        SdrObject* pO=pM->GetMarkedSdrObj();
2892
0
        if (!pO)
2893
0
            continue;
2894
2895
0
        tools::Rectangle aR1(pO->GetCurrentBoundRect());
2896
0
        if (aRect.IsEmpty()) aRect=aR1;
2897
0
        else aRect.Union(aR1);
2898
0
    }
2899
0
    return aRect;
2900
0
}
2901
2902
// ObjRect in model coordinates, no GridOffset added
2903
const tools::Rectangle& SdrMarkView::GetMarkedObjRect() const
2904
236k
{
2905
236k
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2906
236k
    if (mbMarkedObjRectDirty) {
2907
236k
        const_cast<SdrMarkView*>(this)->mbMarkedObjRectDirty=false;
2908
236k
        tools::Rectangle aRect;
2909
236k
        for (size_t nm=0; nm<rMarkList.GetMarkCount(); ++nm) {
2910
0
            SdrMark* pM=rMarkList.GetMark(nm);
2911
0
            SdrObject* pO = pM->GetMarkedSdrObj();
2912
0
            if (!pO)
2913
0
                continue;
2914
2915
0
            tools::Rectangle aR1(pO->GetSnapRect());
2916
0
            if (aRect.IsEmpty()) aRect=aR1;
2917
0
            else aRect.Union(aR1);
2918
0
        }
2919
236k
        const_cast<SdrMarkView*>(this)->maMarkedObjRect=aRect;
2920
236k
    }
2921
236k
    return maMarkedObjRect;
2922
236k
}
2923
2924
2925
OUString SdrMarkView::ImpGetDescriptionString(TranslateId pStrCacheID, ImpGetDescriptionOptions nOpt) const
2926
0
{
2927
0
    OUString sStr = SvxResId(pStrCacheID);
2928
0
    const sal_Int32 nPos = sStr.indexOf("%1");
2929
2930
0
    if(nPos != -1)
2931
0
    {
2932
0
        const SdrMarkList& rMarkList = GetMarkedObjectList();
2933
0
        if(nOpt == ImpGetDescriptionOptions::POINTS)
2934
0
        {
2935
0
            sStr = sStr.replaceAt(nPos, 2, rMarkList.GetPointMarkDescription());
2936
0
        }
2937
0
        else if(nOpt == ImpGetDescriptionOptions::GLUEPOINTS)
2938
0
        {
2939
0
            sStr = sStr.replaceAt(nPos, 2, rMarkList.GetGluePointMarkDescription());
2940
0
        }
2941
0
        else
2942
0
        {
2943
0
            sStr = sStr.replaceAt(nPos, 2, rMarkList.GetMarkDescription());
2944
0
        }
2945
0
    }
2946
2947
0
    return sStr.replaceFirst("%2", "0");
2948
0
}
2949
2950
2951
void SdrMarkView::EnterMarkedGroup()
2952
0
{
2953
    // We enter only the first group found (in only one PageView), because
2954
    // PageView::EnterGroup calls an AdjustMarkHdl.
2955
    // TODO: I'll have to prevent that via a flag.
2956
0
    SdrPageView* pPV = GetSdrPageView();
2957
2958
0
    if(!pPV)
2959
0
        return;
2960
2961
0
    bool bEnter=false;
2962
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2963
0
    for (size_t nm = rMarkList.GetMarkCount(); nm > 0 && !bEnter;)
2964
0
    {
2965
0
        --nm;
2966
0
        SdrMark* pM=rMarkList.GetMark(nm);
2967
0
        if (pM->GetPageView()==pPV) {
2968
0
            SdrObject* pObj=pM->GetMarkedSdrObj();
2969
0
            if (pObj->IsGroupObject()) {
2970
0
                if (pPV->EnterGroup(pObj)) {
2971
0
                    bEnter=true;
2972
0
                }
2973
0
            }
2974
0
        }
2975
0
    }
2976
0
}
2977
2978
2979
void SdrMarkView::MarkListHasChanged()
2980
65.4k
{
2981
65.4k
    GetMarkedObjectListWriteAccess().SetNameDirty();
2982
65.4k
    maSdrViewSelection.SetEdgesOfMarkedNodesDirty();
2983
2984
65.4k
    mbMarkedObjRectDirty=true;
2985
65.4k
    mbMarkedPointsRectsDirty=true;
2986
65.4k
    bool bOneEdgeMarked=false;
2987
65.4k
    const SdrMarkList& rMarkList = GetMarkedObjectList();
2988
65.4k
    if (rMarkList.GetMarkCount()==1) {
2989
0
        const SdrObject* pObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
2990
0
        if (pObj->GetObjInventor()==SdrInventor::Default) {
2991
0
            bOneEdgeMarked = pObj->GetObjIdentifier() == SdrObjKind::Edge;
2992
0
        }
2993
0
    }
2994
65.4k
    ImpSetGlueVisible4(bOneEdgeMarked);
2995
65.4k
}
2996
2997
2998
void SdrMarkView::SetMoveOutside(bool bOn)
2999
0
{
3000
0
    maHdlList.SetMoveOutside(bOn);
3001
0
}
3002
3003
void SdrMarkView::SetDesignMode( bool bOn )
3004
320k
{
3005
320k
    if ( mbDesignMode != bOn )
3006
311k
    {
3007
311k
        mbDesignMode = bOn;
3008
311k
        SdrPageView* pPageView = GetSdrPageView();
3009
311k
        if ( pPageView )
3010
0
            pPageView->SetDesignMode( bOn );
3011
311k
    }
3012
320k
}
3013
3014
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */