Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdpagv.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 <svx/svdpagv.hxx>
21
#include <svx/svdpage.hxx>
22
#include <svx/svdview.hxx>
23
24
#include <svx/svdobj.hxx>
25
#include <svx/svdogrp.hxx>
26
#include <svx/svdtypes.hxx>
27
28
#include <svx/sdr/contact/objectcontact.hxx>
29
#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
30
31
#include <algorithm>
32
33
#include <svx/sdrpagewindow.hxx>
34
#include <svx/sdrpaintwindow.hxx>
35
#include <toolkit/controls/unocontrolcontainer.hxx>
36
#include <comphelper/lok.hxx>
37
#include <comphelper/scopeguard.hxx>
38
#include <basegfx/range/b2irectangle.hxx>
39
#include <osl/diagnose.h>
40
#include <vcl/rendercontext/DrawGridFlags.hxx>
41
42
using namespace ::com::sun::star;
43
44
// interface to SdrPageWindow
45
46
SdrPageWindow* SdrPageView::FindPageWindow(const SdrPaintWindow& rPaintWindow) const
47
235k
{
48
235k
    for(auto & a : maPageWindows)
49
174k
    {
50
174k
        if(&(a->GetPaintWindow()) == &rPaintWindow)
51
174k
        {
52
174k
            return a.get();
53
174k
        }
54
174k
    }
55
56
60.8k
    return nullptr;
57
235k
}
58
59
const SdrPageWindow* SdrPageView::FindPatchedPageWindow( const OutputDevice& _rOutDev ) const
60
0
{
61
0
    for ( auto const & pPageWindow : maPageWindows )
62
0
    {
63
0
        const SdrPaintWindow& rPaintWindow( pPageWindow->GetOriginalPaintWindow() ? *pPageWindow->GetOriginalPaintWindow() : pPageWindow->GetPaintWindow() );
64
0
        if ( &rPaintWindow.GetOutputDevice() == &_rOutDev )
65
0
        {
66
0
            return pPageWindow.get();
67
0
        }
68
0
    }
69
70
0
    return nullptr;
71
0
}
72
73
SdrPageWindow* SdrPageView::FindPageWindow(const OutputDevice& rOutDev) const
74
172k
{
75
172k
    for ( auto const & pPageWindow : maPageWindows )
76
172k
    {
77
172k
        if(&(pPageWindow->GetPaintWindow().GetOutputDevice()) == &rOutDev)
78
172k
        {
79
172k
            return pPageWindow.get();
80
172k
        }
81
172k
    }
82
83
0
    return nullptr;
84
172k
}
85
86
SdrPageWindow* SdrPageView::GetPageWindow(sal_uInt32 nIndex) const
87
186
{
88
186
    return maPageWindows[nIndex].get();
89
186
}
90
91
SdrPageView::SdrPageView(SdrPage* pPage1, SdrView& rNewView)
92
60.8k
:   mrView(rNewView),
93
    // col_auto color lets the view takes the default SvxColorConfig entry
94
60.8k
    maDocumentColor( COL_AUTO ),
95
60.8k
    maBackgroundColor( COL_AUTO ), // #i48367# also react on autocolor
96
60.8k
    mpPreparedPageWindow(nullptr) // #i72752#
97
60.8k
{
98
60.8k
    mpPage = pPage1;
99
100
60.8k
    if(mpPage)
101
60.8k
    {
102
60.8k
        maPageOrigin.setX(mpPage->GetLeftBorder() );
103
60.8k
        maPageOrigin.setY(mpPage->GetUpperBorder() );
104
60.8k
    }
105
    // For example, in the case of charts, there is a LayerAdmin, but it has no valid values. Therefore
106
    // a solution like pLayerAdmin->getVisibleLayersODF(aLayerVisi) is not possible. So use the
107
    // generic SetAll() for now.
108
60.8k
    m_aLayerVisi.SetAll();
109
60.8k
    m_aLayerPrn.SetAll();
110
111
60.8k
    mbHasMarked = false;
112
60.8k
    mbVisible = false;
113
60.8k
    m_pCurrentList = nullptr;
114
60.8k
    m_pCurrentGroup = nullptr;
115
60.8k
    SetCurrentGroupAndList(nullptr, mpPage);
116
117
121k
    for(sal_uInt32 a(0); a < rNewView.PaintWindowCount(); a++)
118
60.8k
    {
119
60.8k
        AddPaintWindowToPageView(*rNewView.GetPaintWindow(a));
120
60.8k
    }
121
60.8k
}
122
123
SdrPageView::~SdrPageView()
124
60.8k
{
125
60.8k
}
126
127
void SdrPageView::AddPaintWindowToPageView(SdrPaintWindow& rPaintWindow)
128
121k
{
129
121k
    if(!FindPageWindow(rPaintWindow))
130
60.8k
    {
131
60.8k
        maPageWindows.emplace_back(new SdrPageWindow(*this, rPaintWindow));
132
60.8k
    }
133
121k
}
134
135
void SdrPageView::RemovePaintWindowFromPageView(SdrPaintWindow& rPaintWindow)
136
0
{
137
0
    auto it = std::find_if(maPageWindows.begin(), maPageWindows.end(),
138
0
        [&rPaintWindow](const std::unique_ptr<SdrPageWindow>& rpWindow) {
139
0
            return &(rpWindow->GetPaintWindow()) == &rPaintWindow;
140
0
        });
141
0
    if (it != maPageWindows.end())
142
0
        maPageWindows.erase(it);
143
0
}
144
145
rtl::Reference< UnoControlContainer > SdrPageView::GetControlContainer( const OutputDevice& _rDevice ) const
146
0
{
147
0
    rtl::Reference< UnoControlContainer > xReturn;
148
0
    const SdrPageWindow* pCandidate = FindPatchedPageWindow( _rDevice );
149
150
0
    if ( pCandidate )
151
0
        xReturn = pCandidate->GetControlContainer();
152
153
0
    return xReturn;
154
0
}
155
156
void SdrPageView::ModelHasChanged()
157
0
{
158
0
    if (GetCurrentGroup()!=nullptr) CheckCurrentGroup();
159
0
}
160
161
bool SdrPageView::IsReadOnly() const
162
0
{
163
0
    return (nullptr == GetPage() || GetView().GetModel().IsReadOnly() || GetPage()->IsReadOnly() || GetObjList()->IsReadOnly());
164
0
}
165
166
void SdrPageView::Show()
167
60.8k
{
168
60.8k
    if(!IsVisible())
169
60.8k
    {
170
60.8k
        mbVisible = true;
171
172
121k
        for(sal_uInt32 a(0); a < GetView().PaintWindowCount(); a++)
173
60.8k
        {
174
60.8k
            AddPaintWindowToPageView(*GetView().GetPaintWindow(a));
175
60.8k
        }
176
60.8k
    }
177
60.8k
}
178
179
void SdrPageView::Hide()
180
60.8k
{
181
60.8k
    if(IsVisible())
182
60.8k
    {
183
60.8k
        if (!comphelper::LibreOfficeKit::isActive())
184
60.8k
        {
185
60.8k
            InvalidateAllWin();
186
60.8k
        }
187
60.8k
        mbVisible = false;
188
60.8k
        maPageWindows.clear();
189
60.8k
    }
190
60.8k
}
191
192
tools::Rectangle SdrPageView::GetPageRect() const
193
0
{
194
0
    if (GetPage()==nullptr) return tools::Rectangle();
195
0
    return tools::Rectangle(Point(),Size(GetPage()->GetWidth()+1,GetPage()->GetHeight()+1));
196
0
}
197
198
void SdrPageView::InvalidateAllWin()
199
243k
{
200
243k
    if(IsVisible() && GetPage())
201
243k
    {
202
243k
        tools::Rectangle aRect(Point(0,0),Size(GetPage()->GetWidth()+1,GetPage()->GetHeight()+1));
203
243k
        aRect.Union(GetPage()->GetAllObjBoundRect());
204
243k
        GetView().InvalidateAllWin(aRect);
205
243k
    }
206
243k
}
207
208
209
void SdrPageView::PrePaint()
210
0
{
211
0
    const sal_uInt32 nCount(PageWindowCount());
212
213
0
    for(sal_uInt32 a(0); a < nCount; a++)
214
0
    {
215
0
        SdrPageWindow* pCandidate = GetPageWindow(a);
216
217
0
        if(pCandidate)
218
0
        {
219
0
            pCandidate->PrePaint();
220
0
        }
221
0
    }
222
0
}
223
224
void SdrPageView::CompleteRedraw(
225
    SdrPaintWindow& rPaintWindow, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector )
226
0
{
227
0
    if(!GetPage())
228
0
        return;
229
230
0
    SdrPageWindow* pPageWindow = FindPageWindow(rPaintWindow);
231
0
    std::unique_ptr<SdrPageWindow> pTempPageWindow;
232
233
0
    if(!pPageWindow)
234
0
    {
235
        // create temp PageWindow
236
0
        pTempPageWindow.reset(new SdrPageWindow(*this, rPaintWindow));
237
0
        pPageWindow = pTempPageWindow.get();
238
0
    }
239
240
    // do the redraw
241
0
    pPageWindow->PrepareRedraw(rReg);
242
0
    pPageWindow->RedrawAll(pRedirector);
243
0
}
244
245
246
// #i74769# use SdrPaintWindow directly
247
248
void SdrPageView::setPreparedPageWindow(SdrPageWindow* pKnownTarget)
249
227k
{
250
    // #i72752# remember prepared SdrPageWindow
251
227k
    mpPreparedPageWindow = pKnownTarget;
252
227k
}
253
254
void SdrPageView::DrawLayer(SdrLayerID nID, OutputDevice* pGivenTarget,
255
        sdr::contact::ViewObjectContactRedirector* pRedirector,
256
        const tools::Rectangle& rRect, basegfx::B2IRectangle const*const pPageFrame)
257
171k
{
258
171k
    if(!GetPage())
259
0
        return;
260
261
171k
    if(pGivenTarget)
262
171k
    {
263
171k
        SdrPageWindow* pKnownTarget = FindPageWindow(*pGivenTarget);
264
265
171k
        if(pKnownTarget)
266
171k
        {
267
            // paint known target
268
171k
            pKnownTarget->RedrawLayer(&nID, pRedirector, pPageFrame);
269
171k
        }
270
0
        else
271
0
        {
272
            // #i72752# DrawLayer() uses an OutputDevice different from BeginDrawLayer. This happens
273
            // e.g. when SW paints a single text line in text edit mode. Try to use it
274
0
            SdrPageWindow* pPreparedTarget = mpPreparedPageWindow;
275
276
0
            if(pPreparedTarget)
277
0
            {
278
                // if we have a prepared target, do not use a new SdrPageWindow since this
279
                // works but is expensive. Just use a temporary PaintWindow
280
0
                SdrPaintWindow aTemporaryPaintWindow(mrView, *pGivenTarget);
281
282
                // Copy existing paint region to use the same as prepared in BeginDrawLayer
283
0
                SdrPaintWindow& rExistingPaintWindow = pPreparedTarget->GetPaintWindow();
284
0
                const vcl::Region& rExistingRegion = rExistingPaintWindow.GetRedrawRegion();
285
0
                bool bUseRect(false);
286
0
                if (!rRect.IsEmpty())
287
0
                {
288
0
                    vcl::Region r(rExistingRegion);
289
0
                    r.Intersect(rRect);
290
                    // fdo#74435: FIXME: visibility check broken if empty
291
0
                    if (!r.IsEmpty())
292
0
                        bUseRect = true;
293
0
                }
294
0
                if (!bUseRect)
295
0
                    aTemporaryPaintWindow.SetRedrawRegion(rExistingRegion);
296
0
                else
297
0
                    aTemporaryPaintWindow.SetRedrawRegion(vcl::Region(rRect));
298
299
                // patch the ExistingPageWindow
300
0
                auto pPreviousWindow = pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow);
301
                // unpatch window when leaving the scope
302
0
                const ::comphelper::ScopeGuard aGuard(
303
0
                    [&pPreviousWindow, &pPreparedTarget]() { pPreparedTarget->unpatchPaintWindow(pPreviousWindow); } );
304
                // redraw the layer
305
0
                pPreparedTarget->RedrawLayer(&nID, pRedirector, pPageFrame);
306
0
            }
307
0
            else
308
0
            {
309
0
                OSL_FAIL("SdrPageView::DrawLayer: Creating temporary SdrPageWindow (ObjectContact), this should never be needed (!)");
310
311
                // None of the known OutputDevices is the target of this paint, use
312
                // a temporary SdrPageWindow for this Redraw.
313
0
                SdrPaintWindow aTemporaryPaintWindow(mrView, *pGivenTarget);
314
0
                SdrPageWindow aTemporaryPageWindow(*this, aTemporaryPaintWindow);
315
316
                // #i72752#
317
                // Copy existing paint region if other PageWindows exist, this was created by
318
                // PrepareRedraw() from BeginDrawLayer(). Needs to be used e.g. when suddenly SW
319
                // paints into an unknown device other than the view was created for (e.g. VirtualDevice)
320
0
                if(PageWindowCount())
321
0
                {
322
0
                    SdrPageWindow* pExistingPageWindow = GetPageWindow(0);
323
0
                    SdrPaintWindow& rExistingPaintWindow = pExistingPageWindow->GetPaintWindow();
324
0
                    const vcl::Region& rExistingRegion = rExistingPaintWindow.GetRedrawRegion();
325
0
                    aTemporaryPaintWindow.SetRedrawRegion(rExistingRegion);
326
0
                }
327
328
0
                aTemporaryPageWindow.RedrawLayer(&nID, pRedirector, nullptr);
329
0
            }
330
0
        }
331
171k
    }
332
0
    else
333
0
    {
334
        // paint in all known windows
335
0
        for(sal_uInt32 a(0); a < PageWindowCount(); a++)
336
0
        {
337
0
            SdrPageWindow* pTarget = GetPageWindow(a);
338
0
            pTarget->RedrawLayer(&nID, pRedirector, nullptr);
339
0
        }
340
0
    }
341
171k
}
342
343
void SdrPageView::SetDesignMode( bool _bDesignMode ) const
344
0
{
345
0
    for ( sal_uInt32 i = 0; i < PageWindowCount(); ++i )
346
0
    {
347
0
        const SdrPageWindow& rPageViewWindow = *GetPageWindow(i);
348
0
        rPageViewWindow.SetDesignMode( _bDesignMode );
349
0
    }
350
0
}
351
352
353
void SdrPageView::DrawPageViewGrid(OutputDevice& rOut, const tools::Rectangle& rRect, Color aColor)
354
0
{
355
0
    if (GetPage()==nullptr)
356
0
        return;
357
358
0
    tools::Long nx1=GetView().maGridBig.Width();
359
0
    tools::Long nx2=GetView().maGridFin.Width();
360
0
    tools::Long ny1=GetView().maGridBig.Height();
361
0
    tools::Long ny2=GetView().maGridFin.Height();
362
363
0
    if (nx1==0) nx1=nx2;
364
0
    if (nx2==0) nx2=nx1;
365
0
    if (ny1==0) ny1=ny2;
366
0
    if (ny2==0) ny2=ny1;
367
0
    if (nx1==0) { nx1=ny1; nx2=ny2; }
368
0
    if (ny1==0) { ny1=nx1; ny2=nx2; }
369
0
    if (nx1<0) nx1=-nx1;
370
0
    if (nx2<0) nx2=-nx2;
371
0
    if (ny1<0) ny1=-ny1;
372
0
    if (ny2<0) ny2=-ny2;
373
374
0
    if (nx1==0)
375
0
        return;
376
377
    // no more global output size, use window size instead to decide grid sizes
378
0
    tools::Long nScreenWdt = rOut.GetOutputSizePixel().Width();
379
380
0
    tools::Long nMinDotPix=2;
381
0
    tools::Long nMinLinPix=4;
382
383
0
    if (nScreenWdt>=1600)
384
0
    {
385
0
        nMinDotPix=4;
386
0
        nMinLinPix=8;
387
0
    }
388
0
    else if (nScreenWdt>=1024)
389
0
    {
390
0
        nMinDotPix=3;
391
0
        nMinLinPix=6;
392
0
    }
393
0
    else
394
0
    { // e. g. 640x480
395
0
        nMinDotPix=2;
396
0
        nMinLinPix=4;
397
0
    }
398
0
    Size aMinDotDist(rOut.PixelToLogic(Size(nMinDotPix,nMinDotPix)));
399
0
    Size aMinLinDist(rOut.PixelToLogic(Size(nMinLinPix,nMinLinPix)));
400
0
    bool bHoriSolid=nx2<aMinDotDist.Width();
401
0
    bool bVertSolid=ny2<aMinDotDist.Height();
402
    // enlarge line offset (minimum 4 pixels)
403
    // enlarge by: *2 *5 *10 *20 *50 *100 ...
404
0
    int nTgl=0;
405
0
    tools::Long nVal0=nx1;
406
0
    while (nx1<aMinLinDist.Width())
407
0
    {
408
0
        tools::Long a=nx1;
409
410
0
        if (nTgl==0) nx1*=2;
411
0
        if (nTgl==1) nx1=nVal0*5; // => nx1*=2.5
412
0
        if (nTgl==2) nx1*=2;
413
414
0
        nVal0=a;
415
0
        nTgl++; if (nTgl>=3) nTgl=0;
416
0
    }
417
0
    nTgl=0;
418
0
    nVal0=ny1;
419
0
    while (ny1<aMinLinDist.Height())
420
0
    {
421
0
        tools::Long a=ny1;
422
423
0
        if (nTgl==0) ny1*=2;
424
0
        if (nTgl==1) ny1=nVal0*5; // => ny1*=2.5
425
0
        if (nTgl==2) ny1*=2;
426
427
0
        nVal0=a;
428
0
        nTgl++;
429
430
0
        if (nTgl>=3) nTgl=0;
431
0
    }
432
433
0
    assert(nx1 > 0);
434
0
    assert(nx2 > 0);
435
0
    assert(ny1 > 0);
436
0
    assert(ny2 > 0);
437
438
0
    bool bHoriFine=nx2<nx1;
439
0
    bool bVertFine=ny2<ny1;
440
0
    bool bHoriLines=bHoriSolid || bHoriFine || !bVertFine;
441
0
    bool bVertLines=bVertSolid || bVertFine;
442
443
0
    Color aOriginalLineColor( rOut.GetLineColor() );
444
0
    rOut.SetLineColor( aColor );
445
446
0
    bool bMap0=rOut.IsMapModeEnabled();
447
448
0
    Point aGridOrigin(maPageOrigin);
449
0
    tools::Long x1 = 0;
450
0
    tools::Long x2 = 0;
451
0
    if (GetPage()->GetWidth() < 0) // ScDrawPage of RTL sheet
452
0
    {
453
0
        x1 = GetPage()->GetWidth() + GetPage()->GetLeftBorder() + 1;
454
0
        x2 = - GetPage()->GetRightBorder() - 1;
455
0
    }
456
0
    else
457
0
    {
458
0
        x1 = GetPage()->GetLeftBorder() + 1;
459
0
        x2 = GetPage()->GetWidth() - GetPage()->GetRightBorder() - 1;
460
0
    }
461
0
    tools::Long y1 = GetPage()->GetUpperBorder() + 1;
462
0
    tools::Long y2 = GetPage()->GetHeight() - GetPage()->GetLowerBorder() - 1;
463
0
    const SdrPageGridFrameList* pFrames=GetPage()->GetGridFrameList(this,nullptr);
464
465
0
    sal_uInt16 nGridPaintCnt=1;
466
0
    if (pFrames!=nullptr) nGridPaintCnt=pFrames->GetCount();
467
0
    for (sal_uInt16 nGridPaintNum=0; nGridPaintNum<nGridPaintCnt; nGridPaintNum++) {
468
0
        if (pFrames!=nullptr) {
469
0
            const SdrPageGridFrame& rGF=(*pFrames)[nGridPaintNum];
470
0
            x1=rGF.GetUserArea().Left();
471
0
            x2=rGF.GetUserArea().Right();
472
0
            y1=rGF.GetUserArea().Top();
473
0
            y2=rGF.GetUserArea().Bottom();
474
0
            aGridOrigin=rGF.GetUserArea().TopLeft();
475
0
        }
476
0
        const tools::Rectangle aGridBoundingBox(x1, y1, x2, y2);
477
0
        if (!rRect.IsEmpty()) {
478
0
            Size a1PixSiz(rOut.PixelToLogic(Size(1,1)));
479
0
            tools::Long nX1Pix=a1PixSiz.Width();  // add 1 pixel of tolerance
480
0
            tools::Long nY1Pix=a1PixSiz.Height();
481
0
            if (x1<rRect.Left()  -nX1Pix) x1=rRect.Left()  -nX1Pix;
482
0
            if (x2>rRect.Right() +nX1Pix) x2=rRect.Right() +nX1Pix;
483
0
            if (y1<rRect.Top()   -nY1Pix) y1=rRect.Top()   -nY1Pix;
484
0
            if (y2>rRect.Bottom()+nY1Pix) y2=rRect.Bottom()+nY1Pix;
485
0
        }
486
487
0
        tools::Long xBigOrg=aGridOrigin.X();
488
0
        while (xBigOrg>=x1) xBigOrg-=nx1;
489
0
        while (xBigOrg<x1) xBigOrg+=nx1;
490
0
        tools::Long xFinOrg=xBigOrg;
491
0
        while (xFinOrg>=x1) xFinOrg-=nx2;
492
0
        while (xFinOrg<x1) xFinOrg+=nx2;
493
494
0
        tools::Long yBigOrg=aGridOrigin.Y();
495
0
        while (yBigOrg>=y1) yBigOrg-=ny1;
496
0
        while (yBigOrg<y1) yBigOrg+=ny1;
497
0
        tools::Long yFinOrg=yBigOrg;
498
0
        while (yFinOrg>=y1) yFinOrg-=ny2;
499
0
        while (yFinOrg<y1) yFinOrg+=ny2;
500
501
0
        if( x1 <= x2 && y1 <= y2 )
502
0
        {
503
0
            const tools::Rectangle aDrawingArea(x1, y1, x2, y2);
504
0
            if( bHoriLines )
505
0
            {
506
0
                if( bHoriSolid )
507
0
                {
508
                    // Make sure the origin of the subgrid is within the drawing area
509
0
                    const Point aSubGridPosition(x1, yBigOrg);
510
0
                    if (aDrawingArea.Contains(aSubGridPosition))
511
0
                    {
512
                        // draw
513
0
                        rOut.DrawGrid(
514
0
                            tools::Rectangle( aSubGridPosition, Point(x2, y2) ),
515
0
                            Size( nx1, ny1 ), DrawGridFlags::HorzLines );
516
0
                    }
517
0
                }
518
0
                else
519
0
                {
520
0
                    const sal_uInt16 nSteps = static_cast<sal_uInt16>(nx1 / nx2);
521
0
                    if (nSteps != 0)
522
0
                    {
523
                        // Use one of the main grid points as anchor for consistent positioning
524
0
                        const tools::Long nAnchorPos = aGridOrigin.X() + (((xFinOrg - aGridOrigin.X()) / nx1) * nx1);
525
0
                        sal_uInt16 nStartStep = std::round(static_cast<double>(xFinOrg - nAnchorPos) / static_cast<double>(nx2));
526
527
                        // The first grid position might be outside of the drawing area, then start with the next one
528
0
                        if(nAnchorPos + ((nx1 * nStartStep) / nSteps) < aDrawingArea.Left())
529
0
                        {
530
0
                            nStartStep += 1;
531
0
                        }
532
533
0
                        for(sal_uInt16 a=0;a<nSteps;a++)
534
0
                        {
535
0
                            Point aSubGridPosition(nAnchorPos + ((nx1 * (nStartStep + a)) / nSteps), yBigOrg);
536
0
                            if(aSubGridPosition.X() == xBigOrg) // Main grid points
537
0
                            {
538
                                // For cross rendering we need an extended grid area to handle partly rendered grid markers
539
0
                                if(aGridBoundingBox.Contains(Point(aSubGridPosition.X() - nx1, aSubGridPosition.Y())))
540
0
                                {
541
0
                                    aSubGridPosition.Move(-nx1, 0);
542
0
                                }
543
544
0
                                if(aGridBoundingBox.Contains(Point(aSubGridPosition.X(), aSubGridPosition.Y() - ny1)))
545
0
                                {
546
0
                                    aSubGridPosition.Move(0, -ny1);
547
0
                                }
548
0
                                rOut.DrawGridOfCrosses(
549
0
                                    tools::Rectangle( aSubGridPosition,
550
0
                                        Point(std::min(x2 + nx1, aGridBoundingBox.Right()), std::min(y2 + ny1, aGridBoundingBox.Bottom()))),
551
0
                                    Size( nx1, ny1 ), aDrawingArea );
552
0
                            }
553
0
                            else // Subdivision points
554
0
                            {
555
                                // Make sure the origin of the subgrid is within the drawing area
556
0
                                if(!aDrawingArea.Contains(aSubGridPosition))
557
0
                                {
558
0
                                    continue;
559
0
                                }
560
561
                                // draw
562
0
                                rOut.DrawGrid(
563
0
                                    tools::Rectangle( aSubGridPosition, Point(x2, y2) ),
564
0
                                    Size( nx1, ny1 ), DrawGridFlags::Dots );
565
0
                            }
566
0
                        }
567
0
                    }
568
0
                }
569
0
            }
570
571
0
            if( bVertLines )
572
0
            {
573
0
                if( bVertSolid )
574
0
                {
575
                    // Make sure the origin of the subgrid is within the drawing area
576
0
                    const Point aSubGridPosition(xBigOrg, y1);
577
0
                    if (aDrawingArea.Contains(aSubGridPosition))
578
0
                    {
579
                        // draw
580
0
                        rOut.DrawGrid(
581
0
                            tools::Rectangle( aSubGridPosition, Point(x2, y2) ),
582
0
                            Size( nx1, ny1 ), DrawGridFlags::VertLines );
583
0
                    }
584
0
                }
585
0
                else
586
0
                {
587
0
                    const sal_uInt16 nSteps = static_cast<sal_uInt16>(ny1 / ny2);
588
0
                    if (nSteps != 0)
589
0
                    {
590
                        // Use one of the main grid points as anchor for consistent positioning
591
0
                        const tools::Long nAnchorPos = aGridOrigin.Y() + (((yFinOrg - aGridOrigin.Y()) / ny1) * ny1);
592
0
                        sal_uInt16 nStartStep = std::round(static_cast<double>(yFinOrg - nAnchorPos) / static_cast<double>(ny2));
593
594
                        // The first grid position might be outside of the drawing area, then start with the next one
595
0
                        if(nAnchorPos + ((ny1 * nStartStep) / nSteps) < aDrawingArea.Top())
596
0
                        {
597
0
                            nStartStep += 1;
598
0
                        }
599
600
0
                        for(sal_uInt16 a=0;a<nSteps;a++)
601
0
                        {
602
0
                            Point aSubGridPosition(xBigOrg, nAnchorPos + ((ny1 * (nStartStep + a)) / nSteps));
603
0
                            if(aSubGridPosition.Y() == yBigOrg) // Main grid points
604
0
                            {
605
                                // For cross rendering we need an extended grid area to handle partly rendered grid markers
606
0
                                if(aGridBoundingBox.Contains(Point(aSubGridPosition.X() - nx1, aSubGridPosition.Y())))
607
0
                                {
608
0
                                    aSubGridPosition.Move(-nx1, 0);
609
0
                                }
610
611
0
                                if(aGridBoundingBox.Contains(Point(aSubGridPosition.X(), aSubGridPosition.Y() - ny1)))
612
0
                                {
613
0
                                    aSubGridPosition.Move(0, -ny1);
614
0
                                }
615
0
                                rOut.DrawGridOfCrosses(
616
0
                                    tools::Rectangle( aSubGridPosition,
617
0
                                        Point(std::min(x2 + nx1, aGridBoundingBox.Right()), std::min(y2 + ny1, aGridBoundingBox.Bottom()))),
618
0
                                    Size( nx1, ny1 ), aDrawingArea );
619
0
                            }
620
0
                            else // Subdivision points
621
0
                            {
622
                                // Make sure the origin of the subgrid is within the drawing area
623
0
                                if(!aDrawingArea.Contains(aSubGridPosition))
624
0
                                {
625
0
                                    continue;
626
0
                                }
627
628
                                // draw
629
0
                                rOut.DrawGrid(
630
0
                                    tools::Rectangle( aSubGridPosition, Point(x2, y2) ),
631
0
                                    Size( nx1, ny1 ), DrawGridFlags::Dots );
632
0
                            }
633
0
                        }
634
0
                    }
635
0
                }
636
0
            }
637
0
        }
638
0
    }
639
640
0
    rOut.EnableMapMode(bMap0);
641
0
    rOut.SetLineColor(aOriginalLineColor);
642
0
}
643
644
void SdrPageView::AdjHdl()
645
182k
{
646
182k
    GetView().AdjustMarkHdl();
647
182k
}
648
649
// return true if changed, false if unchanged
650
bool SdrPageView::SetLayer(const OUString& rName, SdrLayerIDSet& rBS, bool bJa)
651
296k
{
652
296k
    if (!GetPage())
653
0
        return false;
654
655
296k
    SdrLayerID nID = GetPage()->GetLayerAdmin().GetLayerID(rName);
656
657
296k
    if (SDRLAYER_NOTFOUND == nID)
658
0
        return false;
659
660
296k
    if (rBS.IsSet(nID) == bJa)
661
113k
        return false;
662
663
182k
    rBS.Set(nID, bJa);
664
182k
    return true;
665
296k
}
666
667
bool SdrPageView::IsLayer(const OUString& rName, const SdrLayerIDSet& rBS) const
668
56.8k
{
669
56.8k
    if(!GetPage())
670
0
        return false;
671
672
56.8k
    bool bRet(false);
673
674
56.8k
    if (!rName.isEmpty())
675
56.8k
    {
676
56.8k
        SdrLayerID nId = GetPage()->GetLayerAdmin().GetLayerID(rName);
677
678
56.8k
        if(SDRLAYER_NOTFOUND != nId)
679
56.8k
        {
680
56.8k
            bRet = rBS.IsSet(nId);
681
56.8k
        }
682
56.8k
    }
683
684
56.8k
    return bRet;
685
56.8k
}
686
687
bool SdrPageView::IsObjMarkable(SdrObject const * pObj) const
688
30
{
689
30
    if (!pObj)
690
0
        return false;
691
30
    if (pObj->IsMarkProtect())
692
0
        return false;    // excluded from selection?
693
30
    if (!pObj->IsVisible())
694
0
        return false;    // only visible are selectable
695
30
    if (!pObj->IsInserted())
696
0
        return false;    // Obj deleted?
697
30
    if (auto pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
698
0
    {
699
        // If object is a Group object, visibility may depend on
700
        // multiple layers. If one object is markable, Group is markable.
701
0
        SdrObjList* pObjList = pObjGroup->GetSubList();
702
703
0
        if (pObjList && pObjList->GetObjCount())
704
0
        {
705
0
            for (const rtl::Reference<SdrObject>& pCandidate : *pObjList)
706
0
            {
707
                // call recursively
708
0
                if (IsObjMarkable(pCandidate.get()))
709
0
                    return true;
710
0
            }
711
0
            return false;
712
0
        }
713
0
        else
714
0
        {
715
            // #i43302#
716
            // Allow empty groups to be selected to be able to delete them
717
0
            return true;
718
0
        }
719
0
    }
720
30
    if (!pObj->Is3DObj() && pObj->getSdrPageFromSdrObject() != GetPage())
721
0
    {
722
        // Obj suddenly in different Page
723
0
        return false;
724
0
    }
725
726
    // the layer has to be visible and must not be locked
727
30
    SdrLayerID nL = pObj->GetLayer();
728
30
    if (!m_aLayerVisi.IsSet(nL))
729
0
        return false;
730
30
    if (m_aLayerLock.IsSet(nL))
731
0
        return false;
732
30
    return true;
733
30
}
734
735
void SdrPageView::SetPageOrigin(const Point& rOrg)
736
0
{
737
0
    if (rOrg != maPageOrigin)
738
0
    {
739
0
        maPageOrigin = rOrg;
740
0
        if (GetView().IsGridVisible())
741
0
        {
742
0
            InvalidateAllWin();
743
0
        }
744
0
    }
745
0
}
746
747
void SdrPageView::ImpInvalidateHelpLineArea(sal_uInt16 nNum) const
748
0
{
749
0
    if (!(GetView().IsHlplVisible() && nNum<m_aHelpLines.GetCount()))        return;
750
751
0
    const SdrHelpLine& rHL=m_aHelpLines[nNum];
752
753
0
    for(sal_uInt32 a(0); a < GetView().PaintWindowCount(); a++)
754
0
    {
755
0
        SdrPaintWindow* pCandidate = GetView().GetPaintWindow(a);
756
757
0
        if(pCandidate->OutputToWindow())
758
0
        {
759
0
            OutputDevice& rOutDev = pCandidate->GetOutputDevice();
760
0
            tools::Rectangle aR(rHL.GetBoundRect(rOutDev));
761
0
            Size aSiz(rOutDev.PixelToLogic(Size(1,1)));
762
0
            aR.AdjustLeft( -(aSiz.Width()) );
763
0
            aR.AdjustRight(aSiz.Width() );
764
0
            aR.AdjustTop( -(aSiz.Height()) );
765
0
            aR.AdjustBottom(aSiz.Height() );
766
0
            const_cast<SdrView&>(GetView()).InvalidateOneWin(rOutDev, aR);
767
0
        }
768
0
    }
769
0
}
770
771
void SdrPageView::SetHelpLines(const SdrHelpLineList& rHLL)
772
0
{
773
0
    m_aHelpLines=rHLL;
774
0
    InvalidateAllWin();
775
0
}
776
777
void SdrPageView::SetHelpLine(sal_uInt16 nNum, const SdrHelpLine& rNewHelpLine)
778
0
{
779
0
    if (nNum >= m_aHelpLines.GetCount() || m_aHelpLines[nNum] == rNewHelpLine)
780
0
        return;
781
782
0
    bool bNeedRedraw = true;
783
0
    if (m_aHelpLines[nNum].GetKind()==rNewHelpLine.GetKind()) {
784
0
        switch (rNewHelpLine.GetKind()) {
785
0
            case SdrHelpLineKind::Vertical  : if (m_aHelpLines[nNum].GetPos().X()==rNewHelpLine.GetPos().X()) bNeedRedraw = false; break;
786
0
            case SdrHelpLineKind::Horizontal: if (m_aHelpLines[nNum].GetPos().Y()==rNewHelpLine.GetPos().Y()) bNeedRedraw = false; break;
787
0
            default: break;
788
0
        } // switch
789
0
    }
790
0
    if (bNeedRedraw) ImpInvalidateHelpLineArea(nNum);
791
0
    m_aHelpLines[nNum]=rNewHelpLine;
792
0
    if (bNeedRedraw) ImpInvalidateHelpLineArea(nNum);
793
0
}
794
795
void SdrPageView::DeleteHelpLine(sal_uInt16 nNum)
796
0
{
797
0
    if (nNum<m_aHelpLines.GetCount()) {
798
0
        ImpInvalidateHelpLineArea(nNum);
799
0
        m_aHelpLines.Delete(nNum);
800
0
    }
801
0
}
802
803
void SdrPageView::InsertHelpLine(const SdrHelpLine& rHL)
804
0
{
805
0
    sal_uInt16 nNum = m_aHelpLines.GetCount();
806
0
    m_aHelpLines.Insert(rHL,nNum);
807
0
    if (GetView().IsHlplVisible())
808
0
        ImpInvalidateHelpLineArea(nNum);
809
0
}
810
811
// set current group and list
812
void SdrPageView::SetCurrentGroupAndList(SdrObject* pNewGroup, SdrObjList* pNewList)
813
60.8k
{
814
60.8k
    if(m_pCurrentGroup != pNewGroup)
815
0
    {
816
0
        m_pCurrentGroup = pNewGroup;
817
0
    }
818
60.8k
    if(m_pCurrentList != pNewList)
819
60.8k
    {
820
60.8k
        m_pCurrentList = pNewList;
821
60.8k
    }
822
60.8k
}
823
824
bool SdrPageView::EnterGroup(SdrObject* pObj)
825
0
{
826
0
    if(!pObj || !pObj->IsGroupObject())
827
0
        return false;
828
829
    // Don't allow enter Diagrams
830
0
    if(nullptr != pObj && pObj->isDiagram())
831
0
        return false;
832
833
0
    const bool bGlueInvalidate(GetView().ImpIsGlueVisible());
834
835
0
    if (bGlueInvalidate)
836
0
    {
837
0
        GetView().GlueInvalidate();
838
0
    }
839
840
    // deselect all
841
0
    GetView().UnmarkAll();
842
843
    // set current group and list
844
0
    SdrObjList* pNewObjList = pObj->GetSubList();
845
0
    SetCurrentGroupAndList(pObj, pNewObjList);
846
847
    // select contained object if only one object is contained,
848
    // else select nothing and let the user decide what to do next
849
0
    if(pNewObjList && pNewObjList->GetObjCount() == 1)
850
0
    {
851
0
        SdrObject* pFirstObject = pNewObjList->GetObj(0);
852
853
0
        if(GetView().GetSdrPageView())
854
0
        {
855
0
            GetView().MarkObj(pFirstObject, GetView().GetSdrPageView());
856
0
        }
857
0
    }
858
859
    // build new handles
860
0
    GetView().AdjustMarkHdl();
861
862
    // invalidate only when view wants to visualize group entering
863
0
    InvalidateAllWin();
864
865
0
    if (bGlueInvalidate)
866
0
    {
867
0
        GetView().GlueInvalidate();
868
0
    }
869
870
0
    return true;
871
0
}
872
873
void SdrPageView::LeaveOneGroup()
874
0
{
875
0
    SdrObject* pLastGroup = GetCurrentGroup();
876
0
    if (!pLastGroup)
877
0
        return;
878
879
0
    bool bGlueInvalidate = GetView().ImpIsGlueVisible();
880
881
0
    if(bGlueInvalidate)
882
0
        GetView().GlueInvalidate();
883
884
0
    SdrObject* pParentGroup = pLastGroup->getParentSdrObjectFromSdrObject();
885
0
    SdrObjList* pParentList = GetPage();
886
887
0
    if(pParentGroup)
888
0
        pParentList = pParentGroup->GetSubList();
889
890
    // deselect everything
891
0
    GetView().UnmarkAll();
892
893
    // allocations, pCurrentGroup and pCurrentList need to be set
894
0
    SetCurrentGroupAndList(pParentGroup, pParentList);
895
896
    // select the group we just left
897
0
    if (GetView().GetSdrPageView())
898
0
        GetView().MarkObj(pLastGroup, GetView().GetSdrPageView());
899
900
0
    GetView().AdjustMarkHdl();
901
902
    // invalidate only if view wants to visualize group entering
903
0
    InvalidateAllWin();
904
905
0
    if(bGlueInvalidate)
906
0
        GetView().GlueInvalidate();
907
0
}
908
909
void SdrPageView::LeaveAllGroup()
910
0
{
911
0
    SdrObject* pLastGroup = GetCurrentGroup();
912
0
    if (!pLastGroup)
913
0
        return;
914
915
0
    bool bGlueInvalidate = GetView().ImpIsGlueVisible();
916
917
0
    if(bGlueInvalidate)
918
0
        GetView().GlueInvalidate();
919
920
    // deselect everything
921
0
    GetView().UnmarkAll();
922
923
    // allocations, pCurrentGroup and pCurrentList always need to be set
924
0
    SetCurrentGroupAndList(nullptr, GetPage());
925
926
    // find and select uppermost group
927
0
    while (pLastGroup->getParentSdrObjectFromSdrObject())
928
0
        pLastGroup = pLastGroup->getParentSdrObjectFromSdrObject();
929
930
0
    if (GetView().GetSdrPageView())
931
0
        GetView().MarkObj(pLastGroup, GetView().GetSdrPageView());
932
933
0
    GetView().AdjustMarkHdl();
934
935
    // invalidate only when view wants to visualize group entering
936
0
    InvalidateAllWin();
937
938
0
    if(bGlueInvalidate)
939
0
        GetView().GlueInvalidate();
940
0
}
941
942
sal_uInt16 SdrPageView::GetEnteredLevel() const
943
0
{
944
0
    sal_uInt16 nCount=0;
945
0
    SdrObject* pGrp=GetCurrentGroup();
946
0
    while (pGrp!=nullptr) {
947
0
        nCount++;
948
0
        pGrp=pGrp->getParentSdrObjectFromSdrObject();
949
0
    }
950
0
    return nCount;
951
0
}
952
953
void SdrPageView::CheckCurrentGroup()
954
0
{
955
0
    SdrObject* pGrp(GetCurrentGroup());
956
957
0
    while(nullptr != pGrp &&
958
0
        (!pGrp->IsInserted() || nullptr == pGrp->getParentSdrObjListFromSdrObject() || nullptr == pGrp->getSdrPageFromSdrObject()))
959
0
    {
960
        // anything outside of the borders?
961
0
        pGrp = pGrp->getParentSdrObjectFromSdrObject();
962
0
    }
963
964
0
    if(pGrp != GetCurrentGroup())
965
0
    {
966
0
        if(nullptr != pGrp)
967
0
        {
968
0
            EnterGroup(pGrp);
969
0
        }
970
0
        else
971
0
        {
972
0
            LeaveAllGroup();
973
0
        }
974
0
    }
975
0
}
976
977
// Set background color for svx at SdrPageViews
978
void SdrPageView::SetApplicationBackgroundColor(Color aBackgroundColor)
979
0
{
980
0
    maBackgroundColor = aBackgroundColor;
981
0
}
982
983
984
// Set document color for svx at SdrPageViews
985
void SdrPageView::SetApplicationDocumentColor(Color aDocumentColor)
986
0
{
987
0
    maDocumentColor = aDocumentColor;
988
0
}
989
990
void SdrPageView::resetGridOffsetsOfAllPageWindows() const
991
0
{
992
0
    for (auto& pPageWindow : maPageWindows)
993
0
    {
994
0
        assert(pPageWindow && "SdrView::SetMasterPagePaintCaching: Corrupt SdrPageWindow list (!)");
995
996
0
        if (pPageWindow)
997
0
        {
998
0
            sdr::contact::ObjectContact& rObjectContact(pPageWindow->GetObjectContact());
999
1000
0
            if (rObjectContact.supportsGridOffsets())
1001
0
            {
1002
0
                rObjectContact.resetAllGridOffsets();
1003
0
            }
1004
0
        }
1005
0
    }
1006
0
}
1007
1008
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */