weld TabBarEdit

Change-Id: I513c81faa9b93fbcb7eb93ac60152dcc97b41481
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101585
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/solenv/sanitizers/ui/svt.suppr b/solenv/sanitizers/ui/svt.suppr
index 521c142..2ee5632 100644
--- a/solenv/sanitizers/ui/svt.suppr
+++ b/solenv/sanitizers/ui/svt.suppr
@@ -25,5 +25,6 @@ svtools/uiconfig/ui/restartdialog.ui://GtkLabel[@id='reason_extension_install'] 
svtools/uiconfig/ui/restartdialog.ui://GtkLabel[@id='reason_skia'] orphan-label
svtools/uiconfig/ui/restartdialog.ui://GtkLabel[@id='label'] orphan-label
svtools/uiconfig/ui/spinfieldcontrol.ui://GtkSpinButton[@id='spinbutton'] no-labelled-by
svtools/uiconfig/ui/tabbaredit.ui://GtkEntry[@id='entry'] no-labelled-by
svtools/uiconfig/ui/thineditcontrol.ui://GtkEntry[@id='entry'] no-labelled-by
svtools/uiconfig/ui/thineditcontrol.ui://GtkSpinButton[@id='spinbutton'] no-labelled-by
diff --git a/svtools/UIConfig_svt.mk b/svtools/UIConfig_svt.mk
index d11f9ff..4414ba3 100644
--- a/svtools/UIConfig_svt.mk
+++ b/svtools/UIConfig_svt.mk
@@ -30,6 +30,7 @@ $(eval $(call gb_UIConfig_add_uifiles,svt,\
	svtools/uiconfig/ui/querydeletedialog \
	svtools/uiconfig/ui/restartdialog \
	svtools/uiconfig/ui/spinfieldcontrol \
	svtools/uiconfig/ui/tabbaredit \
	svtools/uiconfig/ui/textviewcontrol \
	svtools/uiconfig/ui/thineditcontrol \
))
diff --git a/svtools/source/control/tabbar.cxx b/svtools/source/control/tabbar.cxx
index be068ee..a6ea801 100644
--- a/svtools/source/control/tabbar.cxx
+++ b/svtools/source/control/tabbar.cxx
@@ -21,11 +21,11 @@
#include <svtools/tabbar.hxx>
#include <tools/time.hxx>
#include <tools/poly.hxx>
#include <vcl/InterimItemWindow.hxx>
#include <vcl/svapp.hxx>
#include <vcl/help.hxx>
#include <vcl/decoview.hxx>
#include <vcl/button.hxx>
#include <vcl/edit.hxx>
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/commandevent.hxx>
@@ -370,78 +370,86 @@ void ImplTabSizer::Paint( vcl::RenderContext& rRenderContext, const tools::Recta
namespace {

// Is not named Impl. as it may be both instantiated and derived from
class TabBarEdit : public Edit
class TabBarEdit final : public InterimItemWindow
{
private:
    std::unique_ptr<weld::Entry> m_xEntry;
    Idle            maLoseFocusIdle;
    bool            mbPostEvt;

                    DECL_LINK( ImplEndEditHdl, void*, void );
                    DECL_LINK( ImplEndTimerHdl, Timer*, void );
    DECL_LINK( ImplEndEditHdl, void*, void );
    DECL_LINK( ImplEndTimerHdl, Timer*, void );
    DECL_LINK( ActivatedHdl, weld::Entry&, bool );
    DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
    DECL_LINK( FocusOutHdl, weld::Widget&, void );

public:
                    TabBarEdit( TabBar* pParent, WinBits nWinStyle );
    TabBarEdit(TabBar* pParent);
    virtual void dispose() override;

    TabBar*         GetParent() const { return static_cast<TabBar*>(Window::GetParent()); }

    weld::Entry&    get_widget() { return *m_xEntry; }

    void            SetPostEvent() { mbPostEvt = true; }
    void            ResetPostEvent() { mbPostEvt = false; }

    virtual bool    PreNotify( NotifyEvent& rNEvt ) override;
    virtual void    LoseFocus() override;
};

}

TabBarEdit::TabBarEdit( TabBar* pParent, WinBits nWinStyle ) :
    Edit( pParent, nWinStyle )
TabBarEdit::TabBarEdit(TabBar* pParent)
    : InterimItemWindow(pParent, "svt/ui/tabbaredit.ui", "TabBarEdit")
    , m_xEntry(m_xBuilder->weld_entry("entry"))
{
    InitControlBase(m_xEntry.get());

    mbPostEvt = false;
    maLoseFocusIdle.SetPriority( TaskPriority::REPAINT );
    maLoseFocusIdle.SetInvokeHandler( LINK( this, TabBarEdit, ImplEndTimerHdl ) );
    maLoseFocusIdle.SetDebugName( "svtools::TabBarEdit maLoseFocusIdle" );

    m_xEntry->connect_activate(LINK(this, TabBarEdit, ActivatedHdl));
    m_xEntry->connect_key_press(LINK(this, TabBarEdit, KeyInputHdl));
    m_xEntry->connect_focus_out(LINK(this, TabBarEdit, FocusOutHdl));
}

bool TabBarEdit::PreNotify( NotifyEvent& rNEvt )
void TabBarEdit::dispose()
{
    if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
    {
        const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
        if ( !pKEvt->GetKeyCode().GetModifier() )
        {
            if ( pKEvt->GetKeyCode().GetCode() == KEY_RETURN )
            {
                if ( !mbPostEvt )
                {
                    if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
                        mbPostEvt = true;
                }
                return true;
            }
            else if ( pKEvt->GetKeyCode().GetCode() == KEY_ESCAPE )
            {
                if ( !mbPostEvt )
                {
                    if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(true), true ) )
                        mbPostEvt = true;
                }
                return true;
            }
        }
    }

    return Edit::PreNotify( rNEvt );
    m_xEntry.reset();
    InterimItemWindow::dispose();
}

void TabBarEdit::LoseFocus()
IMPL_LINK_NOARG(TabBarEdit, ActivatedHdl, weld::Entry&, bool)
{
    if ( !mbPostEvt )
    {
        if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
            mbPostEvt = true;
    }
    return true;
}

    Edit::LoseFocus();
IMPL_LINK(TabBarEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{
    if (!rKEvt.GetKeyCode().GetModifier() && rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
    {
        if ( !mbPostEvt )
        {
            if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(true), true ) )
                mbPostEvt = true;
        }
        return true;
    }
    return false;
}

IMPL_LINK_NOARG(TabBarEdit, FocusOutHdl, weld::Widget&, void)
{
    if ( !mbPostEvt )
    {
        if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
            mbPostEvt = true;
    }
}

IMPL_LINK( TabBarEdit, ImplEndEditHdl, void*, pCancel, void )
@@ -449,27 +457,18 @@ IMPL_LINK( TabBarEdit, ImplEndEditHdl, void*, pCancel, void )
    ResetPostEvent();
    maLoseFocusIdle.Stop();

    // We need this query, because the edit gets a losefocus event,
    // when it shows the context menu or the insert symbol dialog
    if ( !HasFocus() && HasChildPathFocus( true ) )
    {
    // do it idle in case we quickly regain focus
    if (!m_xEntry->has_focus())
        maLoseFocusIdle.Start();
    }
    else
        GetParent()->EndEditMode( pCancel != nullptr );
}

IMPL_LINK_NOARG(TabBarEdit, ImplEndTimerHdl, Timer *, void)
{
    if ( HasFocus() )
    if (m_xEntry->has_focus())
        return;

    // We need this query, because the edit gets a losefocus event,
    // when it shows the context menu or the insert symbol dialog
    if ( HasChildPathFocus( true ) )
        maLoseFocusIdle.Start();
    else
        GetParent()->EndEditMode( true );
    GetParent()->EndEditMode( true );
}

struct TabBar_Impl
@@ -480,7 +479,7 @@ struct TabBar_Impl
    ScopedVclPtr<ImplTabButton> mpNextButton;
    ScopedVclPtr<ImplTabButton> mpLastButton;
    ScopedVclPtr<ImplTabButton> mpAddButton;
    ScopedVclPtr<TabBarEdit>    mpEdit;
    ScopedVclPtr<TabBarEdit>    mxEdit;
    std::vector<std::unique_ptr<ImplTabBarItem>> mpItemList;

    vcl::AccessibleFactoryAccess  maAccessibleFactory;
@@ -1447,8 +1446,11 @@ void TabBar::StateChanged(StateChangedType nType)
            mpImpl->mpSizer->EnableRTL(IsRTLEnabled());
        if (mpImpl->mpAddButton)
            mpImpl->mpAddButton->EnableRTL(IsRTLEnabled());
        if (mpImpl->mpEdit)
            mpImpl->mpEdit->EnableRTL(IsRTLEnabled());
        if (mpImpl->mxEdit)
        {
            weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
            rEntry.set_direction(IsRTLEnabled());
        }
    }
}

@@ -2037,7 +2039,7 @@ void TabBar::SetProtectionSymbol(sal_uInt16 nPageId, bool bProtection)
bool TabBar::StartEditMode(sal_uInt16 nPageId)
{
    sal_uInt16 nPos = GetPagePos( nPageId );
    if (mpImpl->mpEdit || (nPos == PAGE_NOT_FOUND) || (mnLastOffX < 8))
    if (mpImpl->mxEdit || (nPos == PAGE_NOT_FOUND) || (mnLastOffX < 8))
        return false;

    mnEditId = nPageId;
@@ -2047,7 +2049,7 @@ bool TabBar::StartEditMode(sal_uInt16 nPageId)
        ImplFormat();
        PaintImmediately();

        mpImpl->mpEdit.disposeAndReset(VclPtr<TabBarEdit>::Create(this, WB_CENTER));
        mpImpl->mxEdit.disposeAndReset(VclPtr<TabBarEdit>::Create(this));
        tools::Rectangle aRect = GetPageRect( mnEditId );
        long nX = aRect.Left();
        long nWidth = aRect.GetWidth();
@@ -2060,8 +2062,9 @@ bool TabBar::StartEditMode(sal_uInt16 nPageId)
            nX = aRect.Left();
            nWidth = aRect.GetWidth();
        }
        mpImpl->mpEdit->SetText(GetPageText(mnEditId));
        mpImpl->mpEdit->setPosSizePixel(nX, aRect.Top() + mnOffY + 1, nWidth, aRect.GetHeight() - 3);
        weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
        rEntry.set_text(GetPageText(mnEditId));
        mpImpl->mxEdit->SetPosSizePixel(Point(nX, aRect.Top() + mnOffY + 1), Size(nWidth, aRect.GetHeight() - 3));
        vcl::Font aFont = GetPointFont(*this); // FIXME RenderContext

        Color   aForegroundColor;
@@ -2091,12 +2094,12 @@ bool TabBar::StartEditMode(sal_uInt16 nPageId)
        {
            aForegroundColor = COL_LIGHTBLUE;
        }
        mpImpl->mpEdit->SetControlFont(aFont);
        mpImpl->mpEdit->SetControlForeground(aForegroundColor);
        mpImpl->mpEdit->SetControlBackground(aBackgroundColor);
        mpImpl->mpEdit->GrabFocus();
        mpImpl->mpEdit->SetSelection(Selection(0, mpImpl->mpEdit->GetText().getLength()));
        mpImpl->mpEdit->Show();
        rEntry.set_font(aFont);
        rEntry.set_font_color(aForegroundColor);
        mpImpl->mxEdit->SetControlBackground(aBackgroundColor);
        rEntry.grab_focus();
        rEntry.select_region(0, -1);
        mpImpl->mxEdit->Show();
        return true;
    }
    else
@@ -2108,19 +2111,20 @@ bool TabBar::StartEditMode(sal_uInt16 nPageId)

bool TabBar::IsInEditMode() const
{
    return bool(mpImpl->mpEdit);
    return bool(mpImpl->mxEdit);
}

void TabBar::EndEditMode(bool bCancel)
{
    if (!mpImpl->mpEdit)
    if (!mpImpl->mxEdit)
        return;

    // call hdl
    bool bEnd = true;
    mbEditCanceled = bCancel;
    maEditText = mpImpl->mpEdit->GetText();
    mpImpl->mpEdit->SetPostEvent();
    weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
    maEditText = rEntry.get_text();
    mpImpl->mxEdit->SetPostEvent();
    if (!bCancel)
    {
        TabBarAllowRenamingReturnCode nAllowRenaming = AllowRenaming();
@@ -2135,13 +2139,13 @@ void TabBar::EndEditMode(bool bCancel)
    // renaming not allowed, then reset edit data
    if (!bEnd)
    {
        mpImpl->mpEdit->ResetPostEvent();
        mpImpl->mpEdit->GrabFocus();
        mpImpl->mxEdit->ResetPostEvent();
        rEntry.grab_focus();
    }
    else
    {
        // close edit and call end hdl
        mpImpl->mpEdit.disposeAndClear();
        mpImpl->mxEdit.disposeAndClear();

        EndRenaming();
        mnEditId = 0;
diff --git a/svtools/uiconfig/ui/tabbaredit.ui b/svtools/uiconfig/ui/tabbaredit.ui
new file mode 100644
index 0000000..da2ee97
--- /dev/null
+++ b/svtools/uiconfig/ui/tabbaredit.ui
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 -->
<interface domain="svt">
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkBox" id="TabBarEdit">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="valign">center</property>
    <property name="hexpand">True</property>
    <property name="vexpand">True</property>
    <property name="spacing">6</property>
    <child>
      <object class="GtkEntry" id="entry">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="hexpand">True</property>
        <property name="vexpand">True</property>
        <property name="has_frame">False</property>
        <property name="activates_default">True</property>
        <property name="width_chars">1</property>
        <property name="xalign">0.5</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">0</property>
      </packing>
    </child>
  </object>
</interface>