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