Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/dialog/infobar.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 <basegfx/polygon/b2dpolygon.hxx>
11
#include <comphelper/dispatchcommand.hxx>
12
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
13
#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
14
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
15
#include <drawinglayer/processor2d/processor2dtools.hxx>
16
#include <memory>
17
#include <officecfg/Office/UI/Infobar.hxx>
18
#include <officecfg/Office/Common.hxx>
19
#include <sfx2/bindings.hxx>
20
#include <sfx2/chalign.hxx>
21
#include <sfx2/dispatch.hxx>
22
#include <sfx2/infobar.hxx>
23
#include <sfx2/objface.hxx>
24
#include <sfx2/sfxsids.hrc>
25
#include <sfx2/viewfrm.hxx>
26
#include <utility>
27
#include <vcl/event.hxx>
28
#include <vcl/image.hxx>
29
#include <vcl/settings.hxx>
30
#include <vcl/svapp.hxx>
31
#include <vcl/virdev.hxx>
32
#include <vcl/weld/Builder.hxx>
33
#include <vcl/weld/Button.hxx>
34
#include <vcl/weld/Container.hxx>
35
#include <vcl/weld/Image.hxx>
36
#include <vcl/weld/Label.hxx>
37
#include <vcl/weld/TextView.hxx>
38
#include <vcl/weld/Toolbar.hxx>
39
#include <vcl/weld/weldutils.hxx>
40
#include <bitmaps.hlst>
41
42
using namespace drawinglayer::geometry;
43
using namespace drawinglayer::processor2d;
44
using namespace drawinglayer::primitive2d;
45
using namespace drawinglayer::attribute;
46
using namespace basegfx;
47
using namespace css::frame;
48
49
namespace
50
{
51
void GetInfoBarColors(InfobarType ibType, BColor& rBackgroundColor, BColor& rForegroundColor,
52
                      BColor& rMessageColor)
53
0
{
54
0
    const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
55
0
    const bool bIsDark = rSettings.GetWindowColor().IsDark();
56
0
    switch (ibType)
57
0
    {
58
0
        case InfobarType::INFO: // blue; #004785/0,71,133; #BDE5F8/189,229,248
59
0
            rBackgroundColor = bIsDark ? basegfx::BColor(0.000, 0.278, 0.522)
60
0
                                       : basegfx::BColor(0.741, 0.898, 0.973);
61
0
            rForegroundColor = bIsDark ? basegfx::BColor(0.741, 0.898, 0.973)
62
0
                                       : basegfx::BColor(0.000, 0.278, 0.522);
63
0
            rMessageColor = rForegroundColor;
64
0
            break;
65
0
        case InfobarType::SUCCESS: // green; #32550C/50,85,12; #DFF2BF/223,242,191
66
0
            rBackgroundColor = bIsDark ? basegfx::BColor(0.196, 0.333, 0.047)
67
0
                                       : basegfx::BColor(0.874, 0.949, 0.749);
68
0
            rForegroundColor = bIsDark ? basegfx::BColor(0.874, 0.949, 0.749)
69
0
                                       : basegfx::BColor(0.196, 0.333, 0.047);
70
0
            rMessageColor = rForegroundColor;
71
0
            break;
72
0
        case InfobarType::WARNING: // orange; #704300/112,67,0; #FEEFB3/254,239,179
73
0
            rBackgroundColor = rSettings.GetWarningColor().getBColor();
74
0
            rForegroundColor = rSettings.GetWarningTextColor().getBColor();
75
0
            rMessageColor = rSettings.GetWarningTextColor().getBColor();
76
0
            break;
77
0
        case InfobarType::DANGER: // red; #7A0006/122,0,6; #FFBABA/255,186,186
78
0
            rBackgroundColor = rSettings.GetErrorColor().getBColor();
79
0
            rForegroundColor = rSettings.GetErrorTextColor().getBColor();
80
0
            rMessageColor = rSettings.GetErrorTextColor().getBColor();
81
0
            break;
82
0
    }
83
84
0
    if (rSettings.GetHighContrastMode())
85
0
    {
86
0
        rBackgroundColor = rSettings.GetLightColor().getBColor();
87
0
        rForegroundColor = rSettings.GetDialogTextColor().getBColor();
88
0
    }
89
0
}
90
OUString GetInfoBarIconName(InfobarType ibType)
91
0
{
92
0
    OUString aRet;
93
94
0
    switch (ibType)
95
0
    {
96
0
        case InfobarType::INFO:
97
0
            aRet = "vcl/res/infobox.png";
98
0
            break;
99
0
        case InfobarType::SUCCESS:
100
0
            aRet = "vcl/res/successbox.png";
101
0
            break;
102
0
        case InfobarType::WARNING:
103
0
            aRet = "vcl/res/warningbox.png";
104
0
            break;
105
0
        case InfobarType::DANGER:
106
0
            aRet = "vcl/res/errorbox.png";
107
0
            break;
108
0
    }
109
110
0
    return aRet;
111
0
}
112
113
} // anonymous namespace
114
115
void SfxInfoBarWindow::SetCloseButtonImage()
116
0
{
117
0
    Size aSize = Image(StockImage::Yes, CLOSEDOC).GetSizePixel();
118
0
    aSize = Size(aSize.Width() * 1.5, aSize.Height() * 1.5);
119
120
0
    ScopedVclPtr<VirtualDevice> xDevice(m_xCloseBtn->create_virtual_device());
121
0
    xDevice->SetOutputSizePixel(Size(24, 24));
122
0
    xDevice->SetBackground(Color(m_aBackgroundColor));
123
0
    xDevice->Erase();
124
125
0
    const int nPos = (24 - aSize.getWidth()) / 2;
126
0
    Point aBtnPos(nPos, nPos);
127
128
0
    const ViewInformation2D aNewViewInfos;
129
0
    const std::unique_ptr<BaseProcessor2D> pProcessor(
130
0
        createProcessor2DFromOutputDevice(*xDevice, aNewViewInfos));
131
132
0
    const ::tools::Rectangle aRect(aBtnPos, xDevice->PixelToLogic(aSize));
133
134
0
    drawinglayer::primitive2d::Primitive2DContainer aSeq(2);
135
136
    // Draw background. The right and bottom need to be extended by 1 or
137
    // there will be a white line on both edges when Skia is enabled.
138
0
    B2DPolygon aPolygon;
139
0
    aPolygon.append(B2DPoint(aRect.Left(), aRect.Top()));
140
0
    aPolygon.append(B2DPoint(aRect.Right() + 1, aRect.Top()));
141
0
    aPolygon.append(B2DPoint(aRect.Right() + 1, aRect.Bottom() + 1));
142
0
    aPolygon.append(B2DPoint(aRect.Left(), aRect.Bottom() + 1));
143
0
    aPolygon.setClosed(true);
144
145
0
    aSeq[0] = new PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), m_aBackgroundColor);
146
147
0
    LineAttribute aLineAttribute(m_aForegroundColor, 2.0);
148
149
    // Cross
150
0
    B2DPolyPolygon aCross;
151
152
0
    B2DPolygon aLine1;
153
0
    aLine1.append(B2DPoint(aRect.Left(), aRect.Top()));
154
0
    aLine1.append(B2DPoint(aRect.Right(), aRect.Bottom()));
155
0
    aCross.append(aLine1);
156
157
0
    B2DPolygon aLine2;
158
0
    aLine2.append(B2DPoint(aRect.Right(), aRect.Top()));
159
0
    aLine2.append(B2DPoint(aRect.Left(), aRect.Bottom()));
160
0
    aCross.append(aLine2);
161
162
0
    aSeq[1]
163
0
        = new PolyPolygonStrokePrimitive2D(std::move(aCross), aLineAttribute, StrokeAttribute());
164
165
0
    pProcessor->process(aSeq);
166
167
0
    m_xCloseBtn->set_item_image(u"close"_ustr, xDevice);
168
0
}
169
170
class ExtraButton
171
{
172
private:
173
    std::unique_ptr<weld::Builder> m_xBuilder;
174
    std::unique_ptr<weld::Container> m_xContainer;
175
    std::unique_ptr<weld::Button> m_xButton;
176
    /** StatusListener. Updates the button as the slot state changes */
177
    rtl::Reference<weld::WidgetStatusListener> m_xStatusListener;
178
    OUString m_aCommand;
179
180
    DECL_LINK(CommandHdl, weld::Button&, void);
181
182
public:
183
    ExtraButton(weld::Container* pContainer, const OUString* pCommand)
184
0
        : m_xBuilder(Application::CreateBuilder(pContainer, u"sfx/ui/extrabutton.ui"_ustr))
185
0
        , m_xContainer(m_xBuilder->weld_container(u"ExtraButton"_ustr))
186
0
        , m_xButton(m_xBuilder->weld_button(u"button"_ustr))
187
0
    {
188
0
        if (pCommand)
189
0
        {
190
0
            m_aCommand = *pCommand;
191
0
            m_xButton->connect_clicked(LINK(this, ExtraButton, CommandHdl));
192
0
            m_xStatusListener.set(new weld::WidgetStatusListener(m_xButton.get(), m_aCommand));
193
0
            m_xStatusListener->startListening();
194
0
        }
195
0
    }
196
197
    ~ExtraButton()
198
0
    {
199
0
        if (m_xStatusListener.is())
200
0
            m_xStatusListener->dispose();
201
0
    }
202
203
0
    weld::Button& get_widget() { return *m_xButton; }
204
};
205
206
IMPL_LINK_NOARG(ExtraButton, CommandHdl, weld::Button&, void)
207
0
{
208
0
    comphelper::dispatchCommand(m_aCommand, css::uno::Sequence<css::beans::PropertyValue>());
209
0
}
210
211
SfxInfoBarWindow::SfxInfoBarWindow(vcl::Window* pParent, OUString sId,
212
                                   const OUString& sPrimaryMessage,
213
                                   const OUString& sSecondaryMessage, InfobarType ibType,
214
                                   bool bShowCloseButton)
215
0
    : InterimItemWindow(pParent, u"sfx/ui/infobar.ui"_ustr, u"InfoBar"_ustr)
216
0
    , m_sId(std::move(sId))
217
0
    , m_eType(ibType)
218
0
    , m_bLayingOut(false)
219
0
    , m_xImage(m_xBuilder->weld_image(u"image"_ustr))
220
0
    , m_xPrimaryMessage(m_xBuilder->weld_label(u"primary"_ustr))
221
0
    , m_xSecondaryMessage(m_xBuilder->weld_text_view(u"secondary"_ustr))
222
0
    , m_xButtonBox(m_xBuilder->weld_container(u"buttonbox"_ustr))
223
0
    , m_xCloseBtn(m_xBuilder->weld_toolbar(u"closebar"_ustr))
224
0
{
225
0
    SetStyle(GetStyle() | WB_DIALOGCONTROL);
226
227
0
    InitControlBase(m_xCloseBtn.get());
228
229
0
    m_xImage->set_from_icon_name(GetInfoBarIconName(ibType));
230
0
    m_xSecondaryMessage->set_margin_top(m_xImage->get_preferred_size().Height() / 4);
231
232
0
    if (!sPrimaryMessage.isEmpty())
233
0
    {
234
0
        m_xPrimaryMessage->set_label(sPrimaryMessage);
235
0
        m_xPrimaryMessage->show();
236
0
    }
237
238
0
    m_xSecondaryMessage->set_text(sSecondaryMessage);
239
0
    m_aOrigMessageSize = m_xSecondaryMessage->get_preferred_size();
240
0
    m_aMessageSize = m_aOrigMessageSize;
241
0
    m_xSecondaryMessage->connect_size_allocate(LINK(this, SfxInfoBarWindow, SizeAllocHdl));
242
243
0
    if (bShowCloseButton)
244
0
    {
245
0
        m_xCloseBtn->connect_clicked(LINK(this, SfxInfoBarWindow, CloseHandler));
246
0
        m_xCloseBtn->show();
247
0
    }
248
249
0
    EnableChildTransparentMode();
250
251
0
    SetForeAndBackgroundColors(m_eType);
252
253
0
    auto nWidth = pParent->GetSizePixel().getWidth();
254
0
    auto nHeight = get_preferred_size().Height();
255
0
    SetSizePixel(Size(nWidth, nHeight + 2));
256
257
0
    Resize();
258
0
}
Unexecuted instantiation: SfxInfoBarWindow::SfxInfoBarWindow(vcl::Window*, rtl::OUString, rtl::OUString const&, rtl::OUString const&, InfobarType, bool)
Unexecuted instantiation: SfxInfoBarWindow::SfxInfoBarWindow(vcl::Window*, rtl::OUString, rtl::OUString const&, rtl::OUString const&, InfobarType, bool)
259
260
IMPL_LINK(SfxInfoBarWindow, SizeAllocHdl, const Size&, rSize, void)
261
0
{
262
0
    if (m_aMessageSize != rSize)
263
0
    {
264
0
        m_aMessageSize = rSize;
265
0
        static_cast<SfxInfoBarContainerWindow*>(GetParent())->TriggerUpdateLayout();
266
0
    }
267
0
}
268
269
Size SfxInfoBarWindow::DoLayout()
270
0
{
271
0
    Size aGivenSize(GetSizePixel());
272
273
    // disconnect SizeAllocHdl because we don't care about the size change
274
    // during layout
275
0
    m_xSecondaryMessage->connect_size_allocate(Link<const Size&, void>());
276
277
    // blow away size cache in case m_aMessageSize.Width() is already the width request
278
    // and we would get the cached preferred size instead of the recalc we want to force
279
0
    m_xSecondaryMessage->set_size_request(-1, -1);
280
    // make the width we were detected as set to by SizeAllocHdl as our desired width
281
0
    m_xSecondaryMessage->set_size_request(m_aMessageSize.Width(), -1);
282
    // get our preferred size with that message width
283
0
    Size aSizeForWidth(aGivenSize.Width(), m_xContainer->get_preferred_size().Height());
284
    // restore the message preferred size so we can freely resize, and get a new
285
    // m_aMessageSize and repeat the process if we do
286
0
    m_xSecondaryMessage->set_size_request(m_aOrigMessageSize.Width(), -1);
287
288
    // connect SizeAllocHdl so changes outside of this layout will trigger a new layout
289
0
    m_xSecondaryMessage->connect_size_allocate(LINK(this, SfxInfoBarWindow, SizeAllocHdl));
290
291
0
    return aSizeForWidth;
292
0
}
293
294
void SfxInfoBarWindow::Layout()
295
0
{
296
0
    if (m_bLayingOut)
297
0
        return;
298
0
    m_bLayingOut = true;
299
300
0
    InterimItemWindow::Layout();
301
302
0
    m_bLayingOut = false;
303
0
}
304
305
bool SfxInfoBarWindow::EventNotify(NotifyEvent& rEvent)
306
0
{
307
0
    const NotifyEventType nType = rEvent.GetType();
308
0
    if (NotifyEventType::KEYINPUT == nType)
309
0
    {
310
0
        const vcl::KeyCode& rKeyCode = rEvent.GetKeyEvent()->GetKeyCode();
311
0
        switch (rKeyCode.GetCode())
312
0
        {
313
0
            case KEY_TAB:
314
0
            case KEY_SPACE:
315
0
            case KEY_RETURN:
316
                // Allow Tab, Space, and Enter to pass through to parent for proper focus handling
317
0
                break;
318
0
            default:
319
                // Consume all other keys to prevent document window interaction
320
0
                return true;
321
0
        }
322
0
    }
323
324
0
    return InterimItemWindow::EventNotify(rEvent);
325
0
}
326
327
weld::Button& SfxInfoBarWindow::addButton(const OUString* pCommand)
328
0
{
329
0
    m_aActionBtns.emplace_back(std::make_unique<ExtraButton>(m_xButtonBox.get(), pCommand));
330
331
0
    return m_aActionBtns.back()->get_widget();
332
0
}
333
334
0
SfxInfoBarWindow::~SfxInfoBarWindow() { disposeOnce(); }
335
336
void SfxInfoBarWindow::SetForeAndBackgroundColors(InfobarType eType)
337
0
{
338
0
    basegfx::BColor aMessageColor;
339
0
    GetInfoBarColors(eType, m_aBackgroundColor, m_aForegroundColor, aMessageColor);
340
341
0
    m_xPrimaryMessage->set_font_color(Color(aMessageColor));
342
0
    m_xSecondaryMessage->set_font_color(Color(aMessageColor));
343
344
0
    Color aBackgroundColor(m_aBackgroundColor);
345
0
    m_xPrimaryMessage->set_background(aBackgroundColor);
346
0
    m_xSecondaryMessage->set_background(aBackgroundColor);
347
0
    m_xContainer->set_background(aBackgroundColor);
348
0
    if (m_xCloseBtn->get_visible())
349
0
    {
350
0
        m_xCloseBtn->set_background(aBackgroundColor);
351
0
        SetCloseButtonImage();
352
0
    }
353
0
}
354
355
void SfxInfoBarWindow::dispose()
356
0
{
357
0
    for (auto& rxBtn : m_aActionBtns)
358
0
        rxBtn.reset();
359
360
0
    m_xImage.reset();
361
0
    m_xPrimaryMessage.reset();
362
0
    m_xSecondaryMessage.reset();
363
0
    m_xButtonBox.reset();
364
0
    m_xCloseBtn.reset();
365
0
    m_aActionBtns.clear();
366
0
    InterimItemWindow::dispose();
367
0
}
368
369
void SfxInfoBarWindow::Update(const OUString& sPrimaryMessage, const OUString& sSecondaryMessage,
370
                              InfobarType eType)
371
0
{
372
0
    if (m_eType != eType)
373
0
    {
374
0
        m_eType = eType;
375
0
        SetForeAndBackgroundColors(m_eType);
376
0
        m_xImage->set_from_icon_name(GetInfoBarIconName(eType));
377
0
    }
378
379
0
    m_xPrimaryMessage->set_label(sPrimaryMessage);
380
0
    m_xSecondaryMessage->set_text(sSecondaryMessage);
381
0
    Resize();
382
0
    Invalidate();
383
0
}
384
385
IMPL_LINK_NOARG(SfxInfoBarWindow, CloseHandler, const OUString&, void)
386
0
{
387
0
    static_cast<SfxInfoBarContainerWindow*>(GetParent())->removeInfoBar(this);
388
0
}
389
390
SfxInfoBarContainerWindow::SfxInfoBarContainerWindow(SfxInfoBarContainerChild* pChildWin)
391
0
    : Window(pChildWin->GetParent(), WB_DIALOGCONTROL)
392
0
    , m_pChildWin(pChildWin)
393
0
    , m_aLayoutIdle("SfxInfoBarContainerWindow m_aLayoutIdle")
394
0
    , m_bResizing(false)
395
0
{
396
0
    m_aLayoutIdle.SetPriority(TaskPriority::HIGHEST);
397
0
    m_aLayoutIdle.SetInvokeHandler(LINK(this, SfxInfoBarContainerWindow, DoUpdateLayout));
398
0
}
Unexecuted instantiation: SfxInfoBarContainerWindow::SfxInfoBarContainerWindow(SfxInfoBarContainerChild*)
Unexecuted instantiation: SfxInfoBarContainerWindow::SfxInfoBarContainerWindow(SfxInfoBarContainerChild*)
399
400
0
IMPL_LINK_NOARG(SfxInfoBarContainerWindow, DoUpdateLayout, Timer*, void) { m_pChildWin->Update(); }
401
402
0
SfxInfoBarContainerWindow::~SfxInfoBarContainerWindow() { disposeOnce(); }
403
404
void SfxInfoBarContainerWindow::dispose()
405
0
{
406
0
    for (auto& infoBar : m_pInfoBars)
407
0
        infoBar.disposeAndClear();
408
0
    m_pInfoBars.clear();
409
0
    Window::dispose();
410
0
}
411
412
VclPtr<SfxInfoBarWindow> SfxInfoBarContainerWindow::appendInfoBar(const OUString& sId,
413
                                                                  const OUString& sPrimaryMessage,
414
                                                                  const OUString& sSecondaryMessage,
415
                                                                  InfobarType ibType,
416
                                                                  bool bShowCloseButton)
417
0
{
418
0
    if (!isInfobarEnabled(sId))
419
0
        return nullptr;
420
421
0
    auto pInfoBar = VclPtr<SfxInfoBarWindow>::Create(this, sId, sPrimaryMessage, sSecondaryMessage,
422
0
                                                     ibType, bShowCloseButton);
423
424
0
    basegfx::BColor aBackgroundColor;
425
0
    basegfx::BColor aForegroundColor;
426
0
    basegfx::BColor aMessageColor;
427
0
    GetInfoBarColors(ibType, aBackgroundColor, aForegroundColor, aMessageColor);
428
0
    pInfoBar->m_aBackgroundColor = aBackgroundColor;
429
0
    pInfoBar->m_aForegroundColor = aForegroundColor;
430
0
    m_pInfoBars.push_back(pInfoBar);
431
432
0
    Resize();
433
0
    return pInfoBar;
434
0
}
435
436
VclPtr<SfxInfoBarWindow> SfxInfoBarContainerWindow::getInfoBar(std::u16string_view sId)
437
0
{
438
0
    for (auto const& infoBar : m_pInfoBars)
439
0
    {
440
0
        if (infoBar->getId() == sId)
441
0
            return infoBar;
442
0
    }
443
0
    return nullptr;
444
0
}
445
446
bool SfxInfoBarContainerWindow::hasInfoBarWithID(std::u16string_view sId)
447
0
{
448
0
    return (getInfoBar(sId) != nullptr);
449
0
}
450
451
void SfxInfoBarContainerWindow::removeInfoBar(VclPtr<SfxInfoBarWindow> const& pInfoBar)
452
0
{
453
    // Remove
454
0
    auto it = std::find(m_pInfoBars.begin(), m_pInfoBars.end(), pInfoBar);
455
0
    if (it != m_pInfoBars.end())
456
0
    {
457
0
        it->disposeAndClear();
458
0
        m_pInfoBars.erase(it);
459
0
    }
460
461
0
    m_pChildWin->Update();
462
0
}
463
464
bool SfxInfoBarContainerWindow::isInfobarEnabled(std::u16string_view sId)
465
0
{
466
0
    if (sId == u"readonly")
467
0
        return officecfg::Office::UI::Infobar::Enabled::Readonly::get();
468
0
    if (sId == u"signature")
469
0
        return officecfg::Office::UI::Infobar::Enabled::Signature::get();
470
0
    if (sId == u"donate")
471
0
        return officecfg::Office::UI::Infobar::Enabled::Donate::get();
472
0
    if (sId == u"getinvolved")
473
0
        return officecfg::Office::UI::Infobar::Enabled::GetInvolved::get();
474
0
    if (sId == u"hyphenationmissing")
475
0
        return officecfg::Office::UI::Infobar::Enabled::HyphenationMissing::get();
476
0
    if (sId == u"whatsnew")
477
0
        return officecfg::Office::UI::Infobar::Enabled::WhatsNew::get();
478
0
    if (sId == u"hiddentrackchanges")
479
0
        return officecfg::Office::UI::Infobar::Enabled::HiddenTrackChanges::get();
480
0
    if (sId == u"macro")
481
0
        return officecfg::Office::UI::Infobar::Enabled::MacrosDisabled::get();
482
0
    if (sId == u"securitywarn")
483
0
    {
484
0
        return officecfg::Office::Common::Security::Scripting::WarnSaveOrSendDoc::get()
485
0
               || officecfg::Office::Common::Security::Scripting::WarnSignDoc::get()
486
0
               || officecfg::Office::Common::Security::Scripting::WarnPrintDoc::get()
487
0
               || officecfg::Office::Common::Security::Scripting::WarnCreatePDF::get();
488
0
    }
489
0
    if (sId == u"autocorr_leadtrail")
490
0
        return officecfg::Office::UI::Infobar::Enabled::AutoCorrLeadTrail::get();
491
0
    if (sId == u"VCL_gen")
492
0
        return officecfg::Office::UI::Infobar::Enabled::WarnGenericVCL::get();
493
494
0
    return true;
495
0
}
496
497
// This triggers the SfxFrame to re-layout its childwindows
498
0
void SfxInfoBarContainerWindow::TriggerUpdateLayout() { m_aLayoutIdle.Start(); }
499
500
void SfxInfoBarContainerWindow::Resize()
501
0
{
502
0
    if (m_bResizing)
503
0
        return;
504
0
    m_bResizing = true;
505
0
    const Size aWindowOrigSize = GetSizePixel();
506
0
    auto nOrigWidth = aWindowOrigSize.getWidth();
507
0
    auto nOrigHeight = aWindowOrigSize.getHeight();
508
509
0
    tools::Long nHeight = 0;
510
511
0
    for (auto& rxInfoBar : m_pInfoBars)
512
0
    {
513
0
        Size aOrigSize = rxInfoBar->GetSizePixel();
514
0
        Size aSize(nOrigWidth, aOrigSize.Height());
515
516
0
        Point aPos(0, nHeight);
517
        // stage 1: provisionally size the infobar,
518
0
        rxInfoBar->SetPosSizePixel(aPos, aSize);
519
520
        // stage 2: perhaps allow height to stretch to fit
521
        // the stage 1 width
522
0
        aSize = rxInfoBar->DoLayout();
523
0
        rxInfoBar->SetPosSizePixel(aPos, aSize);
524
0
        rxInfoBar->Show();
525
526
        // Stretch to fit the infobar(s)
527
0
        nHeight += aSize.getHeight();
528
0
    }
529
530
0
    if (nOrigHeight != nHeight)
531
0
    {
532
0
        SetSizePixel(Size(nOrigWidth, nHeight));
533
0
        TriggerUpdateLayout();
534
0
    }
535
536
0
    m_bResizing = false;
537
0
}
538
539
SFX_IMPL_POS_CHILDWINDOW_WITHID(SfxInfoBarContainerChild, SID_INFOBAR, SFX_OBJECTBAR_OBJECT);
540
541
SfxInfoBarContainerChild::SfxInfoBarContainerChild(vcl::Window* _pParent, sal_uInt16 nId,
542
                                                   SfxBindings* pBindings, SfxChildWinInfo*)
543
0
    : SfxChildWindow(_pParent, nId)
544
0
    , m_pBindings(pBindings)
545
0
{
546
0
    SetWindow(VclPtr<SfxInfoBarContainerWindow>::Create(this));
547
0
    GetWindow()->SetPosSizePixel(Point(0, 0), Size(_pParent->GetSizePixel().getWidth(), 0));
548
0
    GetWindow()->Show();
549
550
0
    SetAlignment(SfxChildAlignment::LOWESTTOP);
551
0
}
552
553
0
SfxInfoBarContainerChild::~SfxInfoBarContainerChild() {}
554
555
SfxChildWinInfo SfxInfoBarContainerChild::GetInfo() const
556
0
{
557
0
    SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
558
0
    return aInfo;
559
0
}
560
561
void SfxInfoBarContainerChild::Update()
562
0
{
563
    // Layout to current width, this may change the height
564
0
    if (vcl::Window* pChild = GetWindow())
565
0
    {
566
0
        Size aSize(pChild->GetSizePixel());
567
0
        pChild->Resize();
568
0
        if (aSize == pChild->GetSizePixel())
569
0
            return;
570
0
    }
571
572
    // Refresh the frame to take the infobars container height change into account
573
0
    const sal_uInt16 nId = GetChildWindowId();
574
0
    SfxViewFrame* pVFrame = m_pBindings->GetDispatcher()->GetFrame();
575
0
    pVFrame->ShowChildWindow(nId);
576
577
    // Give the focus to the document view
578
0
    pVFrame->GetWindow().GrabFocusToDocument();
579
0
}
580
581
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */