Coverage Report

Created: 2025-12-08 09:28

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