diff options
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/salframe.hxx | 6 | ||||
-rw-r--r-- | vcl/inc/salinst.hxx | 11 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkframe.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkinst.hxx | 2 | ||||
-rw-r--r-- | vcl/source/app/help.cxx | 5 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 1085 | ||||
-rw-r--r-- | vcl/source/control/combobox.cxx | 2 | ||||
-rw-r--r-- | vcl/source/control/field.cxx | 14 | ||||
-rw-r--r-- | vcl/source/control/listbox.cxx | 5 | ||||
-rw-r--r-- | vcl/source/window/builder.cxx | 116 | ||||
-rw-r--r-- | vcl/source/window/menuwindow.cxx | 4 | ||||
-rw-r--r-- | vcl/source/window/window2.cxx | 6 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkframe.cxx | 2 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 1572 |
14 files changed, 2819 insertions, 12 deletions
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: */ |