Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdedtv1.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <basegfx/matrix/b2dhommatrix.hxx>
21
#include <basegfx/matrix/b2dhommatrixtools.hxx>
22
#include <editeng/eeitem.hxx>
23
#include <math.h>
24
#include <svl/itemiter.hxx>
25
#include <sal/log.hxx>
26
#include <svl/whiter.hxx>
27
#include <tools/bigint.hxx>
28
#include <tools/debug.hxx>
29
#include <vcl/svapp.hxx>
30
#include <vcl/weld/MessageDialog.hxx>
31
32
#include <getallcharpropids.hxx>
33
#include <svx/dialmgr.hxx>
34
#include <svx/svditer.hxx>
35
#include <svx/strings.hrc>
36
37
#include <AffineMatrixItem.hxx>
38
#include <svx/e3dsceneupdater.hxx>
39
#include <svx/rectenum.hxx>
40
#include <svx/sdr/contact/viewcontact.hxx>
41
#include <svx/sdooitm.hxx>
42
#include <svx/sderitm.hxx>
43
#include <svx/sdtagitm.hxx>
44
#include <svx/svdedtv.hxx>
45
#include <svx/svdetc.hxx>
46
#include <svx/svdopath.hxx>
47
#include <svx/svdpage.hxx>
48
#include <svx/svdpagv.hxx>
49
#include <svx/svdtrans.hxx>
50
#include <svx/svdundo.hxx>
51
#include <svx/svxids.hrc>
52
#include <sxallitm.hxx>
53
#include <sxmovitm.hxx>
54
#include <sxreaitm.hxx>
55
#include <sxreoitm.hxx>
56
#include <sxroaitm.hxx>
57
#include <sxrooitm.hxx>
58
#include <sxsalitm.hxx>
59
#include <sxsoitm.hxx>
60
#include <sxtraitm.hxx>
61
#include <svx/xlnedwit.hxx>
62
#include <svx/xlnstwit.hxx>
63
#include <svx/xlnwtit.hxx>
64
#include <svx/xlnclit.hxx>
65
#include <svx/xflclit.hxx>
66
#include <svx/xlntrit.hxx>
67
#include <svx/xfltrit.hxx>
68
#include <svx/sdprcitm.hxx>
69
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
70
#include <rtl/ustring.hxx>
71
#include <sfx2/viewsh.hxx>
72
#include <comphelper/lok.hxx>
73
#include <osl/diagnose.h>
74
#include <sfx2/objsh.hxx>
75
#include <svl/cryptosign.hxx>
76
77
// EditView
78
79
80
void SdrEditView::SetMarkedObjRect(const tools::Rectangle& rRect)
81
0
{
82
0
    DBG_ASSERT(!rRect.IsEmpty(),"SetMarkedObjRect() with an empty Rect does not make sense.");
83
0
    if (rRect.IsEmpty())
84
0
        return;
85
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
86
0
    const size_t nCount=rMarkList.GetMarkCount();
87
0
    if (nCount==0) return;
88
0
    tools::Rectangle aR0(GetMarkedObjRect());
89
0
    DBG_ASSERT(!aR0.IsEmpty(),"SetMarkedObjRect(): GetMarkedObjRect() is empty.");
90
0
    if (aR0.IsEmpty()) return;
91
0
    tools::Long x0=aR0.Left();
92
0
    tools::Long y0=aR0.Top();
93
0
    tools::Long w0=aR0.Right()-x0;
94
0
    tools::Long h0=aR0.Bottom()-y0;
95
0
    tools::Long x1=rRect.Left();
96
0
    tools::Long y1=rRect.Top();
97
0
    tools::Long w1=rRect.Right()-x1;
98
0
    tools::Long h1=rRect.Bottom()-y1;
99
100
0
    const bool bUndo = IsUndoEnabled();
101
0
    if( bUndo )
102
0
    {
103
0
        EndTextEditCurrentView();
104
0
        BegUndo(ImpGetDescriptionString(STR_EditPosSize));
105
0
    }
106
107
0
    for (size_t nm=0; nm<nCount; ++nm)
108
0
    {
109
0
        SdrMark* pM=rMarkList.GetMark(nm);
110
0
        SdrObject* pO=pM->GetMarkedSdrObj();
111
0
        if (bUndo)
112
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
113
114
0
        tools::Rectangle aR1(pO->GetSnapRect());
115
0
        if (!aR1.IsEmpty())
116
0
        {
117
0
            if (aR1==aR0)
118
0
            {
119
0
                aR1=rRect;
120
0
            }
121
0
            else
122
0
            { // transform aR1 to aR0 after rRect
123
0
                aR1.Move(-x0,-y0);
124
0
                BigInt l(aR1.Left());
125
0
                BigInt r(aR1.Right());
126
0
                BigInt t(aR1.Top());
127
0
                BigInt b(aR1.Bottom());
128
0
                if (w0!=0) {
129
0
                    l*=w1; l/=w0;
130
0
                    r*=w1; r/=w0;
131
0
                } else {
132
0
                    l=0; r=w1;
133
0
                }
134
0
                if (h0!=0) {
135
0
                    t*=h1; t/=h0;
136
0
                    b*=h1; b/=h0;
137
0
                } else {
138
0
                    t=0; b=h1;
139
0
                }
140
0
                aR1.SetLeft(tools::Long(l) );
141
0
                aR1.SetRight(tools::Long(r) );
142
0
                aR1.SetTop(tools::Long(t) );
143
0
                aR1.SetBottom(tools::Long(b) );
144
0
                aR1.Move(x1,y1);
145
0
            }
146
0
            pO->SetSnapRect(aR1);
147
0
        } else {
148
0
            OSL_FAIL("SetMarkedObjRect(): pObj->GetSnapRect() returns empty Rect");
149
0
        }
150
0
    }
151
0
    if( bUndo )
152
0
        EndUndo();
153
0
}
154
155
std::vector< std::unique_ptr<SdrUndoAction> > SdrEditView::CreateConnectorUndo( const SdrObject& rO )
156
0
{
157
0
    std::vector< std::unique_ptr<SdrUndoAction> > vUndoActions;
158
159
0
    if ( rO.GetBroadcaster() )
160
0
    {
161
0
        const SdrPage* pPage = rO.getSdrPageFromSdrObject();
162
0
        if ( pPage )
163
0
        {
164
0
            SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
165
0
            while( aIter.IsMore() )
166
0
            {
167
0
                SdrObject* pPartObj = aIter.Next();
168
0
                if ( dynamic_cast<const SdrEdgeObj*>( pPartObj) !=  nullptr )
169
0
                {
170
0
                    if ( ( pPartObj->GetConnectedNode( false ) == &rO ) ||
171
0
                         ( pPartObj->GetConnectedNode( true  ) == &rO ) )
172
0
                    {
173
0
                        vUndoActions.push_back(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pPartObj));
174
0
                    }
175
0
                }
176
0
            }
177
0
        }
178
0
    }
179
0
    return vUndoActions;
180
0
}
181
182
void SdrEditView::AddUndoActions( std::vector< std::unique_ptr<SdrUndoAction> > aUndoActions )
183
0
{
184
0
    for (auto & rAction : aUndoActions)
185
0
        AddUndo( std::move(rAction) );
186
0
}
187
188
void SdrEditView::MoveMarkedObj(const Size& rSiz, bool bCopy)
189
0
{
190
0
    const bool bUndo = IsUndoEnabled();
191
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
192
193
0
    if( bUndo )
194
0
    {
195
0
        EndTextEditCurrentView();
196
0
        OUString aStr(SvxResId(STR_EditMove));
197
0
        if (bCopy)
198
0
            aStr += SvxResId(STR_EditWithCopy);
199
        // needs its own UndoGroup because of its parameters
200
0
        BegUndo(aStr,rMarkList.GetMarkDescription(),SdrRepeatFunc::Move);
201
0
    }
202
203
0
    if (bCopy)
204
0
        CopyMarkedObj();
205
206
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
207
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
208
0
    {
209
0
        SdrMark* pM=rMarkList.GetMark(nm);
210
0
        SdrObject* pO=pM->GetMarkedSdrObj();
211
0
        if( bUndo )
212
0
        {
213
0
            AddUndoActions( CreateConnectorUndo( *pO ) );
214
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoMoveObject(*pO,rSiz));
215
0
        }
216
0
        pO->Move(rSiz);
217
0
    }
218
219
0
    if( bUndo )
220
0
        EndUndo();
221
0
}
222
223
bool SdrEditView::IsMarkedObjSizeValid(const Size& aTargetSize)
224
0
{
225
0
    if (SdrMark* pM=GetMarkedObjectList().GetMark(0))
226
0
    {
227
0
        if (SdrObject* pO=pM->GetMarkedSdrObj())
228
0
        {
229
0
            if (pO->IsSizeValid(aTargetSize))
230
0
                return true;
231
0
        }
232
0
        else
233
0
            SAL_WARN("svx", "no MarkedSdrObj found");
234
0
    }
235
0
    else
236
0
        SAL_WARN("svx", "no SdrMark found");
237
238
0
    return false;
239
0
}
240
241
void SdrEditView::ResizeMarkedObj(const Point& rRef, double xFact, double yFact, bool bCopy)
242
0
{
243
0
    const bool bUndo = IsUndoEnabled();
244
0
    if( bUndo )
245
0
    {
246
0
        EndTextEditCurrentView();
247
0
        OUString aStr {ImpGetDescriptionString(STR_EditResize)};
248
0
        if (bCopy)
249
0
            aStr+=SvxResId(STR_EditWithCopy);
250
0
        BegUndo(aStr);
251
0
    }
252
253
0
    if (bCopy)
254
0
        CopyMarkedObj();
255
256
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
257
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
258
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
259
0
    {
260
0
        SdrMark* pM=rMarkList.GetMark(nm);
261
0
        SdrObject* pO=pM->GetMarkedSdrObj();
262
0
        if( bUndo )
263
0
        {
264
0
            AddUndoActions( CreateConnectorUndo( *pO ) );
265
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
266
0
        }
267
0
        pO->Resize(rRef,xFact,yFact);
268
0
    }
269
270
0
    if( bUndo )
271
0
        EndUndo();
272
0
}
273
void SdrEditView::ResizeMultMarkedObj(const Point& rRef,
274
    double xFact,
275
    double yFact,
276
    const bool bWdh,
277
    const bool bHgt)
278
0
{
279
0
    const bool bUndo = IsUndoEnabled();
280
0
    if( bUndo )
281
0
    {
282
0
        EndTextEditCurrentView();
283
0
        BegUndo(ImpGetDescriptionString(STR_EditResize));
284
0
    }
285
286
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
287
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
288
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
289
0
    {
290
0
        SdrMark* pM=rMarkList.GetMark(nm);
291
0
        SdrObject* pO=pM->GetMarkedSdrObj();
292
0
        if( bUndo )
293
0
        {
294
0
            AddUndoActions( CreateConnectorUndo( *pO ) );
295
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
296
0
        }
297
298
0
        if (bWdh && xFact != 0.0 && bHgt && yFact != 0.0)
299
0
            pO->Resize(rRef, xFact, yFact);
300
0
        else if (bWdh && xFact != 0.0)
301
0
            pO->Resize(rRef, xFact, 1.0);
302
0
        else if (bHgt && yFact != 0.0)
303
0
            pO->Resize(rRef, 1.0, yFact);
304
0
    }
305
0
    if( bUndo )
306
0
        EndUndo();
307
0
}
308
309
Degree100 SdrEditView::GetMarkedObjRotate() const
310
0
{
311
0
    Degree100 nRetval(0);
312
313
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
314
0
    if(rMarkList.GetMarkCount())
315
0
    {
316
0
        SdrMark* pM = rMarkList.GetMark(0);
317
0
        SdrObject* pO = pM->GetMarkedSdrObj();
318
319
0
        nRetval = pO->GetRotateAngle();
320
0
    }
321
322
0
    return nRetval;
323
0
}
324
325
void SdrEditView::RotateMarkedObj(const Point& rRef, Degree100 nAngle, bool bCopy)
326
0
{
327
0
    const bool bUndo = IsUndoEnabled();
328
0
    if( bUndo )
329
0
    {
330
0
        EndTextEditCurrentView();
331
0
        OUString aStr {ImpGetDescriptionString(STR_EditRotate)};
332
0
        if (bCopy) aStr+=SvxResId(STR_EditWithCopy);
333
0
        BegUndo(aStr);
334
0
    }
335
336
0
    if (bCopy)
337
0
        CopyMarkedObj();
338
339
0
    double nSin = sin(toRadians(nAngle));
340
0
    double nCos = cos(toRadians(nAngle));
341
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
342
0
    const size_t nMarkCount(rMarkList.GetMarkCount());
343
344
0
    if(nMarkCount)
345
0
    {
346
0
        std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
347
348
0
        for(size_t nm = 0; nm < nMarkCount; ++nm)
349
0
        {
350
0
            SdrMark* pM = rMarkList.GetMark(nm);
351
0
            SdrObject* pO = pM->GetMarkedSdrObj();
352
353
0
            if( bUndo )
354
0
            {
355
                // extra undo actions for changed connector which now may hold its laid out path (SJ)
356
0
                AddUndoActions( CreateConnectorUndo( *pO ) );
357
358
0
                AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
359
0
            }
360
361
            // set up a scene updater if object is a 3d object
362
0
            if(DynCastE3dObject(pO))
363
0
            {
364
0
                aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pO));
365
0
            }
366
367
0
            pO->Rotate(rRef,nAngle,nSin,nCos);
368
0
        }
369
370
        // fire scene updaters
371
0
        while(!aUpdaters.empty())
372
0
        {
373
0
            delete aUpdaters.back();
374
0
            aUpdaters.pop_back();
375
0
        }
376
0
    }
377
378
0
    if( bUndo )
379
0
        EndUndo();
380
0
}
381
382
void SdrEditView::MirrorMarkedObj(const Point& rRef1, const Point& rRef2, bool bCopy)
383
0
{
384
0
    const bool bUndo = IsUndoEnabled();
385
386
0
    if( bUndo )
387
0
    {
388
0
        EndTextEditCurrentView();
389
0
        OUString aStr;
390
0
        Point aDif(rRef2-rRef1);
391
0
        if (aDif.X()==0)
392
0
            aStr = ImpGetDescriptionString(STR_EditMirrorHori);
393
0
        else if (aDif.Y()==0)
394
0
            aStr = ImpGetDescriptionString(STR_EditMirrorVert);
395
0
        else if (std::abs(aDif.X()) == std::abs(aDif.Y()))
396
0
            aStr = ImpGetDescriptionString(STR_EditMirrorDiag);
397
0
        else
398
0
            aStr = ImpGetDescriptionString(STR_EditMirrorFree);
399
0
        if (bCopy) aStr+=SvxResId(STR_EditWithCopy);
400
0
        BegUndo(aStr);
401
0
    }
402
403
0
    if (bCopy)
404
0
        CopyMarkedObj();
405
406
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
407
0
    const size_t nMarkCount(rMarkList.GetMarkCount());
408
409
0
    if(nMarkCount)
410
0
    {
411
0
        std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
412
413
0
        for(size_t nm = 0; nm < nMarkCount; ++nm)
414
0
        {
415
0
            SdrMark* pM = rMarkList.GetMark(nm);
416
0
            SdrObject* pO = pM->GetMarkedSdrObj();
417
418
0
            if( bUndo )
419
0
            {
420
                // extra undo actions for changed connector which now may hold its laid out path (SJ)
421
0
                AddUndoActions( CreateConnectorUndo( *pO ) );
422
423
0
                AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
424
0
            }
425
426
            // set up a scene updater if object is a 3d object
427
0
            if(DynCastE3dObject(pO))
428
0
            {
429
0
                aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pO));
430
0
            }
431
432
0
            pO->Mirror(rRef1,rRef2);
433
0
        }
434
435
        // fire scene updaters
436
0
        while(!aUpdaters.empty())
437
0
        {
438
0
            delete aUpdaters.back();
439
0
            aUpdaters.pop_back();
440
0
        }
441
0
    }
442
443
0
    if( bUndo )
444
0
        EndUndo();
445
0
}
446
447
void SdrEditView::MirrorMarkedObjHorizontal()
448
0
{
449
0
    Point aCenter(GetMarkedObjRect().Center());
450
0
    Point aPt2(aCenter);
451
0
    aPt2.AdjustY( 1 );
452
0
    MirrorMarkedObj(aCenter,aPt2);
453
0
}
454
455
void SdrEditView::MirrorMarkedObjVertical()
456
0
{
457
0
    Point aCenter(GetMarkedObjRect().Center());
458
0
    Point aPt2(aCenter);
459
0
    aPt2.AdjustX( 1 );
460
0
    MirrorMarkedObj(aCenter,aPt2);
461
0
}
462
463
Degree100 SdrEditView::GetMarkedObjShear() const
464
0
{
465
0
    bool b1st=true;
466
0
    bool bOk=true;
467
0
    Degree100 nAngle(0);
468
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
469
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
470
0
    for (size_t nm=0; nm<nMarkCount && bOk; ++nm) {
471
0
        SdrMark* pM=rMarkList.GetMark(nm);
472
0
        SdrObject* pO=pM->GetMarkedSdrObj();
473
0
        Degree100 nAngle2=pO->GetShearAngle();
474
0
        if (b1st) nAngle=nAngle2;
475
0
        else if (nAngle2!=nAngle) bOk=false;
476
0
        b1st=false;
477
0
    }
478
0
    if (nAngle>SDRMAXSHEAR) nAngle=SDRMAXSHEAR;
479
0
    if (nAngle<-SDRMAXSHEAR) nAngle=-SDRMAXSHEAR;
480
0
    if (!bOk) nAngle=0_deg100;
481
0
    return nAngle;
482
0
}
483
484
void SdrEditView::ShearMarkedObj(const Point& rRef, Degree100 nAngle, bool bVShear, bool bCopy)
485
0
{
486
0
    const bool bUndo = IsUndoEnabled();
487
488
0
    if( bUndo )
489
0
    {
490
0
        EndTextEditCurrentView();
491
0
        OUString aStr {ImpGetDescriptionString(STR_EditShear)};
492
0
        if (bCopy)
493
0
            aStr+=SvxResId(STR_EditWithCopy);
494
0
        BegUndo(aStr);
495
0
    }
496
497
0
    if (bCopy)
498
0
        CopyMarkedObj();
499
500
0
    double nTan = tan(toRadians(nAngle));
501
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
502
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
503
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
504
0
    {
505
0
        SdrMark* pM=rMarkList.GetMark(nm);
506
0
        SdrObject* pO=pM->GetMarkedSdrObj();
507
0
        if( bUndo )
508
0
        {
509
0
            AddUndoActions( CreateConnectorUndo( *pO ) );
510
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
511
0
        }
512
0
        pO->Shear(rRef,nAngle,nTan,bVShear);
513
0
    }
514
515
0
    if( bUndo )
516
0
        EndUndo();
517
0
}
518
519
void SdrEditView::ImpCrookObj(SdrObject* pO, const Point& rRef, const Point& rRad,
520
    SdrCrookMode eMode, bool bVertical, bool bNoContortion, bool bRotate, const tools::Rectangle& rMarkRect)
521
0
{
522
0
    SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pO );
523
0
    bool bDone = false;
524
525
0
    if(pPath!=nullptr && !bNoContortion)
526
0
    {
527
0
        XPolyPolygon aXPP(pPath->GetPathPoly());
528
0
        switch (eMode) {
529
0
            case SdrCrookMode::Rotate : CrookRotatePoly (aXPP,rRef,rRad,bVertical);           break;
530
0
            case SdrCrookMode::Slant  : CrookSlantPoly  (aXPP,rRef,rRad,bVertical);           break;
531
0
            case SdrCrookMode::Stretch: CrookStretchPoly(aXPP,rRef,rRad,bVertical,rMarkRect); break;
532
0
        } // switch
533
0
        pPath->SetPathPoly(aXPP.getB2DPolyPolygon());
534
0
        bDone = true;
535
0
    }
536
537
0
    if(!bDone && !pPath && pO->IsPolyObj() && 0 != pO->GetPointCount())
538
0
    {
539
        // for PolyObj's, but NOT for SdrPathObj's, e.g. the measurement object
540
0
        sal_uInt32 nPointCount(pO->GetPointCount());
541
0
        XPolygon aXP(static_cast<sal_uInt16>(nPointCount));
542
0
        sal_uInt32 nPtNum;
543
544
0
        for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
545
0
        {
546
0
            Point aPt(pO->GetPoint(nPtNum));
547
0
            aXP[static_cast<sal_uInt16>(nPtNum)]=aPt;
548
0
        }
549
550
0
        switch (eMode)
551
0
        {
552
0
            case SdrCrookMode::Rotate : CrookRotatePoly (aXP,rRef,rRad,bVertical);           break;
553
0
            case SdrCrookMode::Slant  : CrookSlantPoly  (aXP,rRef,rRad,bVertical);           break;
554
0
            case SdrCrookMode::Stretch: CrookStretchPoly(aXP,rRef,rRad,bVertical,rMarkRect); break;
555
0
        }
556
557
0
        for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
558
0
        {
559
            // broadcasting could be optimized here, but for the
560
            // current two points of the measurement object, it's fine
561
0
            pO->SetPoint(aXP[static_cast<sal_uInt16>(nPtNum)],nPtNum);
562
0
        }
563
564
0
        bDone = true;
565
0
    }
566
567
0
    if(bDone)
568
0
        return;
569
570
    // for all others or if bNoContortion
571
0
    Point aCtr0(pO->GetSnapRect().Center());
572
0
    Point aCtr1(aCtr0);
573
0
    bool bRotOk(false);
574
0
    double nSin(0.0), nCos(1.0);
575
0
    double nAngle(0.0);
576
577
0
    if(0 != rRad.X() && 0 != rRad.Y())
578
0
    {
579
0
        bRotOk = bRotate;
580
581
0
        switch (eMode)
582
0
        {
583
0
            case SdrCrookMode::Rotate : nAngle=CrookRotateXPoint (aCtr1,nullptr,nullptr,rRef,rRad,nSin,nCos,bVertical); bRotOk=bRotate; break;
584
0
            case SdrCrookMode::Slant  : nAngle=CrookSlantXPoint  (aCtr1,nullptr,nullptr,rRef,rRad,nSin,nCos,bVertical);           break;
585
0
            case SdrCrookMode::Stretch: nAngle=CrookStretchXPoint(aCtr1,nullptr,nullptr,rRef,rRad,nSin,nCos,bVertical,rMarkRect); break;
586
0
        }
587
0
    }
588
589
0
    aCtr1 -= aCtr0;
590
591
0
    if(bRotOk)
592
0
        pO->Rotate(aCtr0, Degree100(basegfx::fround(basegfx::rad2deg<100>(nAngle))), nSin, nCos);
593
594
0
    pO->Move(Size(aCtr1.X(),aCtr1.Y()));
595
0
}
596
597
void SdrEditView::CrookMarkedObj(const Point& rRef, const Point& rRad, SdrCrookMode eMode,
598
    bool bVertical, bool bNoContortion, bool bCopy)
599
0
{
600
0
    tools::Rectangle aMarkRect(GetMarkedObjRect());
601
0
    const bool bUndo = IsUndoEnabled();
602
603
0
    bool bRotate=bNoContortion && eMode==SdrCrookMode::Rotate && IsRotateAllowed();
604
605
0
    if( bUndo )
606
0
    {
607
0
        EndTextEditCurrentView();
608
0
        OUString aStr {ImpGetDescriptionString(bNoContortion ? STR_EditCrook : STR_EditCrookContortion)};
609
0
        if (bCopy)
610
0
            aStr+=SvxResId(STR_EditWithCopy);
611
0
        BegUndo(aStr);
612
0
    }
613
614
0
    if (bCopy)
615
0
        CopyMarkedObj();
616
617
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
618
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
619
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
620
0
    {
621
0
        SdrMark* pM=rMarkList.GetMark(nm);
622
0
        SdrObject* pO=pM->GetMarkedSdrObj();
623
0
        if (bUndo)
624
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
625
626
0
        const SdrObjList* pOL=pO->GetSubList();
627
0
        if (bNoContortion || pOL==nullptr) {
628
0
            ImpCrookObj(pO,rRef,rRad,eMode,bVertical,bNoContortion,bRotate,aMarkRect);
629
0
        } else {
630
0
            SdrObjListIter aIter(pOL,SdrIterMode::DeepNoGroups);
631
0
            while (aIter.IsMore()) {
632
0
                SdrObject* pO1=aIter.Next();
633
0
                ImpCrookObj(pO1,rRef,rRad,eMode,bVertical,bNoContortion,bRotate,aMarkRect);
634
0
            }
635
0
        }
636
0
    }
637
638
0
    if( bUndo )
639
0
        EndUndo();
640
0
}
641
642
void SdrEditView::ImpDistortObj(SdrObject* pO, const tools::Rectangle& rRef, const XPolygon& rDistortedRect, bool bNoContortion)
643
0
{
644
0
    SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pO );
645
646
0
    if(!bNoContortion && pPath)
647
0
    {
648
0
        XPolyPolygon aXPP(pPath->GetPathPoly());
649
0
        aXPP.Distort(rRef, rDistortedRect);
650
0
        pPath->SetPathPoly(aXPP.getB2DPolyPolygon());
651
0
    }
652
0
    else if(pO->IsPolyObj())
653
0
    {
654
        // e. g. for the measurement object
655
0
        sal_uInt32 nPointCount(pO->GetPointCount());
656
0
        XPolygon aXP(static_cast<sal_uInt16>(nPointCount));
657
0
        sal_uInt32 nPtNum;
658
659
0
        for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
660
0
        {
661
0
            Point aPt(pO->GetPoint(nPtNum));
662
0
            aXP[static_cast<sal_uInt16>(nPtNum)]=aPt;
663
0
        }
664
665
0
        aXP.Distort(rRef, rDistortedRect);
666
667
0
        for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
668
0
        {
669
            // broadcasting could be optimized here, but for the
670
            // current two points of the measurement object it's fine
671
0
            pO->SetPoint(aXP[static_cast<sal_uInt16>(nPtNum)],nPtNum);
672
0
        }
673
0
    }
674
0
}
675
676
void SdrEditView::DistortMarkedObj(const tools::Rectangle& rRef, const XPolygon& rDistortedRect, bool bNoContortion, bool bCopy)
677
0
{
678
0
    const bool bUndo = IsUndoEnabled();
679
680
0
    if( bUndo )
681
0
    {
682
0
        EndTextEditCurrentView();
683
0
        OUString aStr {ImpGetDescriptionString(STR_EditDistort)};
684
0
        if (bCopy)
685
0
            aStr+=SvxResId(STR_EditWithCopy);
686
0
        BegUndo(aStr);
687
0
    }
688
689
0
    if (bCopy)
690
0
        CopyMarkedObj();
691
692
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
693
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
694
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
695
0
    {
696
0
        SdrMark* pM=rMarkList.GetMark(nm);
697
0
        SdrObject* pO=pM->GetMarkedSdrObj();
698
0
        if (bUndo)
699
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pO));
700
701
0
        tools::Rectangle aRefRect(rRef);
702
0
        const SdrObjList* pOL=pO->GetSubList();
703
0
        if (bNoContortion || pOL==nullptr) {
704
0
            ImpDistortObj(pO,aRefRect,rDistortedRect,bNoContortion);
705
0
        } else {
706
0
            SdrObjListIter aIter(pOL,SdrIterMode::DeepNoGroups);
707
0
            while (aIter.IsMore()) {
708
0
                SdrObject* pO1=aIter.Next();
709
0
                ImpDistortObj(pO1,aRefRect,rDistortedRect,bNoContortion);
710
0
            }
711
0
        }
712
0
    }
713
0
    if( bUndo )
714
0
        EndUndo();
715
0
}
716
717
718
void SdrEditView::SetNotPersistAttrToMarked(const SfxItemSet& rAttr)
719
0
{
720
    // bReplaceAll has no effect here
721
0
    tools::Rectangle aAllSnapRect(GetMarkedObjRect());
722
0
    if (const SdrTransformRef1XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1X))
723
0
    {
724
0
        tools::Long n = pPoolItem->GetValue();
725
0
        SetRef1(Point(n,GetRef1().Y()));
726
0
    }
727
0
    if (const SdrTransformRef1YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1Y))
728
0
    {
729
0
        tools::Long n = pPoolItem->GetValue();
730
0
        SetRef1(Point(GetRef1().X(),n));
731
0
    }
732
0
    if (const SdrTransformRef2XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF2X))
733
0
    {
734
0
        tools::Long n = pPoolItem->GetValue();
735
0
        SetRef2(Point(n,GetRef2().Y()));
736
0
    }
737
0
    if (const SdrTransformRef2YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF2Y))
738
0
    {
739
0
        tools::Long n = pPoolItem->GetValue();
740
0
        SetRef2(Point(GetRef2().X(),n));
741
0
    }
742
0
    tools::Long nAllPosX=0; bool bAllPosX=false;
743
0
    tools::Long nAllPosY=0; bool bAllPosY=false;
744
0
    tools::Long nAllWdt=0;  bool bAllWdt=false;
745
0
    tools::Long nAllHgt=0;  bool bAllHgt=false;
746
0
    bool bDoIt=false;
747
0
    if (const SdrAllPositionXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLPOSITIONX))
748
0
    {
749
0
        nAllPosX = pPoolItem->GetValue();
750
0
        bAllPosX=true; bDoIt=true;
751
0
    }
752
0
    if (const SdrAllPositionYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLPOSITIONY))
753
0
    {
754
0
        nAllPosY = pPoolItem->GetValue();
755
0
        bAllPosY=true; bDoIt=true;
756
0
    }
757
0
    if (const SdrAllSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLSIZEWIDTH))
758
0
    {
759
0
        nAllWdt = pPoolItem->GetValue();
760
0
        bAllWdt=true; bDoIt=true;
761
0
    }
762
0
    if (const SdrAllSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLSIZEHEIGHT))
763
0
    {
764
0
        nAllHgt = pPoolItem->GetValue();
765
0
        bAllHgt=true; bDoIt=true;
766
0
    }
767
0
    if (bDoIt) {
768
0
        tools::Rectangle aRect(aAllSnapRect); // TODO: change this for PolyPt's and GluePt's!!!
769
0
        if (bAllPosX) aRect.Move(nAllPosX-aRect.Left(),0);
770
0
        if (bAllPosY) aRect.Move(0,nAllPosY-aRect.Top());
771
0
        if (bAllWdt)  aRect.SetRight(aAllSnapRect.Left()+nAllWdt );
772
0
        if (bAllHgt)  aRect.SetBottom(aAllSnapRect.Top()+nAllHgt );
773
0
        SetMarkedObjRect(aRect);
774
0
    }
775
0
    if (const SdrResizeXAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEXALL))
776
0
    {
777
0
        double fXFact = pPoolItem->GetValue();
778
0
        ResizeMarkedObj(aAllSnapRect.TopLeft(), fXFact, 1.0);
779
0
    }
780
0
    if (const SdrResizeYAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEYALL))
781
0
    {
782
0
        double fYFact = pPoolItem->GetValue();
783
0
        ResizeMarkedObj(aAllSnapRect.TopLeft(), 1.0, fYFact);
784
0
    }
785
0
    if (const SdrRotateAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEALL))
786
0
    {
787
0
        Degree100 nAngle = pPoolItem->GetValue();
788
0
        RotateMarkedObj(aAllSnapRect.Center(),nAngle);
789
0
    }
790
0
    if (const SdrHorzShearAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_HORZSHEARALL))
791
0
    {
792
0
        Degree100 nAngle = pPoolItem->GetValue();
793
0
        ShearMarkedObj(aAllSnapRect.Center(),nAngle);
794
0
    }
795
0
    if (const SdrVertShearAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_VERTSHEARALL))
796
0
    {
797
0
        Degree100 nAngle = pPoolItem->GetValue();
798
0
        ShearMarkedObj(aAllSnapRect.Center(),nAngle,true);
799
0
    }
800
801
0
    const bool bUndo = IsUndoEnabled();
802
803
    // TODO: check if WhichRange is necessary.
804
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
805
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
806
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
807
0
    {
808
0
        const SdrMark* pM=rMarkList.GetMark(nm);
809
0
        SdrObject* pObj=pM->GetMarkedSdrObj();
810
0
        if (bUndo)
811
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
812
813
0
        pObj->ApplyNotPersistAttr(rAttr);
814
0
    }
815
0
}
816
817
void SdrEditView::MergeNotPersistAttrFromMarked(SfxItemSet& rAttr) const
818
0
{
819
    // TODO: Take into account the origin and PvPos.
820
0
    tools::Rectangle aAllSnapRect(GetMarkedObjRect()); // TODO: change this for PolyPt's and GluePt's!!!
821
0
    tools::Long nAllSnapPosX=aAllSnapRect.Left();
822
0
    tools::Long nAllSnapPosY=aAllSnapRect.Top();
823
0
    tools::Long nAllSnapWdt=aAllSnapRect.GetWidth()-1;
824
0
    tools::Long nAllSnapHgt=aAllSnapRect.GetHeight()-1;
825
    // TODO: could go into CheckPossibilities
826
0
    bool bMovProtect = false, bMovProtectDC = false;
827
0
    bool bSizProtect = false, bSizProtectDC = false;
828
0
    bool bPrintable = true, bPrintableDC = false;
829
0
    bool bVisible = true, bVisibleDC = false;
830
0
    SdrLayerID nLayerId(0);
831
0
    bool bLayerDC=false;
832
0
    tools::Long nSnapPosX=0;      bool bSnapPosXDC=false;
833
0
    tools::Long nSnapPosY=0;      bool bSnapPosYDC=false;
834
0
    tools::Long nSnapWdt=0;       bool bSnapWdtDC=false;
835
0
    tools::Long nSnapHgt=0;       bool bSnapHgtDC=false;
836
0
    tools::Long nLogicWdt=0;      bool bLogicWdtDC=false,bLogicWdtDiff=false;
837
0
    tools::Long nLogicHgt=0;      bool bLogicHgtDC=false,bLogicHgtDiff=false;
838
0
    Degree100 nRotAngle(0);      bool bRotAngleDC=false;
839
0
    Degree100 nShrAngle(0);      bool bShrAngleDC=false;
840
0
    tools::Rectangle aSnapRect;
841
0
    tools::Rectangle aLogicRect;
842
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
843
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
844
0
    for (size_t nm=0; nm<nMarkCount; ++nm) {
845
0
        const SdrMark* pM=rMarkList.GetMark(nm);
846
0
        const SdrObject* pObj=pM->GetMarkedSdrObj();
847
0
        if (nm==0) {
848
0
            nLayerId=pObj->GetLayer();
849
0
            bMovProtect=pObj->IsMoveProtect();
850
0
            bSizProtect=pObj->IsResizeProtect();
851
0
            bPrintable =pObj->IsPrintable();
852
0
            bVisible = pObj->IsVisible();
853
0
            tools::Rectangle aSnapRect2(pObj->GetSnapRect());
854
0
            tools::Rectangle aLogicRect2(pObj->GetLogicRect());
855
0
            nSnapPosX=aSnapRect2.Left();
856
0
            nSnapPosY=aSnapRect2.Top();
857
0
            nSnapWdt=aSnapRect2.GetWidth()-1;
858
0
            nSnapHgt=aSnapRect2.GetHeight()-1;
859
0
            nLogicWdt=aLogicRect2.GetWidth()-1;
860
0
            nLogicHgt=aLogicRect2.GetHeight()-1;
861
0
            bLogicWdtDiff=nLogicWdt!=nSnapWdt;
862
0
            bLogicHgtDiff=nLogicHgt!=nSnapHgt;
863
0
            nRotAngle=pObj->GetRotateAngle();
864
0
            nShrAngle=pObj->GetShearAngle();
865
0
        } else {
866
0
            if (!bLayerDC      && nLayerId   !=pObj->GetLayer())        bLayerDC = true;
867
0
            if (!bMovProtectDC && bMovProtect!=pObj->IsMoveProtect())   bMovProtectDC = true;
868
0
            if (!bSizProtectDC && bSizProtect!=pObj->IsResizeProtect()) bSizProtectDC = true;
869
0
            if (!bPrintableDC  && bPrintable !=pObj->IsPrintable())     bPrintableDC = true;
870
0
            if (!bVisibleDC    && bVisible !=pObj->IsVisible())         bVisibleDC=true;
871
0
            if (!bRotAngleDC   && nRotAngle  !=pObj->GetRotateAngle())  bRotAngleDC=true;
872
0
            if (!bShrAngleDC   && nShrAngle  !=pObj->GetShearAngle())   bShrAngleDC=true;
873
0
            if (!bSnapWdtDC || !bSnapHgtDC || !bSnapPosXDC || !bSnapPosYDC || !bLogicWdtDiff || !bLogicHgtDiff) {
874
0
                aSnapRect=pObj->GetSnapRect();
875
0
                if (nSnapPosX!=aSnapRect.Left()) bSnapPosXDC=true;
876
0
                if (nSnapPosY!=aSnapRect.Top()) bSnapPosYDC=true;
877
0
                if (nSnapWdt!=aSnapRect.GetWidth()-1) bSnapWdtDC=true;
878
0
                if (nSnapHgt!=aSnapRect.GetHeight()-1) bSnapHgtDC=true;
879
0
            }
880
0
            if (!bLogicWdtDC || !bLogicHgtDC || !bLogicWdtDiff || !bLogicHgtDiff) {
881
0
                aLogicRect=pObj->GetLogicRect();
882
0
                if (nLogicWdt!=aLogicRect.GetWidth()-1) bLogicWdtDC=true;
883
0
                if (nLogicHgt!=aLogicRect.GetHeight()-1) bLogicHgtDC=true;
884
0
                if (!bLogicWdtDiff && aSnapRect.GetWidth()!=aLogicRect.GetWidth()) bLogicWdtDiff=true;
885
0
                if (!bLogicHgtDiff && aSnapRect.GetHeight()!=aLogicRect.GetHeight()) bLogicHgtDiff=true;
886
0
            }
887
0
        }
888
0
    }
889
890
0
    if (bSnapPosXDC || nAllSnapPosX!=nSnapPosX) rAttr.Put(SdrAllPositionXItem(nAllSnapPosX));
891
0
    if (bSnapPosYDC || nAllSnapPosY!=nSnapPosY) rAttr.Put(SdrAllPositionYItem(nAllSnapPosY));
892
0
    if (bSnapWdtDC  || nAllSnapWdt !=nSnapWdt ) rAttr.Put(SdrAllSizeWidthItem(nAllSnapWdt));
893
0
    if (bSnapHgtDC  || nAllSnapHgt !=nSnapHgt ) rAttr.Put(SdrAllSizeHeightItem(nAllSnapHgt));
894
895
    // items for pure transformations
896
0
    rAttr.Put(SdrMoveXItem());
897
0
    rAttr.Put(SdrMoveYItem());
898
0
    rAttr.Put(SdrResizeXOneItem());
899
0
    rAttr.Put(SdrResizeYOneItem());
900
0
    rAttr.Put(SdrRotateOneItem());
901
0
    rAttr.Put(SdrHorzShearOneItem());
902
0
    rAttr.Put(SdrVertShearOneItem());
903
904
0
    if (nMarkCount>1) {
905
0
        rAttr.Put(SdrResizeXAllItem());
906
0
        rAttr.Put(SdrResizeYAllItem());
907
0
        rAttr.Put(SdrRotateAllItem());
908
0
        rAttr.Put(SdrHorzShearAllItem());
909
0
        rAttr.Put(SdrVertShearAllItem());
910
0
    }
911
912
0
    if(meDragMode == SdrDragMode::Rotate || meDragMode == SdrDragMode::Mirror)
913
0
    {
914
0
        rAttr.Put(SdrTransformRef1XItem(GetRef1().X()));
915
0
        rAttr.Put(SdrTransformRef1YItem(GetRef1().Y()));
916
0
    }
917
918
0
    if(meDragMode == SdrDragMode::Mirror)
919
0
    {
920
0
        rAttr.Put(SdrTransformRef2XItem(GetRef2().X()));
921
0
        rAttr.Put(SdrTransformRef2YItem(GetRef2().Y()));
922
0
    }
923
0
}
924
925
SfxItemSet SdrEditView::GetAttrFromMarked(bool bOnlyHardAttr) const
926
0
{
927
0
    SfxItemSet aSet(GetModel().GetItemPool());
928
0
    MergeAttrFromMarked(aSet,bOnlyHardAttr);
929
    //the EE_FEATURE items should not be set with SetAttrToMarked (see error message there)
930
    //so we do not set them here
931
    // #i32448#
932
    // Do not disable, but clear the items.
933
0
    aSet.ClearItem(EE_FEATURE_TAB);
934
0
    aSet.ClearItem(EE_FEATURE_LINEBR);
935
0
    aSet.ClearItem(EE_FEATURE_NOTCONV);
936
0
    aSet.ClearItem(EE_FEATURE_FIELD);
937
938
0
    return aSet;
939
0
}
940
941
void SdrEditView::MergeAttrFromMarked(SfxItemSet& rAttr, bool bOnlyHardAttr) const
942
0
{
943
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
944
0
    const size_t nMarkCount(rMarkList.GetMarkCount());
945
946
0
    for(size_t a = 0; a < nMarkCount; ++a)
947
0
    {
948
        // #80277# merging was done wrong in the prev version
949
0
        SdrObject *pObj = rMarkList.GetMark(a)->GetMarkedSdrObj();
950
0
        if (!pObj)
951
0
        {
952
0
            continue;
953
0
        }
954
955
0
        pObj = pObj->getDiagramSubSelection();
956
957
0
        const SfxItemSet& rSet = pObj->GetMergedItemSet();
958
0
        SfxWhichIter aIter(rSet);
959
0
        sal_uInt16 nWhich(aIter.FirstWhich());
960
961
0
        while(nWhich)
962
0
        {
963
0
            if(!bOnlyHardAttr)
964
0
            {
965
0
                if(SfxItemState::INVALID == aIter.GetItemState(false))
966
0
                    rAttr.InvalidateItem(nWhich);
967
0
                else
968
0
                    rAttr.MergeValue(rSet.Get(nWhich));
969
0
            }
970
0
            else if(SfxItemState::SET == aIter.GetItemState(false))
971
0
            {
972
0
                const SfxPoolItem& rItem = rSet.Get(nWhich);
973
0
                rAttr.MergeValue(rItem);
974
0
            }
975
976
0
            if (comphelper::LibreOfficeKit::isActive())
977
0
            {
978
0
                OUString sPayload;
979
0
                switch(nWhich)
980
0
                {
981
0
                    case XATTR_LINECOLOR:
982
0
                    {
983
0
                        const XLineColorItem* pItem = rSet.GetItem(XATTR_LINECOLOR);
984
0
                        if (pItem)
985
0
                        {
986
0
                            Color aColor = pItem->GetColorValue();
987
0
                            sPayload = OUString::number(static_cast<sal_uInt32>(aColor));
988
989
0
                            sPayload = ".uno:XLineColor=" + sPayload;
990
0
                        }
991
0
                        break;
992
0
                    }
993
994
0
                    case XATTR_FILLCOLOR:
995
0
                    {
996
0
                        const XFillColorItem* pItem = rSet.GetItem(XATTR_FILLCOLOR);
997
0
                        if (pItem)
998
0
                        {
999
0
                            Color aColor = pItem->GetColorValue();
1000
0
                            sPayload = OUString::number(static_cast<sal_uInt32>(aColor));
1001
1002
0
                            sPayload = ".uno:FillColor=" + sPayload;
1003
0
                        }
1004
0
                        break;
1005
0
                    }
1006
1007
0
                    case XATTR_FILLTRANSPARENCE:
1008
0
                    {
1009
0
                        const XFillTransparenceItem* pItem = rSet.GetItem(XATTR_FILLTRANSPARENCE);
1010
0
                        if (pItem)
1011
0
                        {
1012
0
                            sal_uInt16 nTransparency = pItem->GetValue();
1013
0
                            sPayload = OUString::number(nTransparency);
1014
1015
0
                            sPayload = ".uno:FillTransparence=" + sPayload;
1016
0
                        }
1017
0
                        break;
1018
0
                    }
1019
1020
0
                    case XATTR_LINETRANSPARENCE:
1021
0
                    {
1022
0
                        const SfxUInt16Item* pItem = rSet.GetItem(XATTR_LINETRANSPARENCE);
1023
0
                        if (pItem)
1024
0
                        {
1025
0
                            sal_uInt16 nTransparency = pItem->GetValue();
1026
0
                            sPayload = OUString::number(nTransparency);
1027
1028
0
                            sPayload = ".uno:LineTransparence=" + sPayload;
1029
0
                        }
1030
0
                        break;
1031
0
                    }
1032
1033
0
                    case XATTR_LINEWIDTH:
1034
0
                    {
1035
0
                        const XLineWidthItem* pItem = rSet.GetItem(XATTR_LINEWIDTH);
1036
0
                        if (pItem)
1037
0
                        {
1038
0
                            sal_uInt32 nWidth = pItem->GetValue();
1039
0
                            sPayload = OUString::number(nWidth);
1040
1041
0
                            sPayload = ".uno:LineWidth=" + sPayload;
1042
0
                        }
1043
0
                        break;
1044
0
                    }
1045
1046
0
                    case SDRATTR_SHADOWTRANSPARENCE:
1047
0
                    {
1048
0
                        const SfxUInt16Item* pItem = rSet.GetItem(SDRATTR_SHADOWTRANSPARENCE);
1049
0
                        if (pItem)
1050
0
                        {
1051
0
                            sal_uInt16 nWidth = pItem->GetValue();
1052
0
                            sPayload = OUString::number(nWidth);
1053
1054
0
                            sPayload = ".uno:FillShadowTransparency=" + sPayload;
1055
0
                        }
1056
0
                        break;
1057
0
                    }
1058
0
                }
1059
1060
0
                if (!sPayload.isEmpty())
1061
0
                {
1062
0
                    if (SfxViewShell* pViewShell = GetSfxViewShell())
1063
0
                    {
1064
0
                        pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
1065
0
                            OUStringToOString(sPayload, RTL_TEXTENCODING_ASCII_US));
1066
0
                    }
1067
0
                }
1068
0
            }
1069
1070
0
            nWhich = aIter.NextWhich();
1071
0
        }
1072
0
    }
1073
0
}
1074
1075
std::vector<sal_uInt16> GetAllCharPropIds(const SfxItemSet& rSet)
1076
0
{
1077
0
    std::vector<sal_uInt16> aCharWhichIds;
1078
0
    {
1079
0
        for (SfxItemIter aIter( rSet ); !aIter.IsAtEnd(); aIter.Next())
1080
0
        {
1081
0
            const SfxPoolItem* pItem = aIter.GetCurItem();
1082
0
            if (!IsInvalidItem(pItem))
1083
0
            {
1084
0
                sal_uInt16 nWhich = pItem->Which();
1085
0
                if (nWhich>=EE_CHAR_START && nWhich<=EE_CHAR_END)
1086
0
                    aCharWhichIds.push_back( nWhich );
1087
0
            }
1088
0
        }
1089
0
    }
1090
0
    return aCharWhichIds;
1091
0
}
1092
1093
std::vector<sal_uInt16> GetAllCharPropIds(std::span< const SfxPoolItem* const > aChangedItems)
1094
43.6k
{
1095
43.6k
    std::vector<sal_uInt16> aCharWhichIds;
1096
43.6k
    for (const SfxPoolItem* pItem : aChangedItems)
1097
56.7k
    {
1098
56.7k
        sal_uInt16 nWhich = pItem->Which();
1099
56.7k
        if (nWhich>=EE_CHAR_START && nWhich<=EE_CHAR_END)
1100
13.4k
            aCharWhichIds.push_back( nWhich );
1101
56.7k
    }
1102
43.6k
    return aCharWhichIds;
1103
43.6k
}
1104
1105
void SdrEditView::SetAttrToMarked(const SfxItemSet& rAttr, bool bReplaceAll)
1106
0
{
1107
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1108
0
    if (rMarkList.GetMarkCount() == 0)
1109
0
        return;
1110
1111
#ifdef DBG_UTIL
1112
    {
1113
        bool bHasEEFeatureItems=false;
1114
        for (SfxItemIter aIter( rAttr ); !bHasEEFeatureItems && !aIter.IsAtEnd(); aIter.Next())
1115
        {
1116
            const SfxPoolItem* pItem = aIter.GetCurItem();
1117
            if (!IsInvalidItem(pItem)) {
1118
                sal_uInt16 nW=pItem->Which();
1119
                if (nW>=EE_FEATURE_START && nW<=EE_FEATURE_END) bHasEEFeatureItems=true;
1120
            }
1121
        }
1122
        if(bHasEEFeatureItems)
1123
        {
1124
            std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
1125
                                                          VclMessageType::Info, VclButtonsType::Ok,
1126
                                                          u"SdrEditView::SetAttrToMarked(): Setting EE_FEATURE items at the SdrView does not make sense! It only leads to overhead and unreadable documents."_ustr));
1127
            xInfoBox->run();
1128
        }
1129
    }
1130
#endif
1131
1132
    // #103836# if the user sets character attributes to the complete shape,
1133
    //          we want to remove all hard set character attributes with same
1134
    //          which ids from the text. We do that later but here we remember
1135
    //          all character attribute which id's that are set.
1136
0
    std::vector<sal_uInt16> aCharWhichIds(GetAllCharPropIds(rAttr));
1137
1138
    // To make Undo reconstruct text attributes correctly after Format.Standard
1139
0
    bool bHasEEItems=SearchOutlinerItems(rAttr,bReplaceAll);
1140
1141
    // save additional geometry information when paragraph or character attributes
1142
    // are changed and the geometrical shape of the text object might be changed
1143
0
    bool bPossibleGeomChange(false);
1144
0
    SfxWhichIter aIter(rAttr);
1145
0
    sal_uInt16 nWhich = aIter.FirstWhich();
1146
0
    while(!bPossibleGeomChange && nWhich)
1147
0
    {
1148
0
        SfxItemState eState = aIter.GetItemState();
1149
0
        if(eState == SfxItemState::SET)
1150
0
        {
1151
0
            if((nWhich >= SDRATTR_TEXT_MINFRAMEHEIGHT && nWhich <= SDRATTR_TEXT_CONTOURFRAME)
1152
0
                || nWhich == SDRATTR_3DOBJ_PERCENT_DIAGONAL
1153
0
                || nWhich == SDRATTR_3DOBJ_BACKSCALE
1154
0
                || nWhich == SDRATTR_3DOBJ_DEPTH
1155
0
                || nWhich == SDRATTR_3DOBJ_END_ANGLE
1156
0
                || nWhich == SDRATTR_3DSCENE_DISTANCE)
1157
0
            {
1158
0
                bPossibleGeomChange = true;
1159
0
            }
1160
0
        }
1161
0
        nWhich = aIter.NextWhich();
1162
0
    }
1163
1164
0
    const bool bUndo = IsUndoEnabled();
1165
0
    if( bUndo )
1166
0
    {
1167
0
        EndTextEditCurrentView();
1168
0
        BegUndo(ImpGetDescriptionString(STR_EditSetAttributes));
1169
0
    }
1170
1171
0
    const size_t nMarkCount(rMarkList.GetMarkCount());
1172
0
    std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
1173
1174
    // create ItemSet without SfxItemState::INVALID. Put()
1175
    // uses its second parameter (bInvalidAsDefault) to
1176
    // remove all such items to set them to default.
1177
0
    SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges());
1178
0
    aAttr.Put(rAttr);
1179
1180
    // #i38135#
1181
0
    bool bResetAnimationTimer(false);
1182
1183
0
    const bool bLineStartWidthExplicitChange(SfxItemState::SET
1184
0
                                             == aAttr.GetItemState(XATTR_LINESTARTWIDTH));
1185
0
    const bool bLineEndWidthExplicitChange(SfxItemState::SET
1186
0
                                           == aAttr.GetItemState(XATTR_LINEENDWIDTH));
1187
    // check if LineWidth is part of the change
1188
0
    const bool bAdaptStartEndWidths(!(bLineStartWidthExplicitChange && bLineEndWidthExplicitChange)
1189
0
                                     && SfxItemState::SET == aAttr.GetItemState(XATTR_LINEWIDTH));
1190
0
    sal_Int32 nNewLineWidth(0);
1191
1192
0
    if(bAdaptStartEndWidths)
1193
0
    {
1194
0
        nNewLineWidth = aAttr.Get(XATTR_LINEWIDTH).GetValue();
1195
0
    }
1196
1197
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
1198
0
    {
1199
0
        SdrMark* pM=rMarkList.GetMark(nm);
1200
0
        SdrObject* pObj = pM->GetMarkedSdrObj();
1201
1202
0
        pObj = pObj->getDiagramSubSelection();
1203
1204
0
        if( bUndo )
1205
0
        {
1206
0
            SdrEdgeObj* pEdgeObj = dynamic_cast< SdrEdgeObj* >( pObj );
1207
0
            if ( pEdgeObj )
1208
0
                bPossibleGeomChange = true;
1209
0
            else
1210
0
                AddUndoActions( CreateConnectorUndo( *pObj ) );
1211
0
        }
1212
1213
        // new geometry undo
1214
0
        if(bPossibleGeomChange && bUndo)
1215
0
        {
1216
            // save position and size of object, too
1217
0
            AddUndo( GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
1218
0
        }
1219
1220
0
        if( bUndo )
1221
0
        {
1222
            // #i8508#
1223
            // If this is a text object also rescue the OutlinerParaObject since
1224
            // applying attributes to the object may change text layout when
1225
            // multiple portions exist with multiple formats. If an OutlinerParaObject
1226
            // really exists and needs to be rescued is evaluated in the undo
1227
            // implementation itself.
1228
0
            const bool bRescueText = DynCastSdrTextObj(pObj) != nullptr;
1229
1230
            // add attribute undo
1231
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj,false,bHasEEItems || bPossibleGeomChange || bRescueText));
1232
0
        }
1233
1234
        // set up a scene updater if object is a 3d object
1235
0
        if(DynCastE3dObject(pObj))
1236
0
        {
1237
0
            aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pObj));
1238
0
        }
1239
1240
0
        sal_Int32 nOldLineWidth(0);
1241
0
        if (bAdaptStartEndWidths)
1242
0
        {
1243
0
            nOldLineWidth = pObj->GetMergedItem(XATTR_LINEWIDTH).GetValue();
1244
0
        }
1245
1246
        // set attributes at object
1247
0
        pObj->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
1248
1249
0
        if(bAdaptStartEndWidths)
1250
0
        {
1251
0
            const SfxItemSet& rSet = pObj->GetMergedItemSet();
1252
1253
0
            if(nOldLineWidth != nNewLineWidth)
1254
0
            {
1255
0
                if(SfxItemState::INVALID != rSet.GetItemState(XATTR_LINESTARTWIDTH))
1256
0
                {
1257
0
                    const sal_Int32 nValAct(rSet.Get(XATTR_LINESTARTWIDTH).GetValue());
1258
0
                    const sal_Int32 nValNewStart(std::max(sal_Int32(0), nValAct + (((nNewLineWidth - nOldLineWidth) * 15) / 10)));
1259
1260
0
                    pObj->SetMergedItem(XLineStartWidthItem(nValNewStart));
1261
0
                }
1262
1263
0
                if(SfxItemState::INVALID != rSet.GetItemState(XATTR_LINEENDWIDTH))
1264
0
                {
1265
0
                    const sal_Int32 nValAct(rSet.Get(XATTR_LINEENDWIDTH).GetValue());
1266
0
                    const sal_Int32 nValNewEnd(std::max(sal_Int32(0), nValAct + (((nNewLineWidth - nOldLineWidth) * 15) / 10)));
1267
1268
0
                    pObj->SetMergedItem(XLineEndWidthItem(nValNewEnd));
1269
0
                }
1270
0
            }
1271
0
        }
1272
1273
0
        if(auto pTextObj = DynCastSdrTextObj( pObj))
1274
0
        {
1275
0
            if(!aCharWhichIds.empty())
1276
0
            {
1277
0
                tools::Rectangle aOldBoundRect = pTextObj->GetLastBoundRect();
1278
1279
                // #110094#-14 pTextObj->SendRepaintBroadcast(pTextObj->GetBoundRect());
1280
0
                pTextObj->RemoveOutlinerCharacterAttribs( aCharWhichIds );
1281
1282
                // object has changed, should be called from
1283
                // RemoveOutlinerCharacterAttribs. This will change when the text
1284
                // object implementation changes.
1285
0
                pTextObj->SetChanged();
1286
1287
0
                pTextObj->BroadcastObjectChange();
1288
0
                pTextObj->SendUserCall(SdrUserCallType::ChangeAttr, aOldBoundRect);
1289
0
            }
1290
0
        }
1291
1292
        // #i38495#
1293
0
        if(!bResetAnimationTimer)
1294
0
        {
1295
0
            if(pObj->GetViewContact().isAnimatedInAnyViewObjectContact())
1296
0
            {
1297
0
                bResetAnimationTimer = true;
1298
0
            }
1299
0
        }
1300
0
    }
1301
1302
    // fire scene updaters
1303
0
    while(!aUpdaters.empty())
1304
0
    {
1305
0
        delete aUpdaters.back();
1306
0
        aUpdaters.pop_back();
1307
0
    }
1308
1309
    // #i38135#
1310
0
    if(bResetAnimationTimer)
1311
0
    {
1312
0
        SetAnimationTimer(0);
1313
0
    }
1314
1315
    // better check before what to do:
1316
    // pObj->SetAttr() or SetNotPersistAttr()
1317
    // TODO: missing implementation!
1318
0
    SetNotPersistAttrToMarked(rAttr);
1319
1320
0
    if( bUndo )
1321
0
        EndUndo();
1322
0
}
1323
1324
SfxStyleSheet* SdrEditView::GetStyleSheetFromMarked() const
1325
0
{
1326
0
    SfxStyleSheet* pRet=nullptr;
1327
0
    bool b1st=true;
1328
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1329
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
1330
0
    for (size_t nm=0; nm<nMarkCount; ++nm) {
1331
0
        SdrMark* pM=rMarkList.GetMark(nm);
1332
0
        SfxStyleSheet* pSS=pM->GetMarkedSdrObj()->GetStyleSheet();
1333
0
        if (b1st) pRet=pSS;
1334
0
        else if (pRet!=pSS) return nullptr; // different stylesheets
1335
0
        b1st=false;
1336
0
    }
1337
0
    return pRet;
1338
0
}
1339
1340
void SdrEditView::SetStyleSheetToMarked(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
1341
0
{
1342
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1343
0
    if (rMarkList.GetMarkCount() == 0)
1344
0
        return;
1345
1346
0
    const bool bUndo = IsUndoEnabled();
1347
1348
0
    if( bUndo )
1349
0
    {
1350
0
        EndTextEditCurrentView();
1351
0
        OUString aStr;
1352
0
        if (pStyleSheet!=nullptr)
1353
0
            aStr = ImpGetDescriptionString(STR_EditSetStylesheet);
1354
0
        else
1355
0
            aStr = ImpGetDescriptionString(STR_EditDelStylesheet);
1356
0
        BegUndo(aStr);
1357
0
    }
1358
1359
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
1360
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
1361
0
    {
1362
0
        SdrMark* pM=rMarkList.GetMark(nm);
1363
0
        if( bUndo )
1364
0
        {
1365
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pM->GetMarkedSdrObj()));
1366
0
            AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pM->GetMarkedSdrObj(),true,true));
1367
0
        }
1368
0
        pM->GetMarkedSdrObj()->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
1369
0
    }
1370
1371
0
    if( bUndo )
1372
0
        EndUndo();
1373
0
}
1374
1375
1376
void SdrEditView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
1377
0
{
1378
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1379
0
    if(rMarkList.GetMarkCount())
1380
0
    {
1381
0
        rTargetSet.Put(GetAttrFromMarked(bOnlyHardAttr), false);
1382
0
    }
1383
0
    else
1384
0
    {
1385
0
        SdrMarkView::GetAttributes(rTargetSet, bOnlyHardAttr);
1386
0
    }
1387
0
}
1388
1389
void SdrEditView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
1390
0
{
1391
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1392
0
    if (rMarkList.GetMarkCount()!=0) {
1393
0
        SetAttrToMarked(rSet,bReplaceAll);
1394
0
    } else {
1395
0
        SdrMarkView::SetAttributes(rSet,bReplaceAll);
1396
0
    }
1397
0
}
1398
1399
SfxStyleSheet* SdrEditView::GetStyleSheet() const
1400
0
{
1401
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1402
0
    if (rMarkList.GetMarkCount()!=0) {
1403
0
        return GetStyleSheetFromMarked();
1404
0
    } else {
1405
0
        return SdrMarkView::GetStyleSheet();
1406
0
    }
1407
0
}
1408
1409
void SdrEditView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
1410
0
{
1411
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1412
0
    if (rMarkList.GetMarkCount()!=0) {
1413
0
        SetStyleSheetToMarked(pStyleSheet,bDontRemoveHardAttr);
1414
0
    } else {
1415
0
        SdrMarkView::SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
1416
0
    }
1417
0
}
1418
1419
1420
SfxItemSet SdrEditView::GetGeoAttrFromMarked() const
1421
0
{
1422
0
    SfxItemSet aRetSet(
1423
0
        GetModel().GetItemPool(),
1424
0
        svl::Items< // SID_ATTR_TRANSFORM_... from s:svxids.hrc
1425
0
            SDRATTR_CORNER_RADIUS, SDRATTR_CORNER_RADIUS,
1426
0
            SID_ATTR_TRANSFORM_POS_X, SID_ATTR_TRANSFORM_ANGLE,
1427
0
            SID_ATTR_TRANSFORM_PROTECT_POS, SID_ATTR_TRANSFORM_AUTOHEIGHT>);
1428
1429
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1430
0
    if (rMarkList.GetMarkCount() != 0)
1431
0
    {
1432
0
        SfxItemSet aMarkAttr(GetAttrFromMarked(false)); // because of AutoGrowHeight and corner radius
1433
0
        tools::Rectangle aRect(GetMarkedObjRect());
1434
1435
0
        if(GetSdrPageView())
1436
0
        {
1437
0
            GetSdrPageView()->LogicToPagePos(aRect);
1438
0
        }
1439
1440
        // position
1441
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_X,aRect.Left()));
1442
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_Y,aRect.Top()));
1443
1444
        // size
1445
0
        tools::Long nResizeRefX=aRect.Left();
1446
0
        tools::Long nResizeRefY=aRect.Top();
1447
0
        if (meDragMode==SdrDragMode::Rotate) { // use rotation axis as a reference for resizing, too
1448
0
            nResizeRefX=maRef1.X();
1449
0
            nResizeRefY=maRef1.Y();
1450
0
        }
1451
0
        aRetSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_WIDTH,aRect.Right()-aRect.Left()));
1452
0
        aRetSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_HEIGHT,aRect.Bottom()-aRect.Top()));
1453
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_RESIZE_REF_X,nResizeRefX));
1454
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_RESIZE_REF_Y,nResizeRefY));
1455
1456
0
        Point aRotateAxe(maRef1);
1457
1458
0
        if(GetSdrPageView())
1459
0
        {
1460
0
            GetSdrPageView()->LogicToPagePos(aRotateAxe);
1461
0
        }
1462
1463
        // rotation
1464
0
        tools::Long nRotateRefX=aRect.Center().X();
1465
0
        tools::Long nRotateRefY=aRect.Center().Y();
1466
0
        if (meDragMode==SdrDragMode::Rotate) {
1467
0
            nRotateRefX=aRotateAxe.X();
1468
0
            nRotateRefY=aRotateAxe.Y();
1469
0
        }
1470
0
        aRetSet.Put(SdrAngleItem(SID_ATTR_TRANSFORM_ANGLE,GetMarkedObjRotate()));
1471
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_ROT_X,nRotateRefX));
1472
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_ROT_Y,nRotateRefY));
1473
1474
        // shearing
1475
0
        tools::Long nShearRefX=aRect.Left();
1476
0
        tools::Long nShearRefY=aRect.Bottom();
1477
0
        if (meDragMode==SdrDragMode::Rotate) { // use rotation axis as a reference for shearing, too
1478
0
            nShearRefX=aRotateAxe.X();
1479
0
            nShearRefY=aRotateAxe.Y();
1480
0
        }
1481
0
        aRetSet.Put(SdrAngleItem(SID_ATTR_TRANSFORM_SHEAR,GetMarkedObjShear()));
1482
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_SHEAR_X,nShearRefX));
1483
0
        aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_SHEAR_Y,nShearRefY));
1484
1485
        // check every object whether it is protected
1486
0
        const size_t nMarkCount=rMarkList.GetMarkCount();
1487
0
        SdrObject* pObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
1488
0
        bool bPosProt=pObj->IsMoveProtect();
1489
0
        bool bSizProt=pObj->IsResizeProtect();
1490
0
        bool bPosProtDontCare=false;
1491
0
        bool bSizProtDontCare=false;
1492
0
        for (size_t i=1; i<nMarkCount && (!bPosProtDontCare || !bSizProtDontCare); ++i)
1493
0
        {
1494
0
            pObj=rMarkList.GetMark(i)->GetMarkedSdrObj();
1495
0
            if (bPosProt!=pObj->IsMoveProtect()) bPosProtDontCare=true;
1496
0
            if (bSizProt!=pObj->IsResizeProtect()) bSizProtDontCare=true;
1497
0
        }
1498
1499
        // InvalidateItem sets item to DONT_CARE
1500
0
        if (bPosProtDontCare) {
1501
0
            aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_PROTECT_POS);
1502
0
        } else {
1503
0
            aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_PROTECT_POS,bPosProt));
1504
0
        }
1505
0
        if (bSizProtDontCare) {
1506
0
            aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_PROTECT_SIZE);
1507
0
        } else {
1508
0
            aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_PROTECT_SIZE,bSizProt));
1509
0
        }
1510
1511
0
        SfxItemState eState=aMarkAttr.GetItemState(SDRATTR_TEXT_AUTOGROWWIDTH);
1512
0
        bool bAutoGrow=aMarkAttr.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue();
1513
0
        if (eState==SfxItemState::INVALID) {
1514
0
            aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_AUTOWIDTH);
1515
0
        } else if (eState==SfxItemState::SET) {
1516
0
            aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_AUTOWIDTH,bAutoGrow));
1517
0
        }
1518
1519
0
        eState=aMarkAttr.GetItemState(SDRATTR_TEXT_AUTOGROWHEIGHT);
1520
0
        bAutoGrow=aMarkAttr.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
1521
0
        if (eState==SfxItemState::INVALID) {
1522
0
            aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_AUTOHEIGHT);
1523
0
        } else if (eState==SfxItemState::SET) {
1524
0
            aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_AUTOHEIGHT,bAutoGrow));
1525
0
        }
1526
1527
0
        eState=aMarkAttr.GetItemState(SDRATTR_CORNER_RADIUS);
1528
0
        tools::Long nRadius=aMarkAttr.Get(SDRATTR_CORNER_RADIUS).GetValue();
1529
0
        if (eState==SfxItemState::INVALID) {
1530
0
            aRetSet.InvalidateItem(SDRATTR_CORNER_RADIUS);
1531
0
        } else if (eState==SfxItemState::SET) {
1532
0
            aRetSet.Put(makeSdrEckenradiusItem(nRadius));
1533
0
        }
1534
1535
0
        basegfx::B2DHomMatrix aTransformation;
1536
1537
0
        if(nMarkCount > 1)
1538
0
        {
1539
            // multiple objects, range is collected in aRect
1540
0
            aTransformation = basegfx::utils::createScaleTranslateB2DHomMatrix(
1541
0
                aRect.Left(), aRect.Top(),
1542
0
                aRect.getOpenWidth(), aRect.getOpenHeight());
1543
0
        }
1544
0
        else
1545
0
        {
1546
            // single object, get homogen transformation
1547
0
            basegfx::B2DPolyPolygon aPolyPolygon;
1548
1549
0
            pObj->TRGetBaseGeometry(aTransformation, aPolyPolygon);
1550
0
        }
1551
1552
0
        if(aTransformation.isIdentity())
1553
0
        {
1554
0
            aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_MATRIX);
1555
0
        }
1556
0
        else
1557
0
        {
1558
0
            css::geometry::AffineMatrix2D aAffineMatrix2D;
1559
0
            Point aPageOffset(0, 0);
1560
1561
0
            if(GetSdrPageView())
1562
0
            {
1563
0
                aPageOffset = GetSdrPageView()->GetPageOrigin();
1564
0
            }
1565
1566
0
            aAffineMatrix2D.m00 = aTransformation.get(0, 0);
1567
0
            aAffineMatrix2D.m01 = aTransformation.get(0, 1);
1568
0
            aAffineMatrix2D.m02 = aTransformation.get(0, 2) - aPageOffset.X();
1569
0
            aAffineMatrix2D.m10 = aTransformation.get(1, 0);
1570
0
            aAffineMatrix2D.m11 = aTransformation.get(1, 1);
1571
0
            aAffineMatrix2D.m12 = aTransformation.get(1, 2) - aPageOffset.Y();
1572
1573
0
            aRetSet.Put(AffineMatrixItem(&aAffineMatrix2D));
1574
0
        }
1575
0
    }
1576
1577
0
    return aRetSet;
1578
0
}
1579
1580
static Point ImpGetPoint(const tools::Rectangle& rRect, RectPoint eRP)
1581
0
{
1582
0
    switch(eRP) {
1583
0
        case RectPoint::LT: return rRect.TopLeft();
1584
0
        case RectPoint::MT: return rRect.TopCenter();
1585
0
        case RectPoint::RT: return rRect.TopRight();
1586
0
        case RectPoint::LM: return rRect.LeftCenter();
1587
0
        case RectPoint::MM: return rRect.Center();
1588
0
        case RectPoint::RM: return rRect.RightCenter();
1589
0
        case RectPoint::LB: return rRect.BottomLeft();
1590
0
        case RectPoint::MB: return rRect.BottomCenter();
1591
0
        case RectPoint::RB: return rRect.BottomRight();
1592
0
    }
1593
0
    return Point(); // Should not happen!
1594
0
}
1595
1596
void SdrEditView::SetGeoAttrToMarked(const SfxItemSet& rAttr, bool addPageMargin)
1597
0
{
1598
0
    tools::Rectangle aRect(GetMarkedObjRect());
1599
1600
0
    if(GetSdrPageView())
1601
0
    {
1602
0
        if (addPageMargin)
1603
0
        {
1604
0
            SdrPage * pPage = GetSdrPageView()->GetPage();
1605
0
            Point upperLeft(pPage->GetLeftBorder(), pPage->GetUpperBorder());
1606
0
            aRect.Move(upperLeft.getX(), upperLeft.getY());
1607
0
        }
1608
0
        GetSdrPageView()->LogicToPagePos(aRect);
1609
0
    }
1610
1611
0
    Degree100 nOldRotateAngle=GetMarkedObjRotate();
1612
0
    Degree100 nOldShearAngle=GetMarkedObjShear();
1613
0
    const SdrMarkList& rMarkList=GetMarkedObjectList();
1614
0
    SdrObject* pObj=nullptr;
1615
1616
0
    RectPoint eSizePoint=RectPoint::MM;
1617
0
    tools::Long nPosDX=0;
1618
0
    tools::Long nPosDY=0;
1619
0
    tools::Long nSizX=0;
1620
0
    tools::Long nSizY=0;
1621
0
    Degree100 nRotateAngle(0);
1622
1623
0
    bool bModeIsRotate(meDragMode == SdrDragMode::Rotate);
1624
0
    tools::Long nRotateX(0);
1625
0
    tools::Long nRotateY(0);
1626
0
    tools::Long nOldRotateX(0);
1627
0
    tools::Long nOldRotateY(0);
1628
0
    if(bModeIsRotate)
1629
0
    {
1630
0
        Point aRotateAxe(maRef1);
1631
1632
0
        if(GetSdrPageView())
1633
0
        {
1634
0
            GetSdrPageView()->LogicToPagePos(aRotateAxe);
1635
0
        }
1636
1637
0
        nRotateX = nOldRotateX = aRotateAxe.X();
1638
0
        nRotateY = nOldRotateY = aRotateAxe.Y();
1639
0
    }
1640
1641
0
    Degree100 nShearAngle(0);
1642
0
    tools::Long nShearX=0;
1643
0
    tools::Long nShearY=0;
1644
0
    bool bShearVert=false;
1645
1646
0
    bool bChgPos=false;
1647
0
    bool bChgSiz=false;
1648
0
    bool bChgWdh=false;
1649
0
    bool bChgHgt=false;
1650
0
    bool bRotate=false;
1651
0
    bool bShear =false;
1652
1653
0
    bool bSetAttr=false;
1654
0
    SfxItemSet aSetAttr(GetModel().GetItemPool());
1655
1656
    // position
1657
0
    if (const SfxInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_POS_X))
1658
0
    {
1659
0
        nPosDX = pPoolItem->GetValue() - aRect.Left();
1660
0
        bChgPos=true;
1661
0
    }
1662
0
    if (const SfxInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_POS_Y))
1663
0
    {
1664
0
        nPosDY = pPoolItem->GetValue() - aRect.Top();
1665
0
        bChgPos=true;
1666
0
    }
1667
    // size
1668
0
    if (const SfxUInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_WIDTH))
1669
0
    {
1670
0
        nSizX = pPoolItem->GetValue();
1671
0
        bChgSiz=true;
1672
0
        bChgWdh=true;
1673
0
    }
1674
0
    if (const SfxUInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_HEIGHT))
1675
0
    {
1676
0
        nSizY = pPoolItem->GetValue();
1677
0
        bChgSiz=true;
1678
0
        bChgHgt=true;
1679
0
    }
1680
1681
0
    if (bChgSiz)
1682
0
    {
1683
        // tdf#164285 the item was accessed even when not being set if
1684
        // false == comphelper::LibreOfficeKit::isActive(). For SlotIDs
1685
        // like SID_ATTR_TRANSFORM_SIZE_POINT this will crash by asserting
1686
        // due to SlotIDs having no defaults (see
1687
        // SfxItemPool::GetUserOrPoolDefaultItem line 725)
1688
0
        if (const SfxUInt16Item* pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_SIZE_POINT))
1689
0
            eSizePoint = static_cast<RectPoint>(pPoolItem->GetValue());
1690
0
        else if (comphelper::LibreOfficeKit::isActive())
1691
            // for TiledRendering the default which is set at the start of
1692
            // this method to RectPoint::MM seems purposely being changed to
1693
            // RectPoint::LT here - from a change 6 years ago. Note that this
1694
            // will make choosing another definition point in the UI for the
1695
            // PosSizeDialog except TopLeft not working when
1696
            // comphelper::LibreOfficeKit *is* active.
1697
0
            eSizePoint = RectPoint::LT;
1698
0
    }
1699
1700
    // rotation
1701
0
    if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_DELTA_ANGLE))
1702
0
    {
1703
0
        nRotateAngle = pPoolItem->GetValue();
1704
0
        bRotate = (nRotateAngle != 0_deg100);
1705
0
    }
1706
1707
    // rotation
1708
0
    if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_ANGLE))
1709
0
    {
1710
0
        nRotateAngle = pPoolItem->GetValue() - nOldRotateAngle;
1711
0
        bRotate = (nRotateAngle != 0_deg100);
1712
0
    }
1713
1714
    // position rotation point x
1715
0
    if(bRotate || rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_ROT_X))
1716
0
        nRotateX = rAttr.Get(SID_ATTR_TRANSFORM_ROT_X).GetValue();
1717
1718
    // position rotation point y
1719
0
    if(bRotate || rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_ROT_Y))
1720
0
        nRotateY = rAttr.Get(SID_ATTR_TRANSFORM_ROT_Y).GetValue();
1721
1722
    // shearing
1723
0
    if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_SHEAR))
1724
0
    {
1725
0
        Degree100 nNewShearAngle=pPoolItem->GetValue();
1726
0
        if (nNewShearAngle>SDRMAXSHEAR) nNewShearAngle=SDRMAXSHEAR;
1727
0
        if (nNewShearAngle<-SDRMAXSHEAR) nNewShearAngle=-SDRMAXSHEAR;
1728
0
        if (nNewShearAngle!=nOldShearAngle) {
1729
0
            bShearVert = rAttr.Get(SID_ATTR_TRANSFORM_SHEAR_VERTICAL).GetValue();
1730
0
            if (bShearVert) {
1731
0
                nShearAngle=nNewShearAngle;
1732
0
            } else {
1733
0
                if (nNewShearAngle!=0_deg100 && nOldShearAngle!=0_deg100) {
1734
                    // bug fix
1735
0
                    double nOld = tan(toRadians(nOldShearAngle));
1736
0
                    double nNew = tan(toRadians(nNewShearAngle));
1737
0
                    nNew-=nOld;
1738
0
                    nNew = basegfx::rad2deg<100>(atan(nNew));
1739
0
                    nShearAngle = Degree100(basegfx::fround(nNew));
1740
0
                } else {
1741
0
                    nShearAngle=nNewShearAngle-nOldShearAngle;
1742
0
                }
1743
0
            }
1744
0
            bShear=nShearAngle!=0_deg100;
1745
0
            if (bShear) {
1746
0
                nShearX = rAttr.Get(SID_ATTR_TRANSFORM_SHEAR_X).GetValue();
1747
0
                nShearY = rAttr.Get(SID_ATTR_TRANSFORM_SHEAR_Y).GetValue();
1748
0
            }
1749
0
        }
1750
0
    }
1751
1752
    // AutoGrow
1753
0
    if (const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_AUTOWIDTH))
1754
0
    {
1755
0
        bool bAutoGrow = pPoolItem->GetValue();
1756
0
        aSetAttr.Put(makeSdrTextAutoGrowWidthItem(bAutoGrow));
1757
0
        bSetAttr=true;
1758
0
    }
1759
1760
0
    if (const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_AUTOHEIGHT))
1761
0
    {
1762
0
        bool bAutoGrow = pPoolItem->GetValue();
1763
0
        aSetAttr.Put(makeSdrTextAutoGrowHeightItem(bAutoGrow));
1764
0
        bSetAttr=true;
1765
0
    }
1766
1767
    // corner radius
1768
0
    if (m_bEdgeRadiusAllowed)
1769
0
        if (const SdrMetricItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_CORNER_RADIUS))
1770
0
        {
1771
0
            tools::Long nRadius = pPoolItem->GetValue();
1772
0
            aSetAttr.Put(makeSdrEckenradiusItem(nRadius));
1773
0
            bSetAttr=true;
1774
0
        }
1775
1776
0
    ForcePossibilities();
1777
1778
0
    BegUndo(SvxResId(STR_EditTransform),rMarkList.GetMarkDescription());
1779
1780
0
    if (bSetAttr) {
1781
0
        SetAttrToMarked(aSetAttr,false);
1782
0
    }
1783
1784
    // change size and height
1785
0
    if (bChgSiz && (m_bResizeFreeAllowed || m_bResizePropAllowed)) {
1786
0
        auto nWidth = aRect.Right()-aRect.Left();
1787
0
        double aWdt = nWidth == 0 ? 0 : (double(nSizX) / nWidth);
1788
0
        auto nHeight = aRect.Bottom()-aRect.Top();
1789
0
        double aHgt = nHeight == 0 ? 0 : (double(nSizY) / nHeight);
1790
0
        Point aRef(ImpGetPoint(aRect,eSizePoint));
1791
1792
0
        if(GetSdrPageView())
1793
0
        {
1794
0
            GetSdrPageView()->PagePosToLogic(aRef);
1795
0
        }
1796
1797
0
        ResizeMultMarkedObj(aRef, aWdt, aHgt, bChgWdh, bChgHgt);
1798
0
    }
1799
1800
    // rotate
1801
0
    if (bRotate && (m_bRotateFreeAllowed || m_bRotate90Allowed)) {
1802
0
        Point aRef(nRotateX,nRotateY);
1803
1804
0
        if(GetSdrPageView())
1805
0
        {
1806
0
            GetSdrPageView()->PagePosToLogic(aRef);
1807
0
        }
1808
1809
0
        RotateMarkedObj(aRef,nRotateAngle);
1810
0
    }
1811
1812
    // set rotation point position
1813
0
    if(bModeIsRotate && (nRotateX != nOldRotateX || nRotateY != nOldRotateY))
1814
0
    {
1815
0
        Point aNewRef1(nRotateX, nRotateY);
1816
1817
0
        if(GetSdrPageView())
1818
0
        {
1819
0
            GetSdrPageView()->PagePosToLogic(aNewRef1);
1820
0
        }
1821
1822
0
        SetRef1(aNewRef1);
1823
0
    }
1824
1825
    // shear
1826
0
    if (bShear && m_bShearAllowed) {
1827
0
        Point aRef(nShearX,nShearY);
1828
1829
0
        if(GetSdrPageView())
1830
0
        {
1831
0
            GetSdrPageView()->PagePosToLogic(aRef);
1832
0
        }
1833
1834
0
        ShearMarkedObj(aRef,nShearAngle,bShearVert);
1835
1836
        // #i74358#
1837
        // ShearMarkedObj creates a linear combination of the existing transformation and
1838
        // the new shear to apply. If the object is already transformed (e.g. rotated) the
1839
        // linear combination will not decompose to the same start values again, but to a
1840
        // new combination. Thus it makes no sense to check if the wanted shear is reached
1841
        // or not. Taking out.
1842
0
    }
1843
1844
    // change position
1845
0
    bool bMoveAllowed = m_bMoveAllowed;
1846
0
    SfxViewShell* pViewShell = GetSfxViewShell();
1847
0
    if (!bMoveAllowed && pViewShell && pViewShell->GetSignPDFCertificate().Is())
1848
0
    {
1849
        // If the just added signature line shape is selected, allow moving it.
1850
0
        bMoveAllowed = true;
1851
0
    }
1852
0
    if (bChgPos && bMoveAllowed) {
1853
0
        MoveMarkedObj(Size(nPosDX,nPosDY));
1854
0
    }
1855
1856
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
1857
    // protect position
1858
0
    if(const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_PROTECT_POS))
1859
0
    {
1860
0
        const bool bProtPos(pPoolItem->GetValue());
1861
0
        bool bChanged(false);
1862
1863
0
        for(size_t i = 0; i < nMarkCount; ++i)
1864
0
        {
1865
0
            pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1866
1867
0
            if(pObj->IsMoveProtect() != bProtPos)
1868
0
            {
1869
0
                bChanged = true;
1870
0
                pObj->SetMoveProtect(bProtPos);
1871
1872
0
                if(bProtPos)
1873
0
                {
1874
0
                    pObj->SetResizeProtect(true);
1875
0
                }
1876
0
            }
1877
0
        }
1878
1879
0
        if(bChanged)
1880
0
        {
1881
0
            m_bMoveProtect = bProtPos;
1882
1883
0
            if(bProtPos)
1884
0
            {
1885
0
                m_bResizeProtect = true;
1886
0
            }
1887
1888
            // #i77187# there is no simple method to get the toolbars updated
1889
            // in the application. The App is listening to selection change and i
1890
            // will use it here (even if not true). It's acceptable since changing
1891
            // this model data is pretty rare and only possible using the F4 dialog
1892
0
            MarkListHasChanged();
1893
0
        }
1894
0
    }
1895
1896
0
    if(!m_bMoveProtect)
1897
0
    {
1898
        // protect size
1899
0
        if(const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_PROTECT_SIZE))
1900
0
        {
1901
0
            const bool bProtSize(pPoolItem->GetValue());
1902
0
            bool bChanged(false);
1903
1904
0
            for(size_t i = 0; i < nMarkCount; ++i)
1905
0
            {
1906
0
                pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1907
1908
0
                if(pObj->IsResizeProtect() != bProtSize)
1909
0
                {
1910
0
                    bChanged = true;
1911
0
                    pObj->SetResizeProtect(bProtSize);
1912
0
                }
1913
0
            }
1914
1915
0
            if(bChanged)
1916
0
            {
1917
0
                m_bResizeProtect = bProtSize;
1918
1919
                // #i77187# see above
1920
0
                MarkListHasChanged();
1921
0
            }
1922
0
        }
1923
0
    }
1924
1925
0
    EndUndo();
1926
0
}
1927
1928
1929
bool SdrEditView::IsAlignPossible() const
1930
0
{  // at least two selected objects, at least one of them movable
1931
0
    ForcePossibilities();
1932
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1933
0
    const size_t nCount=rMarkList.GetMarkCount();
1934
0
    if (nCount==0) return false;         // nothing selected!
1935
0
    if (nCount==1) return m_bMoveAllowed;  // align single object to page
1936
0
    return m_bOneOrMoreMovable;          // otherwise: MarkCount>=2
1937
0
}
1938
1939
void SdrEditView::AlignMarkedObjects(SdrHorAlign eHor, SdrVertAlign eVert)
1940
0
{
1941
0
    if (eHor==SdrHorAlign::NONE && eVert==SdrVertAlign::NONE)
1942
0
        return;
1943
1944
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
1945
0
    rMarkList.ForceSort();
1946
0
    if (!rMarkList.GetMarkCount())
1947
0
        return;
1948
1949
0
    const bool bUndo = IsUndoEnabled();
1950
0
    if( bUndo )
1951
0
    {
1952
0
        EndTextEditCurrentView();
1953
0
        OUString aStr(rMarkList.GetMarkDescription());
1954
0
        if (eHor==SdrHorAlign::NONE)
1955
0
        {
1956
0
            switch (eVert)
1957
0
            {
1958
0
                case SdrVertAlign::Top:
1959
0
                    aStr = ImpGetDescriptionString(STR_EditAlignVTop);
1960
0
                    break;
1961
0
                case SdrVertAlign::Bottom:
1962
0
                    aStr = ImpGetDescriptionString(STR_EditAlignVBottom);
1963
0
                    break;
1964
0
                case SdrVertAlign::Center:
1965
0
                    aStr = ImpGetDescriptionString(STR_EditAlignVCenter);
1966
0
                    break;
1967
0
                default: break;
1968
0
            }
1969
0
        }
1970
0
        else if (eVert==SdrVertAlign::NONE)
1971
0
        {
1972
0
            switch (eHor)
1973
0
            {
1974
0
                case SdrHorAlign::Left:
1975
0
                    aStr = ImpGetDescriptionString(STR_EditAlignHLeft);
1976
0
                    break;
1977
0
                case SdrHorAlign::Right:
1978
0
                    aStr = ImpGetDescriptionString(STR_EditAlignHRight);
1979
0
                    break;
1980
0
                case SdrHorAlign::Center:
1981
0
                    aStr = ImpGetDescriptionString(STR_EditAlignHCenter);
1982
0
                    break;
1983
0
                default: break;
1984
0
            }
1985
0
        }
1986
0
        else if (eHor==SdrHorAlign::Center && eVert==SdrVertAlign::Center)
1987
0
        {
1988
0
            aStr = ImpGetDescriptionString(STR_EditAlignCenter);
1989
0
        }
1990
0
        else
1991
0
        {
1992
0
            aStr = ImpGetDescriptionString(STR_EditAlign);
1993
0
        }
1994
0
        BegUndo(aStr);
1995
0
    }
1996
1997
0
    tools::Rectangle aBound;
1998
0
    const size_t nMarkCount=rMarkList.GetMarkCount();
1999
0
    bool bHasFixed=false;
2000
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
2001
0
    {
2002
0
        SdrMark* pM=rMarkList.GetMark(nm);
2003
0
        SdrObject* pObj=pM->GetMarkedSdrObj();
2004
0
        SdrObjTransformInfoRec aInfo;
2005
0
        pObj->TakeObjInfo(aInfo);
2006
0
        if (!aInfo.bMoveAllowed || pObj->IsMoveProtect())
2007
0
        {
2008
0
            tools::Rectangle aObjRect(pObj->GetSnapRect());
2009
0
            aBound.Union(aObjRect);
2010
0
            bHasFixed=true;
2011
0
        }
2012
0
    }
2013
0
    if (!bHasFixed)
2014
0
    {
2015
0
        if (nMarkCount==1)
2016
0
        {   // align single object to page
2017
0
            const SdrObject* pObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
2018
0
            const SdrPage* pPage=pObj->getSdrPageFromSdrObject();
2019
0
            const SdrPageGridFrameList* pGFL=pPage->GetGridFrameList(rMarkList.GetMark(0)->GetPageView(),&(pObj->GetSnapRect()));
2020
0
            const SdrPageGridFrame* pFrame=nullptr;
2021
0
            if (pGFL!=nullptr && pGFL->GetCount()!=0)
2022
0
            { // Writer
2023
0
                pFrame=&((*pGFL)[0]);
2024
0
            }
2025
2026
0
            if (pFrame!=nullptr)
2027
0
            { // Writer
2028
0
                aBound=pFrame->GetUserArea();
2029
0
            }
2030
0
            else
2031
0
            {
2032
0
                aBound=tools::Rectangle(pPage->GetLeftBorder(),pPage->GetUpperBorder(),
2033
0
                                 pPage->GetWidth()-pPage->GetRightBorder(),
2034
0
                                 pPage->GetHeight()-pPage->GetLowerBorder());
2035
0
            }
2036
0
        }
2037
0
        else
2038
0
        {
2039
0
            aBound=GetMarkedObjRect();
2040
0
        }
2041
0
    }
2042
0
    Point aCenter(aBound.Center());
2043
0
    for (size_t nm=0; nm<nMarkCount; ++nm)
2044
0
    {
2045
0
        SdrMark* pM=rMarkList.GetMark(nm);
2046
0
        SdrObject* pObj=pM->GetMarkedSdrObj();
2047
0
        SdrObjTransformInfoRec aInfo;
2048
0
        pObj->TakeObjInfo(aInfo);
2049
0
        if (aInfo.bMoveAllowed && !pObj->IsMoveProtect())
2050
0
        {
2051
0
            tools::Long nXMov=0;
2052
0
            tools::Long nYMov=0;
2053
0
            tools::Rectangle aObjRect(pObj->GetSnapRect());
2054
0
            switch (eVert)
2055
0
            {
2056
0
                case SdrVertAlign::Top   : nYMov=aBound.Top()   -aObjRect.Top()       ; break;
2057
0
                case SdrVertAlign::Bottom: nYMov=aBound.Bottom()-aObjRect.Bottom()    ; break;
2058
0
                case SdrVertAlign::Center: nYMov=aCenter.Y()    -aObjRect.Center().Y(); break;
2059
0
                default: break;
2060
0
            }
2061
0
            switch (eHor)
2062
0
            {
2063
0
                case SdrHorAlign::Left  : nXMov=aBound.Left()  -aObjRect.Left()      ; break;
2064
0
                case SdrHorAlign::Right : nXMov=aBound.Right() -aObjRect.Right()     ; break;
2065
0
                case SdrHorAlign::Center: nXMov=aCenter.X()    -aObjRect.Center().X(); break;
2066
0
                default: break;
2067
0
            }
2068
0
            if (nXMov!=0 || nYMov!=0)
2069
0
            {
2070
                // SdrEdgeObj needs an extra SdrUndoGeoObj since the
2071
                // connections may need to be saved
2072
0
                if( bUndo )
2073
0
                {
2074
0
                    if( dynamic_cast<SdrEdgeObj*>(pObj) )
2075
0
                    {
2076
0
                        AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
2077
0
                    }
2078
2079
0
                    AddUndo(GetModel().GetSdrUndoFactory().CreateUndoMoveObject(*pObj,Size(nXMov,nYMov)));
2080
0
                }
2081
2082
0
                pObj->Move(Size(nXMov,nYMov));
2083
0
            }
2084
0
        }
2085
0
    }
2086
2087
0
    if( bUndo )
2088
0
        EndUndo();
2089
0
}
2090
2091
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */