include/svtools/ctrlbox.hxx                        |   11 +
 include/vcl/combobox.hxx                           |    3 
 include/vcl/weld.hxx                               |   14 +
 svtools/source/control/ctrlbox.cxx                 |   11 +
 svx/UIConfig_svx.mk                                |    1 
 svx/source/inc/InterimItemWindow.hxx               |   35 ++++
 svx/source/sidebar/paragraph/ParaSpacingWindow.cxx |   46 ++++-
 svx/source/sidebar/paragraph/ParaSpacingWindow.hxx |   20 --
 svx/source/tbxctrls/tbunocontroller.cxx            |  182 +++++++++++----------
 svx/uiconfig/ui/fontsizebox.ui                     |   29 +++
 vcl/source/app/salvtables.cxx                      |   26 +++
 vcl/source/control/combobox.cxx                    |   15 +
 vcl/source/window/toolbox.cxx                      |    2 
 vcl/unx/gtk3/gtk3gtkinst.cxx                       |   76 ++++++++
 14 files changed, 359 insertions(+), 112 deletions(-)

New commits:
commit 8950cb8ae6a1621729ec43a6dd1c29cf04260797
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Tue Feb 4 11:34:29 2020 +0000
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Thu Feb 6 12:26:37 2020 +0100

    weld SvxFontSizeBox_Impl
    
    which enables making a native gtk widget a member of a toolbar
    
    This widget wants to distinguish between a value getting selected
    by the menu or not, which is fairly tricky
    
    Change-Id: I9014785530bd0d82ffa66842f940feb2d3237e68
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87971
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/include/svtools/ctrlbox.hxx b/include/svtools/ctrlbox.hxx
index 8036d513ad05..30551c592dc2 100644
--- a/include/svtools/ctrlbox.hxx
+++ b/include/svtools/ctrlbox.hxx
@@ -428,6 +428,7 @@ class SVT_DLLPUBLIC SvtFontSizeBox
                     bPtRelative:1,
                     bStdSize:1;
     Link<weld::ComboBox&, void> m_aChangeHdl;
+    Link<weld::Widget&, void> m_aFocusOutHdl;
     std::unique_ptr<weld::ComboBox> m_xComboBox;
 
     sal_uInt16 GetDecimalDigits() const { return nDecimalDigits; }
@@ -461,14 +462,24 @@ public:
     bool IsPtRelative() const { return bPtRelative; }
 
     void connect_changed(const Link<weld::ComboBox&, void>& rLink) { 
m_aChangeHdl = rLink; }
+    void connect_focus_out(const Link<weld::Widget&, void>& rLink) { 
m_aFocusOutHdl = rLink; }
+    void connect_key_press(const Link<const KeyEvent&, bool>& rLink) { 
m_xComboBox->connect_key_press(rLink); }
     OUString get_active_text() const { return m_xComboBox->get_active_text(); }
     void set_active_text(const OUString& rText) { 
m_xComboBox->set_active_text(rText); }
     void set_sensitive(bool bSensitive) { 
m_xComboBox->set_sensitive(bSensitive); }
+    int get_active() const { return m_xComboBox->get_active(); }
     int get_value() const;
     void set_value(int nValue);
     void save_value() { nSavedValue = get_value(); }
     int get_saved_value() const { return nSavedValue; }
     bool get_value_changed_from_saved() const { return get_value() != 
get_saved_value(); }
+    int get_count() const { return m_xComboBox->get_count(); }
+    OUString get_text(int i) const { return m_xComboBox->get_text(i); }
+    void grab_focus() { m_xComboBox->grab_focus(); }
+    bool has_focus() const { return m_xComboBox->has_focus(); }
+    void connect_entry_activate(const Link<weld::ComboBox&, bool>& rLink) { 
m_xComboBox->connect_entry_activate(rLink); }
+    void disable_entry_completion() { m_xComboBox->set_entry_completion(false, 
false); }
+    boost::property_tree::ptree get_property_tree() const;
 
 private:
     SvtFontSizeBox(const SvtFontSizeBox&) = delete;
diff --git a/include/vcl/combobox.hxx b/include/vcl/combobox.hxx
index ff34c96411b4..f2f96dca1b37 100644
--- a/include/vcl/combobox.hxx
+++ b/include/vcl/combobox.hxx
@@ -152,6 +152,9 @@ public:
     void            SetNoSelection();
     tools::Rectangle       GetBoundingRectangle( sal_Int32  nItem ) const;
 
+    // determine if Select was called due to something selected from the menu
+    bool            IsModifyByMenu() const;
+
     /** checks whether a certain point lies within the bounds of
         a list item and returns the item as well as the character position
         the point is at.
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 742290822c32..464047bdf843 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -27,6 +27,8 @@
 #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
 #include <com/sun/star/accessibility/XAccessible.hpp>
 
+#include <boost/property_tree/ptree_fwd.hpp>
+
 #include <assert.h>
 #include <memory>
 #include <vector>
@@ -263,6 +265,8 @@ public:
 
     virtual css::uno::Reference<css::datatransfer::dnd::XDropTarget> 
get_drop_target() = 0;
 
+    virtual boost::property_tree::ptree get_property_tree() const = 0;
+
     virtual ~Widget() {}
 };
 
@@ -643,7 +647,17 @@ public:
     virtual int find_id(const OUString& rId) const = 0;
     void remove_id(const OUString& rId) { remove(find_id(rId)); }
 
+    /* m_aChangeHdl is called when the active item is changed. The can be due
+       to the user selecting a different item from the list or while typing
+       into the entry of a combo box with an entry.
+
+       Use changed_by_menu() to discover whether an item was actually selected
+       from the menu.
+     */
     void connect_changed(const Link<ComboBox&, void>& rLink) { m_aChangeHdl = 
rLink; }
+
+    virtual bool changed_by_menu() const = 0;
+
     virtual void connect_popup_toggled(const Link<ComboBox&, void>& rLink)
     {
         m_aPopupToggledHdl = rLink;
diff --git a/svtools/source/control/ctrlbox.cxx 
b/svtools/source/control/ctrlbox.cxx
index b47b3ba74e2e..6ecbfd596bc5 100644
--- a/svtools/source/control/ctrlbox.cxx
+++ b/svtools/source/control/ctrlbox.cxx
@@ -52,6 +52,8 @@
 
 #include <rtl/bootstrap.hxx>
 
+#include <boost/property_tree/ptree.hpp>
+
 #include <borderline.hrc>
 
 #include <stdio.h>
@@ -1025,7 +1027,12 @@ 
SvtFontSizeBox::SvtFontSizeBox(std::unique_ptr<weld::ComboBox> p)
     m_xComboBox->connect_changed(LINK(this, SvtFontSizeBox, ModifyHdl));
 }
 
-IMPL_LINK_NOARG(SvtFontSizeBox, ReformatHdl, weld::Widget&, void)
+boost::property_tree::ptree SvtFontSizeBox::get_property_tree() const
+{
+    return m_xComboBox->get_property_tree();
+}
+
+IMPL_LINK(SvtFontSizeBox, ReformatHdl, weld::Widget&, rWidget, void)
 {
     FontSizeNames 
aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
     if (!bRelativeMode || !aFontSizeNames.IsEmpty())
@@ -1035,6 +1042,8 @@ IMPL_LINK_NOARG(SvtFontSizeBox, ReformatHdl, 
weld::Widget&, void)
     }
 
     set_value(get_value());
+
+    m_aFocusOutHdl.Call(rWidget);
 }
 
 IMPL_LINK(SvtFontSizeBox, ModifyHdl, weld::ComboBox&, rBox, void)
diff --git a/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk
index e8a02daec4b6..15f4bb7f7326 100644
--- a/svx/UIConfig_svx.mk
+++ b/svx/UIConfig_svx.mk
@@ -59,6 +59,7 @@ $(eval $(call gb_UIConfig_add_uifiles,svx,\
        svx/uiconfig/ui/fontworkcharacterspacingcontrol \
        svx/uiconfig/ui/fontworkgallerydialog \
        svx/uiconfig/ui/fontworkspacingdialog \
+       svx/uiconfig/ui/fontsizebox \
        svx/uiconfig/ui/formdatamenu \
        svx/uiconfig/ui/formfielddialog \
        svx/uiconfig/ui/formlinkwarndialog \
diff --git a/svx/source/inc/InterimItemWindow.hxx 
b/svx/source/inc/InterimItemWindow.hxx
new file mode 100644
index 000000000000..715cf41fc020
--- /dev/null
+++ b/svx/source/inc/InterimItemWindow.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#include <vcl/layout.hxx>
+
+class InterimItemWindow : public Control
+{
+public:
+    virtual ~InterimItemWindow() override;
+    virtual void dispose() override;
+
+    virtual void Resize() override;
+    virtual Size GetOptimalSize() const override;
+
+protected:
+    InterimItemWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, 
const OString& rID);
+
+    // pass keystrokes from our child window through this to handle focus 
changes correctly
+    // returns true if keystroke is consumed
+    bool ChildKeyInput(const KeyEvent& rKEvt);
+
+    std::unique_ptr<weld::Builder> m_xBuilder;
+    VclPtr<vcl::Window> m_xVclContentArea;
+    std::unique_ptr<weld::Container> m_xContainer;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx 
b/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx
index f098f29cb6e7..8af67e22ab55 100644
--- a/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx
+++ b/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx
@@ -70,6 +70,42 @@ Size InterimItemWindow::GetOptimalSize() const
     return 
VclContainer::getLayoutRequisition(*GetWindow(GetWindowType::FirstChild));
 }
 
+bool InterimItemWindow::ChildKeyInput(const KeyEvent& rKEvt)
+{
+    sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+    if (nCode != KEY_TAB)
+        return false;
+
+    /* if the native widget has focus, then no vcl window has focus.
+
+       We want to grab focus to this vcl widget so that pressing tab will 
travese
+       to the next vcl widget.
+
+       But just using GrabFocus will, because no vcl widget has focus, trigger
+       bringing the toplevel to front with the expectation that a suitable 
widget
+       will be picked for focus when that happen, which is no use to us here.
+
+       SetFakeFocus avoids the problem, allowing GrabFocus to do the expected 
thing
+       then sending the Tab to our parent will do the right traversal
+    */
+    SetFakeFocus(true);
+    GrabFocus();
+
+    /* let toolbox know we have focus so it updates its mnHighItemId to point
+       to this toolitem in case tab means to move to another toolitem within
+       the toolbox
+    */
+    NotifyEvent aNEvt(MouseNotifyEvent::GETFOCUS, this);
+    vcl::Window* pToolBox = GetParent();
+    pToolBox->EventNotify(aNEvt);
+
+    /* now give focus to our toolbox parent and send it the tab */
+    pToolBox->GrabFocus();
+    pToolBox->KeyInput(rKEvt);
+
+    return true;
+}
+
 // ParaULSpacingWindow
 
 ParaULSpacingWindow::ParaULSpacingWindow(vcl::Window* pParent)
@@ -149,7 +185,7 @@ ParaAboveSpacingWindow::ParaAboveSpacingWindow(vcl::Window* 
pParent)
     m_xAboveContainer->show();
     m_xBelowContainer->hide();
 
-    SetSizePixel(GetOptimalSize());
+    SetSizePixel(get_preferred_size());
 }
 
 void ParaAboveSpacingWindow::GetFocus()
@@ -165,7 +201,7 @@ ParaBelowSpacingWindow::ParaBelowSpacingWindow(vcl::Window* 
pParent)
     m_xAboveContainer->hide();
     m_xBelowContainer->show();
 
-    SetSizePixel(GetOptimalSize());
+    SetSizePixel(get_preferred_size());
 }
 
 void ParaBelowSpacingWindow::GetFocus()
@@ -350,7 +386,7 @@ ParaLeftSpacingWindow::ParaLeftSpacingWindow(vcl::Window* 
pParent)
     m_xAfterContainer->hide();
     m_xFirstLineContainer->hide();
 
-    SetSizePixel(GetOptimalSize());
+    SetSizePixel(get_preferred_size());
 }
 
 void ParaLeftSpacingWindow::GetFocus()
@@ -367,7 +403,7 @@ ParaRightSpacingWindow::ParaRightSpacingWindow(vcl::Window* 
pParent)
     m_xAfterContainer->show();
     m_xFirstLineContainer->hide();
 
-    SetSizePixel(GetOptimalSize());
+    SetSizePixel(get_preferred_size());
 }
 
 void ParaRightSpacingWindow::GetFocus()
@@ -384,7 +420,7 @@ 
ParaFirstLineSpacingWindow::ParaFirstLineSpacingWindow(vcl::Window* pParent)
     m_xAfterContainer->hide();
     m_xFirstLineContainer->show();
 
-    SetSizePixel(GetOptimalSize());
+    SetSizePixel(get_preferred_size());
 }
 
 void ParaFirstLineSpacingWindow::GetFocus()
diff --git a/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx 
b/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx
index d25030c3d9f6..af103d5d1f8a 100644
--- a/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx
+++ b/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx
@@ -20,30 +20,12 @@
 #define INCLUDED_SVX_SOURCE_SIDEBAR_PARAGRAPH_PARASPACINGWINDOW_HXX
 
 #include <editeng/ulspitem.hxx>
-#include <vcl/builder.hxx>
-#include <vcl/layout.hxx>
 #include <vcl/EnumContext.hxx>
 #include <svx/relfld.hxx>
+#include <InterimItemWindow.hxx>
 
 using namespace com::sun::star;
 
-class InterimItemWindow : public Control
-{
-public:
-    virtual ~InterimItemWindow() override;
-    virtual void dispose() override;
-
-    virtual void Resize() override;
-    virtual Size GetOptimalSize() const override;
-
-protected:
-    InterimItemWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, 
const OString& rID);
-
-    std::unique_ptr<weld::Builder> m_xBuilder;
-    VclPtr<vcl::Window> m_xVclContentArea;
-    std::unique_ptr<weld::Container> m_xContainer;
-};
-
 namespace svx {
 
 class ParaULSpacingWindow : public InterimItemWindow
diff --git a/svx/source/tbxctrls/tbunocontroller.cxx 
b/svx/source/tbxctrls/tbunocontroller.cxx
index 313810b6a329..980c4dd30385 100644
--- a/svx/source/tbxctrls/tbunocontroller.cxx
+++ b/svx/source/tbxctrls/tbunocontroller.cxx
@@ -41,6 +41,7 @@
 
 #include <sfx2/sidebar/SidebarToolBox.hxx>
 #include <boost/property_tree/ptree.hpp>
+#include <InterimItemWindow.hxx>
 
 using namespace ::com::sun::star;
 
@@ -85,32 +86,40 @@ class FontHeightToolBoxControl : public 
svt::ToolboxController,
         css::awt::FontDescriptor m_aCurrentFont;
 };
 
-class SvxFontSizeBox_Impl : public FontSizeBox
+class SvxFontSizeBox_Impl : public InterimItemWindow
 {
 public:
                         SvxFontSizeBox_Impl( vcl::Window* pParent,
                                              const uno::Reference< 
frame::XFrame >& _xFrame,
                                              FontHeightToolBoxControl& rCtrl );
 
+    virtual void        dispose() override;
+    virtual             ~SvxFontSizeBox_Impl() override;
     void                statusChanged_Impl( long nHeight, bool bErase );
     void                UpdateFont( const css::awt::FontDescriptor& 
rCurrentFont );
     void                SetOptimalSize();
 
-    virtual bool        EventNotify( NotifyEvent& rNEvt ) override;
     virtual boost::property_tree::ptree DumpAsPropertyTree() override;
 
 protected:
-    virtual void        Select() override;
     virtual void        DataChanged( const DataChangedEvent& rDCEvt ) override;
+    virtual void        GetFocus() override;
 
 private:
-    FontHeightToolBoxControl*                  m_pCtrl;
+    FontHeightToolBoxControl&                  m_rCtrl;
     OUString                                   m_aCurText;
-    Size const                                 m_aLogicalSize;
     bool                                       m_bRelease;
     uno::Reference< frame::XFrame >            m_xFrame;
+    std::unique_ptr<SvtFontSizeBox>            m_xWidget;
 
     void                ReleaseFocus_Impl();
+
+    void                Select();
+
+    DECL_LINK(SelectHdl, weld::ComboBox&, void);
+    DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+    DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+    DECL_LINK(FocusOutHdl, weld::Widget&, void);
 };
 
 SvxFontSizeBox_Impl::SvxFontSizeBox_Impl(
@@ -118,16 +127,38 @@ SvxFontSizeBox_Impl::SvxFontSizeBox_Impl(
     const uno::Reference< frame::XFrame >&            _xFrame,
     FontHeightToolBoxControl&                         _rCtrl ) :
 
-    FontSizeBox( _pParent, WinBits( WB_DROPDOWN ) ),
+    InterimItemWindow(_pParent, "svx/ui/fontsizebox.ui", "FontSizeBox"),
 
-    m_pCtrl             ( &_rCtrl ),
-    m_aLogicalSize      ( 0,100 ),
+    m_rCtrl             ( _rCtrl ),
     m_bRelease          ( true ),
-    m_xFrame            ( _xFrame )
+    m_xFrame            ( _xFrame ),
+    m_xWidget(new SvtFontSizeBox(m_xBuilder->weld_combo_box("fontsize")))
 {
-    SetValue( 0 );
-    SetText( "" );
     set_id("fontsizecombobox");
+    m_xWidget->set_value(0);
+    m_xWidget->set_active_text("");
+    m_xWidget->disable_entry_completion();
+
+    m_xWidget->connect_changed(LINK(this, SvxFontSizeBox_Impl, SelectHdl));
+    m_xWidget->connect_key_press(LINK(this, SvxFontSizeBox_Impl, KeyInputHdl));
+    m_xWidget->connect_entry_activate(LINK(this, SvxFontSizeBox_Impl, 
ActivateHdl));
+    m_xWidget->connect_focus_out(LINK(this, SvxFontSizeBox_Impl, FocusOutHdl));
+}
+
+void SvxFontSizeBox_Impl::dispose()
+{
+    m_xWidget.reset();
+    InterimItemWindow::dispose();
+}
+
+SvxFontSizeBox_Impl::~SvxFontSizeBox_Impl()
+{
+    disposeOnce();
+}
+
+void SvxFontSizeBox_Impl::GetFocus()
+{
+    m_xWidget->grab_focus();
 }
 
 void SvxFontSizeBox_Impl::ReleaseFocus_Impl()
@@ -142,30 +173,35 @@ void SvxFontSizeBox_Impl::ReleaseFocus_Impl()
         m_xFrame->getContainerWindow()->setFocus();
 }
 
+IMPL_LINK(SvxFontSizeBox_Impl, SelectHdl, weld::ComboBox&, rCombo, void)
+{
+    if (rCombo.changed_by_menu()) // only when picked from the list
+        Select();
+}
 
-void SvxFontSizeBox_Impl::Select()
+IMPL_LINK_NOARG(SvxFontSizeBox_Impl, ActivateHdl, weld::ComboBox&, bool)
 {
-    FontSizeBox::Select();
+    Select();
+    return true;
+}
 
-    if ( !IsTravelSelect() )
-    {
-        sal_Int64 nSelVal = GetValue();
-        float fSelVal     = float( nSelVal ) / 10;
+void SvxFontSizeBox_Impl::Select()
+{
+    sal_Int64 nSelVal = m_xWidget->get_value();
+    float fSelVal     = float( nSelVal ) / 10;
 
-        uno::Sequence< beans::PropertyValue > aArgs( 1 );
-        aArgs[0].Name  = "FontHeight.Height";
-        aArgs[0].Value <<= fSelVal;
+    uno::Sequence< beans::PropertyValue > aArgs( 1 );
+    aArgs[0].Name  = "FontHeight.Height";
+    aArgs[0].Value <<= fSelVal;
 
-        /*  #i33380# DR 2004-09-03 Moved the following line above the 
Dispatch() call.
-            This instance may be deleted in the meantime (i.e. when a dialog 
is opened
-            while in Dispatch()), accessing members will crash in this case. */
-        ReleaseFocus_Impl();
+    /*  #i33380# DR 2004-09-03 Moved the following line above the Dispatch() 
call.
+        This instance may be deleted in the meantime (i.e. when a dialog is 
opened
+        while in Dispatch()), accessing members will crash in this case. */
+    ReleaseFocus_Impl();
 
-        m_pCtrl->dispatchCommand( aArgs );
-    }
+    m_rCtrl.dispatchCommand( aArgs );
 }
 
-
 void SvxFontSizeBox_Impl::statusChanged_Impl( long nPoint, bool bErase )
 {
     if ( !bErase )
@@ -174,23 +210,22 @@ void SvxFontSizeBox_Impl::statusChanged_Impl( long 
nPoint, bool bErase )
         long nVal = nPoint;
 
         // changed => set new value
-        if ( GetValue() != nVal )
-            SetValue( nVal );
+        if (m_xWidget->get_value() != nVal)
+            m_xWidget->set_value(nVal);
     }
     else
     {
         // delete value in the display
-        SetValue( -1L );
-        SetText( "" );
+        m_xWidget->set_value(-1L);
+        m_xWidget->set_active_text("");
     }
-    SaveValue();
+    m_xWidget->save_value();
 }
 
-
 void SvxFontSizeBox_Impl::UpdateFont( const css::awt::FontDescriptor& 
rCurrentFont )
 {
     // filling up the sizes list
-    sal_Int64 nOldVal = GetValue(); // memorize old value
+    auto nOldVal = m_xWidget->get_value(); // memorize old value
     const FontList* _pFontList = nullptr;
     std::unique_ptr<FontList> aHold( new FontList( this ));
     _pFontList = aHold.get();
@@ -201,61 +236,49 @@ void SvxFontSizeBox_Impl::UpdateFont( const 
css::awt::FontDescriptor& rCurrentFo
         _aFontMetric.SetFamilyName( rCurrentFont.Name );
         _aFontMetric.SetStyleName( rCurrentFont.StyleName );
         _aFontMetric.SetFontHeight( rCurrentFont.Height );
-        Fill( &_aFontMetric, _pFontList );
+        m_xWidget->Fill(&_aFontMetric, _pFontList);
     }
     else
     {
-        Fill( nullptr, _pFontList );
+        m_xWidget->Fill(nullptr, _pFontList);
     }
-    SetValue( nOldVal ); // restore old value
-    m_aCurText = GetText(); // memorize to reset at ESC
+    m_xWidget->set_value(nOldVal); // restore old value
+    m_aCurText = m_xWidget->get_active_text(); // memorize to reset at ESC
 }
 
-
-bool SvxFontSizeBox_Impl::EventNotify( NotifyEvent& rNEvt )
+IMPL_LINK(SvxFontSizeBox_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
 {
     bool bHandled = false;
 
-    if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
-    {
-        sal_uInt16 nCode = rNEvt.GetKeyEvent()->GetKeyCode().GetCode();
+    sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
 
-        switch ( nCode )
-        {
-            case KEY_RETURN:
-            case KEY_TAB:
-            {
-                if ( KEY_TAB == nCode )
-                    m_bRelease = false;
-                else
-                    bHandled = true;
-                Select();
-                break;
-            }
-
-            case KEY_ESCAPE:
-                SetText( m_aCurText );
-                if ( typeid( *GetParent() ) != typeid( 
sfx2::sidebar::SidebarToolBox ) )
-                    ReleaseFocus_Impl();
-                bHandled = true;
-                break;
-        }
-    }
-    else if( MouseNotifyEvent::LOSEFOCUS == rNEvt.GetType() )
+    switch (nCode)
     {
-        vcl::Window* pFocusWin = Application::GetFocusWindow();
-        if(!HasFocus() && GetSubEdit() != pFocusWin)
-            SetText(GetSavedValue());
+        case KEY_TAB:
+            m_bRelease = false;
+            Select();
+            break;
+
+        case KEY_ESCAPE:
+            m_xWidget->set_active_text(m_aCurText);
+            if ( typeid( *GetParent() ) != typeid( 
sfx2::sidebar::SidebarToolBox ) )
+                ReleaseFocus_Impl();
+            bHandled = true;
+            break;
     }
 
-    return bHandled || FontSizeBox::EventNotify( rNEvt );
+    return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(SvxFontSizeBox_Impl, FocusOutHdl, weld::Widget&, void)
+{
+    if (!m_xWidget->has_focus()) // a combobox can be comprised of different 
subwidget so double-check if none of those has focus
+        m_xWidget->set_value(m_xWidget->get_saved_value());
 }
 
 void SvxFontSizeBox_Impl::SetOptimalSize()
 {
-    Size aPrefSize(LogicToPixel(m_aLogicalSize, MapMode(MapUnit::MapAppFont)));
-    aPrefSize.setWidth( get_preferred_size().Width() );
-    SetSizePixel(aPrefSize);
+    SetSizePixel(get_preferred_size());
 }
 
 void SvxFontSizeBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
@@ -265,20 +288,18 @@ void SvxFontSizeBox_Impl::DataChanged( const 
DataChangedEvent& rDCEvt )
     {
         SetOptimalSize();
     }
-
-    FontSizeBox::DataChanged( rDCEvt );
 }
 
 boost::property_tree::ptree SvxFontSizeBox_Impl::DumpAsPropertyTree()
 {
-    boost::property_tree::ptree aTree(FontSizeBox::DumpAsPropertyTree());
+    boost::property_tree::ptree aTree(m_xWidget->get_property_tree());
 
     boost::property_tree::ptree aEntries;
 
-    for (int i = 0; i < GetEntryCount(); ++i)
+    for (int i = 0, nCount = m_xWidget->get_count(); i < nCount; ++i)
     {
         boost::property_tree::ptree aEntry;
-        aEntry.put("", GetEntry(i));
+        aEntry.put("", m_xWidget->get_text(i));
         aEntries.push_back(std::make_pair("", aEntry));
     }
 
@@ -286,14 +307,15 @@ boost::property_tree::ptree 
SvxFontSizeBox_Impl::DumpAsPropertyTree()
 
     boost::property_tree::ptree aSelected;
 
-    for (int i = 0; i < GetSelectedEntryCount(); ++i)
+    int nActive = m_xWidget->get_active();
+    if (nActive != -1)
     {
         boost::property_tree::ptree aEntry;
-        aEntry.put("", GetSelectedEntryPos(i));
+        aEntry.put("", nActive);
         aSelected.push_back(std::make_pair("", aEntry));
     }
 
-    aTree.put("selectedCount", GetSelectedEntryCount());
+    aTree.put("selectedCount", nActive == -1 ? 0 : 1);
     aTree.add_child("selectedEntries", aSelected);
 
     aTree.put("command", ".uno:FontHeight");
diff --git a/svx/uiconfig/ui/fontsizebox.ui b/svx/uiconfig/ui/fontsizebox.ui
new file mode 100644
index 000000000000..c1702822b3e2
--- /dev/null
+++ b/svx/uiconfig/ui/fontsizebox.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+  <requires lib="gtk+" version="3.18"/>
+  <object class="GtkBox" id="FontSizeBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="hexpand">True</property>
+    <property name="spacing">6</property>
+    <child>
+      <object class="GtkComboBoxText" id="fontsize">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="has_entry">True</property>
+        <child internal-child="entry">
+          <object class="GtkEntry">
+            <property name="can_focus">True</property>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index fb68ee0c605d..f1bc5c341d47 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -73,6 +73,8 @@
 #include <bitmaps.hlst>
 #include <wizdlg.hxx>
 
+#include <boost/property_tree/ptree.hpp>
+
 SalFrame::SalFrame()
     : m_pWindow(nullptr)
     , m_pProc(nullptr)
@@ -722,6 +724,11 @@ public:
         return m_xWidget->GetDropTarget();
     }
 
+    virtual boost::property_tree::ptree get_property_tree() const override
+    {
+        return m_xWidget->DumpAsPropertyTree();
+    }
+
     virtual void set_stack_background() override
     {
         
set_background(m_xWidget->GetSettings().GetStyleSettings().GetWindowColor());
@@ -6153,6 +6160,11 @@ public:
         return false;
     }
 
+    virtual bool changed_by_menu() const override
+    {
+        return true;
+    }
+
     virtual void set_entry_message_type(weld::EntryMessageType /*eType*/) 
override
     {
         assert(false);
@@ -6225,6 +6237,11 @@ public:
         return true;
     }
 
+    virtual bool changed_by_menu() const override
+    {
+        return m_xComboBox->IsModifyByMenu(); // && 
!m_xComboBox->IsTravelSelect();
+    }
+
     virtual void set_entry_message_type(weld::EntryMessageType eType) override
     {
         if (eType == weld::EntryMessageType::Error)
@@ -6328,6 +6345,7 @@ private:
     DECL_LINK(KeyPressListener, VclWindowEvent&, void);
     SalInstanceEntry* m_pEntry;
     SalInstanceTreeView* m_pTreeView;
+    bool m_bTreeChange;
 public:
     SalInstanceEntryTreeView(vcl::Window *pContainer, SalInstanceBuilder* 
pBuilder, bool bTakeOwnership,
                              std::unique_ptr<weld::Entry> xEntry, 
std::unique_ptr<weld::TreeView> xTreeView)
@@ -6335,6 +6353,7 @@ public:
         , SalInstanceContainer(pContainer, pBuilder, bTakeOwnership)
         , m_pEntry(dynamic_cast<SalInstanceEntry*>(m_xEntry.get()))
         , m_pTreeView(dynamic_cast<SalInstanceTreeView*>(m_xTreeView.get()))
+        , m_bTreeChange(false)
     {
         assert(m_pEntry && m_pTreeView);
 
@@ -6373,6 +6392,11 @@ public:
         m_xEntry->connect_focus_out(rLink);
     }
 
+    virtual bool changed_by_menu() const override
+    {
+        return m_bTreeChange;
+    }
+
     virtual ~SalInstanceEntryTreeView() override
     {
         Edit& rEntry = m_pEntry->getEntry();
@@ -6398,7 +6422,9 @@ IMPL_LINK(SalInstanceEntryTreeView, KeyPressListener, 
VclWindowEvent&, rEvent, v
         m_xEntry->set_text(m_xTreeView->get_selected_text());
         m_xEntry->select_region(0, -1);
         m_pTreeView->enable_notify_events();
+        m_bTreeChange = true;
         m_pEntry->fire_signal_changed();
+        m_bTreeChange = false;
     }
 }
 
diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx
index 3fac924ea4d6..c42ef08e8e38 100644
--- a/vcl/source/control/combobox.cxx
+++ b/vcl/source/control/combobox.cxx
@@ -57,6 +57,7 @@ struct ComboBox::Impl
     sal_Unicode         m_cMultiSep;
     bool                m_isDDAutoSize        : 1;
     bool                m_isSyntheticModify   : 1;
+    bool                m_isMenuModify        : 1;
     bool                m_isMatchCase         : 1;
     sal_Int32           m_nMaxWidthChars;
     sal_Int32           m_nWidthInChars;
@@ -69,6 +70,7 @@ struct ComboBox::Impl
         , m_cMultiSep(0)
         , m_isDDAutoSize(false)
         , m_isSyntheticModify(false)
+        , m_isMenuModify(false)
         , m_isMatchCase(false)
         , m_nMaxWidthChars(0)
         , m_nWidthInChars(-1)
@@ -142,6 +144,7 @@ void ComboBox::Impl::ImplInitComboBoxData()
     m_nDDHeight         = 0;
     m_isDDAutoSize      = true;
     m_isSyntheticModify = false;
+    m_isMenuModify      = false;
     m_isMatchCase       = false;
     m_cMultiSep         = ';';
     m_nMaxWidthChars    = -1;
@@ -422,9 +425,8 @@ IMPL_LINK_NOARG(ComboBox::Impl, ImplSelectHdl, 
LinkParamNone*, void)
     }
 
     // #84652# Call GrabFocus and EndPopupMode before calling Select/Modify, 
but after changing the text
-
-    if (bPopup && !m_pImplLB->IsTravelSelect() &&
-        (!m_rThis.IsMultiSelectionEnabled() || 
!m_pImplLB->GetSelectModifier()))
+    bool bMenuSelect = bPopup && !m_pImplLB->IsTravelSelect() && 
(!m_rThis.IsMultiSelectionEnabled() || !m_pImplLB->GetSelectModifier());
+    if (bMenuSelect)
     {
         m_pFloatWin->EndPopupMode();
         m_rThis.GrabFocus();
@@ -434,12 +436,19 @@ IMPL_LINK_NOARG(ComboBox::Impl, ImplSelectHdl, 
LinkParamNone*, void)
     {
         m_pSubEdit->SetModifyFlag();
         m_isSyntheticModify = true;
+        m_isMenuModify = bMenuSelect;
         m_rThis.Modify();
+        m_isMenuModify = false;
         m_isSyntheticModify = false;
         m_rThis.Select();
     }
 }
 
+bool ComboBox::IsModifyByMenu() const
+{
+    return m_pImpl->m_isMenuModify;
+}
+
 IMPL_LINK_NOARG( ComboBox::Impl, ImplListItemSelectHdl, LinkParamNone*, void )
 {
     m_rThis.CallEventListeners( VclEventId::DropdownSelect );
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 4eb3e5b4d430..41978048ee36 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -82,6 +82,8 @@
 #include <window.h>
 #include <numeric>
 
+#include <boost/property_tree/ptree.hpp>
+
 using namespace com::sun::star;
 using namespace com::sun::star::uno;
 using namespace com::sun::star::lang;
@@ -2862,6 +2864,12 @@ public:
         return m_xDropTarget.get();
     }
 
+    virtual boost::property_tree::ptree get_property_tree() const override
+    {
+        //not implemented for the gtk variant
+        return boost::property_tree::ptree();
+    }
+
     virtual void set_stack_background() override
     {
         OUString sColor = 
Application::GetSettings().GetStyleSettings().GetWindowColor().AsRGBHexString();
@@ -11749,6 +11757,7 @@ private:
     bool m_bPopupActive;
     bool m_bAutoComplete;
     bool m_bAutoCompleteCaseSensitive;
+    bool m_bChangedByMenu;
     gulong m_nToggleFocusInSignalId;
     gulong m_nToggleFocusOutSignalId;
     gulong m_nChangedSignalId;
@@ -11758,6 +11767,8 @@ private:
     gulong m_nEntryActivateSignalId;
     gulong m_nEntryFocusInSignalId;
     gulong m_nEntryFocusOutSignalId;
+    gulong m_nOriginalMenuActivateEventId;
+    gulong m_nMenuActivateSignalId;
     guint m_nAutoCompleteIdleId;
 
     static gboolean idleAutoComplete(gpointer widget)
@@ -11855,7 +11866,13 @@ private:
     {
         GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
         SolarMutexGuard aGuard;
-        pThis->signal_changed();
+        pThis->fire_signal_changed();
+    }
+
+    void fire_signal_changed()
+    {
+        signal_changed();
+        m_bChangedByMenu = false;
     }
 
     static void signalPopupToggled(GtkComboBox*, GParamSpec*, gpointer widget)
@@ -12012,6 +12029,27 @@ private:
         return pThis->signal_key_press(pEvent);
     }
 
+    static void signalMenuActivate(GtkWidget* pWidget, const gchar *path, 
gpointer widget)
+    {
+        GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
+        return pThis->signal_menu_activate(pWidget, path);
+    }
+
+    void signal_menu_activate(GtkWidget* pWidget, const gchar *path)
+    {
+        // we disabled the original menu-active to get our own handler in first
+        // so we know before changed is called that it will be called by the
+        // menu, now block our handler and unblock the original and replay the
+        // event to call the original handler
+        m_bChangedByMenu = true;
+        g_signal_handler_block(m_pMenu, m_nMenuActivateSignalId);
+        g_signal_handler_unblock(m_pMenu, m_nOriginalMenuActivateEventId);
+        guint nMenuActivateSignalId = g_signal_lookup("menu-activate", 
G_TYPE_FROM_INSTANCE(m_pMenu));
+        g_signal_emit(pWidget, nMenuActivateSignalId, 0, path);
+        g_signal_handler_block(m_pMenu, m_nOriginalMenuActivateEventId);
+        g_signal_handler_unblock(m_pMenu, m_nMenuActivateSignalId);
+    }
+
     bool signal_key_press(const GdkEventKey* pEvent)
     {
         KeyEvent aKEvt(GtkToVcl(*pEvent));
@@ -12134,12 +12172,21 @@ private:
             return;
         m_pMenu = GTK_MENU(pWidget);
 
-        guint nSignalId = g_signal_lookup("key-press-event", GTK_TYPE_MENU);
+        guint nKeyPressSignalId = g_signal_lookup("key-press-event", 
GTK_TYPE_MENU);
         gulong nOriginalMenuKeyPressEventId = g_signal_handler_find(m_pMenu,
                                                                     
static_cast<GSignalMatchType>(G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_ID),
-                                                                    nSignalId, 
0,
+                                                                    
nKeyPressSignalId, 0,
                                                                     nullptr, 
nullptr, m_pComboBox);
 
+        guint nMenuActivateSignalId = g_signal_lookup("menu-activate", 
G_TYPE_FROM_INSTANCE(m_pMenu));
+        m_nOriginalMenuActivateEventId = g_signal_handler_find(m_pMenu,
+                                                               
static_cast<GSignalMatchType>(G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_ID),
+                                                               
nMenuActivateSignalId, 0,
+                                                               nullptr, 
nullptr, m_pComboBox);
+
+        g_signal_handler_block(m_pMenu, m_nOriginalMenuActivateEventId);
+        m_nMenuActivateSignalId = g_signal_connect(m_pMenu, "menu-activate", 
G_CALLBACK(signalMenuActivate), this);
+
         g_signal_handler_block(m_pMenu, nOriginalMenuKeyPressEventId);
         g_signal_connect(m_pMenu, "key-press-event", 
G_CALLBACK(signalKeyPress), this);
     }
@@ -12166,10 +12213,13 @@ public:
         , m_bPopupActive(false)
         , m_bAutoComplete(false)
         , m_bAutoCompleteCaseSensitive(false)
+        , m_bChangedByMenu(false)
         , m_nToggleFocusInSignalId(0)
         , m_nToggleFocusOutSignalId(0)
         , m_nChangedSignalId(g_signal_connect(m_pComboBox, "changed", 
G_CALLBACK(signalChanged), this))
         , m_nPopupShownSignalId(g_signal_connect(m_pComboBox, 
"notify::popup-shown", G_CALLBACK(signalPopupToggled), this))
+        , m_nOriginalMenuActivateEventId(0)
+        , m_nMenuActivateSignalId(0)
         , m_nAutoCompleteIdleId(0)
     {
         GList* cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(m_pComboBox));
@@ -12232,6 +12282,7 @@ public:
         disable_notify_events();
         OString aId(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8));
         gtk_combo_box_set_active_id(m_pComboBox, aId.getStr());
+        m_bChangedByMenu = false;
         enable_notify_events();
     }
 
@@ -12278,6 +12329,7 @@ public:
     {
         disable_notify_events();
         gtk_combo_box_set_active(m_pComboBox, pos);
+        m_bChangedByMenu = false;
         enable_notify_events();
     }
 
@@ -12591,8 +12643,17 @@ public:
         return gtk_widget_has_focus(m_pToggleButton) || 
GtkInstanceWidget::has_focus();
     }
 
+    virtual bool changed_by_menu() const override
+    {
+        return m_bChangedByMenu;
+    }
+
     virtual ~GtkInstanceComboBox() override
     {
+        if (m_nOriginalMenuActivateEventId)
+            g_signal_handler_unblock(m_pMenu, m_nOriginalMenuActivateEventId);
+        if (m_nMenuActivateSignalId)
+            g_signal_handler_disconnect(m_pMenu, m_nMenuActivateSignalId);
         if (m_nAutoCompleteIdleId)
             g_source_remove(m_nAutoCompleteIdleId);
         if (GtkEntry* pEntry = get_entry())
@@ -12622,6 +12683,7 @@ private:
     gulong m_nEntryInsertTextSignalId;
     guint m_nAutoCompleteIdleId;
     bool m_bAutoCompleteCaseSensitive;
+    bool m_bTreeChange;
 
     bool signal_key_press(GdkEventKey* pEvent)
     {
@@ -12646,7 +12708,9 @@ private:
             }
             m_xEntry->select_region(0, -1);
             enable_notify_events();
+            m_bTreeChange = true;
             m_pEntry->fire_signal_changed();
+            m_bTreeChange = false;
             return true;
         }
         return false;
@@ -12747,6 +12811,7 @@ public:
         , m_pTreeView(dynamic_cast<GtkInstanceTreeView*>(m_xTreeView.get()))
         , m_nAutoCompleteIdleId(0)
         , m_bAutoCompleteCaseSensitive(false)
+        , m_bTreeChange(false)
     {
         assert(m_pEntry);
         GtkWidget* pWidget = m_pEntry->getWidget();
@@ -12803,6 +12868,11 @@ public:
         GtkInstanceContainer::disable_notify_events();
     }
 
+    virtual bool changed_by_menu() const override
+    {
+        return m_bTreeChange;
+    }
+
     virtual ~GtkInstanceEntryTreeView() override
     {
         if (m_nAutoCompleteIdleId)
commit 415c1b05242b80ca883596952caa0e179a07b409
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Wed Feb 5 16:00:06 2020 +0000
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Thu Feb 6 12:26:26 2020 +0100

    return true to show pressing tab was consumed
    
    to move focus to another toolitem
    
    Change-Id: I12f8602dd9a963c1e84e46bad780cc3c7dbe427d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88045
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Tested-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx
index c11d7285d5b9..6763ca2d09e0 100644
--- a/vcl/source/window/toolbox.cxx
+++ b/vcl/source/window/toolbox.cxx
@@ -3710,7 +3710,7 @@ bool ToolBox::EventNotify( NotifyEvent& rNEvt )
                 if( bNoTabCycling )
                     return DockingWindow::EventNotify( rNEvt );
                 else if( ImplChangeHighlightUpDn( aKeyCode.IsShift() , 
bNoTabCycling ) )
-                    return false;
+                    return true;
                 else
                     return DockingWindow::EventNotify( rNEvt );
             }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to