Resolves: tdf#157148 spelling dialog sentence box has no scrollbars

Change-Id: Ia1a7c2d73b0a5406ce3b08c4729e85ad724b44ae
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156843
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
diff --git a/cui/source/dialogs/SpellDialog.cxx b/cui/source/dialogs/SpellDialog.cxx
index 692c8e4..1e52d4e 100644
--- a/cui/source/dialogs/SpellDialog.cxx
+++ b/cui/source/dialogs/SpellDialog.cxx
@@ -173,7 +173,7 @@ SpellDialog::SpellDialog(SpellDialogChildWindow* pChildWindow,
    , m_xExplainFT(m_xBuilder->weld_label("explain"))
    , m_xExplainLink(m_xBuilder->weld_link_button("explainlink"))
    , m_xNotInDictFT(m_xBuilder->weld_label("notindictft"))
    , m_xSentenceED(new SentenceEditWindow_Impl)
    , m_xSentenceED(new SentenceEditWindow_Impl(m_xBuilder->weld_scrolled_window("scrolledwindow", true)))
    , m_xSuggestionFT(m_xBuilder->weld_label("suggestionsft"))
    , m_xSuggestionLB(m_xBuilder->weld_tree_view("suggestionslb"))
    , m_xIgnorePB(m_xBuilder->weld_button("ignore"))
@@ -1129,13 +1129,15 @@ bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasRe
    return bRet;
}

SentenceEditWindow_Impl::SentenceEditWindow_Impl()
    : m_pSpellDialog(nullptr)
SentenceEditWindow_Impl::SentenceEditWindow_Impl(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
    : m_xScrolledWindow(std::move(xScrolledWindow))
    , m_pSpellDialog(nullptr)
    , m_pToolbar(nullptr)
    , m_nErrorStart(0)
    , m_nErrorEnd(0)
    , m_bIsUndoEditMode(false)
{
    m_xScrolledWindow->connect_vadjustment_changed(LINK(this, SentenceEditWindow_Impl, ScrollHdl));
}

void SentenceEditWindow_Impl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
@@ -1147,6 +1149,8 @@ void SentenceEditWindow_Impl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
    // tdf#132288 don't merge equal adjacent attributes
    m_xEditEngine->DisableAttributeExpanding();

    m_xEditEngine->SetStatusEventHdl(LINK(this, SentenceEditWindow_Impl, EditStatusHdl));

    // tdf#142631 use document background color in this widget
    Color aBgColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
    OutputDevice& rDevice = pDrawingArea->get_ref_device();
@@ -1155,6 +1159,68 @@ void SentenceEditWindow_Impl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
    m_xEditEngine->SetBackgroundColor(aBgColor);
}

IMPL_LINK_NOARG(SentenceEditWindow_Impl, EditStatusHdl, EditStatus&, void)
{
    SetScrollBarRange();
    DoScroll();
}

IMPL_LINK_NOARG(SentenceEditWindow_Impl, ScrollHdl, weld::ScrolledWindow&, void)
{
    DoScroll();
}

void SentenceEditWindow_Impl::DoScroll()
{
    if (m_xEditView)
    {
        auto currentDocPos = m_xEditView->GetVisArea().Top();
        auto nDiff = currentDocPos - m_xScrolledWindow->vadjustment_get_value();
        // we expect SetScrollBarRange callback to be triggered by Scroll
        // to set where we ended up
        m_xEditView->Scroll(0, nDiff);
    }
}

void SentenceEditWindow_Impl::EditViewScrollStateChange()
{
    // editengine height has changed or editview scroll pos has changed
    SetScrollBarRange();
}

void SentenceEditWindow_Impl::SetScrollBarRange()
{
    EditEngine *pEditEngine = GetEditEngine();
    if (!pEditEngine)
        return;
    if (!m_xScrolledWindow)
        return;
    EditView* pEditView = GetEditView();
    if (!pEditView)
        return;

    int nVUpper = pEditEngine->GetTextHeight();
    int nVCurrentDocPos = pEditView->GetVisArea().Top();
    const Size aOut(pEditView->GetOutputArea().GetSize());
    int nVStepIncrement = aOut.Height() * 2 / 10;
    int nVPageIncrement = aOut.Height() * 8 / 10;
    int nVPageSize = aOut.Height();

    /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
       effectively...

       lower = gtk_adjustment_get_lower
       upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size

       and requires that upper > lower or the deceleration animation never ends
    */
    nVPageSize = std::min(nVPageSize, nVUpper);

    m_xScrolledWindow->vadjustment_configure(nVCurrentDocPos, 0, nVUpper,
                                             nVStepIncrement, nVPageIncrement, nVPageSize);
    m_xScrolledWindow->set_vpolicy(nVUpper > nVPageSize ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
}

SentenceEditWindow_Impl::~SentenceEditWindow_Impl()
{
}
diff --git a/cui/source/inc/SpellDialog.hxx b/cui/source/inc/SpellDialog.hxx
index 3b8d2f9..fdf5e81 100644
--- a/cui/source/inc/SpellDialog.hxx
+++ b/cui/source/inc/SpellDialog.hxx
@@ -46,6 +46,7 @@ struct SpellErrorDescription;
class SentenceEditWindow_Impl : public WeldEditView
{
private:
    std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow;
    std::set<sal_Int32> m_aIgnoreErrorsAt;
    SpellDialog*        m_pSpellDialog;
    weld::Toolbar*      m_pToolbar;
@@ -61,14 +62,20 @@ private:

    bool GetErrorDescription(SpellErrorDescription& rSpellErrorDescription, sal_Int32 nPosition);

    DECL_LINK(ScrollHdl, weld::ScrolledWindow&, void);
    DECL_LINK(EditStatusHdl, EditStatus&, void);
    DECL_LINK(ToolbarHdl, const OUString&, void);

    void DoScroll();
    void SetScrollBarRange();

protected:
    virtual bool    KeyInput( const KeyEvent& rKEvt ) override;

public:
    SentenceEditWindow_Impl();
    SentenceEditWindow_Impl(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow);
    virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
    virtual void EditViewScrollStateChange() override;
    void SetSpellDialog(SpellDialog* pDialog) { m_pSpellDialog = pDialog; }
    virtual ~SentenceEditWindow_Impl() override;

diff --git a/cui/uiconfig/ui/spellingdialog.ui b/cui/uiconfig/ui/spellingdialog.ui
index 87e538d..7177282 100644
--- a/cui/uiconfig/ui/spellingdialog.ui
+++ b/cui/uiconfig/ui/spellingdialog.ui
@@ -154,10 +154,11 @@
              </packing>
            </child>
            <child>
              <object class="GtkScrolledWindow">
              <object class="GtkScrolledWindow" id="scrolledwindow">
                <property name="visible">True</property>
                <property name="can-focus">True</property>
                <property name="border-width">0</property>
                <property name="hscrollbar-policy">never</property>
                <property name="shadow-type">in</property>
                <child>
                  <object class="GtkViewport">