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