weld InputEdit Item Window

Change-Id: I33e4fb378897289b7b54c80b9cb3d7e868381f96
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88822
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/solenv/sanitizers/ui/modules/swriter.suppr b/solenv/sanitizers/ui/modules/swriter.suppr
index 25757e0..24fe10d 100644
--- a/solenv/sanitizers/ui/modules/swriter.suppr
+++ b/solenv/sanitizers/ui/modules/swriter.suppr
@@ -94,6 +94,7 @@ sw/uiconfig/swriter/ui/indexentry.ui://GtkButton[@id='previous'] button-no-label
sw/uiconfig/swriter/ui/indexentry.ui://GtkButton[@id='next'] button-no-label
sw/uiconfig/swriter/ui/indexentry.ui://GtkButton[@id='first'] button-no-label
sw/uiconfig/swriter/ui/indexentry.ui://GtkButton[@id='last'] button-no-label
sw/uiconfig/swriter/ui/inputeditbox.ui://GtkEntry[@id='entry'] no-labelled-by
sw/uiconfig/swriter/ui/insertbookmark.ui://GtkLabel[@id='lbForbiddenChars'] orphan-label
sw/uiconfig/swriter/ui/insertbreak.ui://GtkSpinButton[@id='pagenumsb'] missing-label-for
sw/uiconfig/swriter/ui/insertcaption.ui://GtkEntry[@id='caption_edit'] no-labelled-by
diff --git a/sw/UIConfig_swriter.mk b/sw/UIConfig_swriter.mk
index 1139afe..14d8eba 100644
--- a/sw/UIConfig_swriter.mk
+++ b/sw/UIConfig_swriter.mk
@@ -166,6 +166,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
	sw/uiconfig/swriter/ui/indentpage \
	sw/uiconfig/swriter/ui/infonotfounddialog \
	sw/uiconfig/swriter/ui/inforeadonlydialog \
	sw/uiconfig/swriter/ui/inputeditbox \
	sw/uiconfig/swriter/ui/insertautotextdialog \
	sw/uiconfig/swriter/ui/insertbookmark \
	sw/uiconfig/swriter/ui/insertbreak \
diff --git a/sw/inc/pch/precompiled_msword.hxx b/sw/inc/pch/precompiled_msword.hxx
index 0eff008..92377e6 100644
--- a/sw/inc/pch/precompiled_msword.hxx
+++ b/sw/inc/pch/precompiled_msword.hxx
@@ -13,7 +13,7 @@
 manual changes will be rewritten by the next run of update_pch.sh (which presumably
 also fixes all possible problems, so it's usually better to use it).

 Generated on 2020-02-14 09:24:02 using:
 Generated on 2020-02-17 14:43:22 using:
 ./bin/update_pch sw msword --cutoff=4 --exclude:system --include:module --include:local

 If after updating build fails, use the following command to locate conflicting headers:
@@ -544,6 +544,7 @@
#include <ndarr.hxx>
#include <ndgrf.hxx>
#include <ndhints.hxx>
#include <ndindex.hxx>
#include <ndole.hxx>
#include <ndtxt.hxx>
#include <ndtyp.hxx>
diff --git a/sw/inc/pch/precompiled_sw.hxx b/sw/inc/pch/precompiled_sw.hxx
index 78e52e5..83ced7f 100644
--- a/sw/inc/pch/precompiled_sw.hxx
+++ b/sw/inc/pch/precompiled_sw.hxx
@@ -13,7 +13,7 @@
 manual changes will be rewritten by the next run of update_pch.sh (which presumably
 also fixes all possible problems, so it's usually better to use it).

 Generated on 2020-02-16 16:30:24 using:
 Generated on 2020-02-17 14:43:31 using:
 ./bin/update_pch sw sw --cutoff=7 --exclude:system --exclude:module --include:local

 If after updating build fails, use the following command to locate conflicting headers:
@@ -68,9 +68,6 @@
#include <rtl/math.hxx>
#include <rtl/ref.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/string.h>
#include <rtl/stringconcat.hxx>
#include <rtl/stringutils.hxx>
#include <rtl/tencinfo.h>
#include <rtl/textenc.h>
#include <rtl/unload.h>
diff --git a/sw/source/uibase/inc/inputwin.hxx b/sw/source/uibase/inc/inputwin.hxx
index a8a0123..0073521 100644
--- a/sw/source/uibase/inc/inputwin.hxx
+++ b/sw/source/uibase/inc/inputwin.hxx
@@ -20,7 +20,6 @@
#define INCLUDED_SW_SOURCE_UIBASE_INC_INPUTWIN_HXX

#include <sfx2/InterimItemWindow.hxx>
#include <vcl/edit.hxx>
#include <vcl/menu.hxx>
#include <vcl/toolbox.hxx>

@@ -31,19 +30,75 @@ class SwWrtShell;
class SwView;
class SfxDispatcher;

class InputEdit : public Edit
class InputEdit final : public InterimItemWindow
{
private:
    std::unique_ptr<weld::Entry> m_xWidget;

    DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
    DECL_LINK(ActivateHdl, weld::Entry&, bool);
public:
                    InputEdit(vcl::Window* pParent, WinBits nStyle) :
                        Edit(pParent , nStyle){}
    InputEdit(vcl::Window* pParent)
        : InterimItemWindow(pParent, "modules/swriter/ui/inputeditbox.ui", "InputEditBox")
        , m_xWidget(m_xBuilder->weld_entry("entry"))
    {
        m_xWidget->connect_key_press(LINK(this, InputEdit, KeyInputHdl));
        m_xWidget->connect_activate(LINK(this, InputEdit, ActivateHdl));
        SetSizePixel(m_xWidget->get_preferred_size());
    }

    void            UpdateRange(const OUString& aSel,
                                const OUString& aTableName );
    void UpdateRange(const OUString& rSel, const OUString& rTableName);

protected:
    virtual void    KeyInput( const KeyEvent&  ) override;
    virtual void dispose() override
    {
        m_xWidget.reset();
        InterimItemWindow::dispose();
    }

    virtual void GetFocus() override
    {
        if (m_xWidget)
            m_xWidget->grab_focus();
        InterimItemWindow::GetFocus();
    }

    void set_text(const OUString& rText)
    {
        m_xWidget->set_text(rText);
    }

    OUString get_text() const
    {
        return m_xWidget->get_text();
    }

    void set_accessible_name(const OUString& rName)
    {
        m_xWidget->set_accessible_name(rName);
    }

    void replace_selection(const OUString& rText)
    {
        m_xWidget->replace_selection(rText);
    }

    void select_region(int nStartPos, int nEndPos)
    {
        m_xWidget->select_region(nStartPos, nEndPos);
    }

    void connect_changed(const Link<weld::Entry&, void>& rLink)
    {
        m_xWidget->connect_changed(rLink);
    }

    virtual ~InputEdit() override
    {
        disposeOnce();
    }
};


class PosEdit final : public InterimItemWindow
{
private:
@@ -93,7 +148,7 @@ class SwInputWindow final : public ToolBox
friend class InputEdit;

    VclPtr<PosEdit> mxPos;
    VclPtr<InputEdit> aEdit;
    VclPtr<InputEdit> mxEdit;
    std::unique_ptr<SwFieldMgr> pMgr;
    SwWrtShell*     pWrtShell;
    SwView*         pView;
@@ -109,7 +164,7 @@ friend class InputEdit;
    void CleanupUglyHackWithUndo();

    void DelBoxContent();
    DECL_LINK( ModifyHdl, Edit&, void );
    DECL_LINK(ModifyHdl, weld::Entry&, void);

    using Window::IsActive;

diff --git a/sw/source/uibase/ribbar/inputwin.cxx b/sw/source/uibase/ribbar/inputwin.cxx
index b7e35a5..841dc4a 100644
--- a/sw/source/uibase/ribbar/inputwin.cxx
+++ b/sw/source/uibase/ribbar/inputwin.cxx
@@ -66,7 +66,7 @@ IMPL_LINK(PosEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
SwInputWindow::SwInputWindow(vcl::Window* pParent, SfxDispatcher const * pDispatcher)
    : ToolBox(pParent, WB_3DLOOK|WB_BORDER)
    , mxPos(VclPtr<PosEdit>::Create(this))
    , aEdit(VclPtr<InputEdit>::Create(this, WB_3DLOOK|WB_TABSTOP|WB_BORDER|WB_NOHIDESELECTION))
    , mxEdit(VclPtr<InputEdit>::Create(this))
    , pWrtShell(nullptr)
    , pView(nullptr)
    , m_bDoesUndo(true)
@@ -76,8 +76,6 @@ SwInputWindow::SwInputWindow(vcl::Window* pParent, SfxDispatcher const * pDispat
    bFirst = true;
    bIsTable = bDelSel = false;

    aEdit->SetSizePixel(aEdit->CalcMinimumSize());

    InsertItem(FN_FORMULA_CALC, Image(StockImage::Yes, RID_BMP_FORMULA_CALC),
               SwResId(STR_FORMULA_CALC));
    InsertItem(FN_FORMULA_CANCEL, Image(StockImage::Yes, RID_BMP_FORMULA_CANCEL),
@@ -101,16 +99,16 @@ SwInputWindow::SwInputWindow(vcl::Window* pParent, SfxDispatcher const * pDispat
    SetAccessibleName(SwResId(STR_ACCESS_FORMULA_TOOLBAR));
    InsertSeparator ( 1 );
    InsertSeparator ();
    InsertWindow(ED_FORMULA, aEdit.get());
    InsertWindow(ED_FORMULA, mxEdit.get());
    SetItemText(ED_FORMULA, SwResId(STR_ACCESS_FORMULA_TEXT));
    aEdit->SetAccessibleName(SwResId(STR_ACCESS_FORMULA_TEXT));
    mxEdit->set_accessible_name(SwResId(STR_ACCESS_FORMULA_TEXT));
    SetHelpId(ED_FORMULA, HID_EDIT_FORMULA);

    SetItemBits( FN_FORMULA_CALC, GetItemBits( FN_FORMULA_CALC ) | ToolBoxItemBits::DROPDOWNONLY );
    SetDropdownClickHdl( LINK( this, SwInputWindow, DropdownClickHdl ));

    Size    aSizeTbx = CalcWindowSizePixel();
    Size    aEditSize = aEdit->GetSizePixel();
    Size    aEditSize = mxEdit->GetSizePixel();
    tools::Rectangle aItemRect( GetItemRect(FN_FORMULA_CALC) );
    long nMaxHeight = std::max(aEditSize.Height(), aItemRect.GetHeight());
    if( nMaxHeight+2 > aSizeTbx.Height() )
@@ -124,11 +122,11 @@ SwInputWindow::SwInputWindow(vcl::Window* pParent, SfxDispatcher const * pDispat
    aPosSize.setHeight( nMaxHeight );
    aEditSize.setHeight( nMaxHeight );
    Point aPosPos  = mxPos->GetPosPixel();
    Point aEditPos = aEdit->GetPosPixel();
    Point aEditPos = mxEdit->GetPosPixel();
    aPosPos.setY( (aSize.Height() - nMaxHeight)/2 + 1 );
    aEditPos.setY( (aSize.Height() - nMaxHeight)/2 + 1 );
    mxPos->SetPosSizePixel( aPosPos, aPosSize );
    aEdit->SetPosSizePixel( aEditPos, aEditSize );
    mxEdit->SetPosSizePixel( aEditPos, aEditSize );
}

SwInputWindow::~SwInputWindow()
@@ -151,7 +149,7 @@ void SwInputWindow::dispose()
    CleanupUglyHackWithUndo();

    mxPos.disposeAndClear();
    aEdit.disposeAndClear();
    mxEdit.disposeAndClear();
    ToolBox::dispose();
}

@@ -177,19 +175,18 @@ void SwInputWindow::Resize()
    ToolBox::Resize();

    long    nWidth      = GetSizePixel().Width();
    long    nLeft       = aEdit->GetPosPixel().X();
    Size    aEditSize   = aEdit->GetSizePixel();
    long    nLeft       = mxEdit->GetPosPixel().X();
    Size    aEditSize   = mxEdit->GetSizePixel();

    aEditSize.setWidth( std::max( static_cast<long>(nWidth - nLeft - 5), long(0) ) );
    aEdit->SetSizePixel( aEditSize );
    aEdit->Invalidate();
    mxEdit->SetSizePixel( aEditSize );
}

void SwInputWindow::ShowWin()
{
    bIsTable = false;
    // stop rulers
    if(pView)
    if (pView)
    {
        pView->GetHRuler().SetActive( false );
        pView->GetVRuler().SetActive( false );
@@ -268,22 +265,27 @@ void SwInputWindow::ShowWin()

        bFirst = false;

        aEdit->SetModifyHdl( LINK( this, SwInputWindow, ModifyHdl ));
        mxEdit->connect_changed( LINK( this, SwInputWindow, ModifyHdl ));

        aEdit->SetText( sEdit );
        aEdit->SetSelection( Selection( sEdit.getLength(), sEdit.getLength() ) );
        mxEdit->set_text( sEdit );
        sOldFormula = sEdit;

        aEdit->Invalidate();
        aEdit->Update();
        aEdit->GrabFocus();
        // For input cut the UserInterface

        pView->GetEditWin().LockKeyInput(true);
        pView->GetViewFrame()->GetDispatcher()->Lock(true);
        pWrtShell->Push();
    }

    ToolBox::Show();

    // grab focus after ToolBox is shown so focus isn't potentially lost elsewhere
    if (pView)
    {
        int nPos = mxEdit->get_text().getLength();
        mxEdit->select_region(nPos, nPos);
        mxEdit->GrabFocus();
    }
}

IMPL_LINK( SwInputWindow, MenuHdl, Menu *, pMenu, bool )
@@ -292,7 +294,7 @@ IMPL_LINK( SwInputWindow, MenuHdl, Menu *, pMenu, bool )
    if (!aCommand.isEmpty())
    {
        aCommand += " ";
        aEdit->ReplaceSelected(OStringToOUString(aCommand, RTL_TEXTENCODING_ASCII_US));
        mxEdit->replace_selection(OStringToOUString(aCommand, RTL_TEXTENCODING_ASCII_US));
    }
    return false;
}
@@ -337,7 +339,7 @@ void  SwInputWindow::ApplyFormula()
    pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);

    // Form should always begin with "=", so remove it here again
    OUString sEdit(comphelper::string::strip(aEdit->GetText(), ' '));
    OUString sEdit(comphelper::string::strip(mxEdit->get_text(), ' '));
    if( !sEdit.isEmpty() && '=' == sEdit[0] )
        sEdit = sEdit.copy( 1 );
    SfxStringItem aParam(FN_EDIT_FORMULA, sEdit);
@@ -383,9 +385,9 @@ IMPL_LINK( SwInputWindow, SelTableCellsNotify, SwWrtShell&, rCaller, void )
        if( pTableFormat && aCurrentTableName != pTableFormat->GetName() )
            sTableNm = pTableFormat->GetName();

        aEdit->UpdateRange( sBoxNms, sTableNm );
        mxEdit->UpdateRange( sBoxNms, sTableNm );

        OUString sNew = OUStringChar(CH_LRE) + aEdit->GetText()
        OUString sNew = OUStringChar(CH_LRE) + mxEdit->get_text()
            + OUStringChar(CH_PDF);

        if( sNew != sOldFormula )
@@ -408,7 +410,7 @@ IMPL_LINK( SwInputWindow, SelTableCellsNotify, SwWrtShell&, rCaller, void )
        }
    }
    else
        aEdit->GrabFocus();
        mxEdit->GrabFocus();
}

void SwInputWindow::SetFormula( const OUString& rFormula )
@@ -421,19 +423,18 @@ void SwInputWindow::SetFormula( const OUString& rFormula )
        else
            sEdit += rFormula;
    }
    aEdit->SetText( sEdit );
    aEdit->SetSelection( Selection( sEdit.getLength(), sEdit.getLength() ) );
    aEdit->Invalidate();
    mxEdit->set_text( sEdit );
    mxEdit->select_region(sEdit.getLength(), sEdit.getLength());
    bDelSel = true;
}

IMPL_LINK_NOARG(SwInputWindow, ModifyHdl, Edit&, void)
IMPL_LINK_NOARG(SwInputWindow, ModifyHdl, weld::Entry&, void)
{
    if (bIsTable && m_bResetUndo)
    {
        pWrtShell->StartAllAction();
        DelBoxContent();
        OUString sNew = OUStringChar(CH_LRE) + aEdit->GetText()
        OUString sNew = OUStringChar(CH_LRE) + mxEdit->get_text()
            + OUStringChar(CH_PDF);
        pWrtShell->SwEditShell::Insert2( sNew );
        pWrtShell->EndAllAction();
@@ -457,15 +458,26 @@ void SwInputWindow::DelBoxContent()
    }
}

void InputEdit::KeyInput(const KeyEvent& rEvent)
IMPL_LINK(InputEdit, KeyInputHdl, const KeyEvent&, rEvent, bool)
{
    bool bHandled = false;
    const vcl::KeyCode aCode = rEvent.GetKeyCode();
    if(aCode == KEY_RETURN || aCode == KEY_F2 )
        static_cast<SwInputWindow*>(GetParent())->ApplyFormula();
    if (aCode == KEY_RETURN || aCode == KEY_F2)
    {
        bHandled = ActivateHdl(*m_xWidget);
    }
    else if(aCode == KEY_ESCAPE )
    {
        static_cast<SwInputWindow*>(GetParent())->CancelFormula();
    else
        Edit::KeyInput(rEvent);
        bHandled = true;
    }
    return bHandled || ChildKeyInput(rEvent);
}

IMPL_LINK_NOARG(InputEdit, ActivateHdl, weld::Entry&, bool)
{
    static_cast<SwInputWindow*>(GetParent())->ApplyFormula();
    return true;
}

void InputEdit::UpdateRange(const OUString& rBoxes,
@@ -482,25 +494,29 @@ void InputEdit::UpdateRange(const OUString& rBoxes,
    if(!rName.isEmpty())
        aPrefix += ".";
    OUString aBoxes = aPrefix + rBoxes;
    Selection aSelection(GetSelection());

    int nSelStartPos, nSelEndPos;
    m_xWidget->get_selection_bounds(nSelStartPos, nSelEndPos);

    Selection aSelection(nSelStartPos, nSelEndPos);
    sal_uInt16 nSel = static_cast<sal_uInt16>(aSelection.Len());
    // OS: The following expression ensures that in the overwrite mode,
    // the selected closing parenthesis will be not deleted.
    if( nSel && ( nSel > 1 ||
                  GetText()[ static_cast<sal_uInt16>(aSelection.Min()) ] != cClose ))
        Cut();
                  m_xWidget->get_text()[ static_cast<sal_uInt16>(aSelection.Min()) ] != cClose ))
        m_xWidget->cut_clipboard();
    else
        aSelection.Max() = aSelection.Min();
    OUString aActText(GetText());
    OUString aActText(m_xWidget->get_text());
    const sal_uInt16 nLen = aActText.getLength();
    if( !nLen )
    {
        OUString aStr = OUStringChar(cOpen) + aBoxes + OUStringChar(cClose);
        SetText(aStr);
        m_xWidget->set_text(aStr);
        sal_Int32 nPos = aStr.indexOf( cClose );
        OSL_ENSURE(nPos != -1, "delimiter not found");
        ++nPos;
        SetSelection( Selection( nPos, nPos ));
        m_xWidget->select_region(nPos, nPos);
    }
    else
    {
@@ -549,10 +565,10 @@ void InputEdit::UpdateRange(const OUString& rBoxes,
            aActText = aActText.replaceAt( nPos, 0, aTmp );
            nPos = nPos + aTmp.getLength();
        }
        if( GetText() != aActText )
        if( m_xWidget->get_text() != aActText )
        {
            SetText( aActText );
            SetSelection( Selection( nPos, nPos ) );
            m_xWidget->set_text(aActText);
            m_xWidget->select_region(nPos, nPos);
        }
    }
    GrabFocus();
diff --git a/sw/uiconfig/swriter/ui/inputeditbox.ui b/sw/uiconfig/swriter/ui/inputeditbox.ui
new file mode 100644
index 0000000..11a8cac
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/inputeditbox.ui
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface domain="sc">
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkBox" id="InputEditBox">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="hexpand">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="width_chars">0</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">0</property>
      </packing>
    </child>
  </object>
</interface>