diff options
author | Caolán McNamara <caolanm@redhat.com> | 2020-09-08 09:30:35 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2020-09-21 20:10:06 +0200 |
commit | af90b8089405d6f042207f5639e750f08798ae92 (patch) | |
tree | 0af8401f534cbce9a11e64c1819ef84413ddd912 | |
parent | 416c11d189a18a08c28135b8aa5e0f12cd51dcd6 (diff) |
weld infobars
note: "pushed" status listener case dropped. Doesn't seem to be an expectation
for it to something in infobars, and there doesn't seem to be a working case
anyway.
Change-Id: I7869cc05de9918f0dd70e28b0087205db6c9506c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101945
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | compilerplugins/clang/constantparam.numbers.results | 4 | ||||
-rw-r--r-- | include/sfx2/infobar.hxx | 57 | ||||
-rw-r--r-- | include/sfx2/objsh.hxx | 4 | ||||
-rw-r--r-- | include/sfx2/sfxbasecontroller.hxx | 4 | ||||
-rw-r--r-- | include/sfx2/viewfrm.hxx | 12 | ||||
-rw-r--r-- | include/vcl/weldutils.hxx | 29 | ||||
-rw-r--r-- | sc/source/ui/docshell/docsh4.cxx | 10 | ||||
-rw-r--r-- | sc/source/ui/inc/docsh.hxx | 2 | ||||
-rw-r--r-- | sfx2/UIConfig_sfx.mk | 2 | ||||
-rw-r--r-- | sfx2/source/dialog/infobar.cxx | 380 | ||||
-rw-r--r-- | sfx2/source/doc/objserv.cxx | 10 | ||||
-rw-r--r-- | sfx2/source/view/sfxbasecontroller.cxx | 17 | ||||
-rw-r--r-- | sfx2/source/view/viewfrm.cxx | 56 | ||||
-rw-r--r-- | sfx2/uiconfig/ui/extrabutton.ui | 24 | ||||
-rw-r--r-- | sfx2/uiconfig/ui/infobar.ui | 187 | ||||
-rw-r--r-- | solenv/sanitizers/ui/sfx.suppr | 1 | ||||
-rw-r--r-- | vcl/source/app/weldutils.cxx | 58 |
17 files changed, 584 insertions, 273 deletions
diff --git a/compilerplugins/clang/constantparam.numbers.results b/compilerplugins/clang/constantparam.numbers.results index 0a808e5f2924..add43943e088 100644 --- a/compilerplugins/clang/constantparam.numbers.results +++ b/compilerplugins/clang/constantparam.numbers.results @@ -806,10 +806,6 @@ include/sfx2/frame.hxx:192 void SfxUnoFrameItem::SfxUnoFrameItem(unsigned short,const class com::sun::star::uno::Reference<class com::sun::star::frame::XFrame> &) unsigned short nWhich 6516 -include/sfx2/infobar.hxx:111 - class VclPtr<class SfxInfoBarWindow> SfxInfoBarContainerWindow::appendInfoBar(const class rtl::OUString &,const class rtl::OUString &,const class rtl::OUString &,enum InfobarType,long,_Bool) - long nMessageStyle - 278528 include/sfx2/linkmgr.hxx:63 _Bool sfx2::LinkManager::InsertLink(class sfx2::SvBaseLink *,enum sfx2::SvBaseLinkObjectType,enum SfxLinkUpdateMode,const class rtl::OUString *) enum SfxLinkUpdateMode nUpdateType diff --git a/include/sfx2/infobar.hxx b/include/sfx2/infobar.hxx index 40a1b1ff9fbf..a03c833b957d 100644 --- a/include/sfx2/infobar.hxx +++ b/include/sfx2/infobar.hxx @@ -15,11 +15,7 @@ #include <sfx2/childwin.hxx> #include <sfx2/dllapi.h> - -class FixedImage; -class FixedText; -class Button; -class PushButton; +#include <vcl/InterimItemWindow.hxx> // These must match the values in offapi/com/sun/star/frame/InfobarType.idl enum class InfobarType @@ -57,44 +53,59 @@ public: void Update(); }; +class ExtraButton; + /** Class representing a single InfoBar to be added in a SfxInfoBarContainerWindow. */ -class SFX2_DLLPUBLIC SfxInfoBarWindow final : public vcl::Window +class SFX2_DLLPUBLIC SfxInfoBarWindow final : public InterimItemWindow { private: OUString m_sId; InfobarType m_eType; - VclPtr<FixedImage> m_pImage; - VclPtr<FixedText> m_pPrimaryMessage; - VclPtr<FixedText> m_pSecondaryMessage; - VclPtr<Button> m_pCloseBtn; - std::vector<VclPtr<PushButton>> m_aActionBtns; + Size m_aSize; + Size m_aMessageSize; + Size m_aOrigMessageSize; + bool m_bLayingOut; + std::unique_ptr<weld::Image> m_xImage; + std::unique_ptr<weld::Label> m_xPrimaryMessage; + std::unique_ptr<weld::TextView> m_xSecondaryMessage; + std::unique_ptr<weld::Container> m_xButtonBox; + std::unique_ptr<weld::Toolbar> m_xCloseBtn; + std::vector<std::unique_ptr<ExtraButton>> m_aActionBtns; + + DECL_LINK(SizeAllocHdl, const Size&, void); void SetForeAndBackgroundColors(InfobarType eType); + void SetCloseButtonImage(); public: SfxInfoBarWindow(vcl::Window* parent, const OUString& sId, const OUString& sPrimaryMessage, const OUString& sSecondaryMessage, InfobarType InfobarType, - WinBits nMessageStyle, bool bShowCloseButton); + bool bShowCloseButton); + Size DoLayout(); + virtual void Layout() override; virtual ~SfxInfoBarWindow() override; virtual void dispose() override; const OUString& getId() const { return m_sId; } - virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; - virtual void Resize() override; void Update(const OUString& sPrimaryMessage, const OUString& sSecondaryMessage, InfobarType eType); basegfx::BColor m_aBackgroundColor; basegfx::BColor m_aForegroundColor; /** Add button to Infobar. - * Infobar takes ownership of the button so the button is - * destroyed when the infobar gets destroyed. - */ - void addButton(PushButton* pButton); + * Infobar takes ownership of the button so the button is + * destroyed when the infobar gets destroyed. + * + * The optional "pCommand" is used by extensions, via XInfobarProvider, to + * dispatch pCommand on click. + */ + weld::Button& addButton(const OUString* pCommand = nullptr); + + void SetCommandHandler(weld::Button& rBtn, const OUString& aCommand); private: - DECL_LINK(CloseHandler, Button*, void); + DECL_LINK(CloseHandler, const OString&, void); }; class SfxInfoBarContainerWindow final : public vcl::Window @@ -102,6 +113,10 @@ class SfxInfoBarContainerWindow final : public vcl::Window private: SfxInfoBarContainerChild* m_pChildWin; std::vector<VclPtr<SfxInfoBarWindow>> m_pInfoBars; + Idle m_aLayoutIdle; + bool m_bResizing; + + DECL_LINK(DoUpdateLayout, Timer*, void); public: SfxInfoBarContainerWindow(SfxInfoBarContainerChild* pChildWin); @@ -110,12 +125,14 @@ public: VclPtr<SfxInfoBarWindow> appendInfoBar(const OUString& sId, const OUString& sPrimaryMessage, const OUString& sSecondaryMessage, InfobarType ibType, - WinBits nMessageStyle, bool bShowCloseButton); + bool bShowCloseButton); VclPtr<SfxInfoBarWindow> getInfoBar(const OUString& sId); bool hasInfoBarWithID(const OUString& sId); void removeInfoBar(VclPtr<SfxInfoBarWindow> const& pInfoBar); static bool isInfobarEnabled(const OUString& sId); + void TriggerUpdateLayout(); + virtual void Resize() override; }; diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx index 8da1f2bb7f82..e60139348c26 100644 --- a/include/sfx2/objsh.hxx +++ b/include/sfx2/objsh.hxx @@ -41,6 +41,7 @@ #include <functional> #include <sfx2/AccessibilityIssue.hxx> +namespace weld {class Button; } class SbxValue; class SbxArray; class BasicManager; @@ -58,7 +59,6 @@ class GDIMetaFile; class INetURLObject; class IndexBitSet; class JobSetup; -class Button; class OutputDevice; class Color; class Fraction; @@ -368,7 +368,7 @@ public: const OUString& aComment); SignatureState GetScriptingSignatureState(); void SignScriptingContent(weld::Window* pDialogParent); - DECL_LINK(SignDocumentHandler, Button*, void); + DECL_LINK(SignDocumentHandler, weld::Button&, void); virtual std::shared_ptr<SfxDocumentInfoDialog> CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet); diff --git a/include/sfx2/sfxbasecontroller.hxx b/include/sfx2/sfxbasecontroller.hxx index 7fd536a14ef7..2adae2ec6cdc 100644 --- a/include/sfx2/sfxbasecontroller.hxx +++ b/include/sfx2/sfxbasecontroller.hxx @@ -50,10 +50,10 @@ namespace com::sun::star::frame { struct DispatchDescriptor; } namespace com::sun::star::ui { class XContextMenuInterceptor; } namespace com::sun::star::ui { class XSidebarProvider; } namespace com::sun::star::util { struct URL; } +namespace weld { class Button; } struct IMPL_SfxBaseController_DataContainer ; // impl. struct to hold member of class SfxBaseController -class Button; class NotifyEvent; class SfxViewFrame; class SfxViewShell; @@ -207,7 +207,7 @@ private: SAL_DLLPRIVATE SfxViewFrame& GetViewFrame_Impl() const; SAL_DLLPRIVATE void ShowInfoBars( ); - DECL_LINK( CheckOutHandler, Button*, void ); + DECL_LINK( CheckOutHandler, weld::Button&, void ); std::unique_ptr<IMPL_SfxBaseController_DataContainer> m_pData ; diff --git a/include/sfx2/viewfrm.hxx b/include/sfx2/viewfrm.hxx index 07d1360c57c7..aedd362f8781 100644 --- a/include/sfx2/viewfrm.hxx +++ b/include/sfx2/viewfrm.hxx @@ -30,7 +30,7 @@ #include <svl/poolitem.hxx> #include <vcl/svapp.hxx> -class Button; +namespace weld { class Button; } class SvBorder; class SfxDispatcher; class SfxBindings; @@ -59,11 +59,11 @@ private: protected: virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; - DECL_LINK(GetInvolvedHandler, Button*, void); - DECL_LINK(DonationHandler, Button*, void); - DECL_LINK(WhatsNewHandler, Button*, void); - DECL_LINK(SwitchReadOnlyHandler, Button*, void); - DECL_LINK(SignDocumentHandler, Button*, void); + DECL_LINK(GetInvolvedHandler, weld::Button&, void); + DECL_LINK(DonationHandler, weld::Button&, void); + DECL_LINK(WhatsNewHandler, weld::Button&, void); + DECL_LINK(SwitchReadOnlyHandler, weld::Button&, void); + DECL_LINK(SignDocumentHandler, weld::Button&, void); SAL_DLLPRIVATE void KillDispatcher_Impl(); virtual ~SfxViewFrame() override; diff --git a/include/vcl/weldutils.hxx b/include/vcl/weldutils.hxx index 7eb4334e0156..7d22a456119e 100644 --- a/include/vcl/weldutils.hxx +++ b/include/vcl/weldutils.hxx @@ -11,6 +11,9 @@ #define INCLUDED_VCL_WELDUTILS_HXX #include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> #include <com/sun/star/uno/Reference.hxx> #include <comphelper/interfacecontainer2.hxx> #include <cppuhelper/compbase.hxx> @@ -156,6 +159,32 @@ public: } }; +class VCL_DLLPUBLIC WidgetStatusListener final + : public cppu::WeakImplHelper<css::frame::XStatusListener> +{ +public: + WidgetStatusListener(weld::Widget* widget, const OUString& rCommand); + +private: + weld::Widget* mWidget; /** The widget on which actions are performed */ + + /** Dispatcher. Need to keep a reference to it as long as this StatusListener exists. */ + css::uno::Reference<css::frame::XDispatch> mxDispatch; + css::util::URL maCommandURL; + css::uno::Reference<css::frame::XFrame> mxFrame; + +public: + void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override; + + void SAL_CALL disposing(const css::lang::EventObject& /*Source*/) override; + + const css::uno::Reference<css::frame::XFrame>& getFrame() { return mxFrame; } + + void startListening(); + + void dispose(); +}; + class VCL_DLLPUBLIC EntryFormatter : public Formatter { public: diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx index ecce1c5da91f..a63a8b49619b 100644 --- a/sc/source/ui/docshell/docsh4.cxx +++ b/sc/source/ui/docshell/docsh4.cxx @@ -135,7 +135,7 @@ void ScDocShell::ReloadAllLinks() m_aDocument.UpdateAreaLinks(); } -IMPL_LINK_NOARG( ScDocShell, ReloadAllLinksHdl, Button*, void ) +IMPL_LINK_NOARG( ScDocShell, ReloadAllLinksHdl, weld::Button&, void ) { ReloadAllLinks(); @@ -500,11 +500,9 @@ void ScDocShell::Execute( SfxRequest& rReq ) auto pInfoBar = pViewFrame->AppendInfoBar("enablecontent", "", ScResId(STR_RELOAD_TABLES), InfobarType::WARNING); if (pInfoBar) { - VclPtrInstance<PushButton> xBtn(&pViewFrame->GetWindow()); - xBtn->SetText(ScResId(STR_ENABLE_CONTENT)); - xBtn->SetSizePixel(xBtn->GetOptimalSize()); - xBtn->SetClickHdl(LINK(this, ScDocShell, ReloadAllLinksHdl)); - pInfoBar->addButton(xBtn); + weld::Button& rBtn = pInfoBar->addButton(); + rBtn.set_label(ScResId(STR_ENABLE_CONTENT)); + rBtn.connect_clicked(LINK(this, ScDocShell, ReloadAllLinksHdl)); } } rReq.Done(); diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx index e23067503bae..8a7fc31c1364 100644 --- a/sc/source/ui/inc/docsh.hxx +++ b/sc/source/ui/inc/docsh.hxx @@ -337,7 +337,7 @@ public: void UnlockDocument(); DECL_LINK( DialogClosedHdl, sfx2::FileDialogHelper*, void ); - DECL_LINK( ReloadAllLinksHdl, Button*, void ); + DECL_LINK( ReloadAllLinksHdl, weld::Button&, void ); virtual SfxStyleSheetBasePool* GetStyleSheetPool() override; diff --git a/sfx2/UIConfig_sfx.mk b/sfx2/UIConfig_sfx.mk index 5e79a8399cbf..5bb91d7ac6f6 100644 --- a/sfx2/UIConfig_sfx.mk +++ b/sfx2/UIConfig_sfx.mk @@ -30,6 +30,7 @@ $(eval $(call gb_UIConfig_add_uifiles,sfx,\ sfx2/uiconfig/ui/editdocumentdialog \ sfx2/uiconfig/ui/editdurationdialog \ sfx2/uiconfig/ui/emojicontrol \ + sfx2/uiconfig/ui/extrabutton \ sfx2/uiconfig/ui/errorfindemaildialog \ sfx2/uiconfig/ui/floatingrecord \ sfx2/uiconfig/ui/helpbookmarkpage \ @@ -39,6 +40,7 @@ $(eval $(call gb_UIConfig_add_uifiles,sfx,\ sfx2/uiconfig/ui/helpmanual \ sfx2/uiconfig/ui/helpsearchpage \ sfx2/uiconfig/ui/helpwindow \ + sfx2/uiconfig/ui/infobar \ sfx2/uiconfig/ui/inputdialog \ sfx2/uiconfig/ui/licensedialog \ sfx2/uiconfig/ui/linefragment \ diff --git a/sfx2/source/dialog/infobar.cxx b/sfx2/source/dialog/infobar.cxx index fd64691ffa99..580bd6685801 100644 --- a/sfx2/source/dialog/infobar.cxx +++ b/sfx2/source/dialog/infobar.cxx @@ -8,6 +8,7 @@ */ #include <basegfx/polygon/b2dpolygon.hxx> +#include <comphelper/dispatchcommand.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx> @@ -21,11 +22,13 @@ #include <sfx2/objface.hxx> #include <sfx2/sfxsids.hrc> #include <sfx2/viewfrm.hxx> -#include <vcl/button.hxx> -#include <vcl/fixed.hxx> #include <vcl/decoview.hxx> +#include <vcl/image.hxx> #include <vcl/settings.hxx> #include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <vcl/weldutils.hxx> +#include <bitmaps.hlst> using namespace std; using namespace drawinglayer::geometry; @@ -37,8 +40,6 @@ using namespace css::frame; namespace { -const long INFO_BAR_BASE_HEIGHT = 40; - void GetInfoBarColors(InfobarType ibType, BColor& rBackgroundColor, BColor& rForegroundColor, BColor& rMessageColor) { @@ -79,54 +80,39 @@ OUString GetInfoBarIconName(InfobarType ibType) switch (ibType) { case InfobarType::INFO: - aRet = "vcl/res/infobox.svg"; + aRet = "vcl/res/infobox.png"; break; case InfobarType::SUCCESS: - aRet = "vcl/res/successbox.svg"; + aRet = "vcl/res/successbox.png"; break; case InfobarType::WARNING: - aRet = "vcl/res/warningbox.svg"; + aRet = "vcl/res/warningbox.png"; break; case InfobarType::DANGER: - aRet = "vcl/res/errorbox.svg"; + aRet = "vcl/res/errorbox.png"; break; } return aRet; } -class SfxCloseButton : public PushButton -{ - basegfx::BColor m_aBackgroundColor; - basegfx::BColor m_aForegroundColor; - -public: - explicit SfxCloseButton(vcl::Window* pParent) - : PushButton(pParent, 0) - { - basegfx::BColor aMessageColor; - GetInfoBarColors(InfobarType::WARNING, m_aBackgroundColor, m_aForegroundColor, - aMessageColor); - } +} // anonymous namespace - virtual void Paint(vcl::RenderContext& rRenderContext, - const ::tools::Rectangle& rRect) override; +void SfxInfoBarWindow::SetCloseButtonImage() +{ + Size aSize = Image(StockImage::Yes, CLOSEDOC).GetSizePixel(); + aSize = Size(aSize.Width() * 1.5, aSize.Height() * 1.5); - void setBackgroundColor(const basegfx::BColor& rColor); - void setForegroundColor(const basegfx::BColor& rColor); -}; + VclPtr<VirtualDevice> xDevice(m_xCloseBtn->create_virtual_device()); + xDevice->SetOutputSizePixel(aSize); -void SfxCloseButton::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&) -{ Point aBtnPos(0, 0); - if (GetButtonState() & DrawButtonFlags::Pressed) - aBtnPos.Move(Size(1, 1)); const ViewInformation2D aNewViewInfos; const unique_ptr<BaseProcessor2D> pProcessor( - createBaseProcessor2DFromOutputDevice(rRenderContext, aNewViewInfos)); + createBaseProcessor2DFromOutputDevice(*xDevice, aNewViewInfos)); - const ::tools::Rectangle aRect(aBtnPos, PixelToLogic(GetSizePixel())); + const ::tools::Rectangle aRect(aBtnPos, xDevice->PixelToLogic(aSize)); drawinglayer::primitive2d::Primitive2DContainer aSeq(2); @@ -138,12 +124,8 @@ void SfxCloseButton::Paint(vcl::RenderContext& rRenderContext, const ::tools::Re aPolygon.append(B2DPoint(aRect.Left(), aRect.Bottom())); aPolygon.setClosed(true); - Color aBackgroundColor(m_aBackgroundColor); - if (IsMouseOver() || HasFocus()) - aBackgroundColor.ApplyTintOrShade(-2000); - PolyPolygonColorPrimitive2D* pBack - = new PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), aBackgroundColor.getBColor()); + = new PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), m_aBackgroundColor); aSeq[0] = pBack; LineAttribute aLineAttribute(m_aForegroundColor, 2.0); @@ -167,187 +149,186 @@ void SfxCloseButton::Paint(vcl::RenderContext& rRenderContext, const ::tools::Re aSeq[1] = pCross; pProcessor->process(aSeq); + + m_xCloseBtn->set_item_image("close", xDevice); } -void SfxCloseButton::setBackgroundColor(const basegfx::BColor& rColor) +class ExtraButton { - m_aBackgroundColor = rColor; -} +private: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<weld::Button> m_xButton; + /** StatusListener. Updates the button as the slot state changes */ + rtl::Reference<weld::WidgetStatusListener> m_xStatusListener; + OUString m_aCommand; + + DECL_LINK(CommandHdl, weld::Button&, void); + +public: + ExtraButton(weld::Container* pContainer, const OUString* pCommand) + : m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/extrabutton.ui")) + , m_xContainer(m_xBuilder->weld_container("ExtraButton")) + , m_xButton(m_xBuilder->weld_button("button")) + { + if (pCommand) + { + m_aCommand = *pCommand; + m_xButton->connect_clicked(LINK(this, ExtraButton, CommandHdl)); + m_xStatusListener.set(new weld::WidgetStatusListener(m_xButton.get(), m_aCommand)); + m_xStatusListener->startListening(); + } + } + + ~ExtraButton() + { + if (m_xStatusListener.is()) + m_xStatusListener->dispose(); + } + + weld::Button& get_widget() { return *m_xButton; } +}; -void SfxCloseButton::setForegroundColor(const basegfx::BColor& rColor) +IMPL_LINK_NOARG(ExtraButton, CommandHdl, weld::Button&, void) { - m_aForegroundColor = rColor; + comphelper::dispatchCommand(m_aCommand, css::uno::Sequence<css::beans::PropertyValue>()); } -} // anonymous namespace - SfxInfoBarWindow::SfxInfoBarWindow(vcl::Window* pParent, const OUString& sId, const OUString& sPrimaryMessage, const OUString& sSecondaryMessage, InfobarType ibType, - WinBits nMessageStyle, bool bShowCloseButton) - : Window(pParent, WB_DIALOGCONTROL) + bool bShowCloseButton) + : InterimItemWindow(pParent, "sfx/ui/infobar.ui", "InfoBar") , m_sId(sId) , m_eType(ibType) - , m_pImage(VclPtr<FixedImage>::Create(this, nMessageStyle)) - , m_pPrimaryMessage(VclPtr<FixedText>::Create(this, nMessageStyle | WB_WORDBREAK)) - , m_pSecondaryMessage(VclPtr<FixedText>::Create(this, nMessageStyle | WB_WORDBREAK)) - , m_pCloseBtn(VclPtr<SfxCloseButton>::Create(this)) + , m_bLayingOut(false) + , m_xImage(m_xBuilder->weld_image("image")) + , m_xPrimaryMessage(m_xBuilder->weld_label("primary")) + , m_xSecondaryMessage(m_xBuilder->weld_text_view("secondary")) + , m_xButtonBox(m_xBuilder->weld_container("buttonbox")) + , m_xCloseBtn(m_xBuilder->weld_toolbar("closebar")) , m_aActionBtns() { - m_pCloseBtn->SetStyle(WB_DEFBUTTON | WB_TABSTOP); - SetForeAndBackgroundColors(m_eType); - float fScaleFactor = GetDPIScaleFactor(); - long nWidth = pParent->GetSizePixel().getWidth(); - SetPosSizePixel(Point(0, 0), Size(nWidth, INFO_BAR_BASE_HEIGHT * fScaleFactor)); + SetStyle(GetStyle() | WB_DIALOGCONTROL); - m_pImage->SetImage(Image(StockImage::Yes, GetInfoBarIconName(ibType))); - m_pImage->SetPaintTransparent(true); - m_pImage->Show(); + InitControlBase(m_xCloseBtn.get()); + + m_xImage->set_from_icon_name(GetInfoBarIconName(ibType)); + m_xSecondaryMessage->set_margin_top(m_xImage->get_preferred_size().Height() / 4); - vcl::Font aFont(m_pPrimaryMessage->GetControlFont()); - aFont.SetWeight(WEIGHT_BOLD); - m_pPrimaryMessage->SetControlFont(aFont); if (!sPrimaryMessage.isEmpty()) { - m_pPrimaryMessage->SetText(sPrimaryMessage); - m_pPrimaryMessage->Show(); + m_xPrimaryMessage->set_label(sPrimaryMessage); + m_xPrimaryMessage->show(); } - m_pSecondaryMessage->SetText(sSecondaryMessage); - m_pSecondaryMessage->Show(); + m_xSecondaryMessage->set_text(sSecondaryMessage); + m_aOrigMessageSize = m_xSecondaryMessage->get_preferred_size(); + m_aMessageSize = m_aOrigMessageSize; + m_xSecondaryMessage->connect_size_allocate(LINK(this, SfxInfoBarWindow, SizeAllocHdl)); if (bShowCloseButton) { - m_pCloseBtn->SetClickHdl(LINK(this, SfxInfoBarWindow, CloseHandler)); - m_pCloseBtn->Show(); + m_xCloseBtn->connect_clicked(LINK(this, SfxInfoBarWindow, CloseHandler)); + m_xCloseBtn->show(); } EnableChildTransparentMode(); - Resize(); -} + SetForeAndBackgroundColors(m_eType); + + auto nWidth = pParent->GetSizePixel().getWidth(); + auto nHeight = get_preferred_size().Height(); + SetSizePixel(Size(nWidth, nHeight + 2)); -void SfxInfoBarWindow::addButton(PushButton* pButton) -{ - pButton->SetParent(this); - pButton->Show(); - m_aActionBtns.emplace_back(pButton); Resize(); } -SfxInfoBarWindow::~SfxInfoBarWindow() { disposeOnce(); } - -void SfxInfoBarWindow::SetForeAndBackgroundColors(InfobarType eType) +IMPL_LINK(SfxInfoBarWindow, SizeAllocHdl, const Size&, rSize, void) { - basegfx::BColor aMessageColor; - GetInfoBarColors(eType, m_aBackgroundColor, m_aForegroundColor, aMessageColor); - - static_cast<SfxCloseButton*>(m_pCloseBtn.get())->setBackgroundColor(m_aBackgroundColor); - static_cast<SfxCloseButton*>(m_pCloseBtn.get())->setForegroundColor(m_aForegroundColor); - m_pPrimaryMessage->SetControlForeground(Color(aMessageColor)); - m_pSecondaryMessage->SetControlForeground(Color(aMessageColor)); + if (m_aMessageSize != rSize) + { + m_aMessageSize = rSize; + static_cast<SfxInfoBarContainerWindow*>(GetParent())->TriggerUpdateLayout(); + } } -void SfxInfoBarWindow::dispose() +Size SfxInfoBarWindow::DoLayout() { - for (auto& rxBtn : m_aActionBtns) - rxBtn.disposeAndClear(); - - m_pImage.disposeAndClear(); - m_pPrimaryMessage.disposeAndClear(); - m_pSecondaryMessage.disposeAndClear(); - m_pCloseBtn.disposeAndClear(); - m_aActionBtns.clear(); - vcl::Window::dispose(); + Size aGivenSize(GetSizePixel()); + + // disconnect SizeAllocHdl because we don't care about the size change + // during layout + m_xSecondaryMessage->connect_size_allocate(Link<const Size&, void>()); + + // blow away size cache in case m_aMessageSize.Width() is already the width request + // and we would get the cached preferred size instead of the recalc we want to force + m_xSecondaryMessage->set_size_request(-1, -1); + // make the width we were detected as set to by SizeAllocHdl as our desired width + m_xSecondaryMessage->set_size_request(m_aMessageSize.Width(), -1); + // get our preferred size with that message width + Size aSizeForWidth(aGivenSize.Width(), m_xContainer->get_preferred_size().Height()); + // restore the message preferred size so we can freely resize, and get a new + // m_aMessageSize and repeat the process if we do + m_xSecondaryMessage->set_size_request(m_aOrigMessageSize.Width(), -1); + + // connect SizeAllocHdl so changes outside of this layout will trigger a new layout + m_xSecondaryMessage->connect_size_allocate(LINK(this, SfxInfoBarWindow, SizeAllocHdl)); + + return aSizeForWidth; } -void SfxInfoBarWindow::Paint(vcl::RenderContext& rRenderContext, - const ::tools::Rectangle& rPaintRect) +void SfxInfoBarWindow::Layout() { - const ViewInformation2D aNewViewInfos; - const unique_ptr<BaseProcessor2D> pProcessor( - createBaseProcessor2DFromOutputDevice(rRenderContext, aNewViewInfos)); + if (m_bLayingOut) + return; + m_bLayingOut = true; - const ::tools::Rectangle aRect(Point(0, 0), PixelToLogic(GetSizePixel())); + InterimItemWindow::Layout(); - drawinglayer::primitive2d::Primitive2DContainer aSeq(2); - - // Light background - B2DPolygon aPolygon; - aPolygon.append(B2DPoint(aRect.Left(), aRect.Top())); - aPolygon.append(B2DPoint(aRect.Right(), aRect.Top())); - aPolygon.append(B2DPoint(aRect.Right(), aRect.Bottom())); - aPolygon.append(B2DPoint(aRect.Left(), aRect.Bottom())); - aPolygon.setClosed(true); - - PolyPolygonColorPrimitive2D* pBack - = new PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), m_aBackgroundColor); - aSeq[0] = pBack; - - LineAttribute aLineAttribute(m_aForegroundColor, 1.0); - - // Bottom dark line - B2DPolygon aPolygonBottom; - aPolygonBottom.append(B2DPoint(aRect.Left(), aRect.Bottom())); - aPolygonBottom.append(B2DPoint(aRect.Right(), aRect.Bottom())); - - PolygonStrokePrimitive2D* pLineBottom - = new PolygonStrokePrimitive2D(aPolygonBottom, aLineAttribute); - - aSeq[1] = pLineBottom; - - pProcessor->process(aSeq); - - Window::Paint(rRenderContext, rPaintRect); + m_bLayingOut = false; } -void SfxInfoBarWindow::Resize() +weld::Button& SfxInfoBarWindow::addButton(const OUString* pCommand) { - float fScaleFactor = GetDPIScaleFactor(); + m_aActionBtns.emplace_back(std::make_unique<ExtraButton>(m_xButtonBox.get(), pCommand)); - long nWidth = GetSizePixel().getWidth(); - m_pCloseBtn->SetPosSizePixel(Point(nWidth - 25 * fScaleFactor, 15 * fScaleFactor), - Size(10 * fScaleFactor, 10 * fScaleFactor)); - - // Reparent the buttons and place them on the right of the bar - long nX = m_pCloseBtn->GetPosPixel().getX() - 15 * fScaleFactor; - long nButtonGap = 5 * fScaleFactor; - - for (auto const& actionBtn : m_aActionBtns) - { - long nButtonWidth = actionBtn->GetSizePixel().getWidth(); - nX -= nButtonWidth; - actionBtn->SetPosSizePixel(Point(nX, 5 * fScaleFactor), - Size(nButtonWidth, 30 * fScaleFactor)); - nX -= nButtonGap; - } + return m_aActionBtns.back()->get_widget(); +} - Point aPrimaryMessagePosition(32 * fScaleFactor + 10 * fScaleFactor, 10 * fScaleFactor); - Point aSecondaryMessagePosition(aPrimaryMessagePosition); - Size aMessageSize(nX - 35 * fScaleFactor, 20 * fScaleFactor); - Size aPrimaryTextSize = m_pPrimaryMessage->CalcMinimumSize(aMessageSize.getWidth()); - Size aSecondaryTextSize = m_pSecondaryMessage->CalcMinimumSize(aMessageSize.getWidth() - - aPrimaryTextSize.getWidth()); - if (!m_pPrimaryMessage->GetText().isEmpty()) - aSecondaryMessagePosition.AdjustX(aPrimaryTextSize.getWidth() + 6 * fScaleFactor); +SfxInfoBarWindow::~SfxInfoBarWindow() { disposeOnce(); } - long aMinimumHeight = std::max(m_pPrimaryMessage->CalcMinimumSize().getHeight(), - m_pSecondaryMessage->CalcMinimumSize().getHeight()); +void SfxInfoBarWindow::SetForeAndBackgroundColors(InfobarType eType) +{ + basegfx::BColor aMessageColor; + GetInfoBarColors(eType, m_aBackgroundColor, m_aForegroundColor, aMessageColor); - long aExtraHeight = aSecondaryTextSize.getHeight() - aMinimumHeight; + m_xPrimaryMessage->set_font_color(Color(aMessageColor)); + m_xSecondaryMessage->set_font_color(Color(aMessageColor)); - // The message won't be legible and the window will get too high - if (aMessageSize.getWidth() < 30) + Color aBackgroundColor(m_aBackgroundColor); + m_xPrimaryMessage->set_background(aBackgroundColor); + m_xSecondaryMessage->set_background(aBackgroundColor); + m_xContainer->set_background(aBackgroundColor); + if (m_xCloseBtn->get_visible()) { - aExtraHeight = 0; + m_xCloseBtn->set_background(aBackgroundColor); + SetCloseButtonImage(); } +} - m_pPrimaryMessage->SetPosSizePixel(aPrimaryMessagePosition, aPrimaryTextSize); - m_pSecondaryMessage->SetPosSizePixel(aSecondaryMessagePosition, aSecondaryTextSize); - m_pImage->SetPosSizePixel(Point(4, 4), Size(32 * fScaleFactor, 32 * fScaleFactor)); +void SfxInfoBarWindow::dispose() +{ + for (auto& rxBtn : m_aActionBtns) + rxBtn.reset(); - SetPosSizePixel(GetPosPixel(), Size(nWidth, INFO_BAR_BASE_HEIGHT * fScaleFactor - + aExtraHeight * fScaleFactor)); + m_xImage.reset(); + m_xPrimaryMessage.reset(); + m_xSecondaryMessage.reset(); + m_xButtonBox.reset(); + m_xCloseBtn.reset(); + m_aActionBtns.clear(); + InterimItemWindow::dispose(); } void SfxInfoBarWindow::Update(const OUString& sPrimaryMessage, const OUString& sSecondaryMessage, @@ -357,16 +338,16 @@ void SfxInfoBarWindow::Update(const OUString& sPrimaryMessage, const OUString& s { m_eType = eType; SetForeAndBackgroundColors(m_eType); - m_pImage->SetImage(Image(StockImage::Yes, GetInfoBarIconName(eType))); + m_xImage->set_from_icon_name(GetInfoBarIconName(eType)); } - m_pPrimaryMessage->SetText(sPrimaryMessage); - m_pSecondaryMessage->SetText(sSecondaryMessage); + m_xPrimaryMessage->set_label(sPrimaryMessage); + m_xSecondaryMessage->set_text(sSecondaryMessage); Resize(); Invalidate(); } -IMPL_LINK_NOARG(SfxInfoBarWindow, CloseHandler, Button*, void) +IMPL_LINK_NOARG(SfxInfoBarWindow, CloseHandler, const OString&, void) { static_cast<SfxInfoBarContainerWindow*>(GetParent())->removeInfoBar(this); } @@ -375,9 +356,15 @@ SfxInfoBarContainerWindow::SfxInfoBarContainerWindow(SfxInfoBarContainerChild* p : Window(pChildWin->GetParent(), WB_DIALOGCONTROL) , m_pChildWin(pChildWin) , m_pInfoBars() + , m_bResizing(false) { + m_aLayoutIdle.SetPriority(TaskPriority::HIGHEST); + m_aLayoutIdle.SetInvokeHandler(LINK(this, SfxInfoBarContainerWindow, DoUpdateLayout)); + m_aLayoutIdle.SetDebugName("SfxInfoBarContainerWindow m_aLayoutIdle"); } +IMPL_LINK_NOARG(SfxInfoBarContainerWindow, DoUpdateLayout, Timer*, void) { m_pChildWin->Update(); } + SfxInfoBarContainerWindow::~SfxInfoBarContainerWindow() { disposeOnce(); } void SfxInfoBarContainerWindow::dispose() @@ -388,16 +375,17 @@ void SfxInfoBarContainerWindow::dispose() Window::dispose(); } -VclPtr<SfxInfoBarWindow> -SfxInfoBarContainerWindow::appendInfoBar(const OUString& sId, const OUString& sPrimaryMessage, - const OUString& sSecondaryMessage, InfobarType ibType, - WinBits nMessageStyle, bool bShowCloseButton) +VclPtr<SfxInfoBarWindow> SfxInfoBarContainerWindow::appendInfoBar(const OUString& sId, + const OUString& sPrimaryMessage, + const OUString& sSecondaryMessage, + InfobarType ibType, + bool bShowCloseButton) { if (!isInfobarEnabled(sId)) return nullptr; auto pInfoBar = VclPtr<SfxInfoBarWindow>::Create(this, sId, sPrimaryMessage, sSecondaryMessage, - ibType, nMessageStyle, bShowCloseButton); + ibType, bShowCloseButton); basegfx::BColor aBackgroundColor; basegfx::BColor aForegroundColor; @@ -436,8 +424,6 @@ void SfxInfoBarContainerWindow::removeInfoBar(VclPtr<SfxInfoBarWindow> const& pI m_pInfoBars.erase(it); } - Resize(); - m_pChildWin->Update(); } @@ -457,25 +443,46 @@ bool SfxInfoBarContainerWindow::isInfobarEnabled(const OUString& sId) return true; } +// This triggers the SfxFrame to re-layout its childwindows +void SfxInfoBarContainerWindow::TriggerUpdateLayout() { m_aLayoutIdle.Start(); } + void SfxInfoBarContainerWindow::Resize() { - long nWidth = GetSizePixel().getWidth(); + if (m_bResizing) + return; + m_bResizing = true; + const Size& rOrigSize = GetSizePixel(); + auto nOrigWidth = rOrigSize.getWidth(); + auto nOrigHeight = rOrigSize.getHeight(); + long nHeight = 0; for (auto& rxInfoBar : m_pInfoBars) { - Size aSize = rxInfoBar->GetSizePixel(); - aSize.setWidth(nWidth); + Size aOrigSize = rxInfoBar->GetSizePixel(); + Size aSize(nOrigWidth, aOrigSize.Height()); + Point aPos(0, nHeight); + // stage 1: provisionally size the infobar, + rxInfoBar->SetPosSizePixel(aPos, aSize); + + // stage 2: perhaps allow height to stretch to fit + // the stage 1 width + aSize = rxInfoBar->DoLayout(); rxInfoBar->SetPosSizePixel(aPos, aSize); - rxInfoBar->Resize(); rxInfoBar->Show(); // Stretch to fit the infobar(s) nHeight += aSize.getHeight(); } - SetSizePixel(Size(nWidth, nHeight)); + if (nOrigHeight != nHeight) + { + SetSizePixel(Size(nOrigWidth, nHeight)); + TriggerUpdateLayout(); + } + + m_bResizing = false; } SFX_IMPL_POS_CHILDWINDOW_WITHID(SfxInfoBarContainerChild, SID_INFOBAR, SFX_OBJECTBAR_OBJECT); @@ -502,6 +509,15 @@ SfxChildWinInfo SfxInfoBarContainerChild::GetInfo() const void SfxInfoBarContainerChild::Update() { + // Layout to current width, this may change the height + if (vcl::Window* pChild = GetWindow()) + { + Size aSize(pChild->GetSizePixel()); + pChild->Resize(); + if (aSize == pChild->GetSizePixel()) + return; + } + // Refresh the frame to take the infobars container height change into account const sal_uInt16 nId = GetChildWindowId(); SfxViewFrame* pVFrame = m_pBindings->GetDispatcher()->GetFrame(); diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx index 8ab9ea898e9a..47c25433ee51 100644 --- a/sfx2/source/doc/objserv.cxx +++ b/sfx2/source/doc/objserv.cxx @@ -1434,11 +1434,9 @@ void SfxObjectShell::GetState_Impl(SfxItemSet &rSet) auto pInfoBar = pFrame->AppendInfoBar("signature", "", sMessage, aInfobarType); if (pInfoBar == nullptr || pInfoBar->IsDisposed()) return; - VclPtrInstance<PushButton> xBtn(&(pFrame->GetWindow())); - xBtn->SetText(SfxResId(STR_SIGNATURE_SHOW)); - xBtn->SetSizePixel(xBtn->GetOptimalSize()); - xBtn->SetClickHdl(LINK(this, SfxObjectShell, SignDocumentHandler)); - pInfoBar->addButton(xBtn); + weld::Button& rBtn = pInfoBar->addButton(); + rBtn.set_label(SfxResId(STR_SIGNATURE_SHOW)); + rBtn.connect_clicked(LINK(this, SfxObjectShell, SignDocumentHandler)); } } else // info bar exists already @@ -1475,7 +1473,7 @@ void SfxObjectShell::GetState_Impl(SfxItemSet &rSet) } } -IMPL_LINK_NOARG(SfxObjectShell, SignDocumentHandler, Button*, void) +IMPL_LINK_NOARG(SfxObjectShell, SignDocumentHandler, weld::Button&, void) { GetDispatcher()->Execute(SID_SIGNATURE); } diff --git a/sfx2/source/view/sfxbasecontroller.cxx b/sfx2/source/view/sfxbasecontroller.cxx index a4706277e869..8f4ba77305db 100644 --- a/sfx2/source/view/sfxbasecontroller.cxx +++ b/sfx2/source/view/sfxbasecontroller.cxx @@ -1398,15 +1398,13 @@ void SfxBaseController::ShowInfoBars( ) InfobarType::WARNING); if (pInfoBar) { - VclPtrInstance<PushButton> xBtn(&pViewFrame->GetWindow()); - xBtn->SetText(SfxResId(STR_CHECKOUT)); - xBtn->SetSizePixel(xBtn->GetOptimalSize()); - xBtn->SetClickHdl(LINK(this, SfxBaseController, CheckOutHandler)); - pInfoBar->addButton(xBtn); + weld::Button &rBtn = pInfoBar->addButton(); + rBtn.set_label(SfxResId(STR_CHECKOUT)); + rBtn.connect_clicked(LINK(this, SfxBaseController, CheckOutHandler)); } } -IMPL_LINK_NOARG ( SfxBaseController, CheckOutHandler, Button*, void ) +IMPL_LINK_NOARG ( SfxBaseController, CheckOutHandler, weld::Button&, void ) { if ( m_pData->m_pViewShell ) m_pData->m_pViewShell->GetObjectShell()->CheckOut( ); @@ -1498,11 +1496,8 @@ void SAL_CALL SfxBaseController::appendInfobar(const OUString& sId, const OUStri { if (actionButton.First.isEmpty() || actionButton.Second.isEmpty()) continue; - VclPtrInstance<PushButton> xBtn(&pViewFrame->GetWindow()); - xBtn->SetText(actionButton.First); - xBtn->SetSizePixel(xBtn->GetOptimalSize()); - xBtn->SetCommandHandler(actionButton.Second); - pInfoBar->addButton(xBtn); + weld::Button& rBtn = pInfoBar->addButton(&actionButton.Second); + rBtn.set_label(actionButton.First); } } diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx index 9e4b4b280c59..ccb39350f223 100644 --- a/sfx2/source/view/viewfrm.cxx +++ b/sfx2/source/view/viewfrm.cxx @@ -1258,19 +1258,17 @@ void SfxViewFrame::AppendReadOnlyInfobar() { // SID_SIGNPDF opened a read-write PDF // read-only for signing purposes. - VclPtrInstance<PushButton> xSignButton(&GetWindow()); + weld::Button& rSignButton = pInfoBar->addButton(); if (bSignWithCert) { - xSignButton->SetText(SfxResId(STR_READONLY_FINISH_SIGN)); + rSignButton.set_label(SfxResId(STR_READONLY_FINISH_SIGN)); } else { - xSignButton->SetText(SfxResId(STR_READONLY_SIGN)); + rSignButton.set_label(SfxResId(STR_READONLY_SIGN)); } - xSignButton->SetSizePixel(xSignButton->GetOptimalSize()); - xSignButton->SetClickHdl(LINK(this, SfxViewFrame, SignDocumentHandler)); - pInfoBar->addButton(xSignButton); + rSignButton.connect_clicked(LINK(this, SfxViewFrame, SignDocumentHandler)); } bool showEditDocumentButton = true; @@ -1279,11 +1277,9 @@ void SfxViewFrame::AppendReadOnlyInfobar() if (showEditDocumentButton) { - VclPtrInstance<PushButton> xBtn(&GetWindow()); - xBtn->SetText(SfxResId(STR_READONLY_EDIT)); - xBtn->SetSizePixel(xBtn->GetOptimalSize()); - xBtn->SetClickHdl(LINK(this, SfxViewFrame, SwitchReadOnlyHandler)); - pInfoBar->addButton(xBtn); + weld::Button& rBtn = pInfoBar->addButton(); + rBtn.set_label(SfxResId(STR_READONLY_EDIT)); + rBtn.connect_clicked(LINK(this, SfxViewFrame, SwitchReadOnlyHandler)); } } @@ -1341,11 +1337,9 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("whatsnew", "", SfxResId(STR_WHATSNEW_TEXT), InfobarType::INFO); if (pInfoBar) { - VclPtrInstance<PushButton> xWhatsNewButton(&GetWindow()); - xWhatsNewButton->SetText(SfxResId(STR_WHATSNEW_BUTTON)); - xWhatsNewButton->SetSizePixel(xWhatsNewButton->GetOptimalSize()); - xWhatsNewButton->SetClickHdl(LINK(this, SfxViewFrame, WhatsNewHandler)); - pInfoBar->addButton(xWhatsNewButton); + weld::Button& rWhatsNewButton = pInfoBar->addButton(); + rWhatsNewButton.set_label(SfxResId(STR_WHATSNEW_BUTTON)); + rWhatsNewButton.connect_clicked(LINK(this, SfxViewFrame, WhatsNewHandler)); //update lastversion std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); @@ -1384,11 +1378,9 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) if (pInfoBar) { - VclPtrInstance<PushButton> xGetInvolvedButton(&GetWindow()); - xGetInvolvedButton->SetText(SfxResId(STR_GET_INVOLVED_BUTTON)); - xGetInvolvedButton->SetSizePixel(xGetInvolvedButton->GetOptimalSize()); - xGetInvolvedButton->SetClickHdl(LINK(this, SfxViewFrame, GetInvolvedHandler)); - pInfoBar->addButton(xGetInvolvedButton); + weld::Button& rGetInvolvedButton = pInfoBar->addButton(); + rGetInvolvedButton.set_label(SfxResId(STR_GET_INVOLVED_BUTTON)); + rGetInvolvedButton.connect_clicked(LINK(this, SfxViewFrame, GetInvolvedHandler)); } } @@ -1413,11 +1405,9 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("donate", "", SfxResId(STR_DONATE_TEXT), InfobarType::INFO); if (pInfoBar) { - VclPtrInstance<PushButton> xDonateButton(&GetWindow()); - xDonateButton->SetText(SfxResId(STR_DONATE_BUTTON)); - xDonateButton->SetSizePixel(xDonateButton->GetOptimalSize()); - xDonateButton->SetClickHdl(LINK(this, SfxViewFrame, DonationHandler)); - pInfoBar->addButton(xDonateButton); + weld::Button& rDonateButton = pInfoBar->addButton(); + rDonateButton.set_label(SfxResId(STR_DONATE_BUTTON)); + rDonateButton.connect_clicked(LINK(this, SfxViewFrame, DonationHandler)); } } @@ -1546,33 +1536,33 @@ void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) } } -IMPL_LINK_NOARG(SfxViewFrame, WhatsNewHandler, Button*, void) +IMPL_LINK_NOARG(SfxViewFrame, WhatsNewHandler, weld::Button&, void) { GetDispatcher()->Execute(SID_WHATSNEW); } -IMPL_LINK_NOARG(SfxViewFrame, GetInvolvedHandler, Button*, void) +IMPL_LINK_NOARG(SfxViewFrame, GetInvolvedHandler, weld::Button&, void) { GetDispatcher()->Execute(SID_GETINVOLVED); } -IMPL_LINK_NOARG(SfxViewFrame, DonationHandler, Button*, void) +IMPL_LINK_NOARG(SfxViewFrame, DonationHandler, weld::Button&, void) { GetDispatcher()->Execute(SID_DONATION); } -IMPL_LINK(SfxViewFrame, SwitchReadOnlyHandler, Button*, pButton, void) +IMPL_LINK(SfxViewFrame, SwitchReadOnlyHandler, weld::Button&, rButton, void) { if (m_xObjSh.is() && m_xObjSh->IsSignPDF()) { - SfxEditDocumentDialog aDialog(pButton->GetFrameWeld()); + SfxEditDocumentDialog aDialog(&rButton); if (aDialog.run() != RET_OK) return; } GetDispatcher()->Execute(SID_EDITDOC); } -IMPL_LINK_NOARG(SfxViewFrame, SignDocumentHandler, Button*, void) +IMPL_LINK_NOARG(SfxViewFrame, SignDocumentHandler, weld::Button&, void) { GetDispatcher()->Execute(SID_SIGNATURE); } @@ -3340,7 +3330,7 @@ VclPtr<SfxInfoBarWindow> SfxViewFrame::AppendInfoBar(const OUString& sId, SfxInfoBarContainerWindow* pInfoBarContainer = static_cast<SfxInfoBarContainerWindow*>(pChild->GetWindow()); auto pInfoBar = pInfoBarContainer->appendInfoBar(sId, sPrimaryMessage, sSecondaryMessage, - aInfobarType, WB_LEFT | WB_VCENTER, bShowCloseButton); + aInfobarType, bShowCloseButton); ShowChildWindow(SfxInfoBarContainerChild::GetChildWindowId()); return pInfoBar; } diff --git a/sfx2/uiconfig/ui/extrabutton.ui b/sfx2/uiconfig/ui/extrabutton.ui new file mode 100644 index 000000000000..69619f5d4ed0 --- /dev/null +++ b/sfx2/uiconfig/ui/extrabutton.ui @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="svt"> + <requires lib="gtk+" version="3.18"/> + <object class="GtkBox" id="ExtraButton"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkButton" id="button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="always_show_image">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> +</interface> diff --git a/sfx2/uiconfig/ui/infobar.ui b/sfx2/uiconfig/ui/infobar.ui new file mode 100644 index 000000000000..73fcd6b1122a --- /dev/null +++ b/sfx2/uiconfig/ui/infobar.ui @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="svt"> + <requires lib="gtk+" version="3.18"/> + <object class="GtkBox" id="InfoBar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="hscrollbar_policy">never</property> + <property name="vscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="border_width">2</property> + <property name="column_spacing">6</property> + <child> + <object class="GtkBox" id="right"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">start</property> + <property name="spacing">3</property> + <child> + <object class="GtkBox" id="buttonbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">center</property> + <property name="spacing">6</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="closebar"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="valign">center</property> + <property name="toolbar_style">icons</property> + <property name="show_arrow">False</property> + <property name="icon_size">1</property> + <child> + <object class="GtkToolButton" id="close"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes" context="infobar|close|tooltip_text">Close Infobar</property> + <property name="icon_name">sfx2/res/closedoc.png</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <style> + <class name="small-button"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="left"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">start</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage" id="image"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">center</property> + <property name="stock">gtk-missing-image</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="primary"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="valign">center</property> + <property name="vexpand">True</property> + <property name="label">label</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + <child internal-child="accessible"> + <object class="AtkObject" id="primary-atkobject"> + <property name="AtkObject::accessible-role">static</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="width_request">60</property> + <property name="height_request">6</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="hscrollbar_policy">never</property> + <property name="vscrollbar_policy">never</property> + <child> + <object class="GtkTextView" id="secondary"> + <property name="width_request">60</property> + <property name="height_request">6</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="editable">False</property> + <property name="wrap_mode">word-char</property> + <property name="cursor_visible">False</property> + <property name="accepts_tab">False</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <object class="GtkSizeGroup" id="sizegroup1"> + <property name="mode">vertical</property> + <widgets> + <widget name="right"/> + <widget name="left"/> + </widgets> + </object> +</interface> diff --git a/solenv/sanitizers/ui/sfx.suppr b/solenv/sanitizers/ui/sfx.suppr index b34b687c0128..4edcdb02a842 100644 --- a/solenv/sanitizers/ui/sfx.suppr +++ b/solenv/sanitizers/ui/sfx.suppr @@ -22,6 +22,7 @@ sfx2/uiconfig/ui/documentinfopage.ui://GtkLabel[@id='showtype'] orphan-label sfx2/uiconfig/ui/documentinfopage.ui://GtkLabel[@id='showtemplate'] orphan-label sfx2/uiconfig/ui/documentinfopage.ui://GtkImage[@id='icon'] no-labelled-by sfx2/uiconfig/ui/documentinfopage.ui://GtkLabel[@id='nameed'] orphan-label +sfx2/uiconfig/ui/extrabutton.ui://GtkButton[@id='button'] button-no-label sfx2/uiconfig/ui/helpindexpage.ui://GtkEntry[@id='termentry'] no-labelled-by sfx2/uiconfig/ui/helpwindow.ui://GtkCheckButton[@id='checkbutton'] button-no-label sfx2/uiconfig/ui/helpwindow.ui://GtkToolButton[@id='index'] button-no-label diff --git a/vcl/source/app/weldutils.cxx b/vcl/source/app/weldutils.cxx index ee074df63d93..237645076330 100644 --- a/vcl/source/app/weldutils.cxx +++ b/vcl/source/app/weldutils.cxx @@ -7,6 +7,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <comphelper/processfactory.hxx> #include <svl/zforlist.hxx> #include <svl/zformat.hxx> #include <vcl/builderpage.hxx> @@ -488,6 +491,61 @@ int GetMinimumEditHeight() std::unique_ptr<weld::Entry> xEntry(xBuilder->weld_entry("name_entry")); return xEntry->get_preferred_size().Height(); } + +WidgetStatusListener::WidgetStatusListener(weld::Widget* widget, const OUString& aCommand) + : mWidget(widget) +{ + css::uno::Reference<css::uno::XComponentContext> xContext + = ::comphelper::getProcessComponentContext(); + css::uno::Reference<css::frame::XDesktop2> xDesktop = css::frame::Desktop::create(xContext); + + css::uno::Reference<css::frame::XFrame> xFrame(xDesktop->getActiveFrame()); + if (!xFrame.is()) + xFrame = xDesktop; + + mxFrame = xFrame; + + maCommandURL.Complete = aCommand; + css::uno::Reference<css::util::XURLTransformer> xParser + = css::util::URLTransformer::create(xContext); + xParser->parseStrict(maCommandURL); +} + +void WidgetStatusListener::startListening() +{ + if (mxDispatch.is()) + mxDispatch->removeStatusListener(this, maCommandURL); + + css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(mxFrame, + css::uno::UNO_QUERY); + if (!xDispatchProvider.is()) + return; + + mxDispatch = xDispatchProvider->queryDispatch(maCommandURL, "", 0); + if (mxDispatch.is()) + mxDispatch->addStatusListener(this, maCommandURL); +} + +void WidgetStatusListener::statusChanged(const css::frame::FeatureStateEvent& rEvent) +{ + mWidget->set_sensitive(rEvent.IsEnabled); +} + +void WidgetStatusListener::disposing(const css::lang::EventObject& /*Source*/) +{ + mxDispatch.clear(); +} + +void WidgetStatusListener::dispose() +{ + if (mxDispatch.is()) + { + mxDispatch->removeStatusListener(this, maCommandURL); + mxDispatch.clear(); + } + mxFrame.clear(); + mWidget = nullptr; +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |