diff options
author | Caolán McNamara <caolanm@redhat.com> | 2018-02-13 17:41:03 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2018-02-16 00:35:34 +0100 |
commit | 6a3f9de585fc0e8e6191db5210729ae6b3730e7d (patch) | |
tree | 5d053ebe13d08608812c2321dd60a6c9c23ffc70 | |
parent | 7faa218231b7a807412feada3aa1223b43b5626e (diff) |
native dialog initial basis
Change-Id: I392be563e38257390f748c70bb71c67a66778ddd
Reviewed-on: https://gerrit.libreoffice.org/49677
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
35 files changed, 3699 insertions, 167 deletions
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx index d00adb195ac0..936671f07e58 100644 --- a/desktop/source/app/app.cxx +++ b/desktop/source/app/app.cxx @@ -1995,7 +1995,7 @@ void Desktop::OpenClients() #elif defined WNT aHelpURL += "&System=WIN"; #endif - Application::GetHelp()->Start(aHelpURL, nullptr); + Application::GetHelp()->Start(aHelpURL, static_cast<const vcl::Window*>(nullptr)); return; } } @@ -2361,7 +2361,7 @@ void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent ) break; case ApplicationEvent::Type::OpenHelpUrl: // start help for a specific URL - Application::GetHelp()->Start(rAppEvent.GetStringData(), nullptr); + Application::GetHelp()->Start(rAppEvent.GetStringData(), static_cast<vcl::Window*>(nullptr)); break; case ApplicationEvent::Type::Print: { diff --git a/framework/source/jobs/helponstartup.cxx b/framework/source/jobs/helponstartup.cxx index ebabadf6fd7b..67f670f31e3e 100644 --- a/framework/source/jobs/helponstartup.cxx +++ b/framework/source/jobs/helponstartup.cxx @@ -139,7 +139,7 @@ css::uno::Any SAL_CALL HelpOnStartup::execute(const css::uno::Sequence< css::bea // Note: The help window brings itself to front ... Help* pHelp = Application::GetHelp(); if (pHelp) - pHelp->Start(sModuleDependentHelpURL, nullptr); + pHelp->Start(sModuleDependentHelpURL, static_cast<vcl::Window*>(nullptr)); } } diff --git a/include/sfx2/sfxhelp.hxx b/include/sfx2/sfxhelp.hxx index fb2eeac49707..d9b41b6544f7 100644 --- a/include/sfx2/sfxhelp.hxx +++ b/include/sfx2/sfxhelp.hxx @@ -34,8 +34,10 @@ class SFX2_DLLPUBLIC SfxHelp : public Help private: SAL_DLLPRIVATE static bool Start_Impl( const OUString& rURL, const vcl::Window* pWindow, const OUString& rKeyword ); + SAL_DLLPRIVATE static bool Start_Impl(const OUString& rURL, weld::Widget* pWidget, const OUString& rKeyword); SAL_DLLPRIVATE virtual void SearchKeyword( const OUString& rKeyWord ) override; SAL_DLLPRIVATE virtual bool Start( const OUString& rURL, const vcl::Window* pWindow ) override; + SAL_DLLPRIVATE virtual bool Start(const OUString& rURL, weld::Widget* pWidget) override; SAL_DLLPRIVATE static OUString GetHelpModuleName_Impl(const OUString &rHelpId); SAL_DLLPRIVATE static OUString CreateHelpURL_Impl( const OUString& aCommandURL, const OUString& rModuleName ); diff --git a/include/vcl/field.hxx b/include/vcl/field.hxx index be973f6d8bdf..0380259acf01 100644 --- a/include/vcl/field.hxx +++ b/include/vcl/field.hxx @@ -40,6 +40,7 @@ class VCL_DLLPUBLIC FormatterBase { private: VclPtr<Edit> mpField; + Link<Edit&, bool> maOutputHdl; std::unique_ptr<LocaleDataWrapper> mpLocaleDataWrapper; bool mbReformat; @@ -84,8 +85,9 @@ public: void EnableEmptyFieldValue( bool bEnable ) { mbEmptyFieldValueEnabled = bEnable; } bool IsEmptyFieldValueEnabled() const { return mbEmptyFieldValueEnabled; } -}; + void SetOutputHdl(const Link<Edit&, bool>& rLink) { maOutputHdl = rLink; } +}; #define PATTERN_FORMAT_EMPTYLITERALS (sal_uInt16(0x0001)) diff --git a/include/vcl/help.hxx b/include/vcl/help.hxx index ee51fe40014f..47fcb0264623 100644 --- a/include/vcl/help.hxx +++ b/include/vcl/help.hxx @@ -55,6 +55,10 @@ namespace o3tl #define OOO_HELP_INDEX ".help:index" +namespace weld +{ + class Widget; +} class VCL_DLLPUBLIC Help { @@ -62,7 +66,8 @@ public: Help(); virtual ~Help(); - virtual bool Start( const OUString& rHelpId, const vcl::Window* pWindow ); + virtual bool Start(const OUString& rHelpId, const vcl::Window* pWindow); + virtual bool Start(const OUString& rHelpId, weld::Widget* pWidget); virtual void SearchKeyword( const OUString& rKeyWord ); virtual OUString GetHelpText( const OUString& aHelpURL, const vcl::Window* pWindow ); diff --git a/include/vcl/layout.hxx b/include/vcl/layout.hxx index d73fa7166ce2..ca60679d346c 100644 --- a/include/vcl/layout.hxx +++ b/include/vcl/layout.hxx @@ -654,6 +654,34 @@ public: VclMultiLineEdit *pSecondaryMessage); }; +class VCL_DLLPUBLIC VclDrawingArea : public vcl::Window +{ +private: + Link<vcl::RenderContext&, void> m_aPaintHdl; + Link<const Size&, void> m_aResizeHdl; +public: + VclDrawingArea(vcl::Window *pParent, WinBits nStyle) + : vcl::Window(pParent, nStyle) + { + } + void SetPaintHdl(const Link<vcl::RenderContext&, void>& rLink) + { + m_aPaintHdl = rLink; + } + void SetResizeHdl(const Link<const Size&, void>& rLink) + { + m_aResizeHdl = rLink; + } + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) override + { + m_aPaintHdl.Call(rRenderContext); + } + virtual void Resize() override + { + m_aResizeHdl.Call(GetOutputSizePixel()); + } +}; + //Get first window of a pTopLevel window as //if any intermediate layout widgets didn't exist //i.e. acts like pChild = pChild->GetWindow(GetWindowType::FirstChild); diff --git a/include/vcl/lstbox.hxx b/include/vcl/lstbox.hxx index 9509ac0d25ae..5c8c6d29938e 100644 --- a/include/vcl/lstbox.hxx +++ b/include/vcl/lstbox.hxx @@ -139,6 +139,8 @@ public: tools::Rectangle GetDropDownPosSizePixel() const; + long CalcWindowSizePixel(sal_uInt16 nLines) const; + void AdaptDropDownLineCountToMaximum(); void SetDropDownLineCount( sal_uInt16 nLines ); sal_uInt16 GetDropDownLineCount() const; diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index f68173fe340c..29b8f2c258b3 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -47,6 +47,13 @@ class BitmapEx; +namespace weld +{ + class Builder; + class Container; + class MessageDialog; + class Widget; +} class AllSettings; class DataChangedEvent; class Accelerator; @@ -1384,6 +1391,10 @@ public: // For vclbootstrapprotector: static void setDeInitHook(Link<LinkParamNone*,void> const & hook); + static weld::Builder* CreateBuilder(weld::Widget* pParent, const OUString &rUIFile); + + static weld::MessageDialog* CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, + VclButtonsType eButtonType, const OUString& rPrimaryMessage); private: DECL_STATIC_LINK( Application, PostEventHandler, void*, void ); }; diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx new file mode 100644 index 000000000000..6d438633277c --- /dev/null +++ b/include/vcl/weld.hxx @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_WELD_HXX +#define INCLUDED_VCL_WELD_HXX + +#include <rtl/ustring.hxx> +#include <tools/gen.hxx> +#include <tools/link.hxx> +#include <vcl/dllapi.h> +#include <vcl/field.hxx> +#include <vcl/virdev.hxx> + +namespace weld +{ +class VCL_DLLPUBLIC Widget +{ +public: + virtual void set_sensitive(bool sensitive) = 0; + virtual bool get_sensitive() const = 0; + virtual void set_visible(bool visible) = 0; + virtual bool get_visible() const = 0; + virtual void grab_focus() = 0; + virtual bool has_focus() const = 0; + virtual void show() = 0; + virtual void hide() = 0; + void show(bool bShow) + { + if (bShow) + show(); + else + hide(); + } + virtual void set_size_request(int nWidth, int nHeight) = 0; + virtual Size get_preferred_size() const = 0; + virtual float approximate_char_width() const = 0; + virtual Size get_pixel_size(const OUString& rText) const = 0; + virtual OString get_buildable_name() const = 0; + virtual OString get_help_id() const = 0; + virtual Widget* weld_parent() const = 0; + + virtual ~Widget() {} +}; + +class VCL_DLLPUBLIC Container : virtual public Widget +{ +}; + +class VCL_DLLPUBLIC Frame : virtual public Container +{ +public: + virtual void set_label(const OUString& rText) = 0; + virtual OUString get_label() const = 0; +}; + +class VCL_DLLPUBLIC Notebook : virtual public Container +{ +protected: + Link<const OString&, bool> m_aLeavePageHdl; + Link<const OString&, void> m_aEnterPageHdl; + +public: + virtual int get_current_page() const = 0; + virtual OString get_current_page_ident() const = 0; + virtual void set_current_page(int nPage) = 0; + virtual void set_current_page(const OString& rIdent) = 0; + virtual int get_n_pages() const = 0; + virtual weld::Container* get_page(const OString& rIdent) const = 0; + + void connect_leave_page(const Link<const OString&, bool>& rLink) { m_aLeavePageHdl = rLink; } + + void connect_enter_page(const Link<const OString&, void>& rLink) { m_aEnterPageHdl = rLink; } +}; + +class VCL_DLLPUBLIC Window : virtual public Container +{ +protected: + Link<Widget&, bool> m_aHelpRequestHdl; + +public: + virtual void set_title(const OUString& rTitle) = 0; + virtual OUString get_title() const = 0; + + void connect_help(const Link<Widget&, bool>& rLink) { m_aHelpRequestHdl = rLink; } +}; + +class VCL_DLLPUBLIC Dialog : virtual public Window +{ +public: + virtual int run() = 0; + virtual void response(int response) = 0; +}; + +class VCL_DLLPUBLIC MessageDialog : virtual public Dialog +{ +public: + virtual void set_primary_text(const OUString& rText) = 0; + virtual OUString get_primary_text() const = 0; + virtual void set_secondary_text(const OUString& rText) = 0; + virtual OUString get_secondary_text() const = 0; +}; + +class VCL_DLLPUBLIC ComboBoxText : virtual public Container +{ +private: + OUString m_sSavedValue; + +protected: + Link<ComboBoxText&, void> m_aChangeHdl; + + void signal_changed() { m_aChangeHdl.Call(*this); } + +public: + virtual int get_active() const = 0; + virtual void set_active(int pos) = 0; + virtual OUString get_active_text() const = 0; + virtual OUString get_active_id() const = 0; + virtual void set_active_id(const OUString& rStr) = 0; + virtual OUString get_text(int pos) const = 0; + virtual OUString get_id(int pos) const = 0; + virtual void append_text(const OUString& rStr) = 0; + virtual void insert_text(int pos, const OUString& rStr) = 0; + virtual void append(const OUString& rId, const OUString& rStr) = 0; + virtual void insert(int pos, const OUString& rId, const OUString& rStr) = 0; + virtual int find_text(const OUString& rStr) const = 0; + virtual int get_count() const = 0; + virtual void make_sorted() = 0; + virtual void clear() = 0; + + void connect_changed(const Link<ComboBoxText&, void>& rLink) { m_aChangeHdl = rLink; } + + void set_active(const OUString& rStr) { set_active(find_text(rStr)); } + + void save_value() { m_sSavedValue = get_active_text(); } + + bool get_value_changed_from_saved() const { return m_sSavedValue != get_active_text(); } +}; + +class VCL_DLLPUBLIC TreeView : virtual public Container +{ +protected: + Link<TreeView&, void> m_aChangeHdl; + Link<TreeView&, void> m_aRowActivatedHdl; + + void signal_changed() { m_aChangeHdl.Call(*this); } + + void signal_row_activated() { m_aRowActivatedHdl.Call(*this); } + +public: + virtual void append(const OUString& rText) = 0; + virtual void insert(const OUString& rText, int pos) = 0; + virtual int n_children() const = 0; + virtual void select(int pos) = 0; + virtual void remove(int pos) = 0; + virtual int find(const OUString& rText) const = 0; + virtual void set_top_entry(int pos) = 0; + virtual void clear() = 0; + virtual OUString get_selected() = 0; + virtual int get_selected_index() = 0; + virtual OUString get(int pos) = 0; + virtual int get_height_rows(int nRows) const = 0; + + virtual void freeze() = 0; + virtual void thaw() = 0; + + void connect_changed(const Link<TreeView&, void>& rLink) { m_aChangeHdl = rLink; } + + void connect_row_activated(const Link<TreeView&, void>& rLink) { m_aRowActivatedHdl = rLink; } + + void select(const OUString& rText) { select(find(rText)); } + + void remove(const OUString& rText) { remove(find(rText)); } +}; + +class VCL_DLLPUBLIC Button : virtual public Container +{ +protected: + Link<Button&, void> m_aClickHdl; + + void signal_clicked() { m_aClickHdl.Call(*this); } + +public: + virtual void set_label(const OUString& rText) = 0; + virtual OUString get_label() const = 0; + + void connect_clicked(const Link<Button&, void>& rLink) { m_aClickHdl = rLink; } +}; + +class VCL_DLLPUBLIC ToggleButton : virtual public Button +{ +protected: + Link<ToggleButton&, void> m_aToggleHdl; + TriState m_eSavedValue = TRISTATE_FALSE; + + void signal_toggled() { m_aToggleHdl.Call(*this); } + +public: + virtual void set_active(bool active) = 0; + virtual bool get_active() const = 0; + + virtual void set_inconsistent(bool inconsistent) = 0; + virtual bool get_inconsistent() const = 0; + + TriState get_state() const + { + if (get_inconsistent()) + return TRISTATE_INDET; + else if (get_active()) + return TRISTATE_TRUE; + return TRISTATE_FALSE; + } + + void save_state() { m_eSavedValue = get_state(); } + + TriState get_saved_state() const { return m_eSavedValue; } + + void set_state(TriState eState) + { + switch (eState) + { + case TRISTATE_INDET: + set_inconsistent(true); + break; + case TRISTATE_TRUE: + set_inconsistent(false); + set_active(true); + break; + case TRISTATE_FALSE: + set_inconsistent(false); + set_active(false); + break; + } + } + + bool get_state_changed_from_saved() const { return m_eSavedValue != get_state(); } + + void connect_toggled(const Link<ToggleButton&, void>& rLink) { m_aToggleHdl = rLink; } +}; + +class VCL_DLLPUBLIC CheckButton : virtual public ToggleButton +{ +}; + +class VCL_DLLPUBLIC RadioButton : virtual public ToggleButton +{ +}; + +class VCL_DLLPUBLIC Entry : virtual public Widget +{ +private: + OUString m_sSavedValue; + +protected: + Link<Entry&, void> m_aChangeHdl; + Link<OUString&, bool> m_aInsertTextHdl; + + void signal_changed() { m_aChangeHdl.Call(*this); } + + void signal_insert_text(OUString& rString); + +public: + virtual void set_text(const OUString& rText) = 0; + virtual OUString get_text() const = 0; + virtual void set_width_chars(int nChars) = 0; + + void connect_changed(const Link<Entry&, void>& rLink) { m_aChangeHdl = rLink; } + + void connect_insert_text(const Link<OUString&, bool>& rLink) { m_aInsertTextHdl = rLink; } + + void save_value() { m_sSavedValue = get_text(); } + + bool get_value_changed_from_saved() const { return m_sSavedValue != get_text(); } +}; + +class VCL_DLLPUBLIC SpinButton : virtual public Entry +{ +protected: + Link<SpinButton&, void> m_aValueChangedHdl; + Link<SpinButton&, void> m_aOutputHdl; + + void signal_value_changed() { m_aValueChangedHdl.Call(*this); } + + bool signal_output() + { + if (!m_aOutputHdl.IsSet()) + return false; + m_aOutputHdl.Call(*this); + return true; + } + +public: + virtual void set_value(int value) = 0; + virtual int get_value() const = 0; + virtual void set_range(int min, int max) = 0; + virtual void get_range(int& min, int& max) const = 0; + virtual void set_increments(int step, int page) = 0; + virtual void get_increments(int& step, int& page) const = 0; + virtual void set_digits(unsigned int digits) = 0; + virtual unsigned int get_digits() const = 0; + + void connect_value_changed(const Link<SpinButton&, void>& rLink) { m_aValueChangedHdl = rLink; } + + void connect_output(const Link<SpinButton&, void>& rLink) { m_aOutputHdl = rLink; } + + int normalize(int nValue) const { return (nValue * Power10(get_digits())); } + + int denormalize(int nValue) const; + + static unsigned int Power10(unsigned int n); +}; + +class VCL_DLLPUBLIC MetricSpinButton +{ +protected: + FieldUnit m_eSrcUnit; + std::unique_ptr<weld::SpinButton> m_xSpinButton; + Link<MetricSpinButton&, void> m_aValueChangedHdl; + + DECL_LINK(spin_button_value_changed, weld::SpinButton&, void); + DECL_LINK(spin_button_output, weld::SpinButton&, void); + + void signal_value_changed() { m_aValueChangedHdl.Call(*this); } + + int ConvertValue(int nValue, FieldUnit eInUnit, FieldUnit eOutUnit) const; + OUString format_number(int nValue) const; + void update_width_chars(); + +public: + MetricSpinButton(SpinButton* pSpinButton) + : m_eSrcUnit(FUNIT_CM) + , m_xSpinButton(pSpinButton) + { + update_width_chars(); + m_xSpinButton->connect_output(LINK(this, MetricSpinButton, spin_button_output)); + m_xSpinButton->connect_value_changed( + LINK(this, MetricSpinButton, spin_button_value_changed)); + } + + FieldUnit get_unit() const { return m_eSrcUnit; } + + void set_unit(FieldUnit eUnit) + { + m_eSrcUnit = eUnit; + update_width_chars(); + } + + void set_value(int nValue, FieldUnit eValueUnit) + { + m_xSpinButton->set_value(ConvertValue(nValue, eValueUnit, m_eSrcUnit)); + } + + int get_value(FieldUnit eDestUnit) const + { + int nValue = m_xSpinButton->get_value(); + return ConvertValue(nValue, m_eSrcUnit, eDestUnit); + } + + void set_range(int min, int max, FieldUnit eValueUnit) + { + min = ConvertValue(min, eValueUnit, m_eSrcUnit); + max = ConvertValue(max, eValueUnit, m_eSrcUnit); + m_xSpinButton->set_range(min, max); + update_width_chars(); + } + + void get_range(int& min, int& max, FieldUnit eDestUnit) const + { + m_xSpinButton->get_range(min, max); + min = ConvertValue(min, m_eSrcUnit, eDestUnit); + max = ConvertValue(max, m_eSrcUnit, eDestUnit); + } + + void set_increments(int step, int page, FieldUnit eValueUnit) + { + step = ConvertValue(step, eValueUnit, m_eSrcUnit); + page = ConvertValue(page, eValueUnit, m_eSrcUnit); + m_xSpinButton->set_increments(step, page); + } + + void get_increments(int& step, int& page, FieldUnit eDestUnit) const + { + m_xSpinButton->get_increments(step, page); + step = ConvertValue(step, m_eSrcUnit, eDestUnit); + page = ConvertValue(page, m_eSrcUnit, eDestUnit); + } + + void connect_value_changed(const Link<MetricSpinButton&, void>& rLink) + { + m_aValueChangedHdl = rLink; + } + + int normalize(int nValue) const { return m_xSpinButton->normalize(nValue); } + int denormalize(int nValue) const { return m_xSpinButton->denormalize(nValue); } + void set_sensitive(bool sensitive) { m_xSpinButton->set_sensitive(sensitive); } + bool get_sensitive() const { return m_xSpinButton->get_sensitive(); } + bool get_visible() const { return m_xSpinButton->get_visible(); } + void grab_focus() { m_xSpinButton->grab_focus(); } + bool has_focus() const { return m_xSpinButton->has_focus(); } + void show() { m_xSpinButton->show(); } + void hide() { m_xSpinButton->hide(); } + void set_digits(unsigned int digits) { m_xSpinButton->set_digits(digits); } + unsigned int get_digits() const { return m_xSpinButton->get_digits(); } + void save_value() { m_xSpinButton->save_value(); } + bool get_value_changed_from_saved() const + { + return m_xSpinButton->get_value_changed_from_saved(); + } + void set_text(const OUString& rText) { m_xSpinButton->set_text(rText); } + OUString get_text() const { return m_xSpinButton->get_text(); } + void set_size_request(int nWidth, int nHeight) + { + m_xSpinButton->set_size_request(nWidth, nHeight); + } + Size get_preferred_size() const { return m_xSpinButton->get_preferred_size(); } +}; + +class VCL_DLLPUBLIC Label : virtual public Widget +{ +public: + virtual void set_label(const OUString& rText) = 0; +}; + +class VCL_DLLPUBLIC TextView : virtual public Container +{ +public: + virtual void set_text(const OUString& rText) = 0; + virtual OUString get_text() const = 0; + virtual Selection get_selection() const = 0; + virtual void set_selection(const Selection&) = 0; +}; + +class VCL_DLLPUBLIC DrawingArea : virtual public Widget +{ +protected: + Link<vcl::RenderContext&, void> m_aDrawHdl; + Link<const Size&, void> m_aSizeAllocateHdl; + +public: + void connect_draw(const Link<vcl::RenderContext&, void>& rLink) { m_aDrawHdl = rLink; } + void connect_size_allocate(const Link<const Size&, void>& rLink) { m_aSizeAllocateHdl = rLink; } + virtual void queue_draw() = 0; +}; + +class VCL_DLLPUBLIC Builder +{ +private: + OString m_sHelpRoot; + +public: + Builder(const OUString& rUIFile) + : m_sHelpRoot(OUStringToOString(rUIFile, RTL_TEXTENCODING_UTF8)) + { + sal_Int32 nIdx = m_sHelpRoot.lastIndexOf('.'); + if (nIdx != -1) + m_sHelpRoot = m_sHelpRoot.copy(0, nIdx); + m_sHelpRoot = m_sHelpRoot + OString('/'); + } + virtual MessageDialog* weld_message_dialog(const OString& id, bool bTakeOwnership = false) = 0; + virtual Dialog* weld_dialog(const OString& id, bool bTakeOwnership = false) = 0; + virtual Window* weld_window(const OString& id, bool bTakeOwnership = false) = 0; + virtual Widget* weld_widget(const OString& id, bool bTakeOwnership = false) = 0; + virtual Container* weld_container(const OString& id, bool bTakeOwnership = false) = 0; + virtual Button* weld_button(const OString& id, bool bTakeOwnership = false) = 0; + virtual Frame* weld_frame(const OString& id, bool bTakeOwnership = false) = 0; + virtual Notebook* weld_notebook(const OString& id, bool bTakeOwnership = false) = 0; + virtual RadioButton* weld_radio_button(const OString& id, bool bTakeOwnership = false) = 0; + virtual CheckButton* weld_check_button(const OString& id, bool bTakeOwnership = false) = 0; + virtual SpinButton* weld_spin_button(const OString& id, bool bTakeOwnership = false) = 0; + MetricSpinButton* weld_metric_spin_button(const OString& id, bool bTakeOwnership = false) + { + return new MetricSpinButton(weld_spin_button(id, bTakeOwnership)); + } + virtual ComboBoxText* weld_combo_box_text(const OString& id, bool bTakeOwnership = false) = 0; + virtual TreeView* weld_tree_view(const OString& id, bool bTakeOwnership = false) = 0; + virtual Label* weld_label(const OString& id, bool bTakeOwnership = false) = 0; + virtual TextView* weld_text_view(const OString& id, bool bTakeOwnership = false) = 0; + virtual Entry* weld_entry(const OString& id, bool bTakeOwnership = false) = 0; + virtual DrawingArea* weld_drawing_area(const OString& id, bool bTakeOwnership = false) = 0; + OString get_help_id(const Widget& rWidget) const + { + return m_sHelpRoot + rWidget.get_buildable_name(); + } + virtual ~Builder() {} +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 486ae567c1bc..4c286ba861c7 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -106,6 +106,8 @@ namespace vcl { namespace svt { class PopupWindowControllerImpl; } +namespace weld { class Window; } + template<class T> class VclPtr; enum class TrackingEventFlags @@ -550,6 +552,7 @@ public: SAL_DLLPRIVATE static void ImplInitAppFontData( vcl::Window const * pWindow ); SAL_DLLPRIVATE vcl::Window* ImplGetFrameWindow() const; + weld::Window* GetFrameWeld() const; SalFrame* ImplGetFrame() const; SAL_DLLPRIVATE ImplFrameData* ImplGetFrameData(); diff --git a/sfx2/source/appl/appserv.cxx b/sfx2/source/appl/appserv.cxx index defe7f1fdd2e..e118bbafae24 100644 --- a/sfx2/source/appl/appserv.cxx +++ b/sfx2/source/appl/appserv.cxx @@ -541,7 +541,7 @@ void SfxApplication::MiscExec_Impl( SfxRequest& rReq ) Help* pHelp = Application::GetHelp(); if ( pHelp ) { - pHelp->Start( ".uno:HelpIndex", nullptr ); // show start page + pHelp->Start(".uno:HelpIndex", static_cast<vcl::Window*>(nullptr)); // show start page bDone = true; } break; diff --git a/sfx2/source/appl/sfxhelp.cxx b/sfx2/source/appl/sfxhelp.cxx index 367f4ad68494..9803d63fdb75 100644 --- a/sfx2/source/appl/sfxhelp.cxx +++ b/sfx2/source/appl/sfxhelp.cxx @@ -55,6 +55,7 @@ #include <rtl/uri.hxx> #include <vcl/commandinfoprovider.hxx> #include <vcl/layout.hxx> +#include <vcl/weld.hxx> #include <svtools/ehdl.hxx> #include <svtools/sfxecode.hxx> #include <openuriexternally.hxx> @@ -82,23 +83,48 @@ using namespace ::com::sun::star::util; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::system; -class NoHelpErrorBox : public MessageDialog +namespace old { -public: - explicit NoHelpErrorBox( vcl::Window* _pParent ); + class NoHelpErrorBox : public MessageDialog + { + public: + explicit NoHelpErrorBox(vcl::Window* _pParent) + : MessageDialog(_pParent, SfxResId(RID_STR_HLPFILENOTEXIST)) + { + // Error message: "No help available" + } - virtual void RequestHelp( const HelpEvent& rHEvt ) override; -}; + virtual void RequestHelp( const HelpEvent& ) override + { + // do nothing, because no help available + } + }; +} -NoHelpErrorBox::NoHelpErrorBox( vcl::Window* _pParent ) - : MessageDialog(_pParent, SfxResId(RID_STR_HLPFILENOTEXIST)) +class NoHelpErrorBox { - // Error message: "No help available" -} +private: + std::unique_ptr<weld::MessageDialog> m_xErrBox; +public: + DECL_STATIC_LINK(NoHelpErrorBox, HelpRequestHdl, weld::Widget&, bool); +public: + explicit NoHelpErrorBox(weld::Widget* pParent) + : m_xErrBox(Application::CreateMessageDialog(pParent, VclMessageType::Error, VclButtonsType::Ok, + SfxResId(RID_STR_HLPFILENOTEXIST))) + { + // Error message: "No help available" + m_xErrBox->connect_help(LINK(nullptr, NoHelpErrorBox, HelpRequestHdl)); + } + void run() + { + m_xErrBox->run(); + } +}; -void NoHelpErrorBox::RequestHelp( const HelpEvent& ) +IMPL_STATIC_LINK_NOARG(NoHelpErrorBox, HelpRequestHdl, weld::Widget&, bool) { // do nothing, because no help available + return false; } static OUString HelpLocaleString(); @@ -625,7 +651,7 @@ OUString SfxHelp::GetHelpText( const OUString& aCommandURL, const vcl::Window* p void SfxHelp::SearchKeyword( const OUString& rKeyword ) { - Start_Impl( OUString(), nullptr, rKeyword ); + Start_Impl(OUString(), static_cast<vcl::Window*>(nullptr), rKeyword); } bool SfxHelp::Start( const OUString& rURL, const vcl::Window* pWindow ) @@ -633,6 +659,11 @@ bool SfxHelp::Start( const OUString& rURL, const vcl::Window* pWindow ) return Start_Impl( rURL, pWindow, OUString() ); } +bool SfxHelp::Start(const OUString& rURL, weld::Widget* pWidget) +{ + return Start_Impl(rURL, pWidget, OUString()); +} + /// Redirect the vnd.sun.star.help:// urls to http://help.libreoffice.org static bool impl_showOnlineHelp( const OUString& rURL ) { @@ -709,7 +740,6 @@ static bool impl_showOfflineHelp( const OUString& rURL ) return false; } - bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const OUString& rKeyword) { OUStringBuffer aHelpRootURL("vnd.sun.star.help://"); @@ -821,7 +851,7 @@ bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const return true; else { - ScopedVclPtrInstance< NoHelpErrorBox > aErrBox(const_cast< vcl::Window* >( pWindow )); + ScopedVclPtrInstance< old::NoHelpErrorBox > aErrBox(const_cast< vcl::Window* >( pWindow )); aErrBox->Execute(); return false; } @@ -865,7 +895,151 @@ bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const xTopWindow->toFront(); return true; +} + +bool SfxHelp::Start_Impl(const OUString& rURL, weld::Widget* pWidget, const OUString& rKeyword) +{ + OUStringBuffer aHelpRootURL("vnd.sun.star.help://"); + AppendConfigToken(aHelpRootURL, true); + SfxContentHelper::GetResultSet(aHelpRootURL.makeStringAndClear()); + + /* rURL may be + * - a "real" URL + * - a HelpID (formerly a long, now a string) + * If rURL is a URL, CreateHelpURL should be called for this URL + * If rURL is an arbitrary string, the same should happen, but the URL should be tried out + * if it delivers real help content. In case only the Help Error Document is returned, the + * parent of the window for that help was called, is asked for its HelpID. + * For compatibility reasons this upward search is not implemented for "real" URLs. + * Help keyword search now is implemented as own method; in former versions it + * was done via Help::Start, but this implementation conflicted with the upward search. + */ + OUString aHelpURL; + INetURLObject aParser( rURL ); + INetProtocol nProtocol = aParser.GetProtocol(); + + switch ( nProtocol ) + { + case INetProtocol::VndSunStarHelp: + // already a vnd.sun.star.help URL -> nothing to do + aHelpURL = rURL; + break; + default: + { + OUString aHelpModuleName(GetHelpModuleName_Impl(rURL)); + OUString aRealCommand; + + if ( nProtocol == INetProtocol::Uno ) + // Command can be just an alias to another command. + aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand( rURL, getCurrentModuleIdentifier_Impl() ); + + // no URL, just a HelpID (maybe empty in case of keyword search) + aHelpURL = CreateHelpURL_Impl( aRealCommand.isEmpty() ? rURL : aRealCommand, aHelpModuleName ); + + if ( impl_hasHelpInstalled() && pWidget && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) + { + // no help found -> try with parent help id. + std::unique_ptr<weld::Widget> xParent(pWidget->weld_parent()); + while (xParent) + { + OString aHelpId = xParent->get_help_id(); + aHelpURL = CreateHelpURL( OStringToOUString(aHelpId, RTL_TEXTENCODING_UTF8), aHelpModuleName ); + + if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) + { + break; + } + else + { + xParent.reset(xParent->weld_parent()); + if (!xParent) + { + // create help url of start page ( helpid == 0 -> start page) + aHelpURL = CreateHelpURL( OUString(), aHelpModuleName ); + } + } + } + } + break; + } + } + if ( comphelper::LibreOfficeKit::isActive() ) + { + impl_showOnlineHelp( aHelpURL ); + return true; + } + + if ( impl_hasHTMLHelpInstalled() ) + { + impl_showOfflineHelp(aHelpURL); + return true; + } + + if ( !impl_hasHelpInstalled() ) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pWidget, "sfx/ui/helpmanual.ui")); + std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("onlinehelpmanual")); + + LanguageTag aLangTag = Application::GetSettings().GetUILanguageTag(); + OUString sLocaleString = SvtLanguageTable::GetLanguageString( aLangTag.getLanguageType() ); + OUString sPrimText = xQueryBox->get_primary_text(); + xQueryBox->set_primary_text(Translate::GetReadStringHook()(sPrimText).replaceAll("$UILOCALE", sLocaleString)); + xQueryBox->set_title(Translate::GetReadStringHook()(xQueryBox->get_title())); + xQueryBox->connect_help(LINK(nullptr, NoHelpErrorBox, HelpRequestHdl)); + short OnlineHelpBox = xQueryBox->run(); + xQueryBox->hide(); + if (OnlineHelpBox == RET_OK) + { + if (impl_showOnlineHelp( aHelpURL ) ) + return true; + else + { + NoHelpErrorBox aErrBox(pWidget); + aErrBox.run(); + return false; + } + } + else + { + return false; + } + + } + + // old-help to display + Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() ); + + // check if help window is still open + // If not, create a new one and return access directly to the internal sub frame showing the help content + // search must be done here; search one desktop level could return an arbitrary frame + Reference< XFrame2 > xHelp( + xDesktop->findFrame( "OFFICE_HELP_TASK", FrameSearchFlag::CHILDREN), + UNO_QUERY); + Reference< XFrame > xHelpContent = xDesktop->findFrame( + "OFFICE_HELP", + FrameSearchFlag::CHILDREN); + + SfxHelpWindow_Impl* pHelpWindow = nullptr; + if (!xHelp.is()) + pHelpWindow = impl_createHelp(xHelp, xHelpContent); + else + pHelpWindow = static_cast<SfxHelpWindow_Impl*>(VCLUnoHelper::GetWindow(xHelp->getComponentWindow()).get()); + if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow) + return false; + + SAL_INFO("sfx.appl", "HelpId = " << aHelpURL); + + pHelpWindow->SetHelpURL( aHelpURL ); + pHelpWindow->loadHelpContent(aHelpURL); + if (!rKeyword.isEmpty()) + pHelpWindow->OpenKeyword( rKeyword ); + + Reference < css::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY ); + if ( xTopWindow.is() ) + xTopWindow->toFront(); + + return true; } OUString SfxHelp::CreateHelpURL(const OUString& aCommandURL, const OUString& rModuleName) diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx index 615b40552fb8..f79fa593433c 100644 --- a/sw/inc/swabstdlg.hxx +++ b/sw/inc/swabstdlg.hxx @@ -394,7 +394,7 @@ public: SvStream* pStream ) = 0; virtual VclPtr<VclAbstractDialog> CreateSwInsertBookmarkDlg( vcl::Window *pParent, SwWrtShell &rSh, SfxRequest& rReq ) = 0; - virtual VclPtr<AbstractSwBreakDlg> CreateSwBreakDlg(vcl::Window *pParent, SwWrtShell &rSh) = 0; + virtual VclPtr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) = 0; virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) = 0; virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(vcl::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet, SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) = 0; diff --git a/sw/source/ui/chrdlg/break.cxx b/sw/source/ui/chrdlg/break.cxx index 0e2386f64dc6..c6b61d34acce 100644 --- a/sw/source/ui/chrdlg/break.cxx +++ b/sw/source/ui/chrdlg/break.cxx @@ -36,52 +36,52 @@ #include <strings.hrc> #include <SwStyleNameMapper.hxx> -void SwBreakDlg::Apply() +short SwBreakDlg::Execute() { - nKind = 0; - if(m_pLineBtn->IsChecked()) - nKind = 1; - else if(m_pColumnBtn->IsChecked()) - nKind = 2; - else if(m_pPageBtn->IsChecked()) + short nRet = m_xDialog->run(); + if (nRet == RET_OK) { - nKind = 3; - const sal_Int32 nPos = m_pPageCollBox->GetSelectedEntryPos(); - if(0 != nPos && LISTBOX_ENTRY_NOTFOUND != nPos) + nKind = 0; + if (m_xLineBtn->get_active()) + nKind = 1; + else if(m_xColumnBtn->get_active()) + nKind = 2; + else if(m_xPageBtn->get_active()) { - aTemplate = m_pPageCollBox->GetSelectedEntry(); - oPgNum = boost::none; - if (m_pPageNumBox->IsChecked()) + nKind = 3; + const int nPos = m_xPageCollBox->get_active(); + if (nPos != 0 && nPos != -1) { - oPgNum = static_cast<sal_uInt16>(m_pPageNumEdit->GetValue()); + oPgNum = static_cast<sal_uInt16>(m_xPageNumEdit->get_value()); } } } + return nRet; } -IMPL_LINK_NOARG(SwBreakDlg, ClickHdl, Button*, void) +IMPL_LINK_NOARG(SwBreakDlg, ToggleHdl, weld::ToggleButton&, void) { CheckEnable(); } -IMPL_LINK_NOARG(SwBreakDlg, SelectHdl, ListBox&, void) +IMPL_LINK_NOARG(SwBreakDlg, ChangeHdl, weld::ComboBoxText&, void) { CheckEnable(); } // Handler for Change Page Number -IMPL_LINK( SwBreakDlg, PageNumHdl, Button*, pBox, void ) +IMPL_LINK(SwBreakDlg, PageNumHdl, weld::ToggleButton&, rBox, void) { - if(static_cast<CheckBox*>(pBox)->IsChecked()) - m_pPageNumEdit->SetValue(1); + if (rBox.get_active()) + m_xPageNumEdit->set_value(1); else - m_pPageNumEdit->SetText(OUString()); + m_xPageNumEdit->set_text(OUString()); } // By changing the Page number the checkbox is checked. -IMPL_LINK_NOARG(SwBreakDlg, PageNumModifyHdl, Edit&, void) +IMPL_LINK_NOARG(SwBreakDlg, PageNumModifyHdl, weld::SpinButton&, void) { - m_pPageNumBox->Check(); + m_xPageNumBox->set_active(true); } /* @@ -89,21 +89,21 @@ IMPL_LINK_NOARG(SwBreakDlg, PageNumModifyHdl, Edit&, void) * checks whether pagenumber nPage is a legal pagenumber (left pages with even * numbers etc. for a page template with alternating pages) */ -IMPL_LINK_NOARG(SwBreakDlg, OkHdl, Button*, void) +IMPL_LINK_NOARG(SwBreakDlg, OkHdl, weld::Button&, void) { - if(m_pPageNumBox->IsChecked()) { + if (m_xPageNumBox->get_active()) + { // In case of differing page descriptions, test validity - const sal_Int32 nPos = m_pPageCollBox->GetSelectedEntryPos(); + const int nPos = m_xPageCollBox->get_active(); // position 0 says 'Without'. const SwPageDesc *pPageDesc; - if ( 0 != nPos && LISTBOX_ENTRY_NOTFOUND != nPos ) - pPageDesc = rSh.FindPageDescByName( m_pPageCollBox->GetSelectedEntry(), - true ); + if (nPos != 0 && nPos != -1) + pPageDesc = rSh.FindPageDescByName(m_xPageCollBox->get_active_text(), true); else pPageDesc = &rSh.GetPageDesc(rSh.GetCurPageDesc()); OSL_ENSURE(pPageDesc, "Page description not found."); - const sal_uInt16 nUserPage = sal_uInt16(m_pPageNumEdit->GetValue()); + const sal_uInt16 nUserPage = sal_uInt16(m_xPageNumEdit->get_value()); bool bOk = true; switch(pPageDesc->GetUseOn()) { @@ -113,77 +113,65 @@ IMPL_LINK_NOARG(SwBreakDlg, OkHdl, Button*, void) case UseOnPage::Right: bOk = 1 == nUserPage % 2; break; default:; //prevent warning } - if(!bOk) { - ScopedVclPtrInstance<MessageDialog>(this, SwResId(STR_ILLEGAL_PAGENUM), VclMessageType::Info)->Execute(); - m_pPageNumEdit->GrabFocus(); + if(!bOk) + { + std::unique_ptr<weld::Dialog> xDialog(Application::CreateMessageDialog(m_xPageNumEdit.get(), VclMessageType::Info, + VclButtonsType::Ok, SwResId(STR_ILLEGAL_PAGENUM))); + xDialog->run(); + m_xPageNumEdit->grab_focus(); return; } } - EndDialog(RET_OK); + m_xDialog->response(RET_OK); } -SwBreakDlg::SwBreakDlg( vcl::Window *pParent, SwWrtShell &rS ) - : SvxStandardDialog(pParent, "BreakDialog", "modules/swriter/ui/insertbreak.ui") - , rSh(rS) +SwBreakDlg::SwBreakDlg(weld::Window *pParent, SwWrtShell &rS) + : rSh(rS) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/swriter/ui/insertbreak.ui")) , nKind(0) , bHtmlMode(0 != ::GetHtmlMode(rS.GetView().GetDocShell())) { - get(m_pLineBtn, "linerb"); - get(m_pColumnBtn, "columnrb"); - get(m_pPageBtn, "pagerb"); - get(m_pPageCollText, "styleft"); - get(m_pPageCollBox, "stylelb"); - get(m_pPageNumBox, "pagenumcb"); - get(m_pPageNumEdit, "pagenumsb"); - - Link<Button*,void> aLk = LINK(this,SwBreakDlg,ClickHdl); - m_pPageBtn->SetClickHdl( aLk ); - m_pLineBtn->SetClickHdl( aLk ); - m_pColumnBtn->SetClickHdl( aLk ); - m_pPageCollBox->SetSelectHdl( LINK(this,SwBreakDlg,SelectHdl) ); - - get<OKButton>("ok")->SetClickHdl(LINK(this,SwBreakDlg,OkHdl)); - m_pPageNumBox->SetClickHdl(LINK(this,SwBreakDlg,PageNumHdl)); - m_pPageNumEdit->SetModifyHdl(LINK(this,SwBreakDlg,PageNumModifyHdl)); + m_xDialog.reset(m_xBuilder->weld_dialog("BreakDialog")); + m_xLineBtn.reset(m_xBuilder->weld_radio_button("linerb")); + m_xColumnBtn.reset(m_xBuilder->weld_radio_button("columnrb")); + m_xPageBtn.reset(m_xBuilder->weld_radio_button("pagerb")); + m_xPageCollBox.reset(m_xBuilder->weld_combo_box_text("stylelb")); + m_xPageNumBox.reset(m_xBuilder->weld_check_button("pagenumcb")); + m_xPageNumEdit.reset(m_xBuilder->weld_spin_button("pagenumsb")); + m_xPageCollText.reset(m_xBuilder->weld_label("styleft")); + m_xOkBtn.reset(m_xBuilder->weld_button("ok")); + + Link<weld::ToggleButton&,void> aLk = LINK(this, SwBreakDlg, ToggleHdl); + m_xPageBtn->connect_toggled(aLk); + m_xLineBtn->connect_toggled(aLk); + m_xColumnBtn->connect_toggled(aLk); + m_xPageCollBox->connect_changed(LINK(this, SwBreakDlg, ChangeHdl)); + + m_xOkBtn->connect_clicked(LINK(this, SwBreakDlg, OkHdl)); + m_xPageNumBox->connect_toggled(LINK(this, SwBreakDlg, PageNumHdl)); + m_xPageNumEdit->connect_value_changed(LINK(this, SwBreakDlg, PageNumModifyHdl)); // Insert page description to Listbox const size_t nCount = rSh.GetPageDescCnt(); - for( size_t i = 0; i < nCount; ++i) + for (size_t i = 0; i < nCount; ++i) { const SwPageDesc &rPageDesc = rSh.GetPageDesc(i); - ::InsertStringSorted(rPageDesc.GetName(), *m_pPageCollBox, 1 ); + ::InsertStringSorted(rPageDesc.GetName(), *m_xPageCollBox, 1 ); } OUString aFormatName; - for(sal_uInt16 i = RES_POOLPAGE_BEGIN; i < RES_POOLPAGE_END; ++i) + for (sal_uInt16 i = RES_POOLPAGE_BEGIN; i < RES_POOLPAGE_END; ++i) { aFormatName = SwStyleNameMapper::GetUIName( i, aFormatName ); - if(LISTBOX_ENTRY_NOTFOUND == m_pPageCollBox->GetEntryPos(aFormatName)) - ::InsertStringSorted(aFormatName, *m_pPageCollBox, 1 ); + if (m_xPageCollBox->find_text(aFormatName) == -1) + ::InsertStringSorted(aFormatName, *m_xPageCollBox, 1 ); } //add landscape page aFormatName = SwStyleNameMapper::GetUIName( RES_POOLPAGE_LANDSCAPE, aFormatName ); - if(LISTBOX_ENTRY_NOTFOUND == m_pPageCollBox->GetEntryPos(aFormatName)) - ::InsertStringSorted(aFormatName, *m_pPageCollBox, 1 ); + if (m_xPageCollBox->find_text(aFormatName) == -1) + ::InsertStringSorted(aFormatName, *m_xPageCollBox, 1); CheckEnable(); - m_pPageNumEdit->SetText(OUString()); -} - -SwBreakDlg::~SwBreakDlg() -{ - disposeOnce(); -} - -void SwBreakDlg::dispose() -{ - m_pLineBtn.clear(); - m_pColumnBtn.clear(); - m_pPageBtn.clear(); - m_pPageCollText.clear(); - m_pPageCollBox.clear(); - m_pPageNumBox.clear(); - m_pPageNumEdit.clear(); - SvxStandardDialog::dispose(); + m_xPageNumEdit->set_text(OUString()); } void SwBreakDlg::CheckEnable() @@ -191,32 +179,32 @@ void SwBreakDlg::CheckEnable() bool bEnable = true; if ( bHtmlMode ) { - m_pColumnBtn->Enable(false); - m_pPageCollBox->Enable(false); + m_xColumnBtn->set_sensitive(false); + m_xPageCollBox->set_sensitive(false); bEnable = false; } else if(rSh.GetFrameType(nullptr,true) & (FrameTypeFlags::FLY_ANY | FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | FrameTypeFlags::FOOTNOTE)) { - m_pPageBtn->Enable(false); - if(m_pPageBtn->IsChecked()) - m_pLineBtn->Check(); + m_xPageBtn->set_sensitive(false); + if (m_xPageBtn->get_active()) + m_xLineBtn->set_active(true); bEnable = false; } - const bool bPage = m_pPageBtn->IsChecked(); - m_pPageCollText->Enable( bPage ); - m_pPageCollBox->Enable ( bPage ); + const bool bPage = m_xPageBtn->get_active(); + m_xPageCollText->set_sensitive(bPage); + m_xPageCollBox->set_sensitive(bPage); bEnable &= bPage; if ( bEnable ) { // position 0 says 'Without' page template. - const sal_Int32 nPos = m_pPageCollBox->GetSelectedEntryPos(); - if ( 0 == nPos || LISTBOX_ENTRY_NOTFOUND == nPos ) + const int nPos = m_xPageCollBox->get_active(); + if (nPos == 0 || nPos == -1) bEnable = false; } - m_pPageNumBox->Enable(bEnable); - m_pPageNumEdit->Enable(bEnable); + m_xPageNumBox->set_sensitive(bEnable); + m_xPageNumEdit->set_sensitive(bEnable); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx index 031efef1198e..95f0e34a99bc 100644 --- a/sw/source/ui/dialog/swdlgfact.cxx +++ b/sw/source/ui/dialog/swdlgfact.cxx @@ -93,7 +93,10 @@ IMPL_ABSTDLG_BASE(SwAbstractSfxDialog_Impl); IMPL_ABSTDLG_BASE(AbstractSwAsciiFilterDlg_Impl); IMPL_ABSTDLG_BASE(VclAbstractDialog_Impl); IMPL_ABSTDLG_BASE(AbstractSplitTableDialog_Impl); -IMPL_ABSTDLG_BASE(AbstractSwBreakDlg_Impl); +short AbstractSwBreakDlg_Impl::Execute() +{ + return m_xDlg->Execute(); +} IMPL_ABSTDLG_BASE(AbstractTabDialog_Impl); IMPL_ABSTDLG_BASE(AbstractSwConvertTableDlg_Impl); IMPL_ABSTDLG_BASE(AbstractSwInsertDBColAutoPilot_Impl); @@ -193,17 +196,17 @@ SplitTable_HeadlineOption AbstractSplitTableDialog_Impl::GetSplitMode() OUString AbstractSwBreakDlg_Impl::GetTemplateName() { - return pDlg->GetTemplateName(); + return m_xDlg->GetTemplateName(); } sal_uInt16 AbstractSwBreakDlg_Impl:: GetKind() { - return pDlg->GetKind(); + return m_xDlg->GetKind(); } ::boost::optional<sal_uInt16> AbstractSwBreakDlg_Impl:: GetPageNumber() { - return pDlg->GetPageNumber(); + return m_xDlg->GetPageNumber(); } void AbstractSwConvertTableDlg_Impl::GetValues( sal_Unicode& rDelim,SwInsertTableOptions& rInsTableFlags, @@ -676,11 +679,9 @@ VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwInsertBookmarkDl return VclPtr<VclAbstractDialog_Impl>::Create( pDlg ); } -VclPtr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakDlg(vcl::Window *pParent, - SwWrtShell &rSh) +VclPtr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakDlg(weld::Window* pParent, SwWrtShell &rSh) { - VclPtr<SwBreakDlg> pDlg = VclPtr<SwBreakDlg>::Create(pParent, rSh); - return VclPtr<AbstractSwBreakDlg_Impl>::Create(pDlg); + return VclPtr<AbstractSwBreakDlg_Impl>::Create(new SwBreakDlg(pParent, rSh)); } VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwChangeDBDlg(SwView& rVw) diff --git a/sw/source/ui/dialog/swdlgfact.hxx b/sw/source/ui/dialog/swdlgfact.hxx index 2eeca35fa7f8..dbc95b9c31e9 100644 --- a/sw/source/ui/dialog/swdlgfact.hxx +++ b/sw/source/ui/dialog/swdlgfact.hxx @@ -103,12 +103,19 @@ class VclAbstractDialog_Impl : public VclAbstractDialog class AbstractSwBreakDlg_Impl : public AbstractSwBreakDlg { - DECL_ABSTDLG_BASE(AbstractSwBreakDlg_Impl,SwBreakDlg) +protected: + std::unique_ptr<SwBreakDlg> m_xDlg; +public: + explicit AbstractSwBreakDlg_Impl(SwBreakDlg* p) + : m_xDlg(p) + { + } + virtual short Execute() override; virtual OUString GetTemplateName() override; virtual sal_uInt16 GetKind() override; virtual ::boost::optional<sal_uInt16> GetPageNumber() override; - }; + class AbstractSplitTableDialog_Impl : public AbstractSplitTableDialog // add for { DECL_ABSTDLG_BASE(AbstractSplitTableDialog_Impl, SwSplitTableDlg) @@ -384,7 +391,7 @@ public: virtual VclPtr<AbstractSwAsciiFilterDlg> CreateSwAsciiFilterDlg ( SwDocShell& rDocSh, SvStream* pStream ) override; virtual VclPtr<VclAbstractDialog> CreateSwInsertBookmarkDlg( vcl::Window *pParent, SwWrtShell &rSh, SfxRequest& rReq ) override; - virtual VclPtr<AbstractSwBreakDlg> CreateSwBreakDlg(vcl::Window *pParent, SwWrtShell &rSh) override; + virtual VclPtr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) override; virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) override; virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(vcl::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet, SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) override; diff --git a/sw/source/uibase/inc/break.hxx b/sw/source/uibase/inc/break.hxx index 822e0e436bde..17ac6f34bbc9 100644 --- a/sw/source/uibase/inc/break.hxx +++ b/sw/source/uibase/inc/break.hxx @@ -20,30 +20,28 @@ #ifndef INCLUDED_SW_SOURCE_UIBASE_INC_BREAK_HXX #define INCLUDED_SW_SOURCE_UIBASE_INC_BREAK_HXX -#include <svx/stddlg.hxx> - +#include <vcl/weld.hxx> #include <vcl/button.hxx> - #include <vcl/fixed.hxx> - #include <vcl/lstbox.hxx> - #include <vcl/field.hxx> - #include <boost/optional.hpp> class SwWrtShell; -class SwBreakDlg: public SvxStandardDialog +class SwBreakDlg { SwWrtShell &rSh; - VclPtr<RadioButton> m_pLineBtn; - VclPtr<RadioButton> m_pColumnBtn; - VclPtr<RadioButton> m_pPageBtn; - VclPtr<FixedText> m_pPageCollText; - VclPtr<ListBox> m_pPageCollBox; - VclPtr<CheckBox> m_pPageNumBox; - VclPtr<NumericField> m_pPageNumEdit; + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Dialog> m_xDialog; + std::unique_ptr<weld::RadioButton> m_xLineBtn; + std::unique_ptr<weld::RadioButton> m_xColumnBtn; + std::unique_ptr<weld::RadioButton> m_xPageBtn; + std::unique_ptr<weld::Label> m_xPageCollText; + std::unique_ptr<weld::ComboBoxText> m_xPageCollBox; + std::unique_ptr<weld::CheckButton> m_xPageNumBox; + std::unique_ptr<weld::SpinButton> m_xPageNumEdit; + std::unique_ptr<weld::Button> m_xOkBtn; OUString aTemplate; sal_uInt16 nKind; @@ -51,25 +49,20 @@ class SwBreakDlg: public SvxStandardDialog bool bHtmlMode; - DECL_LINK( ClickHdl, Button*, void ); - DECL_LINK( SelectHdl, ListBox&, void ); - DECL_LINK( PageNumHdl, Button*, void ); - DECL_LINK(PageNumModifyHdl, Edit&, void); - DECL_LINK(OkHdl, Button*, void); + DECL_LINK(ToggleHdl, weld::ToggleButton&, void); + DECL_LINK(ChangeHdl, weld::ComboBoxText&, void); + DECL_LINK(PageNumHdl, weld::ToggleButton&, void); + DECL_LINK(PageNumModifyHdl, weld::SpinButton&, void); + DECL_LINK(OkHdl, weld::Button&, void); void CheckEnable(); -protected: - virtual void Apply() override; - public: - SwBreakDlg( vcl::Window *pParent, SwWrtShell &rSh ); - virtual ~SwBreakDlg() override; - virtual void dispose() override; - - const OUString& GetTemplateName() { return aTemplate; } - sal_uInt16 GetKind() { return nKind; } - const ::boost::optional<sal_uInt16>& GetPageNumber() { return oPgNum; } + SwBreakDlg(weld::Window *pParent, SwWrtShell &rSh); + short Execute(); + const OUString& GetTemplateName() const { return aTemplate; } + sal_uInt16 GetKind() const { return nKind; } + const ::boost::optional<sal_uInt16>& GetPageNumber() const { return oPgNum; } }; #endif diff --git a/sw/source/uibase/inc/uitool.hxx b/sw/source/uibase/inc/uitool.hxx index 2e2924df78b7..932c57ec0638 100644 --- a/sw/source/uibase/inc/uitool.hxx +++ b/sw/source/uibase/inc/uitool.hxx @@ -30,6 +30,7 @@ class SwPageDesc; class SvxTabStopItem; class SwWrtShell; class ListBox; +namespace weld { class ComboBoxText; } class SwDocShell; class SwFrameFormat; class SwTabCols; @@ -94,6 +95,7 @@ SW_DLLPUBLIC void FillCharStyleListBox(ListBox& rToFill, SwDocShell* pDocSh, boo //inserts a string sorted into a ListBox, SW_DLLPUBLIC sal_Int32 InsertStringSorted(const OUString& rEntry, ListBox& rToFill, sal_Int32 nOffset); +SW_DLLPUBLIC void InsertStringSorted(const OUString& rEntry, weld::ComboBoxText& rToFill, int nOffset); // Get table width and alignment SwTwips GetTableWidth( SwFrameFormat const * pFormat, SwTabCols const & rCols, sal_uInt16 *pPercent, diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx index 2266877d68e0..839326e70c34 100644 --- a/sw/source/uibase/shells/textsh1.cxx +++ b/sw/source/uibase/shells/textsh1.cxx @@ -647,10 +647,9 @@ void SwTextShell::Execute(SfxRequest &rReq) else { SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); - OSL_ENSURE(pFact, "SwAbstractDialogFactory fail!"); - - ScopedVclPtr<AbstractSwBreakDlg> pDlg(pFact->CreateSwBreakDlg(GetView().GetWindow(), rWrtSh)); - OSL_ENSURE(pDlg, "Dialog creation failed!"); + assert(pFact && "SwAbstractDialogFactory fail!"); + ScopedVclPtr<AbstractSwBreakDlg> pDlg(pFact->CreateSwBreakDlg(GetView().GetWindow()->GetFrameWeld(), rWrtSh)); + assert(pDlg && "Dialog creation failed!"); if ( pDlg->Execute() == RET_OK ) { nKind = pDlg->GetKind(); diff --git a/sw/source/uibase/utlui/uitool.cxx b/sw/source/uibase/utlui/uitool.cxx index 5ff91b633337..c8a8bfd49eca 100644 --- a/sw/source/uibase/utlui/uitool.cxx +++ b/sw/source/uibase/utlui/uitool.cxx @@ -22,6 +22,7 @@ #include <osl/diagnose.h> #include <tools/datetime.hxx> #include <vcl/svapp.hxx> +#include <vcl/weld.hxx> #include <unotools/collatorwrapper.hxx> #include <svl/urihelper.hxx> #include <svl/stritem.hxx> @@ -713,6 +714,19 @@ sal_Int32 InsertStringSorted(const OUString& rEntry, ListBox& rToFill, sal_Int32 return rToFill.InsertEntry(rEntry, nOffset); } +void InsertStringSorted(const OUString& rEntry, weld::ComboBoxText& rToFill, int nOffset) +{ + CollatorWrapper& rCaseColl = ::GetAppCaseCollator(); + const int nCount = rToFill.get_count(); + while (nOffset < nCount) + { + if (0 < rCaseColl.compareString(rToFill.get_text(nOffset), rEntry)) + break; + ++nOffset; + } + rToFill.insert_text(nOffset, rEntry); +} + void FillCharStyleListBox(ListBox& rToFill, SwDocShell* pDocSh, bool bSorted, bool bWithDefault) { const sal_Int32 nOffset = rToFill.GetEntryCount() > 0 ? 1 : 0; diff --git a/sw/uiconfig/swriter/ui/insertbreak.ui b/sw/uiconfig/swriter/ui/insertbreak.ui index 23dac4839f34..9cfe1bab7732 100644 --- a/sw/uiconfig/swriter/ui/insertbreak.ui +++ b/sw/uiconfig/swriter/ui/insertbreak.ui @@ -261,7 +261,6 @@ </object> </child> <action-widgets> - <action-widget response="0">ok</action-widget> <action-widget response="-6">cancel</action-widget> <action-widget response="-11">help</action-widget> </action-widgets> diff --git a/vcl/inc/salframe.hxx b/vcl/inc/salframe.hxx index 766301256f6e..c04f0a8f767e 100644 --- a/vcl/inc/salframe.hxx +++ b/vcl/inc/salframe.hxx @@ -28,6 +28,7 @@ #include <o3tl/typed_flags_set.hxx> #include <vcl/window.hxx> +#include <vcl/weld.hxx> // complete vcl::Window for SalFrame::CallCallback under -fsanitize=function class AllSettings; @@ -107,7 +108,8 @@ private: // the VCL window corresponding to this frame VclPtr<vcl::Window> m_pWindow; SALFRAMEPROC m_pProc; - +protected: + mutable std::unique_ptr<weld::Window> m_xFrameWeld; public: SalFrame(); virtual ~SalFrame() override; @@ -261,6 +263,8 @@ public: return false; } + virtual weld::Window* GetFrameWeld() const; + // Callbacks (indepent part in vcl/source/window/winproc.cxx) // for default message handling return 0 void SetCallback( vcl::Window* pWindow, SALFRAMEPROC pProc ); diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx index f33d9d4d912a..1eadc7ac382f 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -26,6 +26,7 @@ #include <vcl/dllapi.h> #include <vcl/salgtype.hxx> #include <osl/thread.hxx> +#include <vcl/vclenum.hxx> #include "displayconnectiondispatch.hxx" @@ -34,6 +35,12 @@ #include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> namespace comphelper { class SolarMutex; } +namespace vcl { class Window; } +namespace weld { + class Builder; + class MessageDialog; + class Widget; +} struct SystemParentData; struct SalPrinterQueueInfo; class ImplJobSetup; @@ -147,6 +154,10 @@ public: virtual OpenGLContext* CreateOpenGLContext() = 0; + virtual weld::Builder* CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile); + virtual weld::MessageDialog* CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, + VclButtonsType eButtonType, const OUString& rPrimaryMessage); + // methods for XDisplayConnection void SetEventCallback( rtl::Reference< vcl::DisplayConnectionDispatch > const & pInstance ) diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx index 0ae8250c82f6..6f4e0db8dc7f 100644 --- a/vcl/inc/unx/gtk/gtkframe.hxx +++ b/vcl/inc/unx/gtk/gtkframe.hxx @@ -536,6 +536,7 @@ public: virtual void* ShowPopover(const OUString& rHelpText, const tools::Rectangle& rHelpArea, QuickHelpFlags nFlags) override; virtual bool UpdatePopover(void* nId, const OUString& rHelpText, const tools::Rectangle& rHelpArea) override; virtual bool HidePopover(void* nId) override; + virtual weld::Window* GetFrameWeld() const override; #endif static GtkSalFrame *getFromWindow( GtkWindow *pWindow ); diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx index 4b48a4b3762e..2da209730e93 100644 --- a/vcl/inc/unx/gtk/gtkinst.hxx +++ b/vcl/inc/unx/gtk/gtkinst.hxx @@ -227,6 +227,8 @@ public: virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override; virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override; virtual OpenGLContext* CreateOpenGLContext() override; + virtual weld::Builder* CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile) override; + virtual weld::MessageDialog* CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage) override; #endif virtual const cairo_font_options_t* GetCairoFontOptions() override; diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx index 8d3f406bd30e..7172bc709612 100644 --- a/vcl/source/app/help.cxx +++ b/vcl/source/app/help.cxx @@ -58,6 +58,11 @@ bool Help::Start( const OUString&, const vcl::Window* ) return false; } +bool Help::Start(const OUString&, weld::Widget*) +{ + return false; +} + void Help::SearchKeyword( const OUString& ) { } diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 93697a61ad2d..12ce25351a46 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -27,7 +27,14 @@ #include <salbmp.hxx> #include <salobj.hxx> #include <salmenu.hxx> - +#include <vcl/builder.hxx> +#include <vcl/combobox.hxx> +#include <vcl/lstbox.hxx> +#include <vcl/dialog.hxx> +#include <vcl/layout.hxx> +#include <vcl/tabctrl.hxx> +#include <vcl/tabpage.hxx> +#include <vcl/weld.hxx> SalFrame::SalFrame() : m_pWindow(nullptr) @@ -164,4 +171,1080 @@ SalMenuItem::~SalMenuItem() { } +class SalInstanceWidget : public virtual weld::Widget +{ +private: + VclPtr<vcl::Window> m_xWidget; + bool m_bTakeOwnership; + +public: + SalInstanceWidget(vcl::Window* pWidget, bool bTakeOwnership) + : m_xWidget(pWidget) + , m_bTakeOwnership(bTakeOwnership) + { + } + + virtual void set_sensitive(bool sensitive) override + { + m_xWidget->Enable(sensitive); + } + + virtual bool get_sensitive() const override + { + return m_xWidget->IsEnabled(); + } + + virtual void set_visible(bool visible) override + { + m_xWidget->Show(visible); + } + + virtual bool get_visible() const override + { + return m_xWidget->IsVisible(); + } + + virtual void grab_focus() override + { + m_xWidget->GrabFocus(); + } + + virtual bool has_focus() const override + { + return m_xWidget->HasFocus(); + } + + virtual void show() override + { + m_xWidget->Show(); + } + + virtual void hide() override + { + m_xWidget->Hide(); + } + + virtual void set_size_request(int nWidth, int nHeight) override + { + m_xWidget->set_width_request(nWidth); + m_xWidget->set_height_request(nHeight); + } + + virtual Size get_preferred_size() const override + { + return m_xWidget->get_preferred_size(); + } + + virtual float approximate_char_width() const override + { + return m_xWidget->approximate_char_width(); + } + + virtual Size get_pixel_size(const OUString& rText) const override + { + //TODO, or do I want GetTextBoundRect ?, just using width at the moment anyway + return Size(m_xWidget->GetTextWidth(rText), m_xWidget->GetTextHeight()); + } + + virtual OString get_buildable_name() const override + { + return m_xWidget->get_id().toUtf8(); + } + + virtual OString get_help_id() const override + { + return m_xWidget->GetHelpId(); + } + + virtual Widget* weld_parent() const override + { + vcl::Window* pParent = m_xWidget->GetParent(); + return pParent ? new SalInstanceWidget(pParent, false) : nullptr; + } + + virtual ~SalInstanceWidget() override + { + if (m_bTakeOwnership) + m_xWidget.disposeAndClear(); + } + + vcl::Window* getWidget() + { + return m_xWidget; + } + + SystemWindow* getSystemWindow() + { + return m_xWidget->GetSystemWindow(); + } +}; + +class SalInstanceContainer : public SalInstanceWidget, public virtual weld::Container +{ +private: + VclPtr<vcl::Window> m_xContainer; +public: + SalInstanceContainer(vcl::Window* pContainer, bool bTakeOwnership) + : SalInstanceWidget(pContainer, bTakeOwnership) + , m_xContainer(pContainer) + { + } +}; + +class SalInstanceWindow : public SalInstanceContainer, public virtual weld::Window +{ +private: + VclPtr<SystemWindow> m_xWindow; + +public: + SalInstanceWindow(SystemWindow* pWindow, bool bTakeOwnership) + : SalInstanceContainer(pWindow, bTakeOwnership) + , m_xWindow(pWindow) + { + } + + virtual void set_title(const OUString& rTitle) override + { + m_xWindow->SetText(rTitle); + } + + virtual OUString get_title() const override + { + return m_xWindow->GetText(); + } +}; + +class SalInstanceDialog : public SalInstanceWindow, public virtual weld::Dialog +{ +private: + VclPtr<::Dialog> m_xDialog; + +public: + SalInstanceDialog(::Dialog* pDialog, bool bTakeOwnership) + : SalInstanceWindow(pDialog, bTakeOwnership) + , m_xDialog(pDialog) + { + } + + virtual int run() override + { + m_xDialog->Show(); + return m_xDialog->Execute(); + } + + virtual void response(int nResponse) override + { + m_xDialog->EndDialog(nResponse); + } +}; + +class SalInstanceMessageDialog : public SalInstanceDialog, public virtual weld::MessageDialog +{ +private: + VclPtr<::MessageDialog> m_xMessageDialog; +public: + SalInstanceMessageDialog(::MessageDialog* pDialog, bool bTakeOwnership) + : SalInstanceDialog(pDialog, bTakeOwnership) + , m_xMessageDialog(pDialog) + { + } + + virtual void set_primary_text(const OUString& rText) override + { + m_xMessageDialog->set_primary_text(rText); + } + + virtual OUString get_primary_text() const override + { + return m_xMessageDialog->get_primary_text(); + } + + virtual void set_secondary_text(const OUString& rText) override + { + m_xMessageDialog->set_secondary_text(rText); + } + + virtual OUString get_secondary_text() const override + { + return m_xMessageDialog->get_secondary_text(); + } +}; + +class SalInstanceFrame : public SalInstanceContainer, public virtual weld::Frame +{ +private: + VclPtr<VclFrame> m_xFrame; +public: + SalInstanceFrame(VclFrame* pFrame, bool bTakeOwnership) + : SalInstanceContainer(pFrame, bTakeOwnership) + , m_xFrame(pFrame) + { + } + + virtual void set_label(const OUString& rText) override + { + m_xFrame->set_label(rText); + } + + virtual OUString get_label() const override + { + return m_xFrame->get_label(); + } +}; + +class SalInstanceNotebook : public SalInstanceContainer, public virtual weld::Notebook +{ +private: + VclPtr<TabControl> m_xNotebook; + mutable std::vector<std::unique_ptr<SalInstanceContainer>> m_aPages; + + DECL_LINK(DeactivatePageHdl, TabControl*, bool); + DECL_LINK(ActivatePageHdl, TabControl*, void); + +public: + SalInstanceNotebook(TabControl* pNotebook, bool bTakeOwnership) + : SalInstanceContainer(pNotebook, bTakeOwnership) + , m_xNotebook(pNotebook) + { + m_xNotebook->SetActivatePageHdl(LINK(this, SalInstanceNotebook, ActivatePageHdl)); + m_xNotebook->SetDeactivatePageHdl(LINK(this, SalInstanceNotebook, DeactivatePageHdl)); + } + + virtual int get_current_page() const override + { + return m_xNotebook->GetPagePos(m_xNotebook->GetCurPageId()); + } + + virtual OString get_current_page_ident() const override + { + return m_xNotebook->GetPageName(m_xNotebook->GetCurPageId()); + } + + virtual weld::Container* get_page(const OString& rIdent) const override + { + sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent); + sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(nPageId); + if (nPageIndex == TAB_PAGE_NOTFOUND) + return nullptr; + TabPage* pPage = m_xNotebook->GetTabPage(nPageId); + vcl::Window* pChild = pPage->GetChild(0); + if (m_aPages.size() < nPageIndex + 1U) + m_aPages.resize(nPageIndex + 1U); + if (!m_aPages[nPageIndex]) + m_aPages[nPageIndex].reset(new SalInstanceContainer(pChild, false)); + return m_aPages[nPageIndex].get(); + } + + virtual void set_current_page(int nPage) override + { + m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(nPage)); + } + + virtual void set_current_page(const OString& rIdent) override + { + m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(rIdent)); + } + + virtual int get_n_pages() const override + { + return m_xNotebook->GetPageCount(); + } + + virtual ~SalInstanceNotebook() override + { + m_xNotebook->SetActivatePageHdl(Link<TabControl*,void>()); + m_xNotebook->SetDeactivatePageHdl(Link<TabControl*,bool>()); + } +}; + +IMPL_LINK_NOARG(SalInstanceNotebook, DeactivatePageHdl, TabControl*, bool) +{ + return m_aLeavePageHdl.Call(get_current_page_ident()); +} + +IMPL_LINK_NOARG(SalInstanceNotebook, ActivatePageHdl, TabControl*, void) +{ + m_aEnterPageHdl.Call(get_current_page_ident()); +} + +class SalInstanceButton : public SalInstanceContainer, public virtual weld::Button +{ +private: + VclPtr<::Button> m_xButton; + + DECL_LINK(ClickHdl, ::Button*, void); +public: + SalInstanceButton(::Button* pButton, bool bTakeOwnership) + : SalInstanceContainer(pButton, bTakeOwnership) + , m_xButton(pButton) + { + m_xButton->SetClickHdl(LINK(this, SalInstanceButton, ClickHdl)); + } + + virtual void set_label(const OUString& rText) override + { + m_xButton->SetText(rText); + } + + virtual OUString get_label() const override + { + return m_xButton->GetText(); + } + + virtual ~SalInstanceButton() override + { + m_xButton->SetClickHdl(Link<::Button*,void>()); + } +}; + +IMPL_LINK(SalInstanceButton, ClickHdl, ::Button*, pButton, void) +{ + //if there's no handler set, disengage our intercept and + //run the click again to get default behaviour for cancel/ok + //etc buttons. + if (!m_aClickHdl.IsSet()) + { + pButton->SetClickHdl(Link<::Button*,void>()); + pButton->Click(); + pButton->SetClickHdl(LINK(this, SalInstanceButton, ClickHdl)); + return; + } + signal_clicked(); +} + +class SalInstanceRadioButton : public SalInstanceButton, public virtual weld::RadioButton +{ +private: + VclPtr<::RadioButton> m_xRadioButton; + + DECL_LINK(ToggleHdl, ::RadioButton&, void); + +public: + SalInstanceRadioButton(::RadioButton* pButton, bool bTakeOwnership) + : SalInstanceButton(pButton, bTakeOwnership) + , m_xRadioButton(pButton) + { + m_xRadioButton->SetToggleHdl(LINK(this, SalInstanceRadioButton, ToggleHdl)); + } + + virtual void set_active(bool active) override + { + m_xRadioButton->Check(active); + } + + virtual bool get_active() const override + { + return m_xRadioButton->IsChecked(); + } + + virtual void set_inconsistent(bool /*inconsistent*/) override + { + //not available + } + + virtual bool get_inconsistent() const override + { + return false; + } + + virtual ~SalInstanceRadioButton() override + { + m_xRadioButton->SetToggleHdl(Link<::RadioButton&, void>()); + } +}; + +IMPL_LINK_NOARG(SalInstanceRadioButton, ToggleHdl, ::RadioButton&, void) +{ + signal_toggled(); +} + +class SalInstanceCheckButton : public SalInstanceButton, public virtual weld::CheckButton +{ +private: + VclPtr<CheckBox> m_xCheckButton; + + DECL_LINK(ToggleHdl, CheckBox&, void); +public: + SalInstanceCheckButton(CheckBox* pButton, bool bTakeOwnership) + : SalInstanceButton(pButton, bTakeOwnership) + , m_xCheckButton(pButton) + { + m_xCheckButton->SetToggleHdl(LINK(this, SalInstanceCheckButton, ToggleHdl)); + } + + virtual void set_active(bool active) override + { + m_xCheckButton->Check(active); + } + + virtual bool get_active() const override + { + return m_xCheckButton->IsChecked(); + } + + virtual void set_inconsistent(bool inconsistent) override + { + m_xCheckButton->SetState(inconsistent ? TRISTATE_INDET : TRISTATE_FALSE); + } + + virtual bool get_inconsistent() const override + { + return m_xCheckButton->GetState() == TRISTATE_INDET; + } + + virtual ~SalInstanceCheckButton() override + { + m_xCheckButton->SetToggleHdl(Link<CheckBox&, void>()); + } +}; + +IMPL_LINK_NOARG(SalInstanceCheckButton, ToggleHdl, CheckBox&, void) +{ + signal_toggled(); +} + +class SalInstanceEntry : public SalInstanceWidget, public virtual weld::Entry +{ +private: + VclPtr<Edit> m_xEntry; + + DECL_LINK(ChangeHdl, Edit&, void); + + class WeldTextFilter : public TextFilter + { + private: + Link<OUString&, bool>& m_rInsertTextHdl; + public: + WeldTextFilter(Link<OUString&, bool>& rInsertTextHdl) + : TextFilter(OUString()) + , m_rInsertTextHdl(rInsertTextHdl) + { + } + + virtual OUString filter(const OUString &rText) override + { + if (!m_rInsertTextHdl.IsSet()) + return rText; + OUString sText(rText); + const bool bContinue = m_rInsertTextHdl.Call(sText); + if (!bContinue) + return OUString(); + return sText; + } + }; + + WeldTextFilter m_aTextFilter; +public: + SalInstanceEntry(Edit* pEntry, bool bTakeOwnership) + : SalInstanceWidget(pEntry, bTakeOwnership) + , m_xEntry(pEntry) + , m_aTextFilter(m_aInsertTextHdl) + { + m_xEntry->SetModifyHdl(LINK(this, SalInstanceEntry, ChangeHdl)); + m_xEntry->SetTextFilter(&m_aTextFilter); + } + + virtual void set_text(const OUString& rText) override + { + m_xEntry->SetText(rText); + } + + virtual OUString get_text() const override + { + return m_xEntry->GetText(); + } + + virtual void set_width_chars(int nChars) override + { + m_xEntry->SetWidthInChars(nChars); + } + + virtual ~SalInstanceEntry() override + { + m_xEntry->SetTextFilter(nullptr); + m_xEntry->SetModifyHdl(Link<Edit&, void>()); + } +}; + +IMPL_LINK_NOARG(SalInstanceEntry, ChangeHdl, Edit&, void) +{ + signal_changed(); +} + +class SalInstanceTreeView : public SalInstanceContainer, public virtual weld::TreeView +{ +private: + VclPtr<ListBox> m_xTreeView; + + DECL_LINK(SelectHdl, ListBox&, void); + DECL_LINK(DoubleClickHdl, ListBox&, void); + +public: + SalInstanceTreeView(ListBox* pTreeView, bool bTakeOwnership) + : SalInstanceContainer(pTreeView, bTakeOwnership) + , m_xTreeView(pTreeView) + { + m_xTreeView->SetSelectHdl(LINK(this, SalInstanceTreeView, SelectHdl)); + m_xTreeView->SetDoubleClickHdl(LINK(this, SalInstanceTreeView, DoubleClickHdl)); + } + + virtual void append(const OUString& rText) override + { + m_xTreeView->InsertEntry(rText); + } + + virtual void insert(const OUString& rText, int pos) override + { + m_xTreeView->InsertEntry(rText, pos); + } + + virtual void remove(int pos) override + { + m_xTreeView->RemoveEntry(pos); + } + + virtual int find(const OUString& rText) const override + { + sal_Int32 nRet = m_xTreeView->GetEntryPos(rText); + if (nRet == LISTBOX_ENTRY_NOTFOUND) + return -1; + return nRet; + } + + virtual void set_top_entry(int pos) override + { + m_xTreeView->SetTopEntry(pos); + } + + virtual void clear() override + { + m_xTreeView->Clear(); + } + + virtual int n_children() const override + { + return m_xTreeView->GetEntryCount(); + } + + virtual void select(int pos) override + { + if (pos == -1) + { + m_xTreeView->SetNoSelection(); + return; + } + m_xTreeView->SelectEntryPos(pos); + } + + virtual OUString get_selected() override + { + return m_xTreeView->GetSelectedEntry(); + } + + virtual OUString get(int pos) override + { + return m_xTreeView->GetEntry(pos); + } + + virtual int get_selected_index() override + { + const sal_Int32 nRet = m_xTreeView->GetSelectedEntryPos(); + if (nRet == LISTBOX_ENTRY_NOTFOUND) + return -1; + return nRet; + } + + virtual void freeze() override + { + m_xTreeView->SetUpdateMode(false); + } + + virtual void thaw() override + { + m_xTreeView->SetUpdateMode(true); + } + + virtual int get_height_rows(int nRows) const override + { + return m_xTreeView->CalcWindowSizePixel(nRows); + } + + virtual ~SalInstanceTreeView() override + { + m_xTreeView->SetDoubleClickHdl(Link<ListBox&, void>()); + m_xTreeView->SetSelectHdl(Link<ListBox&, void>()); + } +}; + +IMPL_LINK_NOARG(SalInstanceTreeView, SelectHdl, ListBox&, void) +{ + signal_changed(); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, DoubleClickHdl, ListBox&, void) +{ + signal_row_activated(); +} + +class SalInstanceSpinButton : public SalInstanceEntry, public virtual weld::SpinButton +{ +private: + VclPtr<NumericField> m_xButton; + + DECL_LINK(UpDownHdl, SpinField&, void); + DECL_LINK(LoseFocusHdl, Control&, void); + DECL_LINK(OutputHdl, Edit&, bool); + +public: + SalInstanceSpinButton(NumericField* pButton, bool bTakeOwnership) + : SalInstanceEntry(pButton, bTakeOwnership) + , m_xButton(pButton) + { + m_xButton->SetUpHdl(LINK(this, SalInstanceSpinButton, UpDownHdl)); + m_xButton->SetDownHdl(LINK(this, SalInstanceSpinButton, UpDownHdl)); + m_xButton->SetLoseFocusHdl(LINK(this, SalInstanceSpinButton, LoseFocusHdl)); + m_xButton->SetOutputHdl(LINK(this, SalInstanceSpinButton, OutputHdl)); + } + + virtual int get_value() const override + { + return m_xButton->GetValue(); + } + + virtual void set_value(int value) override + { + m_xButton->SetValue(value); + } + + virtual void set_range(int min, int max) override + { + m_xButton->SetMin(min); + m_xButton->SetFirst(min); + m_xButton->SetMax(max); + m_xButton->SetLast(max); + } + + virtual void get_range(int& min, int& max) const override + { + min = m_xButton->GetMin(); + max = m_xButton->GetMax(); + } + + virtual void set_increments(int step, int /*page*/) override + { + m_xButton->SetSpinSize(step); + } + + virtual void get_increments(int& step, int& page) const override + { + step = m_xButton->GetSpinSize(); + page = m_xButton->GetSpinSize(); + } + + virtual void set_digits(unsigned int digits) override + { + m_xButton->SetDecimalDigits(digits); + } + + virtual unsigned int get_digits() const override + { + return m_xButton->GetDecimalDigits(); + } + + virtual ~SalInstanceSpinButton() override + { + m_xButton->SetOutputHdl(Link<Edit&, bool>()); + m_xButton->SetLoseFocusHdl(Link<Control&, void>()); + m_xButton->SetDownHdl(Link<SpinField&, void>()); + m_xButton->SetUpHdl(Link<SpinField&, void>()); + } +}; + +IMPL_LINK_NOARG(SalInstanceSpinButton, UpDownHdl, SpinField&, void) +{ + signal_value_changed(); +} + +IMPL_LINK_NOARG(SalInstanceSpinButton, LoseFocusHdl, Control&, void) +{ + signal_value_changed(); +} + +IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, Edit&, bool) +{ + return signal_output(); +} + +class SalInstanceLabel : public SalInstanceWidget, public virtual weld::Label +{ +private: + VclPtr<FixedText> m_xLabel; +public: + SalInstanceLabel(FixedText* pLabel, bool bTakeOwnership) + : SalInstanceWidget(pLabel, bTakeOwnership) + , m_xLabel(pLabel) + { + } + + virtual void set_label(const OUString& rText) override + { + m_xLabel->SetText(rText); + } +}; + +class SalInstanceTextView : public SalInstanceContainer, public virtual weld::TextView +{ +private: + VclPtr<VclMultiLineEdit> m_xTextView; + +public: + SalInstanceTextView(VclMultiLineEdit* pTextView, bool bTakeOwnership) + : SalInstanceContainer(pTextView, bTakeOwnership) + , m_xTextView(pTextView) + { + } + + virtual void set_text(const OUString& rText) override + { + m_xTextView->SetText(rText); + } + + virtual OUString get_text() const override + { + return m_xTextView->GetText(); + } + + virtual Selection get_selection() const override + { + return m_xTextView->GetSelection(); + } + + virtual void set_selection(const Selection& rSelection) override + { + m_xTextView->SetSelection(rSelection); + } +}; + +class SalInstanceDrawingArea : public SalInstanceWidget, public virtual weld::DrawingArea +{ +private: + VclPtr<VclDrawingArea> m_xDrawingArea; + + DECL_LINK(PaintHdl, vcl::RenderContext&, void); + DECL_LINK(ResizeHdl, const Size&, void); + +public: + SalInstanceDrawingArea(VclDrawingArea* pDrawingArea, bool bTakeOwnership) + : SalInstanceWidget(pDrawingArea, bTakeOwnership) + , m_xDrawingArea(pDrawingArea) + { + m_xDrawingArea->SetPaintHdl(LINK(this, SalInstanceDrawingArea, PaintHdl)); + m_xDrawingArea->SetResizeHdl(LINK(this, SalInstanceDrawingArea, ResizeHdl)); + } + + virtual void queue_draw() override + { + m_xDrawingArea->Invalidate(); + } + + virtual ~SalInstanceDrawingArea() override + { + m_xDrawingArea->SetResizeHdl(Link<const Size&, void>()); + m_xDrawingArea->SetPaintHdl(Link<vcl::RenderContext&, void>()); + } +}; + +IMPL_LINK(SalInstanceDrawingArea, PaintHdl, vcl::RenderContext&, rDevice, void) +{ + m_aDrawHdl.Call(rDevice); +} + +IMPL_LINK(SalInstanceDrawingArea, ResizeHdl, const Size&, rSize, void) +{ + m_aSizeAllocateHdl.Call(rSize); +} + +//ComboBox and ListBox have the same apis, ComboBoxes in LibreOffice have an edit box and ListBoxes +//don't. This distinction isn't there in Gtk. Use a template to sort this problem out. +template <class vcl_type> +class SalInstanceComboBoxText : public SalInstanceContainer, public virtual weld::ComboBoxText +{ +private: + VclPtr<vcl_type> m_xComboBoxText; + + static void LinkStubSetSelectHdl(void* instance, vcl_type&) + { + return static_cast<SalInstanceComboBoxText*>(instance)->signal_changed(); + } + +public: + SalInstanceComboBoxText(vcl_type* pComboBoxText, bool bTakeOwnership) + : SalInstanceContainer(pComboBoxText, bTakeOwnership) + , m_xComboBoxText(pComboBoxText) + { + m_xComboBoxText->SetSelectHdl(LINK(this, SalInstanceComboBoxText, SetSelectHdl)); + } + + virtual int get_active() const override + { + const sal_Int32 nRet = m_xComboBoxText->GetSelectedEntryPos(); + if (nRet == LISTBOX_ENTRY_NOTFOUND) + return -1; + return nRet; + } + + const OUString* getEntryData(int index) const + { + return static_cast<const OUString*>(m_xComboBoxText->GetEntryData(index)); + } + + virtual OUString get_active_id() const override + { + const OUString* pRet = getEntryData(m_xComboBoxText->GetSelectedEntryPos()); + if (!pRet) + return OUString(); + return *pRet; + } + + virtual void set_active_id(const OUString& rStr) override + { + for (int i = 0; i < get_count(); ++i) + { + const OUString* pId = getEntryData(i); + if (!pId) + continue; + if (*pId == rStr) + m_xComboBoxText->SelectEntryPos(i); + } + } + + virtual void set_active(int pos) override + { + if (pos == -1) + { + m_xComboBoxText->SetNoSelection(); + return; + } + m_xComboBoxText->SelectEntryPos(pos); + } + + virtual OUString get_active_text() const override + { + return m_xComboBoxText->GetSelectedEntry(); + } + + virtual OUString get_text(int pos) const override + { + return m_xComboBoxText->GetEntry(pos); + } + + virtual OUString get_id(int pos) const override + { + const OUString* pRet = getEntryData(pos); + if (!pRet) + return OUString(); + return *pRet; + } + + virtual void append_text(const OUString& rStr) override + { + m_xComboBoxText->InsertEntry(rStr); + } + + virtual void insert_text(int pos, const OUString& rStr) override + { + m_xComboBoxText->InsertEntry(rStr, pos); + } + + virtual void append(const OUString& rId, const OUString& rStr) override + { + m_xComboBoxText->SetEntryData(m_xComboBoxText->InsertEntry(rStr), new OUString(rId)); + } + + virtual void insert(int pos, const OUString& rId, const OUString& rStr) override + { + m_xComboBoxText->SetEntryData(m_xComboBoxText->InsertEntry(rStr, pos), new OUString(rId)); + } + + virtual int get_count() const override + { + return m_xComboBoxText->GetEntryCount(); + } + + virtual int find_text(const OUString& rStr) const override + { + const sal_Int32 nRet = m_xComboBoxText->GetEntryPos(rStr); + if (nRet == LISTBOX_ENTRY_NOTFOUND) + return -1; + return nRet; + } + + virtual void clear() override + { + for (int i = 0; i < get_count(); ++i) + { + const OUString* pId = getEntryData(i); + delete pId; + } + return m_xComboBoxText->Clear(); + } + + virtual void make_sorted() override + { + m_xComboBoxText->SetStyle(m_xComboBoxText->GetStyle() | WB_SORT); + } + + virtual ~SalInstanceComboBoxText() override + { + m_xComboBoxText->SetSelectHdl(Link<vcl_type&, void>()); + clear(); + } +}; + +class SalInstanceBuilder : public weld::Builder +{ +private: + VclBuilder m_aBuilder; +public: + SalInstanceBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile) + : weld::Builder(rUIFile) + , m_aBuilder(pParent, rUIRoot, rUIFile) + { + } + + virtual weld::MessageDialog* weld_message_dialog(const OString &id, bool bTakeOwnership) override + { + MessageDialog* pMessageDialog = m_aBuilder.get<MessageDialog>(id); + return pMessageDialog ? new SalInstanceMessageDialog(pMessageDialog, bTakeOwnership) : nullptr; + } + + virtual weld::Dialog* weld_dialog(const OString &id, bool bTakeOwnership) override + { + Dialog* pDialog = m_aBuilder.get<Dialog>(id); + return pDialog ? new SalInstanceDialog(pDialog, bTakeOwnership) : nullptr; + } + + virtual weld::Window* weld_window(const OString &id, bool bTakeOwnership) override + { + SystemWindow* pWindow = m_aBuilder.get<SystemWindow>(id); + return pWindow ? new SalInstanceWindow(pWindow, bTakeOwnership) : nullptr; + } + + virtual weld::Widget* weld_widget(const OString &id, bool bTakeOwnership) override + { + vcl::Window* pWidget = m_aBuilder.get<vcl::Window>(id); + return pWidget ? new SalInstanceWidget(pWidget, bTakeOwnership) : nullptr; + } + + virtual weld::Container* weld_container(const OString &id, bool bTakeOwnership) override + { + vcl::Window* pContainer = m_aBuilder.get<vcl::Window>(id); + return pContainer ? new SalInstanceContainer(pContainer, bTakeOwnership) : nullptr; + } + + virtual weld::Frame* weld_frame(const OString &id, bool bTakeOwnership) override + { + VclFrame* pFrame = m_aBuilder.get<VclFrame>(id); + return pFrame ? new SalInstanceFrame(pFrame, bTakeOwnership) : nullptr; + } + + virtual weld::Notebook* weld_notebook(const OString &id, bool bTakeOwnership) override + { + TabControl* pNotebook = m_aBuilder.get<TabControl>(id); + return pNotebook ? new SalInstanceNotebook(pNotebook, bTakeOwnership) : nullptr; + } + + virtual weld::Button* weld_button(const OString &id, bool bTakeOwnership) override + { + Button* pButton = m_aBuilder.get<Button>(id); + return pButton ? new SalInstanceButton(pButton, bTakeOwnership) : nullptr; + } + + virtual weld::RadioButton* weld_radio_button(const OString &id, bool bTakeOwnership) override + { + RadioButton* pRadioButton = m_aBuilder.get<RadioButton>(id); + return pRadioButton ? new SalInstanceRadioButton(pRadioButton, bTakeOwnership) : nullptr; + } + + virtual weld::CheckButton* weld_check_button(const OString &id, bool bTakeOwnership) override + { + CheckBox* pCheckButton = m_aBuilder.get<CheckBox>(id); + return pCheckButton ? new SalInstanceCheckButton(pCheckButton, bTakeOwnership) : nullptr; + } + + virtual weld::Entry* weld_entry(const OString &id, bool bTakeOwnership) override + { + Edit* pEntry = m_aBuilder.get<Edit>(id); + return pEntry ? new SalInstanceEntry(pEntry, bTakeOwnership) : nullptr; + } + + virtual weld::SpinButton* weld_spin_button(const OString &id, bool bTakeOwnership) override + { + NumericField* pSpinButton = m_aBuilder.get<NumericField>(id); + return pSpinButton ? new SalInstanceSpinButton(pSpinButton, bTakeOwnership) : nullptr; + } + + virtual weld::ComboBoxText* weld_combo_box_text(const OString &id, bool bTakeOwnership) override + { + vcl::Window* pComboBoxText = m_aBuilder.get<vcl::Window>(id); + ComboBox* pComboBox = dynamic_cast<ComboBox*>(pComboBoxText); + if (pComboBox) + return new SalInstanceComboBoxText<ComboBox>(pComboBox, bTakeOwnership); + ListBox* pListBox = dynamic_cast<ListBox*>(pComboBoxText); + return pListBox ? new SalInstanceComboBoxText<ListBox>(pListBox, bTakeOwnership) : nullptr; + } + + virtual weld::TreeView* weld_tree_view(const OString &id, bool bTakeOwnership) override + { + ListBox* pTreeView = m_aBuilder.get<ListBox>(id); + return pTreeView ? new SalInstanceTreeView(pTreeView, bTakeOwnership) : nullptr; + } + + virtual weld::Label* weld_label(const OString &id, bool bTakeOwnership) override + { + FixedText* pLabel = m_aBuilder.get<FixedText>(id); + return pLabel ? new SalInstanceLabel(pLabel, bTakeOwnership) : nullptr; + } + + virtual weld::TextView* weld_text_view(const OString &id, bool bTakeOwnership) override + { + VclMultiLineEdit* pTextView = m_aBuilder.get<VclMultiLineEdit>(id); + return pTextView ? new SalInstanceTextView(pTextView, bTakeOwnership) : nullptr; + } + + virtual weld::DrawingArea* weld_drawing_area(const OString &id, bool bTakeOwnership) override + { + VclDrawingArea* pDrawingArea = m_aBuilder.get<VclDrawingArea>(id); + return pDrawingArea ? new SalInstanceDrawingArea(pDrawingArea, bTakeOwnership) : nullptr; + } +}; + +weld::Builder* SalInstance::CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile) +{ + SalInstanceWidget* pParentInstance = dynamic_cast<SalInstanceWidget*>(pParent); + vcl::Window* pParentWidget = pParentInstance ? pParentInstance->getWidget() : nullptr; + return new SalInstanceBuilder(pParentWidget, rUIRoot, rUIFile); +} + +weld::MessageDialog* SalInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString& rPrimaryMessage) +{ + SalInstanceWidget* pParentInstance = dynamic_cast<SalInstanceWidget*>(pParent); + SystemWindow* pParentWidget = pParentInstance ? pParentInstance->getSystemWindow() : nullptr; + VclPtrInstance<MessageDialog> xMessageDialog(pParentWidget, rPrimaryMessage, eMessageType, eButtonsType); + return new SalInstanceMessageDialog(xMessageDialog, true); +} + +weld::Window* SalFrame::GetFrameWeld() const +{ + if (!m_xFrameWeld) + { + vcl::Window* pWindow = GetWindow(); + pWindow = pWindow ? pWindow->ImplGetWindow() : nullptr; + SystemWindow* pSystemWindow = pWindow ? pWindow->GetSystemWindow() : nullptr; + if (pSystemWindow) + m_xFrameWeld.reset(new SalInstanceWindow(pSystemWindow, false)); + } + return m_xFrameWeld.get(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx index daf90a3333bc..8e1cc649cb31 100644 --- a/vcl/source/control/combobox.cxx +++ b/vcl/source/control/combobox.cxx @@ -986,7 +986,7 @@ void ComboBox::SetDoubleClickHdl(const Link<ComboBox&,void>& rLink) { m_pImpl->m const Link<ComboBox&,void>& ComboBox::GetDoubleClickHdl() const { return m_pImpl->m_DoubleClickHdl; } -long ComboBox::CalcWindowSizePixel( sal_uInt16 nLines ) const +long ComboBox::CalcWindowSizePixel(sal_uInt16 nLines) const { return m_pImpl->m_pImplLB->GetEntryHeight() * nLines; } diff --git a/vcl/source/control/field.cxx b/vcl/source/control/field.cxx index 1e5085cf007e..d04886eeb228 100644 --- a/vcl/source/control/field.cxx +++ b/vcl/source/control/field.cxx @@ -445,15 +445,21 @@ void FormatterBase::ImplSetText( const OUString& rText, Selection const * pNewSe { if ( mpField ) { - if ( pNewSelection ) - mpField->SetText( rText, *pNewSelection ); + if (pNewSelection) + mpField->SetText(rText, *pNewSelection); else { Selection aSel = mpField->GetSelection(); aSel.Min() = aSel.Max(); - mpField->SetText( rText, aSel ); + mpField->SetText(rText, aSel); + } + if (maOutputHdl.IsSet()) + { + OUString sText(mpField->GetText()); + mpField->SetText(OUString()); + if (!maOutputHdl.Call(*mpField)) + mpField->SetText(sText); } - MarkToBeReformatted( false ); } } diff --git a/vcl/source/control/listbox.cxx b/vcl/source/control/listbox.cxx index df21ca2b1741..c693223bb21a 100644 --- a/vcl/source/control/listbox.cxx +++ b/vcl/source/control/listbox.cxx @@ -1242,6 +1242,11 @@ Size ListBox::CalcSubEditSize() const return aSz; } +long ListBox::CalcWindowSizePixel(sal_uInt16 nLines) const +{ + return mpImplLB->GetEntryHeight() * nLines; +} + Size ListBox::GetOptimalSize() const { return CalcMinimumSize(); diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index 353db7d5c633..d36bc390f319 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -11,7 +11,9 @@ #include <com/sun/star/packages/zip/ZipFileAccess.hpp> #include <comphelper/processfactory.hxx> +#include <i18nutil/unicode.hxx> #include <osl/module.hxx> +#include <osl/file.hxx> #include <sal/log.hxx> #include <unotools/resmgr.hxx> #include <vcl/builder.hxx> @@ -37,12 +39,14 @@ #include <vcl/settings.hxx> #include <vcl/slider.hxx> #include <vcl/listctrl.hxx> +#include <vcl/weld.hxx> #include <vcl/commandinfoprovider.hxx> #include <svdata.hxx> #include <bitmaps.hlst> #include <window.h> #include <xmlreader/xmlreader.hxx> #include <desktop/crashreport.hxx> +#include <salinst.hxx> #include <strings.hrc> #include <tools/svlibrary.h> @@ -120,6 +124,114 @@ namespace } #endif +weld::Builder* Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile) +{ + return ImplGetSVData()->mpDefInst->CreateBuilder(pParent, VclBuilderContainer::getUIRootDir(), rUIFile); +} + +weld::MessageDialog* Application::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, + VclButtonsType eButtonType, const OUString& rPrimaryMessage) +{ + return ImplGetSVData()->mpDefInst->CreateMessageDialog(pParent, eMessageType, eButtonType, rPrimaryMessage); +} + +namespace +{ + const OUString MetricToString(FieldUnit rUnit) + { + FieldUnitStringList* pList = ImplGetFieldUnits(); + if (pList) + { + // return unit's default string (ie, the first one ) + for (auto it = pList->begin(); it != pList->end(); ++it) + { + if (it->second == rUnit) + return it->first; + } + } + + return OUString(); + } +} + +namespace weld +{ + IMPL_LINK_NOARG(MetricSpinButton, spin_button_value_changed, SpinButton&, void) + { + signal_value_changed(); + } + + IMPL_LINK(MetricSpinButton, spin_button_output, SpinButton&, rSpinButton, void) + { + rSpinButton.set_text(format_number(rSpinButton.get_value())); + } + + void MetricSpinButton::update_width_chars() + { + int min, max; + m_xSpinButton->get_range(min, max); + auto width = std::max(m_xSpinButton->get_pixel_size(format_number(min)).Width(), + m_xSpinButton->get_pixel_size(format_number(max)).Width()); + int chars = ceil(width / m_xSpinButton->approximate_char_width()); + m_xSpinButton->set_width_chars(chars); + } + + unsigned int SpinButton::Power10(unsigned int n) + { + unsigned int nValue = 1; + for (unsigned int i = 0; i < n; ++i) + nValue *= 10; + return nValue; + } + + int SpinButton::denormalize(int nValue) const + { + const int nFactor = Power10(get_digits()); + + if ((nValue < (SAL_MIN_INT32 + nFactor)) || (nValue > (SAL_MAX_INT32 - nFactor))) + { + return nValue / nFactor; + } + + const int nHalf = nFactor / 2; + + if (nValue < 0) + return (nValue - nHalf) / nFactor; + return (nValue + nHalf) / nFactor; + } + + OUString MetricSpinButton::format_number(int nValue) const + { + OUString aStr; + + unsigned int nDecimalDigits = m_xSpinButton->get_digits(); + //pawn percent off to icu to decide whether percent is separated from its number for this locale + if (m_eSrcUnit == FUNIT_PERCENT) + { + double fValue = nValue; + fValue /= SpinButton::Power10(nDecimalDigits); + aStr = unicode::formatPercent(fValue, Application::GetSettings().GetUILanguageTag()); + } + else + { + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData(); + aStr = rLocaleData.getNum(nValue, nDecimalDigits, true, true); + if (m_eSrcUnit != FUNIT_NONE && m_eSrcUnit != FUNIT_DEGREE) + aStr += " "; + assert(m_eSrcUnit != FUNIT_PERCENT); + aStr += MetricToString(m_eSrcUnit); + } + + return aStr; + } + + int MetricSpinButton::ConvertValue(int nValue, FieldUnit eInUnit, FieldUnit eOutUnit) const + { + return MetricField::ConvertValue(nValue, 0, m_xSpinButton->get_digits(), eInUnit, eOutUnit); + } +} + VclBuilder::VclBuilder(vcl::Window *pParent, const OUString& sUIDir, const OUString& sUIFile, const OString& sID, const css::uno::Reference<css::frame::XFrame>& rFrame) : m_sID(sID) , m_sHelpRoot(OUStringToOString(sUIFile, RTL_TEXTENCODING_UTF8)) @@ -1189,7 +1301,7 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString & WinBits nBits = WB_MOVEABLE|WB_3DLOOK|WB_CLOSEABLE; if (extractResizable(rMap)) nBits |= WB_SIZEABLE; - xWindow = VclPtr<Dialog>::Create(pParent, nBits); + xWindow = VclPtr<Dialog>::Create(pParent, nBits, !pParent ? Dialog::InitFlag::NoParent : Dialog::InitFlag::Default); } else if (name == "GtkMessageDialog") { @@ -1515,7 +1627,7 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString & else if (name == "GtkDrawingArea") { OUString sBorder = BuilderUtils::extractCustomProperty(rMap); - xWindow = VclPtr<vcl::Window>::Create(pParent, sBorder.isEmpty() ? 0 : WB_BORDER); + xWindow = VclPtr<VclDrawingArea>::Create(pParent, sBorder.isEmpty() ? 0 : WB_BORDER); } else if (name == "GtkTextView") { diff --git a/vcl/source/window/menuwindow.cxx b/vcl/source/window/menuwindow.cxx index 8abfe172af9d..4577f38abdc1 100644 --- a/vcl/source/window/menuwindow.cxx +++ b/vcl/source/window/menuwindow.cxx @@ -99,9 +99,9 @@ bool MenuWindow::ImplHandleHelpEvent(vcl::Window* pMenuWindow, Menu const * pMen aHelpId = OOO_HELP_INDEX; if ( !aCommand.isEmpty() ) - pHelp->Start( aCommand, nullptr ); + pHelp->Start(aCommand, static_cast<vcl::Window*>(nullptr)); else - pHelp->Start( OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), nullptr ); + pHelp->Start(OStringToOUString(aHelpId, RTL_TEXTENCODING_UTF8), static_cast<vcl::Window*>(nullptr)); } bDone = true; } diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx index 85b72726ebc2..6aa4182b11bd 100644 --- a/vcl/source/window/window2.cxx +++ b/vcl/source/window/window2.cxx @@ -897,6 +897,12 @@ SalFrame* Window::ImplGetFrame() const return mpWindowImpl ? mpWindowImpl->mpFrame : nullptr; } +weld::Window* Window::GetFrameWeld() const +{ + SalFrame* pFrame = ImplGetFrame(); + return pFrame ? pFrame->GetFrameWeld() : nullptr; +} + vcl::Window* Window::ImplGetParent() const { return mpWindowImpl ? mpWindowImpl->mpParent.get() : nullptr; diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx index bfdba2f717c1..42c0014a81d8 100644 --- a/vcl/unx/gtk3/gtk3gtkframe.cxx +++ b/vcl/unx/gtk3/gtk3gtkframe.cxx @@ -38,6 +38,7 @@ #include <rtl/process.h> #include <vcl/floatwin.hxx> #include <vcl/svapp.hxx> +#include <vcl/weld.hxx> #include <vcl/window.hxx> #include <vcl/settings.hxx> #include <cppuhelper/exc_hlp.hxx> @@ -3572,6 +3573,7 @@ void GtkSalFrame::signalDestroy( GtkWidget* pObj, gpointer frame ) pThis->m_pEventBox = nullptr; pThis->m_pTopLevelGrid = nullptr; pThis->m_pWindow = nullptr; + pThis->m_xFrameWeld.reset(); pThis->InvalidateGraphics(); } } diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 5497a3d7de4b..0acaed180b20 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -25,8 +25,14 @@ #include <comphelper/processfactory.hxx> #include <comphelper/sequence.hxx> #include <cppuhelper/compbase.hxx> +#include <comphelper/string.hxx> #include <cppuhelper/implbase.hxx> #include <cppuhelper/supportsservice.hxx> +#include <rtl/bootstrap.hxx> +#include <tools/fract.hxx> +#include <tools/stream.hxx> +#include <vcl/pngwrite.hxx> +#include <vcl/weld.hxx> using namespace com::sun::star; using namespace com::sun::star::uno; @@ -130,7 +136,7 @@ std::vector<css::datatransfer::DataFlavor> GtkTransferable::getTransferDataFlavo } aFlavor.MimeType = OUString(pFinalName, - rtl_str_getLength(pFinalName), + strlen(pFinalName), RTL_TEXTENCODING_UTF8); m_aMimeTypeToAtom[aFlavor.MimeType] = targets[i]; @@ -1148,4 +1154,1568 @@ OpenGLContext* GtkInstance::CreateOpenGLContext() return new GtkOpenGLContext; } +class GtkInstanceBuilder; + +namespace +{ + OString get_help_id(const GtkWidget *pWidget) + { + void* pData = g_object_get_data(G_OBJECT(pWidget), "helpid"); + const gchar* pStr = static_cast<const gchar*>(pData); + return OString(pStr, pStr ? strlen(pStr) : 0); + } +} + +class GtkInstanceWidget : public virtual weld::Widget +{ +protected: + GtkWidget* m_pWidget; +private: + bool m_bTakeOwnership; + +public: + GtkInstanceWidget(GtkWidget* pWidget, bool bTakeOwnership) + : m_pWidget(pWidget) + , m_bTakeOwnership(bTakeOwnership) + { + } + + virtual void set_sensitive(bool sensitive) override + { + gtk_widget_set_sensitive(m_pWidget, sensitive); + } + + virtual bool get_sensitive() const override + { + return gtk_widget_get_sensitive(m_pWidget); + } + + virtual void set_visible(bool visible) override + { + gtk_widget_set_visible(m_pWidget, visible); + } + + virtual bool get_visible() const override + { + return gtk_widget_get_visible(m_pWidget); + } + + virtual void grab_focus() override + { + gtk_widget_grab_focus(m_pWidget); + } + + virtual bool has_focus() const override + { + return gtk_widget_has_focus(m_pWidget); + } + + virtual void show() override + { + gtk_widget_show(m_pWidget); + } + + virtual void hide() override + { + gtk_widget_hide(m_pWidget); + } + + virtual void set_size_request(int nWidth, int nHeight) override + { + gtk_widget_set_size_request(m_pWidget, nWidth, nHeight); + } + + virtual Size get_preferred_size() const override + { + GtkRequisition size; + gtk_widget_get_preferred_size(m_pWidget, nullptr, &size); + return Size(size.width, size.height); + } + + virtual float approximate_char_width() const override + { + PangoContext* pContext = gtk_widget_get_pango_context(m_pWidget); + PangoFontMetrics* pMetrics = pango_context_get_metrics(pContext, + pango_context_get_font_description(pContext), + pango_context_get_language(pContext)); + float nCharWidth = pango_font_metrics_get_approximate_char_width(pMetrics); + float nDigitWidth = pango_font_metrics_get_approximate_digit_width(pMetrics); + pango_font_metrics_unref(pMetrics); + + return std::max(nCharWidth, nDigitWidth) / PANGO_SCALE; + } + + virtual Size get_pixel_size(const OUString& rText) const override + { + OString aStr(OUStringToOString(rText, RTL_TEXTENCODING_UTF8)); + PangoLayout* pLayout = gtk_widget_create_pango_layout(m_pWidget, aStr.getStr()); + gint nWidth, nHeight; + pango_layout_get_pixel_size(pLayout, &nWidth, &nHeight); + g_object_unref(pLayout); + return Size(nWidth, nHeight); + } + + virtual weld::Widget* weld_parent() const override + { + GtkWidget* pParent = gtk_widget_get_parent(m_pWidget); + return pParent ? new GtkInstanceWidget(pParent, false) : nullptr; + } + + virtual OString get_buildable_name() const override + { + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(m_pWidget)); + return OString(pStr, pStr ? strlen(pStr) : 0); + } + + virtual OString get_help_id() const override + { + OString sRet = ::get_help_id(m_pWidget); + if (sRet.isEmpty()) + sRet = OString("null"); + return sRet; + } + + GtkWidget* getWidget() + { + return m_pWidget; + } + + GtkWindow* getWindow() + { + return GTK_WINDOW(gtk_widget_get_toplevel(m_pWidget)); + } + + virtual ~GtkInstanceWidget() override + { + if (m_bTakeOwnership) + gtk_widget_destroy(m_pWidget); + } +}; + +class GtkInstanceContainer : public GtkInstanceWidget, public virtual weld::Container +{ +private: + GtkContainer* m_pContainer; +public: + GtkInstanceContainer(GtkContainer* pContainer, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pContainer), bTakeOwnership) + , m_pContainer(pContainer) + { + (void)m_pContainer; + } +}; + +class GtkInstanceWindow : public GtkInstanceContainer, public virtual weld::Window +{ +private: + GtkWindow* m_pWindow; + + static void help_pressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer widget) + { + GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget); + pThis->help(); + } +protected: + void help(); +public: + GtkInstanceWindow(GtkWindow* pWindow, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pWindow), bTakeOwnership) + , m_pWindow(pWindow) + { + //hook up F1 to show help + GtkAccelGroup *pGroup = gtk_accel_group_new(); + GClosure* closure = g_cclosure_new(G_CALLBACK(help_pressed), this, nullptr); + gtk_accel_group_connect(pGroup, GDK_KEY_F1, static_cast<GdkModifierType>(0), GTK_ACCEL_LOCKED, closure); + gtk_window_add_accel_group(pWindow, pGroup); + } + + virtual void set_title(const OUString& rTitle) override + { + gtk_window_set_title(m_pWindow, OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual OUString get_title() const override + { + const gchar* pStr = gtk_window_get_title(m_pWindow); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } +}; + +class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog +{ +private: + GtkDialog* m_pDialog; + gulong m_nCloseSignalId; + + static void signalClose(GtkWidget *, gpointer widget) + { + GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget); + pThis->response(RET_CANCEL); + } +public: + GtkInstanceDialog(GtkDialog* pDialog, bool bTakeOwnership) + : GtkInstanceWindow(GTK_WINDOW(pDialog), bTakeOwnership) + , m_pDialog(pDialog) + , m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this)) + { + } + + virtual int run() override + { + int ret; + while (true) + { + ret = gtk_dialog_run(m_pDialog); + if (ret == GTK_RESPONSE_HELP) + { + help(); + continue; + } + else if (ret == GTK_RESPONSE_OK) + ret = RET_OK; + else if (ret == GTK_RESPONSE_CANCEL) + ret = RET_CANCEL; + break; + } + hide(); + return ret; + } + + virtual void response(int nResponse) override + { + if (nResponse == RET_OK) + nResponse = GTK_RESPONSE_OK; + else if (nResponse == RET_CANCEL) + nResponse = GTK_RESPONSE_CANCEL; + else if (nResponse == RET_HELP) + nResponse = GTK_RESPONSE_HELP; + gtk_dialog_response(m_pDialog, nResponse); + } + + virtual ~GtkInstanceDialog() override + { + g_signal_handler_disconnect(m_pDialog, m_nCloseSignalId); + } +}; + +class GtkInstanceMessageDialog : public GtkInstanceDialog, public virtual weld::MessageDialog +{ +private: + GtkMessageDialog* m_pMessageDialog; +public: + GtkInstanceMessageDialog(GtkMessageDialog* pMessageDialog, bool bTakeOwnership) + : GtkInstanceDialog(GTK_DIALOG(pMessageDialog), bTakeOwnership) + , m_pMessageDialog(pMessageDialog) + { + } + + virtual void set_primary_text(const OUString& rText) override + { + g_object_set(G_OBJECT(m_pMessageDialog), "text", + OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(), + nullptr); + } + + virtual OUString get_primary_text() const override + { + gchar* pText = nullptr; + g_object_get(G_OBJECT(m_pMessageDialog), "text", &pText, nullptr); + return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + } + + virtual void set_secondary_text(const OUString& rText) override + { + g_object_set(G_OBJECT(m_pMessageDialog), "secondary-text", + OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(), + nullptr); + } + + virtual OUString get_secondary_text() const override + { + gchar* pText = nullptr; + g_object_get(G_OBJECT(m_pMessageDialog), "secondary-text", &pText, nullptr); + return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + } +}; + +static OString MapToGtkAccelerator(const OUString &rStr) +{ + return OUStringToOString(rStr.replaceFirst("~", "_"), RTL_TEXTENCODING_UTF8); +} + +class GtkInstanceFrame : public GtkInstanceContainer, public virtual weld::Frame +{ +private: + GtkFrame* m_pFrame; +public: + GtkInstanceFrame(GtkFrame* pFrame, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pFrame), bTakeOwnership) + , m_pFrame(pFrame) + { + } + + virtual void set_label(const OUString& rText) override + { + gtk_label_set_label(GTK_LABEL(gtk_frame_get_label_widget(m_pFrame)), MapToGtkAccelerator(rText).getStr()); + } + + virtual OUString get_label() const override + { + const gchar* pStr = gtk_frame_get_label(m_pFrame); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } +}; + +class GtkInstanceNotebook : public GtkInstanceContainer, public virtual weld::Notebook +{ +private: + GtkNotebook* m_pNotebook; + gulong m_nSignalId; + mutable std::vector<std::unique_ptr<GtkInstanceContainer>> m_aPages; + + static void signalSwitchPage(GtkNotebook*, GtkWidget*, guint nNewPage, gpointer widget) + { + GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget); + pThis->signal_switch_page(nNewPage); + } + + void signal_switch_page(guint nNewPage) + { + bool bAllow = m_aLeavePageHdl.Call(get_current_page_ident()); + if (!bAllow) + { + g_signal_stop_emission_by_name(m_pNotebook, "switch-page"); + OString sNewIdent(get_page_ident(nNewPage)); + m_aEnterPageHdl.Call(sNewIdent); + } + } + + OString get_page_ident(guint nPage) const + { + const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook, gtk_notebook_get_nth_page(m_pNotebook, nPage)); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget)); + return OString(pStr, pStr ? strlen(pStr) : 0); + } + + gint get_page_number(const OString& rIdent) const + { + gint nPages = gtk_notebook_get_n_pages(m_pNotebook); + for (gint i = 0; i < nPages; ++i) + { + const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook, gtk_notebook_get_nth_page(m_pNotebook, i)); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget)); + if (strcmp(pStr, rIdent.getStr()) == 0) + return i; + } + return -1; + } + +public: + GtkInstanceNotebook(GtkNotebook* pNotebook, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pNotebook), bTakeOwnership) + , m_pNotebook(pNotebook) + , m_nSignalId(g_signal_connect(pNotebook, "switch-page", G_CALLBACK(signalSwitchPage), this)) + { + } + + virtual int get_current_page() const override + { + return gtk_notebook_get_current_page(m_pNotebook); + } + + virtual OString get_current_page_ident() const override + { + return get_page_ident(get_current_page()); + } + + virtual weld::Container* get_page(const OString& rIdent) const override + { + int nPage = get_page_number(rIdent); + if (nPage < 0) + return nullptr; + GtkContainer* pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pNotebook, nPage)); + unsigned int nPageIndex = static_cast<unsigned int>(nPage); + if (m_aPages.size() < nPageIndex + 1) + m_aPages.resize(nPageIndex + 1); + if (!m_aPages[nPageIndex]) + m_aPages[nPageIndex].reset(new GtkInstanceContainer(pChild, false)); + return m_aPages[nPageIndex].get(); + } + + virtual void set_current_page(int nPage) override + { + gtk_notebook_set_current_page(m_pNotebook, nPage); + } + + virtual void set_current_page(const OString& rIdent) override + { + gint nPage = get_page_number(rIdent); + set_current_page(nPage); + } + + virtual int get_n_pages() const override + { + return gtk_notebook_get_n_pages(m_pNotebook); + } + + virtual ~GtkInstanceNotebook() override + { + g_signal_handler_disconnect(m_pNotebook, m_nSignalId); + } +}; + +class GtkInstanceButton : public GtkInstanceContainer, public virtual weld::Button +{ +private: + GtkButton* m_pButton; + gulong m_nSignalId; + + static void signalClicked(GtkButton*, gpointer widget) + { + GtkInstanceButton* pThis = static_cast<GtkInstanceButton*>(widget); + pThis->signal_clicked(); + } +public: + GtkInstanceButton(GtkButton* pButton, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pButton), bTakeOwnership) + , m_pButton(pButton) + , m_nSignalId(g_signal_connect(pButton, "clicked", G_CALLBACK(signalClicked), this)) + { + } + + virtual void set_label(const OUString& rText) override + { + gtk_button_set_label(m_pButton, MapToGtkAccelerator(rText).getStr()); + } + + virtual OUString get_label() const override + { + const gchar* pStr = gtk_button_get_label(m_pButton); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } + + virtual ~GtkInstanceButton() override + { + g_signal_handler_disconnect(m_pButton, m_nSignalId); + } +}; + +class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton +{ +private: + GtkToggleButton* m_pToggleButton; + gulong m_nSignalId; + + static void signalToggled(GtkToggleButton*, gpointer widget) + { + GtkInstanceToggleButton* pThis = static_cast<GtkInstanceToggleButton*>(widget); + pThis->signal_toggled(); + } +public: + GtkInstanceToggleButton(GtkToggleButton* pButton, bool bTakeOwnership) + : GtkInstanceButton(GTK_BUTTON(pButton), bTakeOwnership) + , m_pToggleButton(pButton) + , m_nSignalId(g_signal_connect(m_pToggleButton, "toggled", G_CALLBACK(signalToggled), this)) + { + } + + virtual void set_active(bool active) override + { + gtk_toggle_button_set_active(m_pToggleButton, active); + } + + virtual bool get_active() const override + { + return gtk_toggle_button_get_active(m_pToggleButton); + } + + virtual void set_inconsistent(bool inconsistent) override + { + gtk_toggle_button_set_inconsistent(m_pToggleButton, inconsistent); + } + + virtual bool get_inconsistent() const override + { + return gtk_toggle_button_get_inconsistent(m_pToggleButton); + } + + virtual ~GtkInstanceToggleButton() override + { + g_signal_handler_disconnect(m_pToggleButton, m_nSignalId); + } +}; + +class GtkInstanceRadioButton : public GtkInstanceToggleButton, public virtual weld::RadioButton +{ +public: + GtkInstanceRadioButton(GtkRadioButton* pButton, bool bTakeOwnership) + : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pButton), bTakeOwnership) + { + } +}; + +class GtkInstanceCheckButton : public GtkInstanceToggleButton, public virtual weld::CheckButton +{ +public: + GtkInstanceCheckButton(GtkCheckButton* pButton, bool bTakeOwnership) + : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pButton), bTakeOwnership) + { + } +}; + +class GtkInstanceEntry : public GtkInstanceWidget, public virtual weld::Entry +{ +private: + GtkEntry* m_pEntry; + gulong m_nChangedSignalId; + gulong m_nInsertTextSignalId; + + static void signalChanged(GtkEntry*, gpointer widget) + { + GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget); + pThis->signal_changed(); + } + + static void signalInsertText(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength, + gint* position, gpointer widget) + { + GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget); + pThis->signal_insert_text(pEntry, pNewText, nNewTextLength, position); + } + + void signal_insert_text(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength, gint* position) + { + if (!m_aInsertTextHdl.IsSet()) + return; + OUString sText(pNewText, nNewTextLength, RTL_TEXTENCODING_UTF8); + const bool bContinue = m_aInsertTextHdl.Call(sText); + if (bContinue && !sText.isEmpty()) + { + OString sFinalText(OUStringToOString(sText, RTL_TEXTENCODING_UTF8)); + g_signal_handlers_block_by_func(pEntry, gpointer(signalInsertText), this); + gtk_editable_insert_text(GTK_EDITABLE(pEntry), sFinalText.getStr(), sFinalText.getLength(), position); + g_signal_handlers_unblock_by_func(pEntry, gpointer(signalInsertText), this); + } + g_signal_stop_emission_by_name(pEntry, "insert-text"); + } +public: + GtkInstanceEntry(GtkEntry* pEntry, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pEntry), bTakeOwnership) + , m_pEntry(pEntry) + , m_nChangedSignalId(g_signal_connect(pEntry, "changed", G_CALLBACK(signalChanged), this)) + , m_nInsertTextSignalId(g_signal_connect(pEntry, "insert-text", G_CALLBACK(signalInsertText), this)) + { + } + + virtual void set_text(const OUString& rText) override + { + gtk_entry_set_text(m_pEntry, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual OUString get_text() const override + { + const gchar* pText = gtk_entry_get_text(m_pEntry); + OUString sRet(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + return sRet; + } + + virtual void set_width_chars(int nChars) override + { + gtk_entry_set_width_chars(m_pEntry, nChars); + } + + virtual ~GtkInstanceEntry() override + { + g_signal_handler_disconnect(m_pEntry, m_nInsertTextSignalId); + g_signal_handler_disconnect(m_pEntry, m_nChangedSignalId); + } +}; + +namespace +{ + struct Search + { + OString str; + int index = -1; + Search(const OUString& rText) + : str(OUStringToOString(rText, RTL_TEXTENCODING_UTF8)) + , index(-1) + { + } + }; + + gboolean foreach_find(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data) + { + Search* search = static_cast<Search*>(data); + gchar *pStr = nullptr; + gtk_tree_model_get(model, iter, 0, &pStr, -1); + bool found = strcmp(pStr, search->str.getStr()) == 0; + if (found) + search->index = gtk_tree_path_get_indices(path)[0]; + g_free(pStr); + return found; + } +} + +class GtkInstanceTreeView : public GtkInstanceContainer, public virtual weld::TreeView +{ +private: + GtkTreeView* m_pTreeView; + GtkListStore* m_pListStore; + gulong m_nChangedSignalId; + gulong m_nRowActivatedSignalId; + + static void signalChanged(GtkTreeView*, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->signal_changed(); + } + + static void signalRowActivated(GtkTreeView*, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->signal_row_activated(); + } +public: + GtkInstanceTreeView(GtkTreeView* pTreeView, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pTreeView), bTakeOwnership) + , m_pTreeView(pTreeView) + , m_pListStore(GTK_LIST_STORE(gtk_tree_view_get_model(m_pTreeView))) + , m_nChangedSignalId(g_signal_connect(gtk_tree_view_get_selection(pTreeView), "changed", + G_CALLBACK(signalChanged), this)) + , m_nRowActivatedSignalId(g_signal_connect(pTreeView, "row-activated", G_CALLBACK(signalRowActivated), this)) + { + } + + virtual void append(const OUString& rText) override + { + insert(rText, -1); + } + + virtual void insert(const OUString& rText, int pos) override + { + GtkTreeIter iter; + gtk_list_store_insert(m_pListStore, &iter, pos); + gtk_list_store_set(m_pListStore, &iter, 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(), -1); + } + + virtual void remove(int pos) override + { + GtkTreeIter iter; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos); + gtk_list_store_remove(m_pListStore, &iter); + } + + virtual int find(const OUString& rText) const override + { + Search aSearch(rText); + gtk_tree_model_foreach(GTK_TREE_MODEL(m_pListStore), foreach_find, &aSearch); + return aSearch.index; + } + + void move_before(int pos, int before) + { + if (pos == before) + return; + + GtkTreeIter iter; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos); + + GtkTreeIter position; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &position, nullptr, before); + + gtk_list_store_move_before(m_pListStore, &iter, &position); + } + + virtual void set_top_entry(int pos) override + { + move_before(pos, 0); + } + + virtual void clear() override + { + gtk_list_store_clear(m_pListStore); + } + + virtual int n_children() const override + { + return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pListStore), nullptr); + } + + virtual void select(int pos) override + { + if (pos != -1) + { + GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1); + gtk_tree_selection_select_path(gtk_tree_view_get_selection(m_pTreeView), path); + gtk_tree_path_free(path); + } + else + { + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(m_pTreeView)); + } + } + + virtual OUString get_selected() override + { + OUString sRet; + GtkTreeIter iter; + GtkTreeModel* pModel; + if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), &pModel, &iter)) + { + gchar *pStr = nullptr; + gtk_tree_model_get(pModel, &iter, 0, &pStr, -1); + sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + g_free(pStr); + } + return sRet; + } + + virtual OUString get(int pos) override + { + GtkTreeIter iter; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos); + gchar *pStr = nullptr; + gtk_tree_model_get(GTK_TREE_MODEL(m_pListStore), &iter, 0, &pStr, -1); + OUString sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + g_free(pStr); + return sRet; + } + + virtual int get_selected_index() override + { + int nRet = -1; + GtkTreeIter iter; + GtkTreeModel* pModel; + if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), &pModel, &iter)) + { + GtkTreePath* path = gtk_tree_model_get_path(pModel, &iter); + nRet = gtk_tree_path_get_indices(path)[0]; + gtk_tree_path_free(path); + } + return nRet; + } + + virtual void freeze() override + { + g_object_ref(m_pListStore); + gtk_tree_view_set_model(m_pTreeView, nullptr); + } + + virtual void thaw() override + { + gtk_tree_view_set_model(m_pTreeView, GTK_TREE_MODEL(m_pListStore)); + g_object_unref(m_pListStore); + } + + virtual int get_height_rows(int nRows) const override + { + GtkTreeViewColumn* pColumn = gtk_tree_view_get_column(m_pTreeView, 0); + GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)); + GtkCellRenderer* pRenderer = GTK_CELL_RENDERER(g_list_nth_data(pRenderers, 0)); + gint nRowHeight; + gtk_cell_renderer_get_preferred_height(pRenderer, GTK_WIDGET(m_pTreeView), nullptr, &nRowHeight); + g_list_free(pRenderers); + + gint nVerticalSeparator; + gtk_widget_style_get(GTK_WIDGET(m_pTreeView), "vertical-separator", &nVerticalSeparator, nullptr); + + return (nRowHeight * nRows) + (nVerticalSeparator * (nRows + 1)); + } + + virtual ~GtkInstanceTreeView() override + { + g_signal_handler_disconnect(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId); + g_signal_handler_disconnect(m_pTreeView, m_nRowActivatedSignalId); + } +}; + + +class GtkInstanceSpinButton : public GtkInstanceEntry, public virtual weld::SpinButton +{ +private: + GtkSpinButton* m_pButton; + gulong m_nValueChangedSignalId; + gulong m_nOutputSignalId; + + static void signalValueChanged(GtkSpinButton*, gpointer widget) + { + GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget); + pThis->signal_value_changed(); + } + + static gboolean signalOutput(GtkSpinButton*, gpointer widget) + { + GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget); + return pThis->signal_output(); + } + + double toGtk(int nValue) const + { + return static_cast<double>(nValue) / Power10(get_digits()); + } + + int fromGtk(double fValue) const + { + return FRound(fValue * Power10(get_digits())); + } + +public: + GtkInstanceSpinButton(GtkSpinButton* pButton, bool bTakeOwnership) + : GtkInstanceEntry(GTK_ENTRY(pButton), bTakeOwnership) + , m_pButton(pButton) + , m_nValueChangedSignalId(g_signal_connect(pButton, "value-changed", G_CALLBACK(signalValueChanged), this)) + , m_nOutputSignalId(g_signal_connect(pButton, "output", G_CALLBACK(signalOutput), this)) + { + } + + virtual int get_value() const override + { + return fromGtk(gtk_spin_button_get_value(m_pButton)); + } + + virtual void set_value(int value) override + { + gtk_spin_button_set_value(m_pButton, toGtk(value)); + } + + virtual void set_range(int min, int max) override + { + gtk_spin_button_set_range(m_pButton, toGtk(min), toGtk(max)); + } + + virtual void get_range(int& min, int& max) const override + { + double gtkmin, gtkmax; + gtk_spin_button_get_range(m_pButton, >kmin, >kmax); + min = fromGtk(gtkmin); + max = fromGtk(gtkmax); + } + + virtual void set_increments(int step, int page) override + { + gtk_spin_button_set_increments(m_pButton, toGtk(step), toGtk(page)); + } + + virtual void get_increments(int& step, int& page) const override + { + double gtkstep, gtkpage; + gtk_spin_button_get_increments(m_pButton, >kstep, >kpage); + step = fromGtk(gtkstep); + page = fromGtk(gtkpage); + } + + virtual void set_digits(unsigned int digits) override + { + gtk_spin_button_set_digits(m_pButton, digits); + } + + virtual unsigned int get_digits() const override + { + return gtk_spin_button_get_digits(m_pButton); + } + + virtual ~GtkInstanceSpinButton() override + { + g_signal_handler_disconnect(m_pButton, m_nOutputSignalId); + g_signal_handler_disconnect(m_pButton, m_nValueChangedSignalId); + } +}; + +class GtkInstanceLabel : public GtkInstanceWidget, public virtual weld::Label +{ +private: + GtkLabel* m_pLabel; +public: + GtkInstanceLabel(GtkLabel* pLabel, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pLabel), bTakeOwnership) + , m_pLabel(pLabel) + { + } + + virtual void set_label(const OUString& rText) override + { + gtk_label_set_label(m_pLabel, MapToGtkAccelerator(rText).getStr()); + } +}; + +class GtkInstanceTextView : public GtkInstanceContainer, public virtual weld::TextView +{ +private: + GtkTextView* m_pTextView; +public: + GtkInstanceTextView(GtkTextView* pTextView, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pTextView), bTakeOwnership) + , m_pTextView(pTextView) + { + } + + virtual void set_text(const OUString& rText) override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + OString sText(OUStringToOString(rText, RTL_TEXTENCODING_UTF8)); + gtk_text_buffer_set_text(pBuffer, sText.getStr(), sText.getLength()); + } + + virtual OUString get_text() const override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + GtkTextIter start, end; + gtk_text_buffer_get_bounds(pBuffer, &start, &end); + char* pStr = gtk_text_buffer_get_text(pBuffer, &start, &end, true); + OUString sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + g_free(pStr); + return sRet; + } + + virtual Selection get_selection() const override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + GtkTextIter start, end; + gtk_text_buffer_get_selection_bounds(pBuffer, &start, &end); + return Selection(gtk_text_iter_get_offset(&start), gtk_text_iter_get_offset(&end)); + } + + virtual void set_selection(const Selection& rSelection) override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + GtkTextIter start, end; + gtk_text_buffer_get_iter_at_offset(pBuffer, &start, rSelection.Min()); + gtk_text_buffer_get_iter_at_offset(pBuffer, &end, rSelection.Max()); + gtk_text_buffer_select_range(pBuffer, &start, &end); + GtkTextMark* mark = gtk_text_buffer_create_mark(pBuffer, "scroll", &end, true); + gtk_text_view_scroll_mark_onscreen(m_pTextView, mark); + } + +}; + +class GtkInstanceDrawingArea : public GtkInstanceWidget, public virtual weld::DrawingArea +{ +private: + GtkDrawingArea* m_pDrawingArea; + ScopedVclPtrInstance<VirtualDevice> m_xDevice; + std::vector<unsigned char> m_aBuffer; + cairo_surface_t* m_pSurface; + gulong m_nDrawSignalId; + gulong m_nSizeAllocateSignalId; + static gboolean signalDraw(GtkWidget*, cairo_t* cr, gpointer widget) + { + GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget); + pThis->signal_draw(cr); + return false; + } + static void signalSizeAllocate(GtkWidget*, GdkRectangle* allocation, gpointer widget) + { + GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget); + pThis->signal_size_allocate(allocation->width, allocation->height); + } + void signal_size_allocate(guint nWidth, guint nHeight) + { + if (m_pSurface) + cairo_surface_destroy(m_pSurface); + + const int nScale = gtk_widget_get_scale_factor(GTK_WIDGET(m_pDrawingArea)); + const int nStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nWidth * nScale); + m_aBuffer.resize(nHeight * nScale * nStride); + m_xDevice->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth, nHeight), Fraction(1.0), Point(), + m_aBuffer.data()); + m_pSurface = cairo_image_surface_create_for_data(m_aBuffer.data(), CAIRO_FORMAT_ARGB32, + nWidth * nScale, nHeight * nScale, nStride); +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0) + cairo_surface_set_device_scale(m_pSurface, nScale, nScale); +#endif + m_aSizeAllocateHdl.Call(Size(nWidth, nHeight)); + } + void signal_draw(cairo_t* cr) + { + m_aDrawHdl.Call(*m_xDevice); + cairo_surface_mark_dirty(m_pSurface); + + cairo_set_source_surface(cr, m_pSurface, 0, 0); + cairo_paint(cr); + } +public: + GtkInstanceDrawingArea(GtkDrawingArea* pDrawingArea, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pDrawingArea), bTakeOwnership) + , m_pDrawingArea(pDrawingArea) + , m_xDevice(nullptr, Size(1, 1), DeviceFormat::DEFAULT) + , m_pSurface(nullptr) + , m_nDrawSignalId(g_signal_connect(pDrawingArea, "draw", G_CALLBACK(signalDraw), this)) + , m_nSizeAllocateSignalId(g_signal_connect(pDrawingArea, "size_allocate", G_CALLBACK(signalSizeAllocate), this)) + { + } + + virtual void queue_draw() override + { + gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea)); + } + + virtual ~GtkInstanceDrawingArea() override + { + if (m_pSurface) + cairo_surface_destroy(m_pSurface); + g_signal_handler_disconnect(m_pDrawingArea, m_nSizeAllocateSignalId); + g_signal_handler_disconnect(m_pDrawingArea, m_nDrawSignalId); + } +}; + +namespace +{ + gint sort_func(GtkTreeModel* pModel, GtkTreeIter* a, GtkTreeIter* b, gpointer data) + { + comphelper::string::NaturalStringSorter* pSorter = static_cast<comphelper::string::NaturalStringSorter*>(data); + gchar* pName1; + gchar* pName2; + gtk_tree_model_get(pModel, a, 0, &pName1, -1); + gtk_tree_model_get(pModel, b, 0, &pName2, -1); + gint ret = pSorter->compare(OUString(pName1, strlen(pName1), RTL_TEXTENCODING_UTF8), + OUString(pName2, strlen(pName2), RTL_TEXTENCODING_UTF8)); + g_free(pName1); + g_free(pName2); + return ret; + } +} + +class GtkInstanceComboBoxText : public GtkInstanceContainer, public virtual weld::ComboBoxText +{ +private: + GtkComboBoxText* m_pComboBoxText; + std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter; + gulong m_nSignalId; + + static void signalChanged(GtkComboBox*, gpointer widget) + { + GtkInstanceComboBoxText* pThis = static_cast<GtkInstanceComboBoxText*>(widget); + pThis->signal_changed(); + } + + OUString get(int pos, int col) const + { + OUString sRet; + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + GtkTreeIter iter; + if (gtk_tree_model_iter_nth_child(pModel, &iter, nullptr, pos)) + { + gchar* pStr; + gtk_tree_model_get(pModel, &iter, col, &pStr, -1); + sRet = OUString(pStr, strlen(pStr), RTL_TEXTENCODING_UTF8); + g_free(pStr); + } + return sRet; + } + +public: + GtkInstanceComboBoxText(GtkComboBoxText* pComboBoxText, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pComboBoxText), bTakeOwnership) + , m_pComboBoxText(pComboBoxText) + , m_nSignalId(g_signal_connect(pComboBoxText, "changed", G_CALLBACK(signalChanged), this)) + { + } + + virtual int get_active() const override + { + return gtk_combo_box_get_active(GTK_COMBO_BOX(m_pComboBoxText)); + } + + virtual OUString get_active_id() const override + { + const gchar* pText = gtk_combo_box_get_active_id(GTK_COMBO_BOX(m_pComboBoxText)); + return OUString(pText, strlen(pText), RTL_TEXTENCODING_UTF8); + } + + virtual void set_active_id(const OUString& rStr) override + { + OString aId(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8)); + gtk_combo_box_set_active_id(GTK_COMBO_BOX(m_pComboBoxText), aId.getStr()); + } + + virtual void set_active(int pos) override + { + gtk_combo_box_set_active(GTK_COMBO_BOX(m_pComboBoxText), pos); + } + + virtual OUString get_active_text() const override + { + gchar* pText = gtk_combo_box_text_get_active_text(m_pComboBoxText); + OUString sRet(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + g_free(pText); + return sRet; + } + + virtual OUString get_text(int pos) const override + { + return get(pos, 0); + } + + virtual OUString get_id(int pos) const override + { + gint id_column = gtk_combo_box_get_id_column(GTK_COMBO_BOX(m_pComboBoxText)); + return get(pos, id_column); + } + + virtual void append_text(const OUString& rStr) override + { + gtk_combo_box_text_append_text(m_pComboBoxText, OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual void insert_text(int pos, const OUString& rStr) override + { + gtk_combo_box_text_insert_text(m_pComboBoxText, pos, OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual void append(const OUString& rId, const OUString& rStr) override + { + gtk_combo_box_text_append(m_pComboBoxText, + OUStringToOString(rId, RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual void insert(int pos, const OUString& rId, const OUString& rStr) override + { + gtk_combo_box_text_insert(m_pComboBoxText, pos, + OUStringToOString(rId, RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual int get_count() const override + { + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + return gtk_tree_model_iter_n_children(pModel, nullptr); + } + + virtual int find_text(const OUString& rStr) const override + { + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + GtkTreeIter iter; + if (!gtk_tree_model_get_iter_first(pModel, &iter)) + return -1; + + OString aStr(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + int nRet = 0; + do + { + gchar* pStr; + gtk_tree_model_get(pModel, &iter, 0, &pStr, -1); + const bool bEqual = strcmp(pStr, aStr.getStr()) == 0; + g_free(pStr); + if (bEqual) + return nRet; + ++nRet; + } while (gtk_tree_model_iter_next(pModel, &iter)); + + return -1; + } + + virtual void clear() override + { + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + gtk_list_store_clear(GTK_LIST_STORE(pModel)); + } + + virtual void make_sorted() override + { + m_xSorter.reset(new comphelper::string::NaturalStringSorter( + ::comphelper::getProcessComponentContext(), + Application::GetSettings().GetLanguageTag().getLocale())); + GtkTreeModel* pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(pModel); + gtk_tree_sortable_set_sort_func(pSortable, 0, sort_func, m_xSorter.get(), nullptr); + gtk_tree_sortable_set_sort_column_id(pSortable, 0, GTK_SORT_ASCENDING); + } + + virtual ~GtkInstanceComboBoxText() override + { + g_signal_handler_disconnect(m_pComboBoxText, m_nSignalId); + } +}; + +namespace +{ + gboolean signalTooltipQuery(GtkWidget* pWidget, gint /*x*/, gint /*y*/, + gboolean /*keyboard_mode*/, GtkTooltip *tooltip) + { + const ImplSVData* pSVData = ImplGetSVData(); + if (pSVData->maHelpData.mbBalloonHelp) + { + AtkObject* pAtkObject = gtk_widget_get_accessible(pWidget); + const char* pDesc = pAtkObject ? atk_object_get_description(pAtkObject) : nullptr; + if (pDesc) + { + gtk_tooltip_set_text(tooltip, pDesc); + return true; + } + } + + const char* pDesc = gtk_widget_get_tooltip_text(pWidget); + if (pDesc) + { + gtk_tooltip_set_text(tooltip, pDesc); + return true; + } + + return false; + } + + void postprocess(gpointer data, gpointer user_data) + { + GObject* pObject = static_cast<GObject*>(data); + if (!GTK_IS_WIDGET(pObject)) + return; + OString* pHelpRoot = static_cast<OString*>(user_data); + //fixup icons + //wanted: better way to do this, e.g. make gtk use gio for + //loading from a filename and provide gio protocol handler + //for our image in a zip urls + // + //unpack the images and keep them as dirs and just + //add the paths to the gtk icon theme dir + if (GTK_IS_IMAGE(pObject)) + { + GtkImage* pImage = GTK_IMAGE(pObject); + const gchar* icon_name; + gtk_image_get_icon_name(pImage, &icon_name, nullptr); + GtkIconSize size; + g_object_get(pImage, "icon-size", &size, nullptr); + if (icon_name) + { + OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8); + + SvMemoryStream aMemStm; + BitmapEx aBitmap(aIconName); + vcl::PNGWriter aWriter(aBitmap); + aWriter.Write(aMemStm); + + GdkPixbufLoader *pixbuf_loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(pixbuf_loader, static_cast<const guchar*>(aMemStm.GetData()), + aMemStm.Seek(STREAM_SEEK_TO_END), nullptr); + gdk_pixbuf_loader_close(pixbuf_loader, nullptr); + GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(pixbuf_loader); + + gtk_image_set_from_pixbuf(pImage, pixbuf); + g_object_unref(pixbuf_loader); + } + } + //set helpids + GtkWidget* pWidget = GTK_WIDGET(pObject); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget)); + size_t nLen = pStr ? strlen(pStr) : 0; + if (!nLen) + return; + OString sHelpId = *pHelpRoot + OString(pStr, nLen); + gchar *helpid = g_strdup(sHelpId.getStr()); + g_object_set_data_full(pObject, "helpid", helpid, g_free); + //hook up for extended help + const ImplSVData* pSVData = ImplGetSVData(); + if (pSVData->maHelpData.mbBalloonHelp) + { + AtkObject* pAtkObject = gtk_widget_get_accessible(pWidget); + if (pAtkObject && atk_object_get_description(pAtkObject)) + { + gtk_widget_set_has_tooltip(pWidget, true); + g_signal_connect(pObject, "query-tooltip", G_CALLBACK(signalTooltipQuery), nullptr); + } + } + } + + void destroy_toplevels(gpointer data, gpointer /*user_data*/) + { + GObject* pObject = static_cast<GObject*>(data); + if (!GTK_IS_WINDOW(pObject)) + return; + gtk_widget_destroy(GTK_WIDGET(pObject)); + } +} + +class GtkInstanceBuilder : public weld::Builder +{ +private: + OUString m_sHelpRoot; + GtkBuilder* m_pBuilder; + GSList* m_pObjectList; + GtkWidget* m_pParentWidget; +public: + GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile) + : weld::Builder(rUIFile) + , m_sHelpRoot(rUIFile) + , m_pParentWidget(pParent) + { + OUString aUri(rUIRoot + rUIFile); + OUString aPath; + osl::FileBase::getSystemPathFromFileURL(aUri, aPath); + m_pBuilder = gtk_builder_new_from_file(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8).getStr()); + + sal_Int32 nIdx = m_sHelpRoot.lastIndexOf('.'); + if (nIdx != -1) + m_sHelpRoot = m_sHelpRoot.copy(0, nIdx); + m_sHelpRoot = m_sHelpRoot + OUString('/'); + + m_pObjectList = gtk_builder_get_objects(m_pBuilder); + OString aUtf8HelpRoot(OUStringToOString(m_sHelpRoot, RTL_TEXTENCODING_UTF8)); + g_slist_foreach(m_pObjectList, postprocess, &aUtf8HelpRoot); + } + + virtual ~GtkInstanceBuilder() override + { + g_slist_foreach(m_pObjectList, destroy_toplevels, nullptr); + g_slist_free(m_pObjectList); + g_object_unref(m_pBuilder); + } + + //ideally we would have/use weld::Container add and explicitly + //call add when we want to do this, but in the vcl impl the + //parent has to be set when the child is created, so for the + //gtk impl emulate this by doing this implicitly at weld time + void auto_add_parentless_widgets_to_container(GtkWidget* pWidget) + { + if (gtk_widget_get_toplevel(pWidget) == pWidget) + gtk_container_add(GTK_CONTAINER(m_pParentWidget), pWidget); + } + + virtual weld::MessageDialog* weld_message_dialog(const OString &id, bool bTakeOwnership) override + { + GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pMessageDialog) + return nullptr; + gtk_window_set_transient_for(GTK_WINDOW(pMessageDialog), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))); + return new GtkInstanceMessageDialog(pMessageDialog, bTakeOwnership); + } + + virtual weld::Dialog* weld_dialog(const OString &id, bool bTakeOwnership) override + { + GtkDialog* pDialog = GTK_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pDialog) + return nullptr; + gtk_window_set_transient_for(GTK_WINDOW(pDialog), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))); + return new GtkInstanceDialog(pDialog, bTakeOwnership); + } + + virtual weld::Window* weld_window(const OString &id, bool bTakeOwnership) override + { + GtkWindow* pWindow = GTK_WINDOW(gtk_builder_get_object(m_pBuilder, id.getStr())); + return pWindow ? new GtkInstanceWindow(pWindow, bTakeOwnership) : nullptr; + } + + virtual weld::Widget* weld_widget(const OString &id, bool bTakeOwnership) override + { + GtkWidget* pWidget = GTK_WIDGET(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pWidget) + return nullptr; + auto_add_parentless_widgets_to_container(pWidget); + return new GtkInstanceWidget(pWidget, bTakeOwnership); + } + + virtual weld::Container* weld_container(const OString &id, bool bTakeOwnership) override + { + GtkContainer* pContainer = GTK_CONTAINER(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pContainer) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pContainer)); + return new GtkInstanceContainer(pContainer, bTakeOwnership); + } + + virtual weld::Frame* weld_frame(const OString &id, bool bTakeOwnership) override + { + GtkFrame* pFrame = GTK_FRAME(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pFrame) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pFrame)); + return new GtkInstanceFrame(pFrame, bTakeOwnership); + } + + virtual weld::Notebook* weld_notebook(const OString &id, bool bTakeOwnership) override + { + GtkNotebook* pNotebook = GTK_NOTEBOOK(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pNotebook) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pNotebook)); + return new GtkInstanceNotebook(pNotebook, bTakeOwnership); + } + + virtual weld::Button* weld_button(const OString &id, bool bTakeOwnership) override + { + GtkButton* pButton = GTK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pButton)); + return new GtkInstanceButton(pButton, bTakeOwnership); + } + + virtual weld::RadioButton* weld_radio_button(const OString &id, bool bTakeOwnership) override + { + GtkRadioButton* pRadioButton = GTK_RADIO_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pRadioButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pRadioButton)); + return new GtkInstanceRadioButton(pRadioButton, bTakeOwnership); + } + + virtual weld::CheckButton* weld_check_button(const OString &id, bool bTakeOwnership) override + { + GtkCheckButton* pCheckButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pCheckButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pCheckButton)); + return new GtkInstanceCheckButton(pCheckButton, bTakeOwnership); + } + + virtual weld::Entry* weld_entry(const OString &id, bool bTakeOwnership) override + { + GtkEntry* pEntry = GTK_ENTRY(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pEntry) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pEntry)); + return new GtkInstanceEntry(pEntry, bTakeOwnership); + } + + virtual weld::SpinButton* weld_spin_button(const OString &id, bool bTakeOwnership) override + { + GtkSpinButton* pSpinButton = GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pSpinButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pSpinButton)); + return new GtkInstanceSpinButton(pSpinButton, bTakeOwnership); + } + + virtual weld::ComboBoxText* weld_combo_box_text(const OString &id, bool bTakeOwnership) override + { + GtkComboBoxText* pComboBoxText = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pComboBoxText) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pComboBoxText)); + return new GtkInstanceComboBoxText(pComboBoxText, bTakeOwnership); + } + + virtual weld::TreeView* weld_tree_view(const OString &id, bool bTakeOwnership) override + { + GtkTreeView* pTreeView = GTK_TREE_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pTreeView) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pTreeView)); + return new GtkInstanceTreeView(pTreeView, bTakeOwnership); + } + + virtual weld::Label* weld_label(const OString &id, bool bTakeOwnership) override + { + GtkLabel* pLabel = GTK_LABEL(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pLabel) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pLabel)); + return new GtkInstanceLabel(pLabel, bTakeOwnership); + } + + virtual weld::TextView* weld_text_view(const OString &id, bool bTakeOwnership) override + { + GtkTextView* pTextView = GTK_TEXT_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pTextView) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pTextView)); + return new GtkInstanceTextView(pTextView, bTakeOwnership); + } + + virtual weld::DrawingArea* weld_drawing_area(const OString &id, bool bTakeOwnership) override + { + GtkDrawingArea* pDrawingArea = GTK_DRAWING_AREA(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pDrawingArea) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pDrawingArea)); + return new GtkInstanceDrawingArea(pDrawingArea, bTakeOwnership); + } +}; + +void GtkInstanceWindow::help() +{ + //show help for widget with keyboard focus + GtkWidget* pWidget = gtk_window_get_focus(m_pWindow); + if (!pWidget) + pWidget = GTK_WIDGET(m_pWindow); + OString sHelpId = ::get_help_id(pWidget); + while (sHelpId.isEmpty()) + { + pWidget = gtk_widget_get_parent(pWidget); + if (!pWidget) + break; + sHelpId = ::get_help_id(pWidget); + } + std::unique_ptr<weld::Widget> xTemp(pWidget != m_pWidget ? new GtkInstanceWidget(pWidget, false) : nullptr); + weld::Widget* pSource = xTemp ? xTemp.get() : this; + bool bRunNormalHelpRequest = true; + if (m_aHelpRequestHdl.IsSet()) + bRunNormalHelpRequest = m_aHelpRequestHdl.Call(*pSource); + Help* pHelp = bRunNormalHelpRequest ? Application::GetHelp() : nullptr; + if (pHelp) + pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), pSource); +} + +weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile) +{ + GtkInstanceWidget* pParentWidget = dynamic_cast<GtkInstanceWidget*>(pParent); + GtkWidget* pBuilderParent = pParentWidget ? pParentWidget->getWidget() : nullptr; + return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile); +} + +GtkMessageType VclToGtk(VclMessageType eType) +{ + GtkMessageType eRet(GTK_MESSAGE_INFO); + switch (eType) + { + case VclMessageType::Info: + eRet = GTK_MESSAGE_INFO; + break; + case VclMessageType::Warning: + eRet = GTK_MESSAGE_WARNING; + break; + case VclMessageType::Question: + eRet = GTK_MESSAGE_QUESTION; + break; + case VclMessageType::Error: + eRet = GTK_MESSAGE_ERROR; + break; + } + return eRet; +} + +GtkButtonsType VclToGtk(VclButtonsType eType) +{ + GtkButtonsType eRet(GTK_BUTTONS_NONE); + switch (eType) + { + case VclButtonsType::NONE: + eRet = GTK_BUTTONS_NONE; + break; + case VclButtonsType::Ok: + eRet = GTK_BUTTONS_OK; + break; + case VclButtonsType::Close: + eRet = GTK_BUTTONS_CLOSE; + break; + case VclButtonsType::Cancel: + eRet = GTK_BUTTONS_CANCEL; + break; + case VclButtonsType::YesNo: + eRet = GTK_BUTTONS_YES_NO; + break; + case VclButtonsType::OkCancel: + eRet = GTK_BUTTONS_OK_CANCEL; + break; + } + return eRet; +} + +weld::MessageDialog* GtkInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString &rPrimaryMessage) +{ + GtkInstanceWidget* pParentInstance = dynamic_cast<GtkInstanceWidget*>(pParent); + GtkWindow* pParentWindow = pParentInstance ? pParentInstance->getWindow() : nullptr; + GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL, + VclToGtk(eMessageType), VclToGtk(eButtonsType), "%s", + OUStringToOString(rPrimaryMessage, RTL_TEXTENCODING_UTF8).getStr())); + return new GtkInstanceMessageDialog(pMessageDialog, true); +} + +weld::Window* GtkSalFrame::GetFrameWeld() const +{ + if (!m_xFrameWeld) + m_xFrameWeld.reset(new GtkInstanceWindow(GTK_WINDOW(getWindow()), false)); + return m_xFrameWeld.get(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |