Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/source/uibase/docvw/HeaderFooterWin.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
10
#include <strings.hrc>
11
12
#include <doc.hxx>
13
#include <drawdoc.hxx>
14
#include <cmdid.h>
15
#include <DashedLine.hxx>
16
#include <docsh.hxx>
17
#include <edtwin.hxx>
18
#include <fmthdft.hxx>
19
#include <HeaderFooterWin.hxx>
20
#include <pagedesc.hxx>
21
#include <pagefrm.hxx>
22
#include <view.hxx>
23
#include <viewopt.hxx>
24
#include <wrtsh.hxx>
25
#include <IDocumentDrawModelAccess.hxx>
26
27
#include <basegfx/color/bcolortools.hxx>
28
#include <basegfx/matrix/b2dhommatrixtools.hxx>
29
#include <basegfx/polygon/b2dpolygon.hxx>
30
#include <basegfx/range/b2drectangle.hxx>
31
#include <basegfx/vector/b2dsize.hxx>
32
#include <basegfx/utils/gradienttools.hxx>
33
#include <drawinglayer/attribute/fillgradientattribute.hxx>
34
#include <drawinglayer/attribute/fontattribute.hxx>
35
#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
36
#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
37
#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
38
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
39
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
40
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
41
#include <editeng/boxitem.hxx>
42
#include <svx/hdft.hxx>
43
#include <sfx2/bindings.hxx>
44
#include <sfx2/viewfrm.hxx>
45
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
46
#include <drawinglayer/processor2d/processor2dtools.hxx>
47
#include <vcl/canvastools.hxx>
48
#include <vcl/metric.hxx>
49
#include <vcl/svapp.hxx>
50
#include <vcl/settings.hxx>
51
#include <vcl/virdev.hxx>
52
#include <vcl/weld/Builder.hxx>
53
#include <vcl/weld/MenuButton.hxx>
54
#include <memory>
55
56
0
#define TEXT_PADDING 5
57
0
#define BOX_DISTANCE 10
58
0
#define BUTTON_WIDTH 18
59
60
using namespace basegfx;
61
using namespace basegfx::utils;
62
using namespace drawinglayer::attribute;
63
64
namespace
65
{
66
    basegfx::BColor lcl_GetFillColor(const basegfx::BColor& rLineColor)
67
0
    {
68
0
        basegfx::BColor aHslLine = basegfx::utils::rgb2hsl(rLineColor);
69
0
        double nLuminance = aHslLine.getZ() * 2.5;
70
0
        if ( nLuminance == 0 )
71
0
            nLuminance = 0.5;
72
0
        else if ( nLuminance >= 1.0 )
73
0
            nLuminance = aHslLine.getZ() * 0.4;
74
0
        aHslLine.setZ( nLuminance );
75
0
        return basegfx::utils::hsl2rgb( aHslLine );
76
0
    }
77
78
    basegfx::BColor lcl_GetLighterGradientColor(const basegfx::BColor& rDarkColor)
79
0
    {
80
0
        basegfx::BColor aHslDark = basegfx::utils::rgb2hsl(rDarkColor);
81
0
        double nLuminance = aHslDark.getZ() * 255 + 20;
82
0
        aHslDark.setZ( nLuminance / 255.0 );
83
0
        return basegfx::utils::hsl2rgb( aHslDark );
84
0
    }
85
86
    B2DPolygon lcl_GetPolygon( const ::tools::Rectangle& rRect, bool bOnTop )
87
0
    {
88
0
        const double nRadius = 3;
89
0
        const double nKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
90
91
0
        B2DPolygon aPolygon;
92
0
        aPolygon.append( B2DPoint( rRect.Left(), rRect.Top() ) );
93
94
0
        {
95
0
            B2DPoint aCorner( rRect.Left(), rRect.Bottom() );
96
0
            B2DPoint aStart( rRect.Left(), rRect.Bottom() - nRadius );
97
0
            B2DPoint aEnd( rRect.Left() + nRadius, rRect.Bottom() );
98
0
            aPolygon.append( aStart );
99
0
            aPolygon.appendBezierSegment(
100
0
                    interpolate( aStart, aCorner, nKappa ),
101
0
                    interpolate( aEnd, aCorner, nKappa ),
102
0
                    aEnd );
103
0
        }
104
105
0
        {
106
0
            B2DPoint aCorner( rRect.Right(), rRect.Bottom() );
107
0
            B2DPoint aStart( rRect.Right() - nRadius, rRect.Bottom() );
108
0
            B2DPoint aEnd( rRect.Right(), rRect.Bottom() - nRadius );
109
0
            aPolygon.append( aStart );
110
0
            aPolygon.appendBezierSegment(
111
0
                    interpolate( aStart, aCorner, nKappa ),
112
0
                    interpolate( aEnd, aCorner, nKappa ),
113
0
                    aEnd );
114
0
        }
115
116
0
        aPolygon.append( B2DPoint( rRect.Right(), rRect.Top() ) );
117
118
0
        if ( !bOnTop )
119
0
        {
120
0
            B2DRectangle aBRect = vcl::unotools::b2DRectangleFromRectangle(rRect);
121
0
            B2DHomMatrix aRotation = createRotateAroundPoint(
122
0
                   aBRect.getCenterX(), aBRect.getCenterY(), M_PI );
123
0
            aPolygon.transform( aRotation );
124
0
        }
125
126
0
        return aPolygon;
127
0
    }
128
}
129
130
void SwFrameButtonPainter::PaintButton(drawinglayer::primitive2d::Primitive2DContainer& rSeq,
131
                                       const tools::Rectangle& rRect, bool bOnTop)
132
0
{
133
0
    rSeq.clear();
134
0
    B2DPolygon aPolygon = lcl_GetPolygon(rRect, bOnTop);
135
136
    // Colors
137
0
    basegfx::BColor aLineColor = SwViewOption::GetCurrentViewOptions().GetHeaderFooterMarkColor().getBColor();
138
0
    basegfx::BColor aFillColor = lcl_GetFillColor(aLineColor);
139
0
    basegfx::BColor aLighterColor = lcl_GetLighterGradientColor(aFillColor);
140
141
0
    const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
142
0
    if (rSettings.GetHighContrastMode())
143
0
    {
144
0
        aFillColor = rSettings.GetDialogColor().getBColor();
145
0
        aLineColor = rSettings.GetDialogTextColor().getBColor();
146
147
0
        rSeq.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), aFillColor));
148
0
    }
149
0
    else
150
0
    {
151
0
        B2DRectangle aGradientRect = vcl::unotools::b2DRectangleFromRectangle(rRect);
152
0
        double nAngle = M_PI;
153
0
        if (bOnTop)
154
0
            nAngle = 0;
155
156
0
        FillGradientAttribute aFillAttrs(css::awt::GradientStyle_LINEAR, 0.0, 0.0, 0.0, nAngle,
157
0
            basegfx::BColorStops(aLighterColor, aFillColor));
158
0
        rSeq.push_back(new drawinglayer::primitive2d::FillGradientPrimitive2D(aGradientRect, std::move(aFillAttrs)));
159
0
    }
160
161
    // Create the border lines primitive
162
0
    rSeq.push_back(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aPolygon), aLineColor));
163
0
}
164
165
SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin* pEditWin, const SwFrame *pFrame, bool bHeader)
166
0
    : SwDashedLine(pEditWin, &SwViewOption::GetHeaderFooterMarkColor)
167
0
    , m_pEditWin(pEditWin)
168
0
    , m_pFrame(pFrame)
169
0
    , m_bIsHeader(bHeader)
170
0
{
171
0
}
Unexecuted instantiation: SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin*, SwFrame const*, bool)
Unexecuted instantiation: SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin*, SwFrame const*, bool)
172
173
bool SwHeaderFooterDashedLine::IsOnScreen()
174
0
{
175
0
    tools::Rectangle aBounds(GetPosPixel(), GetSizePixel());
176
0
    tools::Rectangle aVisArea = GetEditWin()->LogicToPixel(GetEditWin()->GetView().GetVisArea());
177
0
    return aBounds.Overlaps(aVisArea);
178
0
}
179
180
void SwHeaderFooterDashedLine::EnsureWin()
181
0
{
182
0
    if (!m_pWin)
183
0
    {
184
0
        m_pWin = VclPtr<SwHeaderFooterWin>::Create(m_pEditWin, m_pFrame, m_bIsHeader);
185
0
        m_pWin->SetZOrder(this, ZOrderFlags::Before);
186
0
    }
187
0
}
188
189
void SwHeaderFooterDashedLine::ShowAll(bool bShow)
190
0
{
191
0
    Show(bShow);
192
0
    if (!m_pWin && IsOnScreen())
193
0
        EnsureWin();
194
0
    if (m_pWin)
195
0
        m_pWin->ShowAll(bShow);
196
0
}
197
198
void SwHeaderFooterDashedLine::SetReadonly(bool bReadonly)
199
0
{
200
0
    ShowAll(!bReadonly);
201
0
}
202
203
bool SwHeaderFooterDashedLine::Contains(const Point &rDocPt) const
204
0
{
205
0
    if (m_pWin && m_pWin->Contains(rDocPt))
206
0
        return true;
207
208
0
    ::tools::Rectangle aLineRect(GetPosPixel(), GetSizePixel());
209
0
    return aLineRect.Contains(rDocPt);
210
0
}
211
212
void SwHeaderFooterDashedLine::SetOffset(Point aOffset, tools::Long nXLineStart, tools::Long nXLineEnd)
213
0
{
214
0
    Point aLinePos(nXLineStart, aOffset.Y());
215
0
    Size aLineSize(nXLineEnd - nXLineStart, 1);
216
0
    SetPosSizePixel(aLinePos, aLineSize);
217
218
0
    bool bOnScreen = IsOnScreen();
219
0
    if (!m_pWin && bOnScreen)
220
0
    {
221
0
        EnsureWin();
222
0
        m_pWin->ShowAll(true);
223
0
    }
224
0
    else if (m_pWin && !bOnScreen)
225
0
        m_pWin.disposeAndClear();
226
227
0
    if (m_pWin)
228
0
        m_pWin->SetOffset(aOffset);
229
0
}
230
231
SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin* pEditWin, const SwFrame *pFrame, bool bHeader ) :
232
0
    InterimItemWindow(pEditWin, u"modules/swriter/ui/hfmenubutton.ui"_ustr, u"HFMenuButton"_ustr),
233
0
    m_xMenuButton(m_xBuilder->weld_menu_button(u"menubutton"_ustr)),
234
0
    m_xPushButton(m_xBuilder->weld_button(u"button"_ustr)),
235
0
    m_pEditWin(pEditWin),
236
0
    m_pFrame(pFrame),
237
0
    m_bIsHeader( bHeader ),
238
0
    m_bIsAppearing( false ),
239
0
    m_nFadeRate( 100 ),
240
0
    m_aFadeTimer("SwHeaderFooterWin m_aFadeTimer")
241
0
{
242
0
    m_xVirDev = m_xMenuButton->create_virtual_device();
243
0
    SwFrameMenuButtonBase::SetVirDevFont(*m_xVirDev);
244
245
0
    m_xPushButton->connect_clicked(LINK(this, SwHeaderFooterWin, ClickHdl));
246
0
    m_xMenuButton->connect_selected(LINK(this, SwHeaderFooterWin, SelectHdl));
247
248
    // set the PopupMenu
249
    // Rewrite the menu entries' text
250
0
    if (m_bIsHeader)
251
0
    {
252
0
        m_xMenuButton->set_item_label(u"edit"_ustr, SwResId(STR_FORMAT_HEADER));
253
0
        m_xMenuButton->set_item_label(u"delete"_ustr, SwResId(STR_DELETE_HEADER));
254
0
    }
255
0
    else
256
0
    {
257
0
        m_xMenuButton->set_item_label(u"edit"_ustr, SwResId(STR_FORMAT_FOOTER));
258
0
        m_xMenuButton->set_item_label(u"delete"_ustr, SwResId(STR_DELETE_FOOTER));
259
0
    }
260
261
0
    m_aFadeTimer.SetTimeout(50);
262
0
    m_aFadeTimer.SetInvokeHandler(LINK(this, SwHeaderFooterWin, FadeHandler));
263
0
}
Unexecuted instantiation: SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin*, SwFrame const*, bool)
Unexecuted instantiation: SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin*, SwFrame const*, bool)
264
265
SwHeaderFooterWin::~SwHeaderFooterWin( )
266
0
{
267
0
    disposeOnce();
268
0
}
269
270
void SwHeaderFooterWin::dispose()
271
0
{
272
0
    m_xPushButton.reset();
273
0
    m_xMenuButton.reset();
274
0
    m_pEditWin.reset();
275
0
    m_xVirDev.disposeAndClear();
276
0
    InterimItemWindow::dispose();
277
0
}
278
279
void SwHeaderFooterWin::SetOffset(Point aOffset)
280
0
{
281
    // Compute the text to show
282
0
    const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
283
0
    const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
284
0
    bool bIsFirst = !pDesc->IsFirstShared() && pPageFrame->OnFirstPage();
285
0
    bool bIsLeft  = !pDesc->IsHeaderShared() && !pPageFrame->OnRightPage();
286
0
    bool bIsRight = !pDesc->IsHeaderShared() && pPageFrame->OnRightPage();
287
0
    m_sLabel = SwResId(STR_HEADER_TITLE);
288
0
    if (!m_bIsHeader)
289
0
        m_sLabel = bIsFirst ? SwResId(STR_FIRST_FOOTER_TITLE)
290
0
            : bIsLeft  ? SwResId(STR_LEFT_FOOTER_TITLE)
291
0
            : bIsRight ? SwResId(STR_RIGHT_FOOTER_TITLE)
292
0
            : SwResId(STR_FOOTER_TITLE );
293
0
    else
294
0
        m_sLabel = bIsFirst ? SwResId(STR_FIRST_HEADER_TITLE)
295
0
            : bIsLeft  ? SwResId(STR_LEFT_HEADER_TITLE)
296
0
            : bIsRight ? SwResId(STR_RIGHT_HEADER_TITLE)
297
0
            : SwResId(STR_HEADER_TITLE);
298
299
0
    sal_Int32 nPos = m_sLabel.lastIndexOf("%1");
300
0
    m_sLabel = m_sLabel.replaceAt(nPos, 2, pDesc->GetName().toString());
301
0
    m_xMenuButton->set_accessible_name(m_sLabel);
302
303
    // Compute the text size and get the box position & size from it
304
0
    ::tools::Rectangle aTextRect;
305
0
    m_xVirDev->GetTextBoundRect(aTextRect, m_sLabel);
306
0
    ::tools::Rectangle aTextPxRect = m_xVirDev->LogicToPixel(aTextRect);
307
0
    FontMetric aFontMetric = m_xVirDev->GetFontMetric(m_xVirDev->GetFont());
308
0
    Size aBoxSize (aTextPxRect.GetWidth() + BUTTON_WIDTH + TEXT_PADDING * 2,
309
0
                   aFontMetric.GetLineHeight() + TEXT_PADDING  * 2 );
310
311
0
    tools::Long nYFooterOff = 0;
312
0
    if (!m_bIsHeader)
313
0
        nYFooterOff = aBoxSize.Height();
314
315
0
    Point aBoxPos(aOffset.X() - aBoxSize.Width() - BOX_DISTANCE,
316
0
                  aOffset.Y() - nYFooterOff);
317
318
0
    if (AllSettings::GetLayoutRTL())
319
0
    {
320
0
        aBoxPos.setX( aOffset.X() + BOX_DISTANCE );
321
0
    }
322
323
    // Set the position & Size of the window
324
0
    SetPosSizePixel(aBoxPos, aBoxSize);
325
326
0
    m_xVirDev->SetOutputSizePixel(aBoxSize);
327
0
    PaintButton();
328
0
}
329
330
void SwHeaderFooterWin::ShowAll(bool bShow)
331
0
{
332
0
    bool bIsEmptyHeaderFooter = IsEmptyHeaderFooter();
333
0
    m_xMenuButton->set_visible(!bIsEmptyHeaderFooter);
334
0
    m_xPushButton->set_visible(bIsEmptyHeaderFooter);
335
336
0
    m_bIsAppearing = bShow;
337
338
0
    if (m_aFadeTimer.IsActive())
339
0
        m_aFadeTimer.Stop();
340
0
    m_aFadeTimer.Start();
341
0
}
342
343
bool SwHeaderFooterWin::Contains( const Point &rDocPt ) const
344
0
{
345
0
    ::tools::Rectangle aRect(GetPosPixel(), GetSizePixel());
346
0
    return aRect.Contains(rDocPt);
347
0
}
348
349
void SwHeaderFooterWin::PaintButton()
350
0
{
351
0
    if (!m_xVirDev)
352
0
        return;
353
354
    // Use pixels for the rest of the drawing
355
0
    SetMapMode(MapMode(MapUnit::MapPixel));
356
0
    drawinglayer::primitive2d::Primitive2DContainer aSeq;
357
0
    const ::tools::Rectangle aRect(::tools::Rectangle(Point(0, 0), m_xVirDev->PixelToLogic(GetSizePixel())));
358
359
0
    SwFrameButtonPainter::PaintButton(aSeq, aRect, m_bIsHeader);
360
361
    // Create the text primitive
362
0
    basegfx::BColor aLineColor = SwViewOption::GetCurrentViewOptions().GetHeaderFooterMarkColor().getBColor();
363
0
    B2DVector aFontSize;
364
0
    FontAttribute aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, m_xVirDev->GetFont(), false, false);
365
366
0
    FontMetric aFontMetric = m_xVirDev->GetFontMetric(m_xVirDev->GetFont());
367
0
    double nTextOffsetY = aFontMetric.GetAscent() + TEXT_PADDING;
368
0
    Point aTextPos(TEXT_PADDING, nTextOffsetY);
369
370
0
    basegfx::B2DHomMatrix aTextMatrix(createScaleTranslateB2DHomMatrix(
371
0
                                            aFontSize.getX(), aFontSize.getY(),
372
0
                                            double(aTextPos.X()), double(aTextPos.Y())));
373
374
0
    aSeq.push_back(new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
375
0
                        aTextMatrix, m_sLabel, 0, m_sLabel.getLength(),
376
0
                        std::vector<double>(), {}, std::move(aFontAttr), css::lang::Locale(), aLineColor));
377
378
    // Create the 'plus' or 'arrow' primitive
379
0
    B2DRectangle aSignArea(B2DPoint(aRect.Right() - BUTTON_WIDTH, 0.0),
380
0
                           B2DVector(aRect.Right(), aRect.getOpenHeight()));
381
382
0
    B2DPolygon aSign;
383
0
    bool bIsEmptyHeaderFooter = IsEmptyHeaderFooter();
384
0
    if (bIsEmptyHeaderFooter)
385
0
    {
386
        // Create the + polygon
387
0
        double nLeft = aSignArea.getMinX() + TEXT_PADDING;
388
0
        double nRight = aSignArea.getMaxX() - TEXT_PADDING;
389
0
        double nHalfW = ( nRight - nLeft ) / 2.0;
390
391
0
        double nTop = aSignArea.getCenterY() - nHalfW;
392
0
        double nBottom = aSignArea.getCenterY() + nHalfW;
393
394
0
        aSign.append(B2DPoint(nLeft, aSignArea.getCenterY() - 1.0));
395
0
        aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, aSignArea.getCenterY() - 1.0));
396
0
        aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, nTop));
397
0
        aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, nTop));
398
0
        aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, aSignArea.getCenterY() - 1.0));
399
0
        aSign.append(B2DPoint(nRight, aSignArea.getCenterY() - 1.0));
400
0
        aSign.append(B2DPoint(nRight, aSignArea.getCenterY() + 1.0));
401
0
        aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, aSignArea.getCenterY() + 1.0));
402
0
        aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, nBottom));
403
0
        aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, nBottom));
404
0
        aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, aSignArea.getCenterY() + 1.0));
405
0
        aSign.append(B2DPoint(nLeft, aSignArea.getCenterY() + 1.0));
406
0
        aSign.setClosed(true);
407
0
    }
408
0
    else
409
0
    {
410
        // Create the v polygon
411
0
        B2DPoint aLeft(aSignArea.getMinX() + TEXT_PADDING, aSignArea.getCenterY());
412
0
        B2DPoint aRight(aSignArea.getMaxX() - TEXT_PADDING, aSignArea.getCenterY());
413
0
        B2DPoint aBottom((aLeft.getX() + aRight.getX()) / 2.0, aLeft.getY() + 4.0);
414
0
        aSign.append(aLeft);
415
0
        aSign.append(aRight);
416
0
        aSign.append(aBottom);
417
0
        aSign.setClosed(true);
418
0
    }
419
420
0
    BColor aSignColor = COL_BLACK.getBColor();
421
0
    if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
422
0
        aSignColor = COL_WHITE.getBColor();
423
424
0
    aSeq.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
425
0
                                        B2DPolyPolygon(aSign), aSignColor) );
426
427
    // Create the processor and process the primitives
428
0
    const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
429
0
    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
430
0
        drawinglayer::processor2d::createProcessor2DFromOutputDevice(*m_xVirDev, aNewViewInfos));
431
432
    // TODO Ghost it all if needed
433
0
    drawinglayer::primitive2d::Primitive2DContainer aGhostedSeq;
434
0
    double nFadeRate = double(m_nFadeRate) / 100.0;
435
436
0
    basegfx::BColorModifierSharedPtr aBColorModifier =
437
0
        std::make_shared<basegfx::BColorModifier_interpolate>(COL_WHITE.getBColor(),
438
0
                                                1.0 - nFadeRate);
439
440
0
    aGhostedSeq.push_back(new drawinglayer::primitive2d::ModifiedColorPrimitive2D(std::move(aSeq), std::move(aBColorModifier)));
441
442
0
    pProcessor->process(aGhostedSeq);
443
444
0
    if (bIsEmptyHeaderFooter)
445
0
        m_xPushButton->set_custom_button(m_xVirDev.get());
446
0
    else
447
0
        m_xMenuButton->set_custom_button(m_xVirDev.get());
448
0
}
449
450
bool SwHeaderFooterWin::IsEmptyHeaderFooter( ) const
451
0
{
452
0
    bool bResult = true;
453
454
0
    const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
455
0
    if (!pPageFrame)
456
0
    {
457
0
        return bResult;
458
0
    }
459
460
    // Actually check it
461
0
    const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
462
463
0
    bool const bFirst(pPageFrame->OnFirstPage());
464
0
    const SwFrameFormat *const pFormat = (pPageFrame->OnRightPage())
465
0
        ? pDesc->GetRightFormat(bFirst)
466
0
        : pDesc->GetLeftFormat(bFirst);
467
468
0
    if ( pFormat )
469
0
    {
470
0
        if ( m_bIsHeader )
471
0
            bResult = !pFormat->GetHeader().IsActive();
472
0
        else
473
0
            bResult = !pFormat->GetFooter().IsActive();
474
0
    }
475
476
0
    return bResult;
477
0
}
478
479
void SwHeaderFooterWin::ExecuteCommand(std::u16string_view rIdent)
480
0
{
481
0
    SwView& rView = m_pEditWin->GetView();
482
0
    SwWrtShell& rSh = rView.GetWrtShell();
483
484
0
    const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
485
0
    const UIName& rStyleName = pPageFrame->GetPageDesc()->GetName();
486
0
    if (rIdent == u"edit")
487
0
    {
488
0
        OUString sPageId = m_bIsHeader ? u"header"_ustr : u"footer"_ustr;
489
0
        rView.GetDocShell()->FormatPage(rView.GetFrameWeld(), rStyleName, sPageId, rSh);
490
0
    }
491
0
    else if (rIdent == u"borderback")
492
0
    {
493
0
        SwPageDesc& rPageDesc = const_cast<SwPageDesc&>(*pPageFrame->GetPageDesc());
494
0
        SwFrameFormat& rMaster = rPageDesc.GetMaster();
495
0
        SwFrameFormat* pHFFormat = const_cast< SwFrameFormat* >( rMaster.GetFooter().GetFooterFormat() );
496
0
        if ( m_bIsHeader )
497
0
            pHFFormat = const_cast< SwFrameFormat* >( rMaster.GetHeader().GetHeaderFormat() );
498
0
        SfxItemSet aSet( pHFFormat->GetAttrSet() );
499
500
        // Items to hand over XPropertyList things like XColorList,
501
        // XHatchList, XGradientList, and XBitmapList to the Area TabPage:
502
0
        aSet.MergeRange( SID_COLOR_TABLE, SID_PATTERN_LIST );
503
        // create needed items for XPropertyList entries from the DrawModel so that
504
        // the Area TabPage can access them
505
0
        rSh.GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->PutAreaListItems( aSet );
506
507
0
        aSet.MergeRange(SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER);
508
        // Create a box info item... needed by the dialog
509
0
        std::shared_ptr<SvxBoxInfoItem> aBoxInfo(std::make_shared<SvxBoxInfoItem>(SID_ATTR_BORDER_INNER));
510
0
        if (const SvxBoxInfoItem *pBoxInfo = pHFFormat->GetAttrSet().GetItemIfSet(SID_ATTR_BORDER_INNER))
511
0
            aBoxInfo.reset(pBoxInfo->Clone());
512
513
0
        aBoxInfo->SetTable(false);
514
0
        aBoxInfo->SetDist(true);
515
0
        aBoxInfo->SetMinDist(false);
516
0
        aBoxInfo->SetDefDist(MIN_BORDER_DIST);
517
0
        aBoxInfo->SetValid(SvxBoxInfoItemValidFlags::DISABLE);
518
0
        aSet.Put(*aBoxInfo);
519
520
0
        if (svx::ShowBorderBackgroundDlg( GetFrameWeld(), &aSet ) )
521
0
        {
522
            // Apply the modified format to all (first, even, odd) of the page style's FrameFormats
523
0
            aSet.DisableItem(RES_CNTNT); // don't duplicate the content though...
524
0
            rPageDesc.SetFormatAttrOnAll(aSet, m_bIsHeader);
525
0
            rView.GetDocShell()->SetModified();
526
0
        }
527
0
    }
528
0
    else if (rIdent == u"delete")
529
0
    {
530
0
        rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, false, true );
531
        // warning: "this" may be disposed now
532
0
        rSh.GetWin()->GrabFocusToDocument();
533
0
    }
534
0
    else if (rIdent == u"insert_pagenumber")
535
0
    {
536
0
        SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame();
537
0
        rVFrame.GetBindings().Execute(FN_INSERT_FLD_PGNUMBER);
538
0
    }
539
0
    else if (rIdent == u"insert_pagecount")
540
0
    {
541
0
        SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame();
542
0
        rVFrame.GetBindings().Execute(FN_INSERT_FLD_PGCOUNT);
543
0
    }
544
0
    else if (rIdent == u"insert_pagecount_in_range")
545
0
    {
546
0
        SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame();
547
0
        rVFrame.GetBindings().Execute(FN_INSERT_FLD_RANGE_PGCOUNT);
548
0
    }
549
0
}
550
551
IMPL_LINK_NOARG(SwHeaderFooterWin, ClickHdl, weld::Button&, void)
552
0
{
553
0
    SwView& rView = m_pEditWin->GetView();
554
0
    SwWrtShell& rSh = rView.GetWrtShell();
555
556
0
    const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
557
0
    const UIName& rStyleName = pPageFrame->GetPageDesc()->GetName();
558
0
    {
559
0
        VclPtr<SwHeaderFooterWin> xThis(this);
560
0
        rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, true, false );
561
        //tdf#153059 after ChangeHeaderOrFooter is it possible that "this" is disposed
562
0
        if (xThis->isDisposed())
563
0
            return;
564
0
    }
565
0
    m_xPushButton->hide();
566
0
    m_xMenuButton->show();
567
0
    PaintButton();
568
0
}
569
570
IMPL_LINK(SwHeaderFooterWin, SelectHdl, const OUString&, rIdent, void)
571
0
{
572
0
    ExecuteCommand(rIdent);
573
0
}
574
575
IMPL_LINK_NOARG(SwHeaderFooterWin, FadeHandler, Timer *, void)
576
0
{
577
0
    if (m_bIsAppearing && m_nFadeRate > 0)
578
0
        m_nFadeRate -= 25;
579
0
    else if (!m_bIsAppearing && m_nFadeRate < 100)
580
0
        m_nFadeRate += 25;
581
582
0
    if (m_nFadeRate != 100 && !IsVisible())
583
0
    {
584
0
        Show();
585
0
    }
586
0
    else if (m_nFadeRate == 100 && IsVisible())
587
0
    {
588
0
        Show(false);
589
0
    }
590
0
    else
591
0
        PaintButton();
592
593
0
    if (IsVisible() && m_nFadeRate > 0 && m_nFadeRate < 100)
594
0
        m_aFadeTimer.Start();
595
0
}
596
597
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */