weld SpellDialog

a) use EditEngine instead of TextEngine as the former can be hosted in a
   foreign widget
b) use a SfxGrabBagItem to hold the custom spellchecking info inside the
   EditEngine
c) in longer paragraphs the current word is now auto-scrolled into view
d) rename Invalidate to InvalidateDialog

Change-Id: Ic6db019c32cdfd5f354c58ee7394fdaa040b86e1
Reviewed-on: https://gerrit.libreoffice.org/74535
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index 2d46420..cce2b70 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -132,7 +132,6 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
    cui/source/dialogs/SignSignatureLineDialog \
    cui/source/dialogs/sdrcelldlg \
    cui/source/dialogs/showcols \
    cui/source/dialogs/SpellAttrib \
    cui/source/dialogs/SpellDialog \
    cui/source/dialogs/splitcelldlg \
    cui/source/dialogs/srchxtra \
diff --git a/cui/source/dialogs/SpellAttrib.cxx b/cui/source/dialogs/SpellAttrib.cxx
deleted file mode 100644
index 9d761a5..0000000
--- a/cui/source/dialogs/SpellAttrib.cxx
+++ /dev/null
@@ -1,105 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "SpellAttrib.hxx"
#include <vcl/font.hxx>

using namespace svx;
using namespace com::sun::star::linguistic2;
using namespace com::sun::star::uno;


SpellErrorAttrib::SpellErrorAttrib( const SpellErrorDescription& rDesc ) :
    TextAttrib(TEXTATTR_SPELL_ERROR),
    m_aSpellErrorDescription( rDesc )
{
}


void SpellErrorAttrib::SetFont( vcl::Font&  ) const
{
    //this attribute doesn't have a visual effect
}


std::unique_ptr<TextAttrib> SpellErrorAttrib::Clone() const
{
    return std::unique_ptr<TextAttrib>(new SpellErrorAttrib(*this));
}


bool SpellErrorAttrib::operator==( const TextAttrib& rAttr ) const
{
    return Which() == rAttr.Which() &&
            m_aSpellErrorDescription == static_cast<const SpellErrorAttrib&>(rAttr).m_aSpellErrorDescription;
}


SpellLanguageAttrib::SpellLanguageAttrib(LanguageType eLang) :
    TextAttrib(TEXTATTR_SPELL_LANGUAGE),
    m_eLanguage(eLang)
{
}


void SpellLanguageAttrib::SetFont( vcl::Font&  ) const
{
    //no visual effect
}


std::unique_ptr<TextAttrib> SpellLanguageAttrib::Clone() const
{
    return std::unique_ptr<TextAttrib>(new SpellLanguageAttrib(*this));
}


bool SpellLanguageAttrib::operator==( const TextAttrib& rAttr ) const
{
    return Which() == rAttr.Which() &&
            m_eLanguage == static_cast<const SpellLanguageAttrib&>(rAttr).m_eLanguage;
}


SpellBackgroundAttrib::SpellBackgroundAttrib(const Color& rCol) :
    TextAttrib(TEXTATTR_SPELL_BACKGROUND),
    m_aBackgroundColor(rCol)
{
}


void SpellBackgroundAttrib::SetFont( vcl::Font& rFont ) const
{
    rFont.SetFillColor(m_aBackgroundColor);
}


std::unique_ptr<TextAttrib> SpellBackgroundAttrib::Clone() const
{
    return std::unique_ptr<TextAttrib>(new SpellBackgroundAttrib(*this));
}


bool SpellBackgroundAttrib::operator==( const TextAttrib& rAttr ) const
{
    return Which() == rAttr.Which() &&
            m_aBackgroundColor == static_cast<const SpellBackgroundAttrib&>(rAttr).m_aBackgroundColor;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/SpellAttrib.hxx b/cui/source/dialogs/SpellAttrib.hxx
index 2a45816..a106bce 100644
--- a/cui/source/dialogs/SpellAttrib.hxx
+++ b/cui/source/dialogs/SpellAttrib.hxx
@@ -19,7 +19,6 @@
#ifndef INCLUDED_CUI_SOURCE_DIALOGS_SPELLATTRIB_HXX
#define INCLUDED_CUI_SOURCE_DIALOGS_SPELLATTRIB_HXX

#include <vcl/txtattr.hxx>
#include <i18nlangtag/lang.h>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/uno/Sequence.h>
@@ -27,10 +26,6 @@
#include <com/sun/star/linguistic2/XProofreader.hpp>
#include <tools/color.hxx>

#define TEXTATTR_SPELL_ERROR            (TEXTATTR_USER_START + 1)
#define TEXTATTR_SPELL_LANGUAGE         (TEXTATTR_USER_START + 2)
#define TEXTATTR_SPELL_BACKGROUND       (TEXTATTR_USER_START + 3)

namespace svx{
struct SpellErrorDescription
{
@@ -61,16 +56,21 @@ struct SpellErrorDescription
        aLocale( rLocale ),
        xGrammarChecker( rxGrammarChecker ),
        aSuggestions( rSuggestions )
        {
            if( pDialogTitle )
                sDialogTitle = *pDialogTitle;
            if( pExplanation )
                sExplanation = *pExplanation;
            if( pExplanationURL )
                sExplanationURL = *pExplanationURL;
            if( pRuleId )
                sRuleId = *pRuleId;
        };
    {
        if( pDialogTitle )
            sDialogTitle = *pDialogTitle;
        if( pExplanation )
            sExplanation = *pExplanation;
        if( pExplanationURL )
            sExplanationURL = *pExplanationURL;
        if( pRuleId )
            sRuleId = *pRuleId;
    };

    SpellErrorDescription()
        : bIsGrammarError(false)
    {
    }

    bool operator==( const SpellErrorDescription& rDesc ) const
    {
@@ -86,54 +86,36 @@ struct SpellErrorDescription
                sExplanationURL == rDesc.sExplanationURL &&
                sRuleId == rDesc.sRuleId;
    }

    css::uno::Sequence<css::uno::Any> toSequence() const
    {
        css::uno::Sequence<css::uno::Any> aEntries(9);
        aEntries[0] <<= bIsGrammarError;
        aEntries[1] <<= sErrorText;
        aEntries[2] <<= sDialogTitle;
        aEntries[3] <<= sExplanation;
        aEntries[4] <<= sExplanationURL;
        aEntries[5] <<= aLocale;
        aEntries[6] <<= xGrammarChecker;
        aEntries[7] <<= aSuggestions;
        aEntries[8] <<= sRuleId;
        return aEntries;
    }

    void fromSequence(const css::uno::Sequence<css::uno::Any>& rEntries)
    {
        rEntries[0] >>= bIsGrammarError;
        rEntries[1] >>= sErrorText;
        rEntries[2] >>= sDialogTitle;
        rEntries[3] >>= sExplanation;
        rEntries[4] >>= sExplanationURL;
        rEntries[5] >>= aLocale;
        rEntries[6] >>= xGrammarChecker;
        rEntries[7] >>= aSuggestions;
        rEntries[8] >>= sRuleId;
    }
};


class SpellErrorAttrib : public TextAttrib
{
public:

private:
    SpellErrorDescription        m_aSpellErrorDescription;

public:
                            SpellErrorAttrib( const SpellErrorDescription& );

    const SpellErrorDescription& GetErrorDescription() const { return m_aSpellErrorDescription; }


    virtual void            SetFont( vcl::Font& rFont ) const override;
    virtual std::unique_ptr<TextAttrib> Clone() const override;
    virtual bool            operator==( const TextAttrib& rAttr ) const override;
};


class SpellLanguageAttrib : public TextAttrib
{
    LanguageType m_eLanguage;

public:
                            SpellLanguageAttrib(LanguageType eLanguage);

    LanguageType            GetLanguage() const {return m_eLanguage;}

    virtual void            SetFont( vcl::Font& rFont ) const override;
    virtual std::unique_ptr<TextAttrib> Clone() const override;
    virtual bool            operator==( const TextAttrib& rAttr ) const override;
};


class SpellBackgroundAttrib : public TextAttrib
{
    Color   m_aBackgroundColor;

public:
                            SpellBackgroundAttrib(const Color& rCol);

    virtual void            SetFont( vcl::Font& rFont ) const override;
    virtual std::unique_ptr<TextAttrib> Clone() const override;
    virtual bool            operator==( const TextAttrib& rAttr ) const override;
};
}//namespace svx
#endif

diff --git a/cui/source/dialogs/SpellDialog.cxx b/cui/source/dialogs/SpellDialog.cxx
index ac3b22b..6d77aeb 100644
--- a/cui/source/dialogs/SpellDialog.cxx
+++ b/cui/source/dialogs/SpellDialog.cxx
@@ -18,25 +18,20 @@
 */

#include <memory>
#include <vcl/event.hxx>
#include <vcl/weld.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/menu.hxx>
#include <vcl/scrbar.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include "SpellAttrib.hxx"
#include <sfx2/dispatch.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/viewfrm.hxx>
#include <svl/grabbagitem.hxx>
#include <svl/undo.hxx>
#include <unotools/lingucfg.hxx>
#include <vcl/textdata.hxx>
#include <vcl/textview.hxx>
#include <vcl/graphicfilter.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/colritem.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/splwrap.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/wghtitem.hxx>
#include <linguistic/lngprops.hxx>
#include <linguistic/misc.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
@@ -48,8 +43,15 @@
#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
#include <sfx2/app.hxx>
#include <vcl/help.hxx>
#include <vcl/cursor.hxx>
#include <vcl/event.hxx>
#include <vcl/graph.hxx>
#include <vcl/help.hxx>
#include <vcl/graphicfilter.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <osl/file.hxx>
#include <editeng/optitems.hxx>
#include <editeng/svxenum.hxx>
@@ -165,81 +167,73 @@ sal_uInt16 SpellUndoAction_Impl::GetId()const
// class SvxSpellCheckDialog ---------------------------------------------

SpellDialog::SpellDialog(SpellDialogChildWindow* pChildWindow,
    vcl::Window * pParent, SfxBindings* _pBindings)
    : SfxModelessDialog (_pBindings, pChildWindow,
        pParent, "SpellingDialog", "cui/ui/spellingdialog.ui")
    weld::Window * pParent, SfxBindings* _pBindings)
    : SfxModelessDialogController (_pBindings, pChildWindow,
        pParent, "cui/ui/spellingdialog.ui", "SpellingDialog")
    , aDialogUndoLink(LINK (this, SpellDialog, DialogUndoHdl))
    , bFocusLocked(true)
    , rParent(*pChildWindow)
    , pImpl( new SpellDialog_Impl )
    , m_xAltTitle(m_xBuilder->weld_label("alttitleft"))
    , m_xResumeFT(m_xBuilder->weld_label("resumeft"))
    , m_xNoSuggestionsFT(m_xBuilder->weld_label("nosuggestionsft"))
    , m_xLanguageFT(m_xBuilder->weld_label("languageft"))
    , m_xLanguageLB(new LanguageBox(m_xBuilder->weld_combo_box("languagelb")))
    , 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_xSuggestionFT(m_xBuilder->weld_label("suggestionsft"))
    , m_xSuggestionLB(m_xBuilder->weld_tree_view("suggestionslb"))
    , m_xIgnorePB(m_xBuilder->weld_button("ignore"))
    , m_xIgnoreAllPB(m_xBuilder->weld_button("ignoreall"))
    , m_xIgnoreRulePB(m_xBuilder->weld_button("ignorerule"))
    , m_xAddToDictPB(m_xBuilder->weld_button("add"))
    , m_xAddToDictMB(m_xBuilder->weld_menu_button("addmb"))
    , m_xChangePB(m_xBuilder->weld_button("change"))
    , m_xChangeAllPB(m_xBuilder->weld_button("changeall"))
    , m_xAutoCorrPB(m_xBuilder->weld_button("autocorrect"))
    , m_xCheckGrammarCB(m_xBuilder->weld_check_button("checkgrammar"))
    , m_xOptionsPB(m_xBuilder->weld_button("options"))
    , m_xUndoPB(m_xBuilder->weld_button("undo"))
    , m_xClosePB(m_xBuilder->weld_button("close"))
    , m_xToolbar(m_xBuilder->weld_toolbar("toolbar"))
    , m_xSentenceEDWeld(new weld::CustomWeld(*m_xBuilder, "sentence", *m_xSentenceED))
{
    m_sTitleSpellingGrammar = GetText();
    m_sTitleSpelling = get<FixedText>("alttitleft")->GetText();
    m_xSentenceED->SetSpellDialog(this);
    m_xSentenceED->Init(m_xToolbar.get());

    m_sTitleSpellingGrammar = m_xDialog->get_title();
    m_sTitleSpelling = m_xAltTitle->get_label();

    // fdo#68794 set initial title for cases where no text has been processed
    // yet to show its language attributes
    OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
    SetText(sTitle.replaceFirst("$LANGUAGE ($LOCATION)", ""));
    m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle.replaceFirst("$LANGUAGE ($LOCATION)", "")));

    m_sResumeST = get<FixedText>("resumeft")->GetText();
    m_sNoSuggestionsST = get<FixedText>("nosuggestionsft")->GetText();
    m_sResumeST = m_xResumeFT->get_label();
    m_sNoSuggestionsST = m_xNoSuggestionsFT->strip_mnemonic(m_xNoSuggestionsFT->get_label());

    get(m_pLanguageFT, "languageft");
    get(m_pLanguageLB, "languagelb");
    get(m_pExplainFT, "explain");
    get(m_pExplainLink, "explainlink");
    get(m_pNotInDictFT, "notindictft");
    get(m_pSentenceED, "sentence");
    Size aEdSize(LogicToPixel(Size(197, 48), MapMode(MapUnit::MapAppFont)));
    m_pSentenceED->set_width_request(aEdSize.Width());
    m_pSentenceED->set_height_request(aEdSize.Height());
    get(m_pSuggestionFT, "suggestionsft");
    get(m_pSuggestionLB, "suggestionslb");
    m_pSuggestionLB->SetDropDownLineCount(5);
    m_pSuggestionLB->set_width_request(aEdSize.Width());
    get(m_pIgnorePB, "ignore");
    m_sIgnoreOnceST = m_pIgnorePB->GetText();
    get(m_pIgnoreAllPB, "ignoreall");
    get(m_pIgnoreRulePB, "ignorerule");
    get(m_pAddToDictPB, "add");
    get(m_pAddToDictMB, "addmb");
    m_pAddToDictMB->SetHelpId(m_pAddToDictPB->GetHelpId());
    get(m_pChangePB, "change");
    get(m_pChangeAllPB, "changeall");
    get(m_pAutoCorrPB, "autocorrect");
    get(m_pCheckGrammarCB, "checkgrammar");
    get(m_pOptionsPB, "options");
    get(m_pUndoPB, "undo");
    get(m_pClosePB, "close");
    get(m_pToolbar, "toolbar");
    m_pSentenceED->Init(m_pToolbar);
    Size aEdSize(m_xSuggestionLB->get_approximate_digit_width() * 60,
                 m_xSuggestionLB->get_height_rows(6));
    m_xSuggestionLB->set_size_request(aEdSize.Width(), -1);
    m_sIgnoreOnceST = m_xIgnorePB->get_label();
    m_xAddToDictMB->set_help_id(m_xAddToDictPB->get_help_id());
    xSpell = LinguMgr::GetSpellChecker();

    const StyleSettings& rSettings = GetSettings().GetStyleSettings();
    Color aCol = rSettings.GetHelpColor();
    Wallpaper aWall( aCol );
    m_pExplainLink->SetBackground( aWall );
    m_pExplainFT->SetBackground( aWall );

    Init_Impl();

    // disable controls if service is missing
    Enable(xSpell.is());
    m_xDialog->set_sensitive(xSpell.is());

    //InitHdl wants to use virtual methods, so it
    //can't be called during the ctor, so init
    //it on next event cycle post-ctor
    Application::PostUserEvent(
        LINK( this, SpellDialog, InitHdl ), nullptr, true );
    Application::PostUserEvent(LINK(this, SpellDialog, InitHdl));
}

SpellDialog::~SpellDialog()
{
    disposeOnce();
}

void SpellDialog::dispose()
{
    if (pImpl)
    {
        // save possibly modified user-dictionaries
@@ -249,90 +243,69 @@ void SpellDialog::dispose()

        pImpl.reset();
    }
    m_pLanguageFT.clear();
    m_pLanguageLB.clear();
    m_pExplainFT.clear();
    m_pExplainLink.clear();
    m_pNotInDictFT.clear();
    m_pSentenceED.clear();
    m_pSuggestionFT.clear();
    m_pSuggestionLB.clear();
    m_pIgnorePB.clear();
    m_pIgnoreAllPB.clear();
    m_pIgnoreRulePB.clear();
    m_pAddToDictPB.clear();
    m_pAddToDictMB.clear();
    m_pChangePB.clear();
    m_pChangeAllPB.clear();
    m_pAutoCorrPB.clear();
    m_pCheckGrammarCB.clear();
    m_pOptionsPB.clear();
    m_pUndoPB.clear();
    m_pClosePB.clear();
    m_pToolbar.clear();
    SfxModelessDialog::dispose();
}

void SpellDialog::Init_Impl()
{
    // initialize handler
    m_pClosePB->SetClickHdl(LINK( this, SpellDialog, CancelHdl ) );
    m_pChangePB->SetClickHdl(LINK( this, SpellDialog, ChangeHdl ) );
    m_pChangeAllPB->SetClickHdl(LINK( this, SpellDialog, ChangeAllHdl ) );
    m_pIgnorePB->SetClickHdl(LINK( this, SpellDialog, IgnoreHdl ) );
    m_pIgnoreAllPB->SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
    m_pIgnoreRulePB->SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
    m_pUndoPB->SetClickHdl(LINK( this, SpellDialog, UndoHdl ) );
    m_xClosePB->connect_clicked(LINK( this, SpellDialog, CancelHdl ) );
    m_xChangePB->connect_clicked(LINK( this, SpellDialog, ChangeHdl ) );
    m_xChangeAllPB->connect_clicked(LINK( this, SpellDialog, ChangeAllHdl ) );
    m_xIgnorePB->connect_clicked(LINK( this, SpellDialog, IgnoreHdl ) );
    m_xIgnoreAllPB->connect_clicked(LINK( this, SpellDialog, IgnoreAllHdl ) );
    m_xIgnoreRulePB->connect_clicked(LINK( this, SpellDialog, IgnoreAllHdl ) );
    m_xUndoPB->connect_clicked(LINK( this, SpellDialog, UndoHdl ) );

    m_pAutoCorrPB->SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
    m_pCheckGrammarCB->SetClickHdl( LINK( this, SpellDialog, CheckGrammarHdl ));
    m_pOptionsPB->SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
    m_xAutoCorrPB->connect_clicked( LINK( this, SpellDialog, ExtClickHdl ) );
    m_xCheckGrammarCB->connect_clicked( LINK( this, SpellDialog, CheckGrammarHdl ));
    m_xOptionsPB->connect_clicked( LINK( this, SpellDialog, ExtClickHdl ) );

    m_pSuggestionLB->SetDoubleClickHdl( LINK( this, SpellDialog, DoubleClickChangeHdl ) );
    m_xSuggestionLB->connect_row_activated( LINK( this, SpellDialog, DoubleClickChangeHdl ) );

    m_pSentenceED->SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
    m_xSentenceED->SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );

    m_pAddToDictMB->SetSelectHdl(LINK ( this, SpellDialog, AddToDictSelectHdl ) );
    m_pAddToDictPB->SetClickHdl(LINK ( this, SpellDialog, AddToDictClickHdl ) );
    m_xAddToDictMB->connect_selected(LINK ( this, SpellDialog, AddToDictSelectHdl ) );
    m_xAddToDictPB->connect_clicked(LINK ( this, SpellDialog, AddToDictClickHdl ) );

    m_pLanguageLB->SetSelectHdl(LINK( this, SpellDialog, LanguageSelectHdl ) );
    m_xLanguageLB->connect_changed(LINK( this, SpellDialog, LanguageSelectHdl ) );

    // initialize language ListBox
    m_pLanguageLB->SetLanguageList( SvxLanguageListFlags::SPELL_USED, false, true );
    m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::SPELL_USED, false, false, true);

    m_pSentenceED->ClearModifyFlag();
    m_xSentenceED->ClearModifyFlag();
    LinguMgr::GetChangeAllList()->clear();
}

void SpellDialog::UpdateBoxes_Impl(bool bCallFromSelectHdl)
{
    sal_Int32 i;
    m_pSuggestionLB->Clear();
    m_xSuggestionLB->clear();

    const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
    SpellErrorDescription aSpellErrorDescription;
    bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);

    LanguageType nAltLanguage = LANGUAGE_NONE;
    Sequence< OUString > aNewWords;
    bool bIsGrammarError = false;
    if( pSpellErrorDescription )
    if( bSpellErrorDescription )
    {
        nAltLanguage    = LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale );
        aNewWords       = pSpellErrorDescription->aSuggestions;
        bIsGrammarError = pSpellErrorDescription->bIsGrammarError;
        m_pExplainLink->SetURL( pSpellErrorDescription->sExplanationURL );
        m_pExplainFT->SetText( pSpellErrorDescription->sExplanation );
        nAltLanguage    = LanguageTag::convertToLanguageType( aSpellErrorDescription.aLocale );
        aNewWords       = aSpellErrorDescription.aSuggestions;
        bIsGrammarError = aSpellErrorDescription.bIsGrammarError;
        m_xExplainLink->set_uri( aSpellErrorDescription.sExplanationURL );
        m_xExplainFT->set_label( aSpellErrorDescription.sExplanation );
    }
    if( pSpellErrorDescription && !pSpellErrorDescription->sDialogTitle.isEmpty() )
    if( bSpellErrorDescription && !aSpellErrorDescription.sDialogTitle.isEmpty() )
    {
        // use this function to apply the correct image to be used...
        SetTitle_Impl( nAltLanguage );
        // then change the title to the one to be actually used
        SetText( pSpellErrorDescription->sDialogTitle );
        m_xDialog->set_title(m_xDialog->strip_mnemonic(aSpellErrorDescription.sDialogTitle));
    }
    else
        SetTitle_Impl( nAltLanguage );
    if( !bCallFromSelectHdl )
        m_pLanguageLB->SelectLanguage( nAltLanguage );
        m_xLanguageLB->set_active_id( nAltLanguage );
    int nDicts = InitUserDicts();

    // enter alternatives
@@ -341,76 +314,73 @@ void SpellDialog::UpdateBoxes_Impl(bool bCallFromSelectHdl)
    for ( i = 0; i < nSize; ++i )
    {
        OUString aTmp( pNewWords[i] );
        if ( LISTBOX_ENTRY_NOTFOUND == m_pSuggestionLB->GetEntryPos( aTmp ) )
        {
            m_pSuggestionLB->InsertEntry( aTmp );
            m_pSuggestionLB->SetEntryFlags(m_pSuggestionLB->GetEntryCount() - 1, ListBoxEntryFlags::MultiLine);
        }
        if (m_xSuggestionLB->find_text(aTmp) == -1)
            m_xSuggestionLB->append_text(aTmp);
    }
    if(!nSize)
        m_pSuggestionLB->InsertEntry(m_sNoSuggestionsST);
    m_pAutoCorrPB->Enable( nSize > 0 );
        m_xSuggestionLB->append_text(m_sNoSuggestionsST);
    m_xAutoCorrPB->set_sensitive( nSize > 0 );

    m_pSuggestionFT->Enable(nSize > 0);
    m_pSuggestionLB->Enable(nSize > 0);
    m_xSuggestionFT->set_sensitive(nSize > 0);
    m_xSuggestionLB->set_sensitive(nSize > 0);
    if( nSize )
    {
        m_pSuggestionLB->SelectEntryPos(0);
        m_xSuggestionLB->select(0);
    }
    m_pChangePB->Enable( nSize > 0);
    m_pChangeAllPB->Enable(nSize > 0);
    m_xChangePB->set_sensitive( nSize > 0);
    m_xChangeAllPB->set_sensitive(nSize > 0);
    bool bShowChangeAll = !bIsGrammarError;
    m_pChangeAllPB->Show( bShowChangeAll );
    m_pExplainFT->Show( !bShowChangeAll );
    m_pLanguageLB->Enable( bShowChangeAll );
    m_pIgnoreAllPB->Show( bShowChangeAll );
    m_xChangeAllPB->set_visible( bShowChangeAll );
    m_xExplainFT->set_visible( !bShowChangeAll );
    m_xLanguageLB->set_sensitive( bShowChangeAll );
    m_xIgnoreAllPB->set_visible( bShowChangeAll );

    m_pAddToDictMB->Show( bShowChangeAll && nDicts > 1);
    m_pAddToDictPB->Show( bShowChangeAll && nDicts <= 1);
    m_pIgnoreRulePB->Show( !bShowChangeAll );
    m_pIgnoreRulePB->Enable(pSpellErrorDescription && !pSpellErrorDescription->sRuleId.isEmpty());
    m_pAutoCorrPB->Show( bShowChangeAll && rParent.HasAutoCorrection() );
    m_xAddToDictMB->set_visible( bShowChangeAll && nDicts > 1);
    m_xAddToDictPB->set_visible( bShowChangeAll && nDicts <= 1);
    m_xIgnoreRulePB->set_visible( !bShowChangeAll );
    m_xIgnoreRulePB->set_sensitive(bSpellErrorDescription && !aSpellErrorDescription.sRuleId.isEmpty());
    m_xAutoCorrPB->set_visible( bShowChangeAll && rParent.HasAutoCorrection() );

    bool bOldShowGrammar = m_pCheckGrammarCB->IsVisible();
    bool bOldShowExplain = m_pExplainLink->IsVisible();
    bool bOldShowGrammar = m_xCheckGrammarCB->get_visible();
    bool bOldShowExplain = m_xExplainLink->get_visible();

    m_pCheckGrammarCB->Show(rParent.HasGrammarChecking());
    m_pExplainLink->Show(!m_pExplainLink->GetURL().isEmpty());
    if (m_pExplainFT->GetText().isEmpty())
    m_xCheckGrammarCB->set_visible(rParent.HasGrammarChecking());
    m_xExplainLink->set_visible(!m_xExplainLink->get_uri().isEmpty());
    if (m_xExplainFT->get_label().isEmpty())
    {
        m_pExplainFT->Hide();
        m_pExplainLink->Hide();
        m_xExplainFT->hide();
        m_xExplainLink->hide();
    }

    if (bOldShowExplain != m_pExplainLink->IsVisible() || bOldShowGrammar != m_pCheckGrammarCB->IsVisible())
        setOptimalLayoutSize();
    if (bOldShowExplain != m_xExplainLink->get_visible() || bOldShowGrammar != m_xCheckGrammarCB->get_visible())
        m_xDialog->resize_to_request();
}


void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrentError )
{
    //initially or after the last error of a sentence MarkNextError will fail
    //then GetNextSentence() has to be called followed again by MarkNextError()
    //MarkNextError is not initially called if the UndoEdit mode is active
    bool bNextSentence = false;
    if((!m_pSentenceED->IsUndoEditMode() && m_pSentenceED->MarkNextError( bIgnoreCurrentError, xSpell )) ||
            ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence, m_pSentenceED->IsUndoEditMode()) && m_pSentenceED->MarkNextError( false, xSpell )))
    if((!m_xSentenceED->IsUndoEditMode() && m_xSentenceED->MarkNextError( bIgnoreCurrentError, xSpell )) ||
            ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence, m_xSentenceED->IsUndoEditMode()) && m_xSentenceED->MarkNextError( false, xSpell )))
    {
        const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
        if( pSpellErrorDescription )
        SpellErrorDescription aSpellErrorDescription;
        bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
        if (bSpellErrorDescription)
        {
            UpdateBoxes_Impl();
            Control* aControls[] =
            weld::Widget* aControls[] =
            {
                m_pNotInDictFT,
                m_pSentenceED,
                m_pLanguageFT,
                m_xNotInDictFT.get(),
                m_xSentenceED->GetDrawingArea(),
                m_xLanguageFT.get(),
                nullptr
            };
            sal_Int32 nIdx = 0;
            do
            {
                aControls[nIdx]->Enable();
                aControls[nIdx]->set_sensitive(true);
            }
            while(aControls[++nIdx]);

@@ -418,8 +388,8 @@ void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrent
        if( bNextSentence )
        {
            //remove undo if a new sentence is active
            m_pSentenceED->ResetUndo();
            m_pUndoPB->Enable(false);
            m_xSentenceED->ResetUndo();
            m_xUndoPB->set_sensitive(false);
        }
    }
}
@@ -428,12 +398,12 @@ void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrent
 */
IMPL_LINK_NOARG( SpellDialog, InitHdl, void*, void)
{
    SetUpdateMode( false );
    m_xDialog->freeze();
    //show or hide AutoCorrect depending on the modules abilities
    m_pAutoCorrPB->Show(rParent.HasAutoCorrection());
    m_xAutoCorrPB->set_visible(rParent.HasAutoCorrection());
    SpellContinue_Impl();
    m_pSentenceED->ResetUndo();
    m_pUndoPB->Enable(false);
    m_xSentenceED->ResetUndo();
    m_xUndoPB->set_sensitive(false);

    // get current language
    UpdateBoxes_Impl();
@@ -442,41 +412,40 @@ IMPL_LINK_NOARG( SpellDialog, InitHdl, void*, void)
    InitUserDicts();

    LockFocusChanges(true);
    if( m_pChangePB->IsEnabled() )
        m_pChangePB->GrabFocus();
    else if( m_pIgnorePB->IsEnabled() )
        m_pIgnorePB->GrabFocus();
    else if( m_pClosePB->IsEnabled() )
        m_pClosePB->GrabFocus();
    if( m_xChangePB->get_sensitive() )
        m_xChangePB->grab_focus();
    else if( m_xIgnorePB->get_sensitive() )
        m_xIgnorePB->grab_focus();
    else if( m_xClosePB->get_sensitive() )
        m_xClosePB->grab_focus();
    LockFocusChanges(false);
    //show grammar CheckBox depending on the modules abilities
    m_pCheckGrammarCB->Check( rParent.IsGrammarChecking() );
    SetUpdateMode( true );
    Show();
    m_xCheckGrammarCB->set_active(rParent.IsGrammarChecking());
    m_xDialog->thaw();
};


IMPL_LINK( SpellDialog, ExtClickHdl, Button *, pBtn, void )
IMPL_LINK( SpellDialog, ExtClickHdl, weld::Button&, rBtn, void )
{
    if (m_pOptionsPB == pBtn)
    if (m_xOptionsPB.get() == &rBtn)
        StartSpellOptDlg_Impl();
    else if (m_pAutoCorrPB == pBtn)
    else if (m_xAutoCorrPB.get() == &rBtn)
    {
        //get the currently selected wrong word
        OUString sCurrentErrorText = m_pSentenceED->GetErrorText();
        OUString sCurrentErrorText = m_xSentenceED->GetErrorText();
        //get the wrong word from the XSpellAlternative
        const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
        if( pSpellErrorDescription )
        SpellErrorDescription aSpellErrorDescription;
        bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
        if (bSpellErrorDescription)
        {
            OUString sWrong(pSpellErrorDescription->sErrorText);
            OUString sWrong(aSpellErrorDescription.sErrorText);
            //if the word has not been edited in the MultiLineEdit then
            //the current suggestion should be used
            //if it's not the 'no suggestions' entry
            if(sWrong == sCurrentErrorText &&
                    m_pSuggestionLB->IsEnabled() && m_pSuggestionLB->GetSelectedEntryCount() > 0 &&
                    m_sNoSuggestionsST != m_pSuggestionLB->GetSelectedEntry())
                    m_xSuggestionLB->get_sensitive() && m_xSuggestionLB->get_selected_index() != -1 &&
                    m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
            {
                sCurrentErrorText = m_pSuggestionLB->GetSelectedEntry();
                sCurrentErrorText = m_xSuggestionLB->get_selected_text();
            }
            if(sWrong != sCurrentErrorText)
            {
@@ -488,16 +457,16 @@ IMPL_LINK( SpellDialog, ExtClickHdl, Button *, pBtn, void )
    }
}

IMPL_LINK( SpellDialog, CheckGrammarHdl, Button*, pBox, void )
IMPL_LINK_NOARG(SpellDialog, CheckGrammarHdl, weld::Button&, void)
{
    rParent.SetGrammarChecking( static_cast<CheckBox*>(pBox)->IsChecked() );
    rParent.SetGrammarChecking(m_xCheckGrammarCB->get_active());
    Impl_Restore(true);
}

void SpellDialog::StartSpellOptDlg_Impl()
{
    SfxItemSet aSet( SfxGetpApp()->GetPool(), svl::Items<SID_AUTOSPELL_CHECK,SID_AUTOSPELL_CHECK>{});
    SfxSingleTabDialogController aDlg(GetFrameWeld(), &aSet, "cui/ui/spelloptionsdialog.ui", "SpellOptionsDialog");
    SfxSingleTabDialogController aDlg(m_xDialog.get(), &aSet, "cui/ui/spelloptionsdialog.ui", "SpellOptionsDialog");

    TabPageParent aParent(aDlg.get_content_area(), &aDlg);
    VclPtr<SfxTabPage> xPage = SvxLinguTabPage::Create(aParent, &aSet);
@@ -530,54 +499,51 @@ namespace
    }
}


OUString SpellDialog::getReplacementString() const
{
    OUString sOrigString = m_pSentenceED->GetErrorText();
    OUString sOrigString = m_xSentenceED->GetErrorText();

    OUString sReplacement(sOrigString);

    if(m_pSuggestionLB->IsEnabled() &&
            m_pSuggestionLB->GetSelectedEntryCount()>0 &&
            m_sNoSuggestionsST != m_pSuggestionLB->GetSelectedEntry())
        sReplacement = m_pSuggestionLB->GetSelectedEntry();
    if(m_xSuggestionLB->get_sensitive() &&
            m_xSuggestionLB->get_selected_index() != -1 &&
            m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
        sReplacement = m_xSuggestionLB->get_selected_text();

    return getDotReplacementString(sOrigString, sReplacement);
}


IMPL_LINK_NOARG(SpellDialog, DoubleClickChangeHdl, ListBox&, void)
IMPL_LINK_NOARG(SpellDialog, DoubleClickChangeHdl, weld::TreeView&, void)
{
    ChangeHdl(nullptr);
    ChangeHdl(*m_xChangePB);
}

IMPL_LINK_NOARG(SpellDialog, ChangeHdl, Button*, void)
IMPL_LINK_NOARG(SpellDialog, ChangeHdl, weld::Button&, void)
{
    if(m_pSentenceED->IsUndoEditMode())
    if (m_xSentenceED->IsUndoEditMode())
    {
        SpellContinue_Impl();
    }
    else
    {
        m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
        m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
        OUString aString = getReplacementString();
        m_pSentenceED->ChangeMarkedWord(aString, GetSelectedLang_Impl());
        m_xSentenceED->ChangeMarkedWord(aString, GetSelectedLang_Impl());
        SpellContinue_Impl();
        m_pSentenceED->UndoActionEnd();
        m_xSentenceED->UndoActionEnd();
    }
    if(!m_pChangePB->IsEnabled())
        m_pIgnorePB->GrabFocus();
    if(!m_xChangePB->get_sensitive())
        m_xIgnorePB->grab_focus();
}


IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl, Button*, void)
IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl, weld::Button&, void)
{
    m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
    m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
    OUString aString = getReplacementString();
    LanguageType eLang = GetSelectedLang_Impl();

    // add new word to ChangeAll list
    OUString  aOldWord( m_pSentenceED->GetErrorText() );
    OUString  aOldWord( m_xSentenceED->GetErrorText() );
    SvxPrepareAutoCorrect( aOldWord, aString );
    Reference<XDictionary> aXDictionary( LinguMgr::GetChangeAllList(), UNO_QUERY );
    DictionaryError nAdded = AddEntryToDic( aXDictionary,
@@ -590,31 +556,31 @@ IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl, Button*, void)
                        SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
        pAction->SetDictionary(aXDictionary);
        pAction->SetAddedWord(aOldWord);
        m_pSentenceED->AddUndoAction(std::move(pAction));
        m_xSentenceED->AddUndoAction(std::move(pAction));
    }

    m_pSentenceED->ChangeMarkedWord(aString, eLang);
    m_xSentenceED->ChangeMarkedWord(aString, eLang);
    SpellContinue_Impl();
    m_pSentenceED->UndoActionEnd();
    m_xSentenceED->UndoActionEnd();
}


IMPL_LINK( SpellDialog, IgnoreAllHdl, Button *, pButton, void )
IMPL_LINK( SpellDialog, IgnoreAllHdl, weld::Button&, rButton, void )
{
    m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
    m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
    // add word to IgnoreAll list
    Reference< XDictionary > aXDictionary( LinguMgr::GetIgnoreAllList(), UNO_QUERY );
    //in case the error has been changed manually it has to be restored
    m_pSentenceED->RestoreCurrentError();
    if (pButton == m_pIgnoreRulePB)
    m_xSentenceED->RestoreCurrentError();
    if (&rButton == m_xIgnoreRulePB.get())
    {
        const SpellErrorDescription* pSpellErrorDescription = m_pSentenceED->GetAlternatives();
        SpellErrorDescription aSpellErrorDescription;
        bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
        try
        {
            if( pSpellErrorDescription && pSpellErrorDescription->xGrammarChecker.is() )
            if( bSpellErrorDescription && aSpellErrorDescription.xGrammarChecker.is() )
            {
                pSpellErrorDescription->xGrammarChecker->ignoreRule( pSpellErrorDescription->sRuleId,
                    pSpellErrorDescription->aLocale );
                aSpellErrorDescription.xGrammarChecker->ignoreRule(aSpellErrorDescription.sRuleId,
                    aSpellErrorDescription.aLocale);
                // refresh the layout (workaround to launch a dictionary event)
                aXDictionary->setActive(false);
                aXDictionary->setActive(true);
@@ -626,30 +592,29 @@ IMPL_LINK( SpellDialog, IgnoreAllHdl, Button *, pButton, void )
    }
    else
    {
        OUString sErrorText(m_pSentenceED->GetErrorText());
        OUString sErrorText(m_xSentenceED->GetErrorText());
        DictionaryError nAdded = AddEntryToDic( aXDictionary,
            sErrorText, false,
            OUString() );
        if(nAdded == DictionaryError::NONE)
        if (nAdded == DictionaryError::NONE)
        {
            std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
                            SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
            pAction->SetDictionary(aXDictionary);
            pAction->SetAddedWord(sErrorText);
            m_pSentenceED->AddUndoAction(std::move(pAction));
            m_xSentenceED->AddUndoAction(std::move(pAction));
        }
    }

    SpellContinue_Impl();
    m_pSentenceED->UndoActionEnd();
    m_xSentenceED->UndoActionEnd();
}


IMPL_LINK_NOARG(SpellDialog, UndoHdl, Button*, void)
IMPL_LINK_NOARG(SpellDialog, UndoHdl, weld::Button&, void)
{
    m_pSentenceED->Undo();
    if(!m_pSentenceED->GetUndoActionCount())
        m_pUndoPB->Enable(false);
    m_xSentenceED->Undo();
    if(!m_xSentenceED->GetUndoActionCount())
        m_xUndoPB->set_sensitive(false);
}


@@ -660,14 +625,14 @@ IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl&, rAction, void )
        case SPELLUNDO_CHANGE_TEXTENGINE:
        {
            if(rAction.IsEnableChangePB())
                m_pChangePB->Enable(false);
                m_xChangePB->set_sensitive(false);
            if(rAction.IsEnableChangeAllPB())
                m_pChangeAllPB->Enable(false);
                m_xChangeAllPB->set_sensitive(false);
        }
        break;
        case SPELLUNDO_CHANGE_NEXTERROR:
        {
            m_pSentenceED->MoveErrorMarkTo(static_cast<sal_Int32>(rAction.GetOldErrorStart()),
            m_xSentenceED->MoveErrorMarkTo(static_cast<sal_Int32>(rAction.GetOldErrorStart()),
                                           static_cast<sal_Int32>(rAction.GetOldErrorEnd()),
                                           false);
            if(rAction.IsErrorLanguageSelected())
@@ -685,7 +650,7 @@ IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl&, rAction, void )
        case SPELLUNDO_MOVE_ERROREND :
        {
            if(rAction.GetOffset() != 0)
                m_pSentenceED->MoveErrorEnd(rAction.GetOffset());
                m_xSentenceED->MoveErrorEnd(rAction.GetOffset());
        }
        break;
        case SPELLUNDO_UNDO_EDIT_MODE :
@@ -705,16 +670,16 @@ void SpellDialog::Impl_Restore(bool bUseSavedSentence)
    //clear the "ChangeAllList"
    LinguMgr::GetChangeAllList()->clear();
    //get a new sentence
    m_pSentenceED->SetText(OUString());
    m_pSentenceED->ResetModified();
    m_xSentenceED->SetText(OUString());
    m_xSentenceED->ResetModified();
    //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
    SpellContinue_Impl(bUseSavedSentence);
    m_pIgnorePB->SetText(m_sIgnoreOnceST);
    m_xIgnorePB->set_label(m_sIgnoreOnceST);
}

IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, Button*, void)
IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, weld::Button&, void)
{
    if (m_sResumeST == m_pIgnorePB->GetText())
    if (m_sResumeST == m_xIgnorePB->get_label())
    {
        Impl_Restore(false);
    }
@@ -722,35 +687,35 @@ IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, Button*, void)
    {
        //in case the error has been changed manually it has to be restored,
        // since the users choice now was to ignore the error
        m_pSentenceED->RestoreCurrentError();
        m_xSentenceED->RestoreCurrentError();

        // the word is being ignored
        SpellContinue_Impl( false, true );
    }
}


bool SpellDialog::Close()
void SpellDialog::Close()
{
    if (IsClosing())
        return;

    // We have to call ToggleChildWindow directly; calling SfxDispatcher's
    // Execute() does not work here when we are in a document with protected
    // section - in that case, the cursor can move from the editable field to
    // the protected area, and the slots get disabled because of
    // SfxDisableFlags::SwOnProtectedCursor (see FN_SPELL_GRAMMAR_DIALOG in .sdi).
    SfxViewFrame::Current()->ToggleChildWindow(rParent.GetType());

    return true;
    SfxViewFrame* pViewFrame = SfxViewFrame::Current();
    if (pViewFrame)
        pViewFrame->ToggleChildWindow(rParent.GetType());
}


LanguageType SpellDialog::GetSelectedLang_Impl() const
{
    LanguageType nLang = m_pLanguageLB->GetSelectedLanguage();
    LanguageType nLang = m_xLanguageLB->get_active_id();
    return nLang;
}


IMPL_LINK(SpellDialog, LanguageSelectHdl, ListBox&, rBox, void)
IMPL_LINK_NOARG(SpellDialog, LanguageSelectHdl, weld::ComboBox&, void)
{
    //If selected language changes, then add->list should be regenerated to
    //match
@@ -758,37 +723,36 @@ IMPL_LINK(SpellDialog, LanguageSelectHdl, ListBox&, rBox, void)

    //if currently an error is selected then search for alternatives for
    //this word and fill the alternatives ListBox accordingly
    OUString sError = m_pSentenceED->GetErrorText();
    m_pSuggestionLB->Clear();
    if(!sError.isEmpty())
    OUString sError = m_xSentenceED->GetErrorText();
    m_xSuggestionLB->clear();
    if (!sError.isEmpty())
    {
        LanguageType eLanguage = static_cast<SvxLanguageBox*>(&rBox)->GetSelectedLanguage();
        LanguageType eLanguage = m_xLanguageLB->get_active_id();
        Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, static_cast<sal_uInt16>(eLanguage),
                                            Sequence< PropertyValue >() );
        if( xAlt.is() )
            m_pSentenceED->SetAlternatives( xAlt );
            m_xSentenceED->SetAlternatives( xAlt );
        else
        {
            m_pSentenceED->ChangeMarkedWord( sError, eLanguage );
            m_xSentenceED->ChangeMarkedWord( sError, eLanguage );
            SpellContinue_Impl();
        }

        m_pSentenceED->AddUndoAction(std::make_unique<SpellUndoAction_Impl>(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
        m_xSentenceED->AddUndoAction(std::make_unique<SpellUndoAction_Impl>(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
    }
    SpellDialog::UpdateBoxes_Impl(true);
}


void SpellDialog::SetTitle_Impl(LanguageType nLang)
{
    OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
    sTitle = sTitle.replaceFirst( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
    SetText( sTitle );
    m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle));
}

int SpellDialog::InitUserDicts()
{
    const LanguageType nLang = m_pLanguageLB->GetSelectedLanguage();
    const LanguageType nLang = m_xLanguageLB->get_active_id();

    const Reference< XDictionary >  *pDic = nullptr;

@@ -812,10 +776,7 @@ int SpellDialog::InitUserDicts()
    bool bEnable = false;
    const sal_Int32 nSize = pImpl->aDics.getLength();
    pDic = pImpl->aDics.getConstArray();
    PopupMenu* pMenu = m_pAddToDictMB->GetPopupMenu();
    assert(pMenu);
    pMenu->Clear();
    pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics);
    m_xAddToDictMB->clear();
    sal_uInt16 nItemId = 1;     // menu items should be enumerated from 1 and not 0
    for (sal_Int32 i = 0; i < nSize; ++i)
    {
@@ -830,57 +791,51 @@ int SpellDialog::InitUserDicts()
            && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
            && (!xStor.is() || !xStor->isReadonly()) )
        {
            pMenu->InsertItem( nItemId, xDicTmp->getName() );
            bEnable = true;

            OUString aDictionaryImageUrl;
            uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
            if (xSvcInfo.is())
            {
                OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage(
                        xSvcInfo->getImplementationName()) );
                if (!aDictionaryImageUrl.isEmpty())
                {
                    Image aImage( aDictionaryImageUrl );
                    pMenu->SetItemImage( nItemId, aImage );
                }
                aDictionaryImageUrl = aCfg.GetSpellAndGrammarContextDictionaryImage(
                        xSvcInfo->getImplementationName());
            }

            m_xAddToDictMB->append_item(OUString::number(nItemId), xDicTmp->getName(), aDictionaryImageUrl);

            ++nItemId;
        }
    }
    m_pAddToDictMB->Enable( bEnable );
    m_pAddToDictPB->Enable( bEnable );
    m_xAddToDictMB->set_sensitive( bEnable );
    m_xAddToDictPB->set_sensitive( bEnable );

    int nDicts = nItemId-1;

    m_pAddToDictMB->Show( nDicts > 1 );
    m_pAddToDictPB->Show( nDicts <= 1 );
    m_xAddToDictMB->set_visible( nDicts > 1 );
    m_xAddToDictPB->set_visible( nDicts <= 1 );

    return nDicts;
}


IMPL_LINK_NOARG(SpellDialog, AddToDictClickHdl, Button*, void)
IMPL_LINK_NOARG(SpellDialog, AddToDictClickHdl, weld::Button&, void)
{
    AddToDictionaryExecute(1, m_pAddToDictMB->GetPopupMenu());
    AddToDictionaryExecute(OString::number(1));
}


IMPL_LINK(SpellDialog, AddToDictSelectHdl, MenuButton*, pButton, void )
IMPL_LINK(SpellDialog, AddToDictSelectHdl, const OString&, rIdent, void)
{
    AddToDictionaryExecute(pButton->GetCurItemId(), pButton->GetPopupMenu());
    AddToDictionaryExecute(rIdent);
}


void SpellDialog::AddToDictionaryExecute( sal_uInt16 nItemId, PopupMenu const *pMenu )
void SpellDialog::AddToDictionaryExecute(const OString& rItemId)
{
    m_pSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );
    m_xSentenceED->UndoActionStart( SPELLUNDO_CHANGE_GROUP );

    //GetErrorText() returns the current error even if the text is already
    //manually changed
    const OUString aNewWord = m_pSentenceED->GetErrorText();
    const OUString aNewWord = m_xSentenceED->GetErrorText();

    OUString aDicName ( pMenu->GetItemText( nItemId ) );
    OUString aDicName(m_xAddToDictMB->get_item_label(rItemId));

    uno::Reference< linguistic2::XDictionary >      xDic;
    uno::Reference< linguistic2::XSearchableDictionaryList >  xDicList( LinguMgr::GetDictionaryList() );
@@ -902,7 +857,7 @@ void SpellDialog::AddToDictionaryExecute( sal_uInt16 nItemId, PopupMenu const *p
                            SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
            pAction->SetDictionary( xDic );
            pAction->SetAddedWord( aNewWord );
            m_pSentenceED->AddUndoAction( std::move(pAction) );
            m_xSentenceED->AddUndoAction( std::move(pAction) );
        }
        // failed because there is already an entry?
        if (DictionaryError::NONE != nAddRes && xDic->getEntry( aNewWord ).is())
@@ -910,48 +865,42 @@ void SpellDialog::AddToDictionaryExecute( sal_uInt16 nItemId, PopupMenu const *p
    }
    if (DictionaryError::NONE != nAddRes)
    {
        SvxDicError(GetFrameWeld(), nAddRes);
        SvxDicError(m_xDialog.get(), nAddRes);
        return; // don't continue
    }

    // go on
    SpellContinue_Impl();
    m_pSentenceED->UndoActionEnd();
    m_xSentenceED->UndoActionEnd();
}


IMPL_LINK(SpellDialog, ModifyHdl, Edit&, rEd, void)
IMPL_LINK_NOARG(SpellDialog, ModifyHdl, LinkParamNone*, void)
{
    if (m_pSentenceED == &rEd)
    m_xSuggestionLB->unselect_all();
    m_xSuggestionLB->set_sensitive(false);
    m_xAutoCorrPB->set_sensitive(false);
    std::unique_ptr<SpellUndoAction_Impl> pSpellAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink));
    if(!m_xChangeAllPB->get_sensitive())
    {
        m_pSuggestionLB->SetNoSelection();
        m_pSuggestionLB->Disable();
        m_pAutoCorrPB->Disable();
        std::unique_ptr<SpellUndoAction_Impl> pSpellAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink));
        if(!m_pChangeAllPB->IsEnabled())
        {
            m_pChangeAllPB->Enable();
            pSpellAction->SetEnableChangeAllPB();
        }
        if(!m_pChangePB->IsEnabled())
        {
            m_pChangePB->Enable();
            pSpellAction->SetEnableChangePB();
        }
        m_pSentenceED->AddUndoAction(std::move(pSpellAction));
        m_xChangeAllPB->set_sensitive(true);
        pSpellAction->SetEnableChangeAllPB();
    }
};
    if(!m_xChangePB->get_sensitive())
    {
        m_xChangePB->set_sensitive(true);
        pSpellAction->SetEnableChangePB();
    }
    m_xSentenceED->AddUndoAction(std::move(pSpellAction));
}


IMPL_LINK_NOARG(SpellDialog, CancelHdl, Button*, void)
IMPL_LINK_NOARG(SpellDialog, CancelHdl, weld::Button&, void)
{
    //apply changes and ignored text parts first - if there are any
    rParent.ApplyChangedSentence(m_pSentenceED->CreateSpellPortions(), false);
    rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), false);
    Close();
}


bool SpellDialog::EventNotify( NotifyEvent& rNEvt )
void SpellDialog::ToplevelFocusChanged()
{
    /* #i38338#
    *   FIXME: LoseFocus and GetFocus are signals from vcl that
@@ -962,66 +911,75 @@ bool SpellDialog::EventNotify( NotifyEvent& rNEvt )
    *   The only sensible thing would be to call the new Method differently,
    *   e.g. DialogGot/LostFocus or so.
    */
    if( IsVisible() && !bFocusLocked )
    if (m_xDialog->get_visible() && !bFocusLocked)
    {
        if( rNEvt.GetType() ==  MouseNotifyEvent::GETFOCUS )
        if (m_xDialog->has_toplevel_focus())
        {
            //notify the child window of the focus change
            rParent.GetFocus();
        }
        else if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
        else
        {
            //notify the child window of the focus change
            rParent.LoseFocus();
        }
    }
    return SfxModelessDialog::EventNotify(rNEvt);
}

void SpellDialog::Activate()
{
    SfxModelessDialogController::Activate();
    ToplevelFocusChanged();
}

void SpellDialog::Deactivate()
{
    SfxModelessDialogController::Activate();
    ToplevelFocusChanged();
}

void SpellDialog::InvalidateDialog()
{
    if( bFocusLocked )
        return;
    m_pIgnorePB->SetText(m_sResumeST);
    vcl::Window* aDisableArr[] =
    m_xIgnorePB->set_label(m_sResumeST);
    weld::Widget* aDisableArr[] =
    {
        m_pNotInDictFT,
        m_pSentenceED,
        m_pSuggestionFT,
        m_pSuggestionLB,
        m_pLanguageFT,
        m_pLanguageLB,
        m_pIgnoreAllPB,
        m_pIgnoreRulePB,
        m_pAddToDictMB,
        m_pAddToDictPB,
        m_pChangePB,
        m_pChangeAllPB,
        m_pAutoCorrPB,
        m_pUndoPB,
        m_xNotInDictFT.get(),
        m_xSentenceED->GetDrawingArea(),
        m_xSuggestionFT.get(),
        m_xSuggestionLB.get(),
        m_xLanguageFT.get(),
        m_xLanguageLB->get_widget(),
        m_xIgnoreAllPB.get(),
        m_xIgnoreRulePB.get(),
        m_xAddToDictMB.get(),
        m_xAddToDictPB.get(),
        m_xChangePB.get(),
        m_xChangeAllPB.get(),
        m_xAutoCorrPB.get(),
        m_xUndoPB.get(),
        nullptr
    };
    sal_Int16 i = 0;
    while(aDisableArr[i])
    {
        aDisableArr[i]->Enable(false);
        aDisableArr[i]->set_sensitive(false);
        i++;
    }
    SfxModelessDialog::Deactivate();
    SfxModelessDialogController::Deactivate();
}


bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
{
    bool bRet = false;
    if(!bUseSavedSentence)
    {
        //apply changes and ignored text parts
        rParent.ApplyChangedSentence(m_pSentenceED->CreateSpellPortions(), bRecheck);
        rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), bRecheck);
    }
    m_pSentenceED->ResetIgnoreErrorsAt();
    m_pSentenceED->ResetModified();
    m_xSentenceED->ResetIgnoreErrorsAt();
    m_xSentenceED->ResetModified();
    SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
    if(!bUseSavedSentence)
        m_aSavedSentence = aSentence;
@@ -1049,7 +1007,7 @@ bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
            if(!elem.bIsHidden)
                sText.append(elem.sText);
        }
        m_pSentenceED->SetText(sText.makeStringAndClear());
        m_xSentenceED->SetText(sText.makeStringAndClear());
        sal_Int32 nStartPosition = 0;
        sal_Int32 nEndPosition = 0;

@@ -1067,7 +1025,9 @@ bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
                        sServiceName = xNamed->getName();
                    SpellErrorDescription aDesc( false, elem.xAlternatives->getWord(),
                                    elem.xAlternatives->getLocale(), elem.xAlternatives->getAlternatives(), nullptr);
                    m_pSentenceED->SetAttrib( SpellErrorAttrib(aDesc), 0, nStartPosition, nEndPosition );
                    SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
                    aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
                    m_xSentenceED->SetAttrib(aSpellErrorDescription, nStartPosition, nEndPosition);
                }
                else if(elem.bIsGrammarError )
                {
@@ -1093,19 +1053,23 @@ bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
                        &elem.aGrammarError.aFullComment,
                        &elem.aGrammarError.aRuleIdentifier,
                        &sFullCommentURL );
                    m_pSentenceED->SetAttrib( SpellErrorAttrib(aDesc), 0, nStartPosition, nEndPosition );

                    SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
                    aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
                    m_xSentenceED->SetAttrib(aSpellErrorDescriptionItem, nStartPosition, nEndPosition);
                }
                if(elem.bIsField)
                    m_pSentenceED->SetAttrib( SpellBackgroundAttrib(COL_LIGHTGRAY), 0, nStartPosition, nEndPosition );
                m_pSentenceED->SetAttrib( SpellLanguageAttrib(elem.eLanguage), 0, nStartPosition, nEndPosition );

                if (elem.bIsField)
                    m_xSentenceED->SetAttrib(SvxBackgroundColorItem(COL_LIGHTGRAY, EE_CHAR_BKGCOLOR), nStartPosition, nEndPosition);
                m_xSentenceED->SetAttrib(SvxLanguageItem(elem.eLanguage, EE_CHAR_LANGUAGE), nStartPosition, nEndPosition);
                nStartPosition = nEndPosition;
            }
        }
        //the edit field needs to be modified to apply the change from the ApplyChangeAllList
        if(!bHasReplaced)
            m_pSentenceED->ClearModifyFlag();
        m_pSentenceED->ResetUndo();
        m_pUndoPB->Enable(false);
            m_xSentenceED->ClearModifyFlag();
        m_xSentenceED->ResetUndo();
        m_xUndoPB->set_sensitive(false);
        bRet = nStartPosition > 0;
    }
    return bRet;
@@ -1145,26 +1109,149 @@ bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasRe
    return bRet;
}


SentenceEditWindow_Impl::SentenceEditWindow_Impl(vcl::Window * pParent, WinBits nBits)
    : VclMultiLineEdit(pParent, nBits)
    , m_nErrorStart(0)
SentenceEditWindow_Impl::SentenceEditWindow_Impl()
    : m_nErrorStart(0)
    , m_nErrorEnd(0)
    , m_bIsUndoEditMode(false)
{
    DisableSelectionOnFocus();
}

void SentenceEditWindow_Impl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
{
    Size aSize(pDrawingArea->get_approximate_digit_width() * 60,
               pDrawingArea->get_text_height() * 6);

    pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
    SetOutputSizePixel(aSize);

    weld::CustomWidgetController::SetDrawingArea(pDrawingArea);

    EnableRTL(false);

    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    Color aBgColor = rStyleSettings.GetWindowColor();

    OutputDevice& rDevice = pDrawingArea->get_ref_device();

    rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
    rDevice.SetBackground(aBgColor);

    Size aOutputSize(rDevice.PixelToLogic(aSize));
    aSize = aOutputSize;
    aSize.setHeight( aSize.Height() * 4 );

    m_xEditEngine.reset(new EditEngine(EditEngine::CreatePool()));
    m_xEditEngine->SetPaperSize( aSize );
    m_xEditEngine->SetRefDevice( &rDevice );

    m_xEditEngine->SetControlWord(m_xEditEngine->GetControlWord() | EEControlBits::MARKFIELDS);

    m_xEdView.reset(new EditView(m_xEditEngine.get(), nullptr));
    m_xEdView->setEditViewCallbacks(this);
    m_xEdView->SetOutputArea(tools::Rectangle(Point(0,0), aOutputSize));

    m_xEdView->SetBackgroundColor(aBgColor);
    m_xEditEngine->InsertView(m_xEdView.get());

    pDrawingArea->set_cursor(PointerStyle::Text);
}

void SentenceEditWindow_Impl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
    //note: ClassificationEditView::Paint is similar

    rRenderContext.Push(PushFlags::ALL);
    rRenderContext.SetClipRegion();

    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    Color aBgColor = rStyleSettings.GetWindowColor();

    m_xEdView->SetBackgroundColor(aBgColor);

    rRenderContext.SetBackground(aBgColor);

    tools::Rectangle aLogicRect(rRenderContext.PixelToLogic(rRect));
    m_xEdView->Paint(aLogicRect, &rRenderContext);

    if (HasFocus())
    {
        m_xEdView->ShowCursor();
        vcl::Cursor* pCursor = m_xEdView->GetCursor();
        pCursor->DrawToDevice(rRenderContext);
    }

    std::vector<tools::Rectangle> aLogicRects;

    // get logic selection
    m_xEdView->GetSelectionRectangles(aLogicRects);

    rRenderContext.SetLineColor();
    rRenderContext.SetFillColor(COL_BLACK);
    rRenderContext.SetRasterOp(RasterOp::Invert);

    for (const auto &rSelectionRect : aLogicRects)
        rRenderContext.DrawRect(rSelectionRect);

    rRenderContext.Pop();
}

bool SentenceEditWindow_Impl::MouseMove(const MouseEvent& rMEvt)
{
    return m_xEdView->MouseMove(rMEvt);
}

bool SentenceEditWindow_Impl::MouseButtonDown(const MouseEvent& rMEvt)
{
    if (!HasFocus())
        GrabFocus();

    return m_xEdView->MouseButtonDown(rMEvt);
}

bool SentenceEditWindow_Impl::MouseButtonUp(const MouseEvent& rMEvt)
{
    return m_xEdView->MouseButtonUp(rMEvt);
}

void SentenceEditWindow_Impl::Resize()
{
    OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
    Size aOutputSize(rDevice.PixelToLogic(GetOutputSizePixel()));
    Size aSize(aOutputSize);
    aSize.setHeight( aSize.Height() * 4 );
    m_xEditEngine->SetPaperSize(aSize);
    m_xEdView->SetOutputArea(tools::Rectangle(Point(0,0), aOutputSize));
    weld::CustomWidgetController::Resize();
}

SentenceEditWindow_Impl::~SentenceEditWindow_Impl()
{
    disposeOnce();
}

extern "C" SAL_DLLPUBLIC_EXPORT void makeSentenceEditWindow(VclPtr<vcl::Window> & rRet, VclPtr<vcl::Window> & pParent, VclBuilder::stringmap &)
namespace
{
    rRet = VclPtr<SentenceEditWindow_Impl>::Create(pParent, WB_BORDER|WB_VSCROLL|WB_IGNORETAB);
}
    const EECharAttrib* FindCharAttrib(int nStartPosition, int nEndPosition, sal_uInt16 nWhich, std::vector<EECharAttrib>& rAttribList)
    {
        for (const auto& rTextAtr : rAttribList)
        {
            if (rTextAtr.pAttr->Which() != nWhich)
                continue;
            if (rTextAtr.nStart <= nStartPosition && rTextAtr.nEnd >= nEndPosition)
            {
                return &rTextAtr;
            }
        }

        return nullptr;
    }

    void ExtractErrorDescription(const EECharAttrib& rEECharAttrib, SpellErrorDescription& rSpellErrorDescription)
    {
        css::uno::Sequence<css::uno::Any> aSequence;
        static_cast<const SfxGrabBagItem*>(rEECharAttrib.pAttr)->GetGrabBag().find("SpellErrorDescription")->second >>= aSequence;
        rSpellErrorDescription.fromSequence(aSequence);
    }
}

/*-------------------------------------------------------------------------
    The selection before inputting a key may have a range or not
@@ -1239,309 +1326,312 @@ extern "C" SAL_DLLPUBLIC_EXPORT void makeSentenceEditWindow(VclPtr<vcl::Window> 
#define ACTION_SELECTFIELD 2
#define ACTION_EXPAND      3

bool SentenceEditWindow_Impl::PreNotify( NotifyEvent& rNEvt )
bool SentenceEditWindow_Impl::KeyInput(const KeyEvent& rKeyEvt)
{
    bool bChange = false;
    if(rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
    if (rKeyEvt.GetKeyCode().GetCode() == KEY_TAB)
        return false;

    bool bConsumed = false;

    bool bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
    if (bChange && !IsUndoEditMode())
    {
        const KeyEvent& rKeyEvt = *rNEvt.GetKeyEvent();
        bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
        if(bChange && !IsUndoEditMode() &&
            rKeyEvt.GetKeyCode().GetCode() != KEY_TAB)
        bConsumed = true;

        ESelection aCurrentSelection(m_xEdView->GetSelection());
        aCurrentSelection.Adjust();

        //determine if the selection contains a field
        bool bHasFieldLeft = false;
        bool bHasErrorLeft = false;

        bool bHasRange = aCurrentSelection.HasRange();
        sal_uInt8 nSelectionType = 0; // invalid type!

        std::vector<EECharAttrib> aAttribList;
        m_xEditEngine->GetCharAttribs(0, aAttribList);

        auto nCursor = aCurrentSelection.nStartPos;
        const EECharAttrib* pBackAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_BKGCOLOR, aAttribList);
        const EECharAttrib* pErrorAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
        const EECharAttrib* pBackAttrLeft = nullptr;
        const EECharAttrib* pErrorAttrLeft = nullptr;

        bool bHasField = pBackAttr != nullptr && (bHasRange || pBackAttr->nEnd > nCursor);
        bool bHasError = pErrorAttr != nullptr && (bHasRange || pErrorAttr->nEnd > nCursor);
        if (bHasRange)
        {
            TextEngine* pTextEngine = GetTextEngine();
            TextView* pTextView = pTextEngine->GetActiveView();
            TextSelection aCurrentSelection = pTextView->GetSelection();
            aCurrentSelection.Justify();
            //determine if the selection contains a field
            bool bHasFieldLeft = false;
            bool bHasErrorLeft = false;

            bool bHasRange = aCurrentSelection.HasRange();
            sal_uInt8 nSelectionType = 0; // invalid type!

            TextPaM aCursor(aCurrentSelection.GetStart());
            const TextCharAttrib* pBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
            const TextCharAttrib* pErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
            const TextCharAttrib* pBackAttrLeft = nullptr;
            const TextCharAttrib* pErrorAttrLeft = nullptr;

            bool bHasField = pBackAttr != nullptr && (bHasRange || pBackAttr->GetEnd() > aCursor.GetIndex());
            bool bHasError = pErrorAttr != nullptr && (bHasRange || pErrorAttr->GetEnd() > aCursor.GetIndex());
            if(bHasRange)
            if (pBackAttr &&
                    pBackAttr->nStart == aCurrentSelection.nStartPos &&
                    pBackAttr->nEnd == aCurrentSelection.nEndPos)
            {
                if(pBackAttr &&
                        pBackAttr->GetStart() == aCurrentSelection.GetStart().GetIndex() &&
                        pBackAttr->GetEnd() == aCurrentSelection.GetEnd().GetIndex())
                {
                    nSelectionType = FULL;
                }
                else if(pErrorAttr &&
                        pErrorAttr->GetStart() <= aCurrentSelection.GetStart().GetIndex() &&
                        pErrorAttr->GetEnd() >= aCurrentSelection.GetEnd().GetIndex())
                {
                    nSelectionType = INSIDE_YES;
                }
                else
                {
                    nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
                    while(aCursor.GetIndex() < aCurrentSelection.GetEnd().GetIndex())
                    {
                        ++aCursor.GetIndex();
                        const TextCharAttrib* pIntBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
                        const TextCharAttrib* pIntErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
                        //if any attr has been found then BRACE
                        if(pIntBackAttr || pIntErrorAttr)
                            nSelectionType = BRACE;
                        //the field has to be selected
                        if(pIntBackAttr && !pBackAttr)
                            pBackAttr = pIntBackAttr;
                        bHasField |= pIntBackAttr != nullptr;
                    }
                }
                nSelectionType = FULL;
            }
            else if (pErrorAttr &&
                     pErrorAttr->nStart <= aCurrentSelection.nStartPos &&
                     pErrorAttr->nEnd >= aCurrentSelection.nEndPos)
            {
                nSelectionType = INSIDE_YES;
            }
            else
            {
                //no range selection: then 1 2 3 and 8 are possible
                const TextCharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
                if(pCurAttr)
                nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
                while (nCursor < aCurrentSelection.nEndPos)
                {
                    nSelectionType = pCurAttr->GetStart() == aCurrentSelection.GetStart().GetIndex() ?
                            LEFT_NO : pCurAttr->GetEnd() == aCurrentSelection.GetEnd().GetIndex() ? RIGHT_NO : INSIDE_NO;
                }
                else
                    nSelectionType = OUTSIDE_NO;

                bHasFieldLeft = pBackAttr && pBackAttr->GetEnd() == aCursor.GetIndex();
                if(bHasFieldLeft)
                {
                    pBackAttrLeft = pBackAttr;
                    pBackAttr = nullptr;
                }
                bHasErrorLeft = pErrorAttr && pErrorAttr->GetEnd() == aCursor.GetIndex();
                if(bHasErrorLeft)
                {
                    pErrorAttrLeft = pErrorAttr;
                    pErrorAttr = nullptr;
                }

                //check previous position if this exists
                //that is a redundant in the case the attribute found above already is on the left cursor side
                //but it's o.k. for two errors/fields side by side
                if(aCursor.GetIndex())
                {
                    --aCursor.GetIndex();
                    pBackAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
                    pErrorAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
                    bHasFieldLeft = pBackAttrLeft !=nullptr;
                    bHasErrorLeft = pErrorAttrLeft != nullptr;
                    ++aCursor.GetIndex();
                    ++nCursor;
                    const EECharAttrib* pIntBackAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_BKGCOLOR, aAttribList);
                    const EECharAttrib* pIntErrorAttr = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
                    //if any attr has been found then BRACE
                    if (pIntBackAttr || pIntErrorAttr)
                        nSelectionType = BRACE;
                    //the field has to be selected
                    if (pIntBackAttr && !pBackAttr)
                        pBackAttr = pIntBackAttr;
                    bHasField |= pIntBackAttr != nullptr;
                }
            }
            //Here we have to determine if the error found is the one currently active
            bool bIsErrorActive = (pErrorAttr && pErrorAttr->GetStart() == m_nErrorStart) ||
                    (pErrorAttrLeft && pErrorAttrLeft->GetStart() == m_nErrorStart);

            SAL_WARN_IF(
                nSelectionType == INVALID, "cui.dialogs",
                "selection type not set");

            const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
            bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
            bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;

            sal_Int8 nAction = ACTION_CONTINUE;
            switch(nSelectionType)
            {
//    1 - backspace                   delete                      any other
//        UE                          on field FS on error CO     on field FS on error CO
                case LEFT_NO    :
                    if(bBackspace)
                    {
                        nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
                        //to force the use of pBackAttrLeft
                        pBackAttr = nullptr;
                    }
                    else if(bDelete)
                        nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
                    else
                        nAction = bHasError && !aCursor.GetIndex() ? ACTION_CONTINUE :
                            bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
                break;
//    2 - on field FS on error C
                case INSIDE_NO  :
                    nAction =  bHasField ? ACTION_SELECTFIELD :
                        bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
                break;
//    3 - backspace                   delete                      any other
//        on field FS on error CO     UE                          on field UE on error EX
                case RIGHT_NO   :
                    if(bBackspace)
                        nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
                    else if(bDelete)
                        nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
                    else
                        nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
                            bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
                break;
//    4 - on field UE and on error CO
                case FULL       :
                    nAction = ACTION_UNDOEDIT;
                break;
//    5 - on field FS and on error CO
                case INSIDE_YES :
                    nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
                break;
//    6 - on field FS and on error UE
                case BRACE      :
                    nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
                break;
//    7 - UE
//    8 - UE
                case OUTSIDE_NO :
                case OUTSIDE_YES:
                    nAction = ACTION_UNDOEDIT;
                break;
            }
            //save the current paragraph
            sal_Int32 nCurrentLen = GetText().getLength();
            if(nAction != ACTION_SELECTFIELD)
                pTextView->GetWindow()->KeyInput(rKeyEvt);
            else
            {
                const TextCharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
                if(pCharAttr)
                {
                    TextPaM aStart(0, pCharAttr->GetStart());
                    TextPaM aEnd(0, pCharAttr->GetEnd());
                    TextSelection aNewSel(aStart, aEnd);
                    pTextView->SetSelection( aNewSel);
                }
            }
            if(nAction == ACTION_EXPAND)
            {
                DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
                //text has been added on the right and only the 'error attribute has to be corrected
                if(pErrorAttrLeft)
                {
                    std::unique_ptr<TextAttrib> pNewError(pErrorAttrLeft->GetAttr().Clone());
                    const sal_Int32 nStart = pErrorAttrLeft->GetStart();
                    sal_Int32 nEnd = pErrorAttrLeft->GetEnd();
                    pTextEngine->RemoveAttrib( 0, *pErrorAttrLeft );
                    SetAttrib( *pNewError, 0, nStart, ++nEnd );
                    //only active errors move the mark
                    if(bIsErrorActive)
                    {
                        bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
                        MoveErrorMarkTo(nStart, nEnd, bGrammar);
                    }
                }
                //text has been added on the left then the error attribute has to be expanded and the
                //field attribute on the right - if any - has to be contracted
                else if(pErrorAttr)
                {
                    //determine the change
                    sal_Int32 nAddedChars = GetText().getLength() - nCurrentLen;

                    std::unique_ptr<TextAttrib> pNewError(pErrorAttr->GetAttr().Clone());
                    sal_Int32 nStart = pErrorAttr->GetStart();
                    sal_Int32 nEnd = pErrorAttr->GetEnd();
                    pTextEngine->RemoveAttrib( 0, *pErrorAttr );
                    nStart = nStart - nAddedChars;
                    SetAttrib( *pNewError, 0, nStart - nAddedChars, nEnd );
                    //only if the error is active the mark is moved here
                    if(bIsErrorActive)
                    {
                        bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
                        MoveErrorMarkTo(nStart, nEnd, bGrammar);
                    }
                    pNewError.reset();

                    if(pBackAttrLeft)
                    {
                        std::unique_ptr<TextAttrib> pNewBack(pBackAttrLeft->GetAttr().Clone());
                        const sal_Int32 _nStart = pBackAttrLeft->GetStart();
                        const sal_Int32 _nEnd = pBackAttrLeft->GetEnd();
                        pTextEngine->RemoveAttrib( 0, *pBackAttrLeft );
                        SetAttrib( *pNewBack, 0, _nStart, _nEnd - nAddedChars);
                    }
                }
            }
            else if(nAction == ACTION_UNDOEDIT)
            {
                SetUndoEditMode(true);
            }
            //make sure the error positions are correct after text changes
            //the old attribute may have been deleted
            //all changes inside of the current error leave the error attribute at the current
            //start position
            if(!IsUndoEditMode() && bIsErrorActive)
            {
                const TextCharAttrib* pFontColor = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_FONTCOLOR );
                const TextCharAttrib*  pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
                if(pFontColor && pErrorAttrib )
                {
                    m_nErrorStart = pFontColor->GetStart();
                    m_nErrorEnd = pFontColor->GetEnd();
                    if(pErrorAttrib->GetStart() != m_nErrorStart || pErrorAttrib->GetEnd() != m_nErrorEnd)
                    {
                        std::unique_ptr<TextAttrib> pNewError(pErrorAttrib->GetAttr().Clone());
                        pTextEngine->RemoveAttrib( 0, *pErrorAttr );
                        SetAttrib( *pNewError, 0, m_nErrorStart, m_nErrorEnd );
                    }
                }
            }
            //this is not a modification anymore
            if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
                CallModifyLink();
        }
        else
            bChange = false;
        {
            //no range selection: then 1 2 3 and 8 are possible
            const EECharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
            if (pCurAttr)
            {
                nSelectionType = pCurAttr->nStart == aCurrentSelection.nStartPos ?
                        LEFT_NO : pCurAttr->nEnd == aCurrentSelection.nEndPos ? RIGHT_NO : INSIDE_NO;
            }
            else
                nSelectionType = OUTSIDE_NO;

            bHasFieldLeft = pBackAttr && pBackAttr->nEnd == nCursor;
            if(bHasFieldLeft)
            {
                pBackAttrLeft = pBackAttr;
                pBackAttr = nullptr;
            }
            bHasErrorLeft = pErrorAttr && pErrorAttr->nEnd == nCursor;
            if(bHasErrorLeft)
            {
                pErrorAttrLeft = pErrorAttr;
                pErrorAttr = nullptr;
            }

            //check previous position if this exists
            //that is a redundant in the case the attribute found above already is on the left cursor side
            //but it's o.k. for two errors/fields side by side
            if (nCursor)
            {
                --nCursor;
                pBackAttrLeft = FindCharAttrib(nCursor, nCursor, EE_CHAR_BKGCOLOR, aAttribList);
                pErrorAttrLeft = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
                bHasFieldLeft = pBackAttrLeft !=nullptr;
                bHasErrorLeft = pErrorAttrLeft != nullptr;
                ++nCursor;
            }
        }
        //Here we have to determine if the error found is the one currently active
        bool bIsErrorActive = (pErrorAttr && pErrorAttr->nStart == m_nErrorStart) ||
                (pErrorAttrLeft && pErrorAttrLeft->nStart == m_nErrorStart);

        SAL_WARN_IF(
            nSelectionType == INVALID, "cui.dialogs",
            "selection type not set");

        const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
        bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
        bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;

        sal_Int8 nAction = ACTION_CONTINUE;
        switch(nSelectionType)
        {
//    1 - backspace                   delete                      any other
//        UE                          on field FS on error CO     on field FS on error CO
            case LEFT_NO    :
                if(bBackspace)
                {
                    nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
                    //to force the use of pBackAttrLeft
                    pBackAttr = nullptr;
                }
                else if(bDelete)
                    nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
                else
                    nAction = bHasError && !nCursor ? ACTION_CONTINUE :
                        bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
            break;
//    2 - on field FS on error C
            case INSIDE_NO  :
                nAction =  bHasField ? ACTION_SELECTFIELD :
                    bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
            break;
//    3 - backspace                   delete                      any other
//        on field FS on error CO     UE                          on field UE on error EX
            case RIGHT_NO   :
                if(bBackspace)
                    nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
                else if(bDelete)
                    nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
                else
                    nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
                        bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
            break;
//    4 - on field UE and on error CO
            case FULL       :
                nAction = ACTION_UNDOEDIT;
            break;
//    5 - on field FS and on error CO
            case INSIDE_YES :
                nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
            break;
//    6 - on field FS and on error UE
            case BRACE      :
                nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
            break;
//    7 - UE
//    8 - UE
            case OUTSIDE_NO :
            case OUTSIDE_YES:
                nAction = ACTION_UNDOEDIT;
            break;
        }
        //save the current paragraph
        sal_Int32 nCurrentLen = m_xEditEngine->GetText().getLength();
        if (nAction != ACTION_SELECTFIELD)
        {
            m_xEdView->PostKeyEvent(rKeyEvt);
        }
        else
        {
            const EECharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
            if (pCharAttr)
                m_xEdView->SetSelection(ESelection(0, pCharAttr->nStart, 0, pCharAttr->nEnd));
        }
        if(nAction == ACTION_EXPAND)
        {
            DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
            //text has been added on the right and only the 'error attribute has to be corrected
            if (pErrorAttrLeft)
            {
                SpellErrorDescription aSpellErrorDescription;
                ExtractErrorDescription(*pErrorAttrLeft, aSpellErrorDescription);

                std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrLeft->pAttr->Clone());
                sal_Int32 nStart = pErrorAttrLeft->nStart;
                sal_Int32 nEnd = pErrorAttrLeft->nEnd + 1;
                m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
                SetAttrib(*xNewError, nStart, nEnd);
                //only active errors move the mark
                if (bIsErrorActive)
                {
                    bool bGrammar = aSpellErrorDescription.bIsGrammarError;
                    MoveErrorMarkTo(nStart, nEnd, bGrammar);
                }
            }
            //text has been added on the left then the error attribute has to be expanded and the
            //field attribute on the right - if any - has to be contracted
            else if (pErrorAttr)
            {
                SpellErrorDescription aSpellErrorDescription;
                ExtractErrorDescription(*pErrorAttr, aSpellErrorDescription);

                //determine the change
                sal_Int32 nAddedChars = m_xEditEngine->GetText().getLength() - nCurrentLen;

                std::unique_ptr<SfxPoolItem> xNewError(pErrorAttr->pAttr->Clone());
                sal_Int32 nStart = pErrorAttr->nStart + nAddedChars;
                sal_Int32 nEnd = pErrorAttr->nEnd + nAddedChars;
                m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
                nStart = pErrorAttr->nStart;
                SetAttrib(*xNewError, nStart, nEnd);
                //only if the error is active the mark is moved here
                if (bIsErrorActive)
                {
                    bool bGrammar = aSpellErrorDescription.bIsGrammarError;
                    MoveErrorMarkTo(nStart, nEnd, bGrammar);
                }
                xNewError.reset();

                if (pBackAttrLeft)
                {
                    std::unique_ptr<SfxPoolItem> xNewBack(pBackAttrLeft->pAttr->Clone());
                    sal_Int32 _nStart = pBackAttrLeft->nStart + nAddedChars;
                    sal_Int32 _nEnd = pBackAttrLeft->nEnd + nAddedChars;
                    m_xEditEngine->RemoveAttribs(ESelection(0, _nStart, 0, _nEnd), false, EE_CHAR_BKGCOLOR);
                    _nStart = pBackAttrLeft->nStart;
                    SetAttrib(*xNewBack, _nStart, _nEnd);
                }
            }
        }
        else if(nAction == ACTION_UNDOEDIT)
        {
            SetUndoEditMode(true);
        }
        //make sure the error positions are correct after text changes
        //the old attribute may have been deleted
        //all changes inside of the current error leave the error attribute at the current
        //start position
        if (!IsUndoEditMode() && bIsErrorActive)
        {
            const EECharAttrib* pFontColor = FindCharAttrib(nCursor, nCursor, EE_CHAR_COLOR, aAttribList);
            const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
            if (pFontColor && pErrorAttrib)
            {
                m_nErrorStart = pFontColor->nStart;
                m_nErrorEnd = pFontColor->nEnd;
                if (pErrorAttrib->nStart != m_nErrorStart || pErrorAttrib->nEnd != m_nErrorEnd)
                {
                    std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrib->pAttr->Clone());
                    m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttr->nStart, 0, pErrorAttr->nEnd), false, EE_CHAR_GRABBAG);
                    SetAttrib(*xNewError, m_nErrorStart, m_nErrorEnd);
                }
            }
        }
        //this is not a modification anymore
        if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
            CallModifyLink();
    }
    return bChange || VclMultiLineEdit::PreNotify(rNEvt);
    else
        bConsumed = m_xEdView->PostKeyEvent(rKeyEvt);

    return bConsumed;
}

void SentenceEditWindow_Impl::Init(VclPtr<ToolBox> const &rToolbar)
void SentenceEditWindow_Impl::Init(weld::Toolbar* pToolbar)
{
    m_xToolbar = rToolbar;
    m_xToolbar->SetSelectHdl(LINK(this,SentenceEditWindow_Impl,ToolbarHdl));
    m_pToolbar = pToolbar;
    m_pToolbar->connect_clicked(LINK(this,SentenceEditWindow_Impl,ToolbarHdl));
}

IMPL_LINK_NOARG(SentenceEditWindow_Impl, ToolbarHdl, ToolBox *, void)
IMPL_LINK(SentenceEditWindow_Impl, ToolbarHdl, const OString&, rCurItemId, void)
{
    const sal_uInt16 nCurItemId = m_xToolbar->GetCurItemId();
    if (nCurItemId == m_xToolbar->GetItemId("paste"))
    if (rCurItemId == "paste")
    {
        Paste();
        m_xEdView->Paste();
        CallModifyLink();
    }
    else if (nCurItemId == m_xToolbar->GetItemId("insert"))
    else if (rCurItemId == "insert")
    {
        if (Edit::GetGetSpecialCharsFunction())
        {
            OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() );
            OUString aChars = Edit::GetGetSpecialCharsFunction()(GetDrawingArea(), m_xEditEngine->GetStandardFont(0));
            if (!aChars.isEmpty())
            {
                ReplaceSelected(aChars);
                ESelection aCurrentSelection(m_xEdView->GetSelection());
                m_xEditEngine->QuickInsertText(aChars, aCurrentSelection);
                CallModifyLink();
            }
        }
    }
}

void SentenceEditWindow_Impl::dispose()
{
    m_xToolbar.clear();
    VclMultiLineEdit::dispose();
}

bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css::uno::Reference<css::linguistic2::XSpellChecker1>& xSpell )
{
    if (bIgnoreCurrentError)
        m_aIgnoreErrorsAt.insert( m_nErrorStart );
    ExtTextEngine* pTextEngine = GetTextEngine();
    const sal_Int32 nTextLen = pTextEngine->GetTextLen(0);
    if(m_nErrorEnd >= nTextLen - 1)

    const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);

    if (m_nErrorEnd >= nTextLen - 1)
        return false;
    //if it's not already modified the modified flag has to be reset at the end of the marking
    bool bModified = IsModified();
@@ -1551,42 +1641,62 @@ bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css

    //create a cursor behind the end of the last error
    //- or at 0 at the start of the sentence
    TextPaM aCursor(0, m_nErrorEnd ? m_nErrorEnd + 1 : 0);
    //search for SpellErrorAttrib
    int nCursor(m_nErrorEnd ? m_nErrorEnd + 1 : 0);

    const TextCharAttrib* pNextError = nullptr;
    //search for SpellErrorDescription
    SpellErrorDescription aSpellErrorDescription;

    std::vector<EECharAttrib> aAttribList;
    m_xEditEngine->GetCharAttribs(0, aAttribList);

    //iterate over the text and search for the next error that maybe has
    //to be replace by a ChangeAllList replacement
    bool bGrammarError = false;
    while(aCursor.GetIndex() < nTextLen)
    while (nCursor < nTextLen)
    {
        while(aCursor.GetIndex() < nTextLen &&
                nullptr == (pNextError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR)))
        {
            ++aCursor.GetIndex();
        }
        // maybe the error found here is already in the ChangeAllList and has to be replaced
        const SpellErrorDescription* pSpellErrorDescription = nullptr;
        const EECharAttrib* pEECharAttrib = nullptr;

        sal_Int32 nMinPos = nTextLen + 1;
        for (const auto& rTextAtr : aAttribList)
        {
            if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG)
                continue;
            if (rTextAtr.nEnd > nCursor && rTextAtr.nStart < nMinPos)
            {
                nMinPos = rTextAtr.nStart;
                pEECharAttrib = &rTextAtr;
            }
        }

        if (pEECharAttrib)
        {
            ExtractErrorDescription(*pEECharAttrib, aSpellErrorDescription);

            bGrammarError = aSpellErrorDescription.bIsGrammarError;
            m_nErrorStart = pEECharAttrib->nStart;
            m_nErrorEnd = pEECharAttrib->nEnd;

            pSpellErrorDescription = &aSpellErrorDescription;
        }

        nCursor = nMinPos;

        // maybe the error found here is already in the ChangeAllList and has to be replaced
        Reference<XDictionary> xChangeAll( LinguMgr::GetChangeAllList(), UNO_QUERY );
        Reference<XDictionaryEntry> xEntry;

        const SpellErrorDescription* pSpellErrorDescription = nullptr;
        if(pNextError)
        {
            pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pNextError->GetAttr()).GetErrorDescription();
            bGrammarError = pSpellErrorDescription->bIsGrammarError;
            m_nErrorStart = pNextError->GetStart();
            m_nErrorEnd = pNextError->GetEnd();
        }
        if(xChangeAll->getCount() && pSpellErrorDescription &&
        if (xChangeAll->getCount() && pSpellErrorDescription &&
                (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
        {

            OUString sReplacement(getDotReplacementString(GetErrorText(), xEntry->getReplacementText()));

            ChangeMarkedWord(sReplacement, LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale ));
            int nLenChange = ChangeMarkedWord(sReplacement, LanguageTag::convertToLanguageType(pSpellErrorDescription->aLocale));

            aCursor.GetIndex() += sReplacement.getLength();
            nCursor += sReplacement.getLength();

            if (nLenChange)
                m_xEditEngine->GetCharAttribs(0, aAttribList);
            // maybe the error found here is already added to the dictionary and has to be ignored
        }
        else if(pSpellErrorDescription && !bGrammarError &&
@@ -1594,26 +1704,30 @@ bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css
                                static_cast<sal_uInt16>(LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale )),
                                Sequence< PropertyValue >() ))
        {
            ++aCursor.GetIndex();
            ++nCursor;
        }
        else
            break;
    }

    //if an attrib has been found search for the end of the error string
    if(aCursor.GetIndex() < nTextLen)
    if (nCursor < nTextLen)
    {
        MoveErrorMarkTo(aCursor.GetIndex(), pNextError->GetEnd(), bGrammarError);
        MoveErrorMarkTo(nCursor, m_nErrorEnd, bGrammarError);
        bRet = true;
        //add an undo action
        std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
                SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink));
        pAction->SetErrorMove(nOldErrorStart, nOldErrorEnd);
        const SpellErrorAttrib* pOldAttrib = static_cast<const SpellErrorAttrib*>(
                pTextEngine->FindAttrib( TextPaM(0, nOldErrorStart), TEXTATTR_SPELL_ERROR ));
        pAction->SetErrorLanguageSelected(pOldAttrib && pOldAttrib->GetErrorDescription().aSuggestions.getLength() &&
                LanguageTag( pOldAttrib->GetErrorDescription().aLocale).getLanguageType() ==
                                        GetSpellDialog()->m_pLanguageLB->GetSelectedLanguage());

        if (GetErrorDescription(aSpellErrorDescription, nOldErrorStart))
        {
            pAction->SetErrorLanguageSelected(aSpellErrorDescription.aSuggestions.hasElements() &&
                LanguageTag(aSpellErrorDescription.aLocale).getLanguageType() == GetSpellDialog()->m_xLanguageLB->get_active_id());
        }
        else
            pAction->SetErrorLanguageSelected(false);

        AddUndoAction(std::move(pAction));
    }
    else
@@ -1621,75 +1735,93 @@ bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css
    if( !bModified )
        ClearModifyFlag();
    SpellDialog* pSpellDialog = GetSpellDialog();
    pSpellDialog->m_pIgnorePB->Enable(bRet);
    pSpellDialog->m_pIgnoreAllPB->Enable(bRet);
    pSpellDialog->m_pAutoCorrPB->Enable(bRet);
    pSpellDialog->m_pAddToDictMB->Enable(bRet);
    pSpellDialog->m_pAddToDictPB->Enable(bRet);
    pSpellDialog->m_xIgnorePB->set_sensitive(bRet);
    pSpellDialog->m_xIgnoreAllPB->set_sensitive(bRet);
    pSpellDialog->m_xAutoCorrPB->set_sensitive(bRet);
    pSpellDialog->m_xAddToDictMB->set_sensitive(bRet);
    pSpellDialog->m_xAddToDictPB->set_sensitive(bRet);
    return bRet;
}


void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_Int32 nStart, sal_Int32 nEnd, bool bGrammarError)
{
    TextEngine* pTextEngine = GetTextEngine();
    pTextEngine->RemoveAttribs( 0, sal_uInt16(TEXTATTR_FONTCOLOR) );
    pTextEngine->RemoveAttribs( 0, sal_uInt16(TEXTATTR_FONTWEIGHT) );
    pTextEngine->SetAttrib( TextAttribFontWeight(WEIGHT_BOLD), 0, nStart, nEnd );
    pTextEngine->SetAttrib( TextAttribFontColor(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED), 0, nStart, nEnd );
    ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);

    SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
    aSet.Put(SvxColorItem(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED, EE_CHAR_COLOR));
    aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT));
    aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CJK));
    aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CTL));

    m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
    // so the editview will autoscroll to make this visible
    m_xEdView->SetSelection(ESelection(0, nStart));
    Invalidate();

    m_nErrorStart = nStart;
    m_nErrorEnd = nEnd;
}


void SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage)
int SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage)
{
    //calculate length changes
    long nDiffLen = rNewWord.getLength() - m_nErrorEnd + m_nErrorStart;
    TextSelection aSel(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd));
    //Remove spell error attribute
    ExtTextEngine* pTextEngine = GetTextEngine();
    pTextEngine->UndoActionStart();
    const TextCharAttrib*  pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
    std::unique_ptr<TextCharAttrib> pReleasedErrorAttrib;
    std::unique_ptr<TextCharAttrib> pReleasedLangAttrib;
    std::unique_ptr<TextCharAttrib> pReleasedBackAttrib;
    DBG_ASSERT(pErrorAttrib, "no error attribute found");
    const SpellErrorDescription* pSpellErrorDescription = nullptr;
    if(pErrorAttrib)
    {
        pReleasedErrorAttrib = pTextEngine->RemoveAttrib(0, *pErrorAttrib);
        pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pErrorAttrib->GetAttr()).GetErrorDescription();
    }
    const TextCharAttrib*  pBackAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_BACKGROUND );
    pTextEngine->ReplaceText( aSel, rNewWord );
    std::vector<EECharAttrib> aAttribList;
    m_xEditEngine->GetCharAttribs(0, aAttribList);

    if(!m_nErrorStart)
    //calculate length changes
    auto nDiffLen = rNewWord.getLength() - m_nErrorEnd + m_nErrorStart;
    //Remove spell error attribute
    m_xEditEngine->UndoActionStart(SPELLUNDO_MOVE_ERROREND);
    const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
    DBG_ASSERT(pErrorAttrib, "no error attribute found");
    bool bSpellErrorDescription = false;
    SpellErrorDescription aSpellErrorDescription;
    if (pErrorAttrib)
    {
        ExtractErrorDescription(*pErrorAttrib, aSpellErrorDescription);
        m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttrib->nStart, 0, pErrorAttrib->nEnd), false, EE_CHAR_GRABBAG);
        bSpellErrorDescription = true;
    }

    const EECharAttrib* pBackAttrib = FindCharAttrib(m_nErrorStart, m_nErrorStart, EE_CHAR_BKGCOLOR, aAttribList);

    ESelection aSel(0, m_nErrorStart, 0, m_nErrorEnd);
    m_xEditEngine->QuickInsertText(rNewWord, aSel);

    const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);

    if (nDiffLen)
        m_xEditEngine->GetCharAttribs(0, aAttribList);

    if (!m_nErrorStart)
    {
        //attributes following an error at the start of the text are not moved but expanded from the
        //text engine - this is done to keep full-paragraph-attributes
        //in the current case that handling is not desired
        const TextCharAttrib*  pLangAttrib =
                pTextEngine->FindCharAttrib(
                    TextPaM(0, m_nErrorEnd), TEXTATTR_SPELL_LANGUAGE );
        const sal_Int32 nTextLen = pTextEngine->GetTextLen( 0 );
        if(pLangAttrib && !pLangAttrib->GetStart() && pLangAttrib->GetEnd() ==
            nTextLen)
        const EECharAttrib* pLangAttrib = FindCharAttrib(m_nErrorEnd, m_nErrorEnd, EE_CHAR_LANGUAGE, aAttribList);

        if (pLangAttrib && !pLangAttrib->nStart && pLangAttrib->nEnd == nTextLen)
        {
            SpellLanguageAttrib aNewLangAttrib( static_cast<const SpellLanguageAttrib&>(pLangAttrib->GetAttr()).GetLanguage());
            pReleasedLangAttrib = pTextEngine->RemoveAttrib(0, *pLangAttrib);
            pTextEngine->SetAttrib( aNewLangAttrib, 0, m_nErrorEnd + nDiffLen, nTextLen );
            LanguageType eNewLanguage = static_cast<const SvxLanguageItem*>(pLangAttrib->pAttr)->GetLanguage();
            m_xEditEngine->RemoveAttribs(ESelection(0, pLangAttrib->nStart, 0, pLangAttrib->nEnd), false, EE_CHAR_LANGUAGE);
            SetAttrib(SvxLanguageItem(eNewLanguage, EE_CHAR_LANGUAGE), m_nErrorEnd + nDiffLen, nTextLen);
        }
    }

    // undo expanded attributes!
    if( pBackAttrib && pBackAttrib->GetStart() < m_nErrorStart && pBackAttrib->GetEnd() == m_nErrorEnd + nDiffLen)
    if (pBackAttrib && pBackAttrib->nStart < m_nErrorStart && pBackAttrib->nEnd == m_nErrorEnd + nDiffLen)
    {
        std::unique_ptr<TextAttrib> pNewBackground(pBackAttrib->GetAttr().Clone());
        const sal_Int32 nStart = pBackAttrib->GetStart();
        pReleasedBackAttrib = pTextEngine->RemoveAttrib(0, *pBackAttrib);
        pTextEngine->SetAttrib(*pNewBackground, 0, nStart, m_nErrorStart);
        std::unique_ptr<SfxPoolItem> xNewBackground(pBackAttrib->pAttr->Clone());
        const sal_Int32 nStart = pBackAttrib->nStart;

        m_xEditEngine->RemoveAttribs(ESelection(0, pBackAttrib->nStart, 0, pBackAttrib->nEnd), false, EE_CHAR_BKGCOLOR);

        SetAttrib(*xNewBackground, nStart, m_nErrorStart);
    }
    pTextEngine->SetModified(true);
    m_xEditEngine->SetModified();

    //adjust end position
    long nEndTemp = m_nErrorEnd;
@@ -1700,48 +1832,56 @@ void SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, Languag
                    SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink));
    pAction->SetOffset(nDiffLen);
    AddUndoAction(std::move(pAction));
    if(pSpellErrorDescription)
        SetAttrib( SpellErrorAttrib(*pSpellErrorDescription), 0, m_nErrorStart, m_nErrorEnd );
    SetAttrib( SpellLanguageAttrib(eLanguage), 0, m_nErrorStart, m_nErrorEnd );
    pTextEngine->UndoActionEnd();
}
    if (bSpellErrorDescription)
    {
        SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
        aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aSpellErrorDescription.toSequence();
        SetAttrib(aSpellErrorDescriptionItem, m_nErrorStart, m_nErrorEnd);
    }
    SetAttrib(SvxLanguageItem(eLanguage, EE_CHAR_LANGUAGE), m_nErrorStart, m_nErrorEnd);
    m_xEditEngine->UndoActionEnd();

    Invalidate();

    return nDiffLen;
}

OUString SentenceEditWindow_Impl::GetErrorText() const
{
    return GetTextEngine()->GetText(TextSelection(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd) ));
    return m_xEditEngine->GetText(ESelection(0, m_nErrorStart, 0, m_nErrorEnd));
}


const SpellErrorDescription* SentenceEditWindow_Impl::GetAlternatives()
bool SentenceEditWindow_Impl::GetErrorDescription(SpellErrorDescription& rSpellErrorDescription, sal_Int32 nPosition)
{
    TextPaM aCursor(0, m_nErrorStart);
    const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
            GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
    return pAttrib ? &pAttrib->GetErrorDescription() : nullptr;
    std::vector<EECharAttrib> aAttribList;
    m_xEditEngine->GetCharAttribs(0, aAttribList);

    if (const EECharAttrib* pEECharAttrib = FindCharAttrib(nPosition, nPosition, EE_CHAR_GRABBAG, aAttribList))
    {
        ExtractErrorDescription(*pEECharAttrib, rSpellErrorDescription);
        return true;
    }

    return false;
}

bool SentenceEditWindow_Impl::GetAlternatives(SpellErrorDescription& rSpellErrorDescription)
{
    return GetErrorDescription(rSpellErrorDescription, m_nErrorStart);
}

void SentenceEditWindow_Impl::RestoreCurrentError()
{
    TextPaM aCursor(0, m_nErrorStart);
    const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
            GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
    if( pAttrib )
    SpellErrorDescription aSpellErrorDescription;
    if (GetErrorDescription(aSpellErrorDescription, m_nErrorStart))
    {
        const SpellErrorDescription& rDesc = pAttrib->GetErrorDescription();
        if( rDesc.sErrorText != GetErrorText() )
            ChangeMarkedWord(rDesc.sErrorText, LanguageTag::convertToLanguageType( rDesc.aLocale ));
        if (aSpellErrorDescription.sErrorText != GetErrorText() )
            ChangeMarkedWord(aSpellErrorDescription.sErrorText, LanguageTag::convertToLanguageType(aSpellErrorDescription.aLocale));
    }
}


void SentenceEditWindow_Impl::SetAlternatives( const Reference< XSpellAlternatives>& xAlt )
{
    TextPaM aCursor(0, m_nErrorStart);
    DBG_ASSERT(static_cast<const SpellErrorAttrib*>(
            GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR)), "no error set?");

    OUString aWord;
    lang::Locale    aLocale;
    uno::Sequence< OUString >    aAlts;
@@ -1756,22 +1896,25 @@ void SentenceEditWindow_Impl::SetAlternatives( const Reference< XSpellAlternativ
            sServiceName = xNamed->getName();
    }
    SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, nullptr);
    GetTextEngine()->SetAttrib( SpellErrorAttrib(aDesc), 0, m_nErrorStart, m_nErrorEnd );
    SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
    aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
    SetAttrib(aSpellErrorDescription, m_nErrorStart, m_nErrorEnd);
}

void SentenceEditWindow_Impl::SetAttrib( const TextAttrib& rAttr, sal_uInt32 nPara, sal_Int32 nStart, sal_Int32 nEnd )
void SentenceEditWindow_Impl::SetAttrib(const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd)
{
    GetTextEngine()->SetAttrib(rAttr, nPara, nStart, nEnd);
    SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
    aSet.Put(rItem);
    m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
    Invalidate();
}


void SentenceEditWindow_Impl::SetText( const OUString& rStr )
{
    m_nErrorStart = m_nErrorEnd = 0;
    GetTextEngine()->SetText(rStr);
    m_xEditEngine->SetText(rStr);
}


struct LanguagePosition_Impl
{
    sal_Int32       nPosition;
@@ -1808,6 +1951,7 @@ static void lcl_InsertBreakPosition_Impl(
    }
    rBreakPositions.emplace_back(nInsert, eLanguage);
}

/*-------------------------------------------------------------------------
    Returns the text in spell portions. Each portion contains text with an
    equal language and attribute. The spell alternatives are empty.
@@ -1815,35 +1959,39 @@ static void lcl_InsertBreakPosition_Impl(
svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions() const
{
    svx::SpellPortions aRet;
    ExtTextEngine* pTextEngine = GetTextEngine();
    const sal_Int32 nTextLen = pTextEngine->GetTextLen(0);
    if(nTextLen)

    const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);

    std::vector<EECharAttrib> aAttribList;
    m_xEditEngine->GetCharAttribs(0, aAttribList);

    if (nTextLen)
    {
        TextPaM aCursor(0, 0);
        int nCursor(0);
        LanguagePositions_Impl aBreakPositions;
        const TextCharAttrib* pLastLang = nullptr;
        const TextCharAttrib* pLastError = nullptr;
        const EECharAttrib* pLastLang = nullptr;
        const EECharAttrib* pLastError = nullptr;
        LanguageType eLang = LANGUAGE_DONTKNOW;
        const TextCharAttrib* pError = nullptr;
        while(aCursor.GetIndex() < nTextLen)
        const EECharAttrib* pError = nullptr;
        while (nCursor < nTextLen)
        {
            const TextCharAttrib* pLang = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_LANGUAGE);
            const EECharAttrib* pLang = FindCharAttrib(nCursor, nCursor, EE_CHAR_LANGUAGE, aAttribList);
            if(pLang && pLang != pLastLang)
            {
                eLang = static_cast<const SpellLanguageAttrib&>(pLang->GetAttr()).GetLanguage();
                lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetStart(), eLang);
                lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetEnd(), eLang);
                eLang = static_cast<const SvxLanguageItem*>(pLang->pAttr)->GetLanguage();
                lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nStart, eLang);
                lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nEnd, eLang);
                pLastLang = pLang;
            }
            pError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR);
            if(pError && pLastError != pError)
            pError = FindCharAttrib(nCursor, nCursor, EE_CHAR_GRABBAG, aAttribList);
            if (pError && pLastError != pError)
            {
                lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetStart(), eLang);
                lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetEnd(), eLang);
                lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nStart, eLang);
                lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nEnd, eLang);
                pLastError = pError;

            }
            ++aCursor.GetIndex();
            ++nCursor;
        }

        if (aBreakPositions.empty())
@@ -1851,11 +1999,10 @@ svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions() const
            //if all content has been overwritten the attributes may have been removed, too
            svx::SpellPortion aPortion1;
            aPortion1.eLanguage = GetSpellDialog()->GetSelectedLang_Impl();
            aPortion1.sText = pTextEngine->GetText(
                        TextSelection(TextPaM(0, 0), TextPaM(0, nTextLen)));

            aPortion1.sText = m_xEditEngine->GetText(ESelection(0, 0, 0, nTextLen));

            aRet.push_back(aPortion1);

        }
        else
        {
@@ -1870,8 +2017,9 @@ svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions() const
            {
                svx::SpellPortion aPortion1;
                aPortion1.eLanguage = eLang;
                aPortion1.sText = pTextEngine->GetText(
                            TextSelection(TextPaM(0, nStart), TextPaM(0, aStart->nPosition)));

                aPortion1.sText = m_xEditEngine->GetText(ESelection(0, nStart, 0, aStart->nPosition));

                bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
                if( bIsIgnoreError )
                {
@@ -1884,17 +2032,17 @@ svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions() const
            }
        }

        // quick partly fix of #i71318. Correct fix needs to patch the TextEngine itself...
        // quick partly fix of #i71318. Correct fix needs to patch the EditEngine itself...
        // this one will only prevent text from disappearing. It may to not have the
        // correct language and will probably not spell checked...
        const sal_uInt32 nPara = pTextEngine->GetParagraphCount();
        const sal_uInt32 nPara = m_xEditEngine->GetParagraphCount();
        if (nPara > 1)
        {
            OUStringBuffer aLeftOverText;
            for (sal_uInt32 i = 1; i < nPara; ++i)
            {
                aLeftOverText.append("\x0a");    // the manual line break...
                aLeftOverText.append(pTextEngine->GetText(i));
                aLeftOverText.append(m_xEditEngine->GetText(i));
            }
            if (pError)
            {   // we need to add a new portion containing the left-over text
@@ -1908,14 +2056,14 @@ svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions() const
                aRet[ aRet.size() - 1 ].sText += aLeftOverText;
            }
        }
   }
    }

    return aRet;
}


void SentenceEditWindow_Impl::Undo()
{
    SfxUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
    SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
    DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
    if(!GetUndoActionCount())
        return;
@@ -1932,39 +2080,34 @@ void SentenceEditWindow_Impl::Undo()
        GetSpellDialog()->UpdateBoxes_Impl();
}


void SentenceEditWindow_Impl::ResetUndo()
{
    GetTextEngine()->ResetUndo();
    SfxUndoManager& rUndo = m_xEditEngine->GetUndoManager();
    rUndo.Clear();
}


void SentenceEditWindow_Impl::AddUndoAction( std::unique_ptr<SfxUndoAction> pAction )
{
    SfxUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
    SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
    rUndoMgr.AddUndoAction(std::move(pAction));
    GetSpellDialog()->m_pUndoPB->Enable();
    GetSpellDialog()->m_xUndoPB->set_sensitive(true);
}


size_t SentenceEditWindow_Impl::GetUndoActionCount()
{
    return GetTextEngine()->GetUndoManager().GetUndoActionCount();
    return m_xEditEngine->GetUndoManager().GetUndoActionCount();
}


void SentenceEditWindow_Impl::UndoActionStart( sal_uInt16 nId )
{
    GetTextEngine()->UndoActionStart(nId);
    m_xEditEngine->UndoActionStart(nId);
}


void SentenceEditWindow_Impl::UndoActionEnd()
{
    GetTextEngine()->UndoActionEnd();
    m_xEditEngine->UndoActionEnd();
}


void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
{
    // Shouldn't we always add the real signed value instead???
@@ -1975,44 +2118,47 @@ void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
}


void  SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
void SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
{
    DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
    m_bIsUndoEditMode = bSet;
    //disable all buttons except the Change
    SpellDialog* pSpellDialog = GetSpellDialog();
    Control* aControls[] =
    weld::Widget* aControls[] =
    {
        pSpellDialog->m_pChangeAllPB,
        pSpellDialog->m_pExplainFT,
        pSpellDialog->m_pIgnoreAllPB,
        pSpellDialog->m_pIgnoreRulePB,
        pSpellDialog->m_pIgnorePB,
        pSpellDialog->m_pSuggestionLB,
        pSpellDialog->m_pSuggestionFT,
        pSpellDialog->m_pLanguageFT,
        pSpellDialog->m_pLanguageLB,
        pSpellDialog->m_pAddToDictMB,
        pSpellDialog->m_pAddToDictPB,
        pSpellDialog->m_pAutoCorrPB,
        pSpellDialog->m_xChangeAllPB.get(),
        pSpellDialog->m_xExplainFT.get(),
        pSpellDialog->m_xIgnoreAllPB.get(),
        pSpellDialog->m_xIgnoreRulePB.get(),
        pSpellDialog->m_xIgnorePB.get(),
        pSpellDialog->m_xSuggestionLB.get(),
        pSpellDialog->m_xSuggestionFT.get(),
        pSpellDialog->m_xLanguageFT.get(),
        pSpellDialog->m_xLanguageLB->get_widget(),
        pSpellDialog->m_xAddToDictMB.get(),
        pSpellDialog->m_xAddToDictPB.get(),
        pSpellDialog->m_xAutoCorrPB.get(),
        nullptr
    };
    sal_Int32 nIdx = 0;
    do
    {
        aControls[nIdx]->Enable(false);
        aControls[nIdx]->set_sensitive(false);
    }
    while(aControls[++nIdx]);

    //remove error marks
    TextEngine* pTextEngine = GetTextEngine();
    pTextEngine->RemoveAttribs( 0, sal_uInt16(TEXTATTR_FONTCOLOR) );
    pTextEngine->RemoveAttribs( 0, sal_uInt16(TEXTATTR_FONTWEIGHT) );
    ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
    m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
    Invalidate();

    //put the appropriate action on the Undo-stack
    AddUndoAction( std::make_unique<SpellUndoAction_Impl>(
                        SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink) );
    pSpellDialog->m_pChangePB->Enable();
    pSpellDialog->m_xChangePB->set_sensitive(true);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index 61899ea..f8c38f5 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -51,7 +51,7 @@

using namespace css;

SvxCharacterMap::SvxCharacterMap(weld::Window* pParent, const SfxItemSet* pSet,
SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
                                 const css::uno::Reference<css::frame::XFrame>& rFrame)
    : SfxDialogController(pParent, "cui/ui/specialcharacters.ui", "SpecialCharactersDialog")
    , m_xVirDev(VclPtr<VirtualDevice>::Create())
diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx
index af99be3..4ad9e490 100644
--- a/cui/source/factory/dlgfact.cxx
+++ b/cui/source/factory/dlgfact.cxx
@@ -271,7 +271,15 @@ short AbstractLinksDialog_Impl::Execute()
    return m_xDlg->run();
}

IMPL_ABSTDLG_BASE(AbstractSpellDialog_Impl);
short AbstractSpellDialog_Impl::Execute()
{
    return m_xDlg->run();
}

bool AbstractSpellDialog_Impl::StartExecuteAsync(AsyncContext &rCtx)
{
    return SfxDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
}

short AbstractSvxPostItDialog_Impl::Execute()
{
@@ -524,19 +532,19 @@ const SfxItemSet* AbstractSvxZoomDialog_Impl::GetOutputItemSet() const
    return m_xDlg->GetOutputItemSet();
}

void  AbstractSpellDialog_Impl::Invalidate()
void AbstractSpellDialog_Impl::InvalidateDialog()
{
    pDlg->InvalidateDialog();
    m_xDlg->InvalidateDialog();
}

vcl::Window*     AbstractSpellDialog_Impl::GetWindow()
std::shared_ptr<SfxDialogController> AbstractSpellDialog_Impl::GetController()
{
    return pDlg;
    return m_xDlg;
}

SfxBindings& AbstractSpellDialog_Impl::GetBindings()
{
    return pDlg->GetBindings();
    return m_xDlg->GetBindings();
}

OUString AbstractTitleDialog_Impl::GetTitle() const
@@ -1050,12 +1058,11 @@ VclPtr<AbstractSvxZoomDialog> AbstractDialogFactory_Impl::CreateSvxZoomDialog(we
}

VclPtr<AbstractSpellDialog> AbstractDialogFactory_Impl::CreateSvxSpellDialog(
                        vcl::Window* pParent,
                        weld::Window* pParent,
                        SfxBindings* pBindings,
                        svx::SpellDialogChildWindow* pSpellChildWindow )
                        svx::SpellDialogChildWindow* pSpellChildWindow)
{
    VclPtrInstance<svx::SpellDialog> pDlg(pSpellChildWindow, pParent, pBindings);
    return VclPtr<AbstractSpellDialog_Impl>::Create(pDlg);
    return VclPtr<AbstractSpellDialog_Impl>::Create(std::make_unique<svx::SpellDialog>(pSpellChildWindow, pParent, pBindings));
}

VclPtr<VclAbstractDialog> AbstractDialogFactory_Impl::CreateActualizeProgressDialog(weld::Window* pParent,
diff --git a/cui/source/factory/dlgfact.hxx b/cui/source/factory/dlgfact.hxx
index ca07530a..2f83409 100644
--- a/cui/source/factory/dlgfact.hxx
+++ b/cui/source/factory/dlgfact.hxx
@@ -236,10 +236,16 @@ public:
namespace svx{ class SpellDialog;}
class AbstractSpellDialog_Impl : public AbstractSpellDialog
{
 public:
    DECL_ABSTDLG_BASE(AbstractSpellDialog_Impl, svx::SpellDialog)
    virtual void        Invalidate() override;
    virtual vcl::Window*     GetWindow() override;
    std::shared_ptr<svx::SpellDialog> m_xDlg;
public:
    explicit AbstractSpellDialog_Impl(std::unique_ptr<svx::SpellDialog> p)
        : m_xDlg(std::move(p))
    {
    }
    virtual short Execute() override;
    virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
    virtual void InvalidateDialog() override;
    virtual std::shared_ptr<SfxDialogController> GetController() override;
    virtual SfxBindings& GetBindings() override;
};

@@ -750,7 +756,7 @@ public:
                                                                     const SdrView* pSdrView,
                                                                     bool bSizeTabPage) override;
    virtual VclPtr<AbstractSpellDialog>  CreateSvxSpellDialog(
                            vcl::Window* pParent,
                            weld::Window* pParent,
                            SfxBindings* pBindings,
                            svx::SpellDialogChildWindow* pSpellChildWindow ) override;

diff --git a/cui/source/factory/init.cxx b/cui/source/factory/init.cxx
index eb3a99d..87f3105 100644
--- a/cui/source/factory/init.cxx
+++ b/cui/source/factory/init.cxx
@@ -23,10 +23,10 @@
// caution: needs C-Linkage since dynamically loaded via symbol name
extern "C"
{
SAL_DLLPUBLIC_EXPORT bool GetSpecialCharsForEdit(vcl::Window const * i_pParent, const vcl::Font& i_rFont, OUString& o_rResult)
SAL_DLLPUBLIC_EXPORT bool GetSpecialCharsForEdit(weld::Widget* i_pParent, const vcl::Font& i_rFont, OUString& o_rResult)
{
    bool bRet = false;
    SvxCharacterMap aDlg(i_pParent ? i_pParent->GetFrameWeld() : nullptr, nullptr, nullptr);
    SvxCharacterMap aDlg(i_pParent, nullptr, nullptr);
    aDlg.DisableFontSelection();
    aDlg.SetCharFont(i_rFont);
    if (aDlg.run() == RET_OK)
diff --git a/cui/source/inc/SpellDialog.hxx b/cui/source/inc/SpellDialog.hxx
index 83ea575..ee6d477 100644
--- a/cui/source/inc/SpellDialog.hxx
+++ b/cui/source/inc/SpellDialog.hxx
@@ -37,6 +37,10 @@
#include <svl/lstner.hxx>
#include <vcl/fixedhyper.hxx>
#include <vcl/xtextedt.hxx>
#include <vcl/txtattr.hxx>
#include <vcl/customweld.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editview.hxx>
#include <editeng/SpellPortions.hxx>

#include <set>
@@ -55,39 +59,74 @@ namespace svx{
class SpellDialog;
struct SpellErrorDescription;

class SentenceEditWindow_Impl : public VclMultiLineEdit
class SentenceEditWindow_Impl : public weld::CustomWidgetController
                              , public EditViewCallbacks
{
    using VclMultiLineEdit::SetText;

private:
    std::set< sal_Int32 >      m_aIgnoreErrorsAt;
    VclPtr<ToolBox>     m_xToolbar;
    std::unique_ptr<EditEngine> m_xEditEngine;
    std::unique_ptr<EditView> m_xEdView;

    std::set<sal_Int32> m_aIgnoreErrorsAt;
    SpellDialog*        m_pSpellDialog;
    weld::Toolbar*      m_pToolbar;
    sal_Int32           m_nErrorStart;
    sal_Int32           m_nErrorEnd;
    bool                m_bIsUndoEditMode;

    Link<Edit&,void>    m_aModifyLink;
    Link<LinkParamNone*,void> m_aModifyLink;

    void            CallModifyLink() {m_aModifyLink.Call(*this);}
    void            CallModifyLink() {m_aModifyLink.Call(nullptr); }

    inline SpellDialog* GetSpellDialog() const;
    SpellDialog* GetSpellDialog() const { return m_pSpellDialog; }

    DECL_LINK(ToolbarHdl, ToolBox*, void);
    bool GetErrorDescription(SpellErrorDescription& rSpellErrorDescription, sal_Int32 nPosition);

    DECL_LINK(ToolbarHdl, const OString&, void);

protected:
    virtual bool    PreNotify( NotifyEvent& rNEvt ) override;
    virtual void    Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
    virtual bool    MouseMove( const MouseEvent& rMEvt ) override;
    virtual bool    MouseButtonDown( const MouseEvent& rMEvt ) override;
    virtual bool    MouseButtonUp( const MouseEvent& rMEvt ) override;
    virtual bool    KeyInput( const KeyEvent& rKEvt ) override;
    virtual void    Resize() override;

    virtual void EditViewInvalidate(const tools::Rectangle& rRect) const override
    {
        weld::DrawingArea* pDrawingArea = GetDrawingArea();
        pDrawingArea->queue_draw_area(rRect.Left(), rRect.Top(), rRect.GetWidth(), rRect.GetHeight());
    }

    virtual void EditViewSelectionChange() const override
    {
        weld::DrawingArea* pDrawingArea = GetDrawingArea();
        pDrawingArea->queue_draw();
    }

    virtual OutputDevice& EditViewOutputDevice() const override
    {
        return GetDrawingArea()->get_ref_device();
    }

public:
    SentenceEditWindow_Impl(vcl::Window* pParent, WinBits nBits);
    SentenceEditWindow_Impl();
    virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
    void SetSpellDialog(SpellDialog* pDialog) { m_pSpellDialog = pDialog; }
    virtual ~SentenceEditWindow_Impl() override;

    void            Init(VclPtr<ToolBox> const &rToolbar);
    void            SetModifyHdl(const Link<Edit&,void>& rLink) override { m_aModifyLink = rLink;}
    void            Init(weld::Toolbar* pToolbar);
    void            SetModifyHdl(const Link<LinkParamNone*,void>& rLink)
    {
        m_aModifyLink = rLink;
        m_xEditEngine->SetModifyHdl(m_aModifyLink);
    }

    void            SetAttrib( const TextAttrib& rAttr, sal_uInt32 nPara, sal_Int32 nStart, sal_Int32 nEnd );
    void            SetText( const OUString& rStr ) override;
    void            SetAttrib(const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd);

    void            SetText(const OUString& rStr);

    bool            MarkNextError( bool bIgnoreCurrentError, const css::uno::Reference<css::linguistic2::XSpellChecker1>& );
    void            ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage);
    int             ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage);
    void            MoveErrorMarkTo(sal_Int32 nErrorStart, sal_Int32 nErrorEnd, bool bGrammar);
    OUString        GetErrorText() const;
    void            RestoreCurrentError();
@@ -95,12 +134,11 @@ public:
    void            SetAlternatives(
                        const css::uno::Reference<css::linguistic2::XSpellAlternatives>& );

    const SpellErrorDescription* GetAlternatives();
    bool            GetAlternatives(SpellErrorDescription& rDesc);


    void            ResetModified()   { GetTextEngine()->SetModified(false); m_bIsUndoEditMode = false;}
    virtual bool    IsModified() const override { return GetTextEngine()->IsModified(); }
    virtual void    dispose() override;
    void            ClearModifyFlag() { m_xEditEngine->ClearModifyFlag(); }
    void            ResetModified() { ClearModifyFlag(); m_bIsUndoEditMode = false;}
    bool            IsModified() const { return m_xEditEngine->IsModified(); }

    bool            IsUndoEditMode() const { return m_bIsUndoEditMode;}
    void            SetUndoEditMode(bool bSet);
@@ -122,42 +160,10 @@ public:
// class SvxSpellDialog ---------------------------------------------
class SpellDialogChildWindow;

class SpellDialog : public SfxModelessDialog
class SpellDialog : public SfxModelessDialogController
{
    using Window::Invalidate;

    friend class SentenceEditWindow_Impl;
private:

    VclPtr<FixedText>      m_pLanguageFT;
    VclPtr<SvxLanguageBox> m_pLanguageLB;

    VclPtr<FixedText>      m_pExplainFT;
    VclPtr<FixedHyperlink> m_pExplainLink;

    VclPtr<FixedText>      m_pNotInDictFT;
    VclPtr<SentenceEditWindow_Impl> m_pSentenceED;

    VclPtr<FixedText>      m_pSuggestionFT;
    VclPtr<ListBox>        m_pSuggestionLB;

    VclPtr<PushButton>     m_pIgnorePB;
    VclPtr<PushButton>     m_pIgnoreAllPB;
    VclPtr<PushButton>     m_pIgnoreRulePB;
    VclPtr<PushButton>     m_pAddToDictPB;
    VclPtr<MenuButton>     m_pAddToDictMB;

    VclPtr<PushButton>     m_pChangePB;
    VclPtr<PushButton>     m_pChangeAllPB;
    VclPtr<PushButton>     m_pAutoCorrPB;

    VclPtr<CheckBox>       m_pCheckGrammarCB;

    VclPtr<PushButton>     m_pOptionsPB;
    VclPtr<PushButton>     m_pUndoPB;
    VclPtr<CloseButton>    m_pClosePB;
    VclPtr<ToolBox>        m_pToolbar;

    OUString        m_sResumeST;
    OUString        m_sIgnoreOnceST;
    OUString        m_sNoSuggestionsST;
@@ -176,30 +182,58 @@ private:
    css::uno::Reference<
        css::linguistic2::XSpellChecker1 >     xSpell;

    DECL_LINK(ChangeHdl, Button*, void);
    DECL_LINK(DoubleClickChangeHdl, ListBox&, void);
    DECL_LINK(ChangeAllHdl, Button*, void);
    DECL_LINK( IgnoreAllHdl, Button*, void );
    DECL_LINK(IgnoreHdl, Button*, void);
    DECL_LINK( CheckGrammarHdl, Button*, void );
    DECL_LINK( ExtClickHdl, Button*, void );
    DECL_LINK(CancelHdl, Button*, void);
    DECL_LINK( ModifyHdl, Edit&, void);
    DECL_LINK(UndoHdl, Button*, void);
    DECL_LINK( AddToDictSelectHdl, MenuButton*, void );
    DECL_LINK( AddToDictClickHdl, Button*, void );
    DECL_LINK( LanguageSelectHdl, ListBox&, void );
    DECL_LINK( DialogUndoHdl, SpellUndoAction_Impl&, void );
    std::unique_ptr<weld::Label> m_xAltTitle;
    std::unique_ptr<weld::Label> m_xResumeFT;
    std::unique_ptr<weld::Label> m_xNoSuggestionsFT;
    std::unique_ptr<weld::Label> m_xIgnoreOnceFT;
    std::unique_ptr<weld::Label> m_xLanguageFT;
    std::unique_ptr<LanguageBox> m_xLanguageLB;
    std::unique_ptr<weld::Label> m_xExplainFT;
    std::unique_ptr<weld::LinkButton> m_xExplainLink;
    std::unique_ptr<weld::Label> m_xNotInDictFT;
    std::unique_ptr<SentenceEditWindow_Impl> m_xSentenceED;
    std::unique_ptr<weld::Label> m_xSuggestionFT;
    std::unique_ptr<weld::TreeView> m_xSuggestionLB;
    std::unique_ptr<weld::Button> m_xIgnorePB;
    std::unique_ptr<weld::Button> m_xIgnoreAllPB;
    std::unique_ptr<weld::Button> m_xIgnoreRulePB;
    std::unique_ptr<weld::Button> m_xAddToDictPB;
    std::unique_ptr<weld::MenuButton> m_xAddToDictMB;
    std::unique_ptr<weld::Button> m_xChangePB;
    std::unique_ptr<weld::Button> m_xChangeAllPB;
    std::unique_ptr<weld::Button> m_xAutoCorrPB;
    std::unique_ptr<weld::CheckButton> m_xCheckGrammarCB;
    std::unique_ptr<weld::Button> m_xOptionsPB;
    std::unique_ptr<weld::Button> m_xUndoPB;
    std::unique_ptr<weld::Button> m_xClosePB;
    std::unique_ptr<weld::Toolbar> m_xToolbar;
    std::unique_ptr<weld::CustomWeld> m_xSentenceEDWeld;

    DECL_LINK( InitHdl, void*, void );
    DECL_LINK(ChangeHdl, weld::Button&, void);
    DECL_LINK(DoubleClickChangeHdl, weld::TreeView&, void);
    DECL_LINK(ChangeAllHdl, weld::Button&, void);
    DECL_LINK(IgnoreAllHdl, weld::Button&, void);
    DECL_LINK(IgnoreHdl, weld::Button&, void);
    DECL_LINK(CheckGrammarHdl, weld::Button&, void);
    DECL_LINK(ExtClickHdl, weld::Button&, void);
    DECL_LINK(CancelHdl, weld::Button&, void);
    DECL_LINK(ModifyHdl, LinkParamNone*, void);
    DECL_LINK(UndoHdl, weld::Button&, void);
    DECL_LINK(AddToDictSelectHdl, const OString&, void);
    DECL_LINK(AddToDictClickHdl, weld::Button&, void);
    DECL_LINK(LanguageSelectHdl, weld::ComboBox&, void);
    DECL_LINK(DialogUndoHdl, SpellUndoAction_Impl&, void);

    void            AddToDictionaryExecute( sal_uInt16 ItemId, PopupMenu const *pMenu );
    DECL_LINK(InitHdl, void*, void);

    void            AddToDictionaryExecute(const OString& rItemId);
    void            StartSpellOptDlg_Impl();
    int             InitUserDicts();
    void            UpdateBoxes_Impl(bool bCallFromSelectHdl = false);
    void            Init_Impl();
    void            SpellContinue_Impl(bool UseSavedSentence = false, bool bIgnoreCurrentError = false );
    void            LockFocusChanges( bool bLock ) {bFocusLocked = bLock;}
    void            ToplevelFocusChanged();
    void            Impl_Restore(bool bUseSavedSentence);

    LanguageType    GetSelectedLang_Impl() const;
@@ -213,25 +247,24 @@ private:
    void            SetTitle_Impl(LanguageType nLang);

protected:
    virtual bool    EventNotify( NotifyEvent& rNEvt ) override;

    OUString getReplacementString() const;

public:
    SpellDialog(
        svx::SpellDialogChildWindow* pChildWindow,
        vcl::Window * pParent,
        weld::Window * pParent,
        SfxBindings* pBindings);
    virtual ~SpellDialog() override;
    virtual void dispose() override;

    virtual bool    Close() override;
    virtual void    Activate() override;
    virtual void    Deactivate() override;

    virtual void    Close() override;

    void            InvalidateDialog();
};

SpellDialog* SentenceEditWindow_Impl::GetSpellDialog() const {return static_cast<SpellDialog*>(GetParentDialog());}

} //namespace svx

#endif
diff --git a/cui/uiconfig/ui/spellingdialog.ui b/cui/uiconfig/ui/spellingdialog.ui
index a1046a7..2019f32 100644
--- a/cui/uiconfig/ui/spellingdialog.ui
+++ b/cui/uiconfig/ui/spellingdialog.ui
@@ -1,14 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.19.0 -->
<!-- Generated with glade 3.22.1 -->
<interface domain="cui">
  <requires lib="gtk+" version="3.18"/>
  <requires lib="LibreOffice" version="1.0"/>
  <object class="GtkMenu" id="addmenu">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
  </object>
  <object class="GtkTreeStore" id="liststore1">
    <columns>
      <!-- column-name text -->
      <column type="gchararray"/>
      <!-- column-name id -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkListStore" id="liststore6">
    <columns>
      <!-- column-name text -->
      <column type="gchararray"/>
      <!-- column-name id -->
      <column type="gchararray"/>
      <!-- column-name image -->
      <column type="GdkPixbuf"/>
    </columns>
  </object>
  <object class="GtkDialog" id="SpellingDialog">
    <property name="can_focus">False</property>
    <property name="border_width">6</property>
    <property name="title" translatable="yes" context="spellingdialog|SpellingDialog">Spelling: $LANGUAGE ($LOCATION)</property>
    <property name="resizable">False</property>
    <property name="default_width">0</property>
    <property name="default_height">0</property>
    <property name="type_hint">dialog</property>
    <child>
      <placeholder/>
    </child>
    <child internal-child="vbox">
      <object class="GtkBox" id="dialog-vbox1">
        <property name="can_focus">False</property>
@@ -95,10 +121,25 @@
            <property name="row_spacing">6</property>
            <property name="column_spacing">12</property>
            <child>
              <object class="svxcorelo-SvxLanguageBox" id="languagelb">
              <object class="GtkComboBox" id="languagelb">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="halign">end</property>
                <property name="model">liststore6</property>
                <property name="entry_text_column">0</property>
                <property name="id_column">1</property>
                <child>
                  <object class="GtkCellRendererText" id="cellrenderertext9"/>
                  <attributes>
                    <attribute name="text">0</attribute>
                  </attributes>
                </child>
                <child>
                  <object class="GtkCellRendererPixbuf" id="cellrenderertext6"/>
                  <attributes>
                    <attribute name="pixbuf">2</attribute>
                  </attributes>
                </child>
              </object>
              <packing>
                <property name="left_attach">1</property>
@@ -120,20 +161,6 @@
              </packing>
            </child>
            <child>
              <object class="cuilo-SentenceEditWindow" id="sentence">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="vexpand">True</property>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">3</property>
                <property name="width">2</property>
                <property name="height">5</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="change">
                <property name="label" translatable="yes" context="spellingdialog|change">Co_rrect</property>
                <property name="visible">True</property>
@@ -298,24 +325,6 @@
              </packing>
            </child>
            <child>
              <object class="GtkTreeView" id="suggestionslb">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="vexpand">True</property>
                <property name="show_expanders">False</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection" id="treeview-selection1"/>
                </child>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">9</property>
                <property name="width">2</property>
                <property name="height">3</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="add">
                <property name="label" translatable="yes" context="spellingdialog|add">_Add to Dictionary</property>
                <property name="visible">True</property>
@@ -330,13 +339,18 @@
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="addmb:addmenu">
              <object class="GtkMenuButton" id="addmb">
                <property name="label" translatable="yes" context="spellingdialog|addmb">_Add to Dictionary</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="no_show_all">True</property>
                <property name="valign">center</property>
                <property name="use_underline">True</property>
                <property name="popup">addmenu</property>
                <property name="use_popover">False</property>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="left_attach">2</property>
@@ -383,7 +397,6 @@
                  <object class="GtkToolButton" id="paste">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="action_name">paste</property>
                    <property name="label" translatable="yes" context="spellingdialog|paste">Paste</property>
                    <property name="use_underline">True</property>
                    <property name="icon_name">cmd/sc_paste.png</property>
@@ -397,7 +410,6 @@
                  <object class="GtkToolButton" id="insert">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="action_name">insert</property>
                    <property name="label" translatable="yes" context="spellingdialog|insert">Special Character</property>
                    <property name="use_underline">True</property>
                    <property name="icon_name">cmd/sc_insertsymbol.png</property>
@@ -414,6 +426,73 @@
              </packing>
            </child>
            <child>
              <object class="GtkScrolledWindow">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="border_width">0</property>
                <property name="shadow_type">in</property>
                <child>
                  <object class="GtkViewport">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkDrawingArea" id="sentence">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">3</property>
                <property name="width">2</property>
                <property name="height">5</property>
              </packing>
            </child>
            <child>
              <object class="GtkScrolledWindow">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="vexpand">True</property>
                <property name="shadow_type">in</property>
                <child>
                  <object class="GtkTreeView" id="suggestionslb">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="hexpand">True</property>
                    <property name="vexpand">True</property>
                    <property name="model">liststore1</property>
                    <property name="headers_visible">False</property>
                    <property name="show_expanders">False</property>
                    <child internal-child="selection">
                      <object class="GtkTreeSelection" id="treeview-selection1"/>
                    </child>
                    <child>
                      <object class="GtkTreeViewColumn" id="treeviewcolumn2">
                        <property name="spacing">6</property>
                        <child>
                          <object class="GtkCellRendererText" id="cellrenderertext2"/>
                          <attributes>
                            <attribute name="text">0</attribute>
                          </attributes>
                        </child>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">9</property>
                <property name="width">2</property>
                <property name="height">3</property>
              </packing>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
@@ -435,8 +514,4 @@
      <action-widget response="-7">close</action-widget>
    </action-widgets>
  </object>
  <object class="GtkMenu" id="addmenu">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
  </object>
</interface>
diff --git a/extras/source/glade/libreoffice-catalog.xml.in b/extras/source/glade/libreoffice-catalog.xml.in
index bdfd89c..ed9f543 100644
--- a/extras/source/glade/libreoffice-catalog.xml.in
+++ b/extras/source/glade/libreoffice-catalog.xml.in
@@ -27,9 +27,6 @@
    <glade-widget-class title="Search Results Box" name="sfxlo-SearchResultsBox"
                        generic-name="SearchResultsBox" parent="GtkComboBoxText"
                        icon-name="widget-gtk-comboboxtext"/>
    <glade-widget-class title="Spelling View" name="cuilo-SentenceEditWindow"
                        generic-name="SentenceEditWindow" parent="GtkTextView"
                        icon-name="widget-gtk-textview"/>
    <glade-widget-class title="Condition Edit" name="rptuilo-ConditionField"
                        generic-name="ConditionEdit" parent="GtkEntry"
                        icon-name="widget-gtk-comboboxtext"/>
diff --git a/include/cui/cuicharmap.hxx b/include/cui/cuicharmap.hxx
index c69107b..fbe9b11 100644
--- a/include/cui/cuicharmap.hxx
+++ b/include/cui/cuicharmap.hxx
@@ -143,7 +143,7 @@ private:
    void selectCharByCode(Radix radix);

public:
    SvxCharacterMap(weld::Window* pParent, const SfxItemSet* pSet,
    SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
                    const css::uno::Reference<css::frame::XFrame>& rFrame);
    virtual short run() override;

diff --git a/include/sfx2/basedlgs.hxx b/include/sfx2/basedlgs.hxx
index 88f4af7..183ef5b 100644
--- a/include/sfx2/basedlgs.hxx
+++ b/include/sfx2/basedlgs.hxx
@@ -100,8 +100,7 @@ class SFX2_DLLPUBLIC SfxDialogController : public weld::GenericDialogController
private:
    DECL_DLLPRIVATE_STATIC_LINK(SfxDialogController, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*);

    DECL_DLLPRIVATE_LINK(FocusInHdl, weld::Widget&, void);
    DECL_DLLPRIVATE_LINK(FocusOutHdl, weld::Widget&, void);
    DECL_DLLPRIVATE_LINK(FocusChangeHdl, weld::Widget&, void);

public:
    SfxDialogController(weld::Widget* pParent, const OUString& rUIFile, const OString& rDialogId);
diff --git a/include/svx/ClassificationEditView.hxx b/include/svx/ClassificationEditView.hxx
index 7c7070e..f3ce3b9 100644
--- a/include/svx/ClassificationEditView.hxx
+++ b/include/svx/ClassificationEditView.hxx
@@ -28,8 +28,8 @@ public:
    virtual OUString CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, boost::optional<Color>& rTxtColor, boost::optional<Color>& rFldColor) override;
};

class SVX_DLLPUBLIC ClassificationEditView : public weld::CustomWidgetController,
                                             public EditViewCallbacks
class SVX_DLLPUBLIC ClassificationEditView : public weld::CustomWidgetController
                                           , public EditViewCallbacks
{
public:
    ClassificationEditView();
diff --git a/include/svx/langbox.hxx b/include/svx/langbox.hxx
index 48efdc2..7d94059 100644
--- a/include/svx/langbox.hxx
+++ b/include/svx/langbox.hxx
@@ -175,7 +175,7 @@ public:
    int find_text(const OUString& rStr) const { return m_xControl->find_text(rStr); }
    OUString get_text(int nPos) const { return m_xControl->get_text(nPos); }
    int get_count() const { return m_xControl->get_count(); }
    const weld::ComboBox* get_widget() const { return m_xControl.get(); }
    weld::ComboBox* get_widget() { return m_xControl.get(); }
};

class SVX_DLLPUBLIC SvxLanguageComboBox : public ComboBox, public SvxLanguageBoxBase
diff --git a/include/svx/svxdlg.hxx b/include/svx/svxdlg.hxx
index 58acee4b..82f22e6 100644
--- a/include/svx/svxdlg.hxx
+++ b/include/svx/svxdlg.hxx
@@ -100,8 +100,8 @@ class AbstractSpellDialog : public VclAbstractDialog
protected:
    virtual ~AbstractSpellDialog() override = default;
public:
    virtual void        Invalidate() = 0;
    virtual vcl::Window*     GetWindow()  = 0;
    virtual void InvalidateDialog() = 0;
    virtual std::shared_ptr<SfxDialogController> GetController() = 0;
    virtual SfxBindings& GetBindings() = 0;
};

@@ -353,7 +353,7 @@ public:

    virtual VclPtr<AbstractSvxZoomDialog> CreateSvxZoomDialog(weld::Window* pParent, const SfxItemSet& rCoreSet) = 0;

    virtual VclPtr<AbstractSpellDialog>   CreateSvxSpellDialog(vcl::Window* pParent,
    virtual VclPtr<AbstractSpellDialog>   CreateSvxSpellDialog(weld::Window* pParent,
                                            SfxBindings* pBindings,
                                            svx::SpellDialogChildWindow* pSpellChildWindow )=0;

diff --git a/include/vcl/edit.hxx b/include/vcl/edit.hxx
index caf7597..bc18f3a 100644
--- a/include/vcl/edit.hxx
+++ b/include/vcl/edit.hxx
@@ -50,7 +50,7 @@ struct Impl_IMEInfos;
#define EDIT_NOLIMIT                SAL_MAX_INT32
#define EDIT_UPDATEDATA_TIMEOUT     350

typedef OUString (*FncGetSpecialChars)( vcl::Window* pWin, const vcl::Font& rFont );
typedef OUString (*FncGetSpecialChars)( weld::Widget* pWin, const vcl::Font& rFont );

class VCL_DLLPUBLIC TextFilter
{
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 7393131..35e645a 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -337,6 +337,9 @@ class VCL_DLLPUBLIC Window : virtual public Container
{
protected:
    Link<Widget&, bool> m_aHelpRequestHdl;
    Link<Widget&, void> m_aTopLevelFocusChangedHdl;

    void signal_toplevel_focus_changed() { m_aTopLevelFocusChangedHdl.Call(*this); }

public:
    virtual void set_title(const OUString& rTitle) = 0;
@@ -367,6 +370,10 @@ public:
    virtual css::uno::Reference<css::awt::XWindow> GetXWindow() = 0;

    void connect_help(const Link<Widget&, bool>& rLink) { m_aHelpRequestHdl = rLink; }
    virtual void connect_toplevel_focus_changed(const Link<Widget&, void>& rLink)
    {
        m_aTopLevelFocusChangedHdl = rLink;
    }

    virtual SystemEnvData get_system_data() const = 0;

@@ -1007,9 +1014,11 @@ public:
    virtual void insert_separator(int pos, const OUString& rId) = 0;
    void append_separator(const OUString& rId) { insert_separator(-1, rId); }
    virtual void remove_item(const OString& rId) = 0;
    virtual void clear() = 0;
    virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) = 0;
    virtual void set_item_active(const OString& rIdent, bool bActive) = 0;
    virtual void set_item_label(const OString& rIdent, const OUString& rLabel) = 0;
    virtual OUString get_item_label(const OString& rIdent) const = 0;
    virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) = 0;
    virtual void set_item_visible(const OString& rIdent, bool bVisible) = 0;
    virtual OString get_item_help_id(const OString& rIdent) const = 0;
@@ -1096,6 +1105,7 @@ public:
    virtual void set_max_length(int nChars) = 0;
    // nEndPos can be -1 in order to select all text
    virtual void select_region(int nStartPos, int nEndPos) = 0;
    // returns true if the selection has nonzero length
    virtual bool get_selection_bounds(int& rStartPos, int& rEndPos) = 0;
    virtual void replace_selection(const OUString& rText) = 0;
    // nCursorPos can be -1 to set to the end
diff --git a/sc/source/ui/inc/spelleng.hxx b/sc/source/ui/inc/spelleng.hxx
index cec0676..2add815 100644
--- a/sc/source/ui/inc/spelleng.hxx
+++ b/sc/source/ui/inc/spelleng.hxx
@@ -28,6 +28,8 @@ class ScDocShell;
class ScDocument;
class SfxItemPool;

namespace weld { class Window; }

/** Base class for special type of edit engines, i.e. for spell checker and text conversion. */
class ScConversionEngineBase : public ScEditEngineDefaulter
{
@@ -119,7 +121,7 @@ protected:

private:
    /** Returns the spelling dialog if it is open. */
    vcl::Window*             GetDialogParent();
    weld::Window*       GetDialogParent();
};

/** Edit engine for text conversion. */
diff --git a/sc/source/ui/view/cellsh.cxx b/sc/source/ui/view/cellsh.cxx
index 26020a8..3d21cd9 100644
--- a/sc/source/ui/view/cellsh.cxx
+++ b/sc/source/ui/view/cellsh.cxx
@@ -1209,8 +1209,8 @@ void ScCellShell::GetState(SfxItemSet &rSet)
                        if ( pViewFrame && pViewFrame->HasChildWindow( nWhich ) )
                        {
                            SfxChildWindow* pChild = pViewFrame->GetChildWindow( nWhich );
                            vcl::Window* pWin = ( pChild ? pChild->GetWindow() : nullptr );
                            if ( pWin && pWin->IsVisible() )
                            std::shared_ptr<SfxDialogController> xController = pChild ? pChild->GetController() : nullptr;
                            if (xController && xController->getDialog()->get_visible())
                            {
                                bVisible = true;
                            }
diff --git a/sc/source/ui/view/spelleng.cxx b/sc/source/ui/view/spelleng.cxx
index 49c076c..af1ea81 100644
--- a/sc/source/ui/view/spelleng.cxx
+++ b/sc/source/ui/view/spelleng.cxx
@@ -305,10 +305,10 @@ bool ScSpellingEngine::NeedsConversion()

bool ScSpellingEngine::ShowTableWrapDialog()
{
    vcl::Window* pParent = GetDialogParent();
    ScWaitCursorOff aWaitOff( pParent );
    weld::Window* pParent = GetDialogParent();
    weld::WaitObject aWaitOff(pParent);

    std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent ? pParent->GetFrameWeld() : nullptr,
    std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
                                              VclMessageType::Question, VclButtonsType::YesNo,
                                              ScResId(STR_SPELLING_BEGIN_TAB))); // "delete data?"
    xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0));
@@ -318,26 +318,37 @@ bool ScSpellingEngine::ShowTableWrapDialog()

void ScSpellingEngine::ShowFinishDialog()
{
    vcl::Window* pParent = GetDialogParent();
    ScWaitCursorOff aWaitOff( pParent );
    std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent ? pParent->GetFrameWeld() : nullptr,
    weld::Window* pParent = GetDialogParent();
    weld::WaitObject aWaitOff(pParent);
    std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
                                                  VclMessageType::Info, VclButtonsType::Ok,
                                                  ScResId(STR_SPELLING_STOP_OK)));
    xInfoBox->run();
}

vcl::Window* ScSpellingEngine::GetDialogParent()
weld::Window* ScSpellingEngine::GetDialogParent()
{
    sal_uInt16 nWinId = ScSpellDialogChildWindow::GetChildWindowId();
    SfxViewFrame* pViewFrm = mrViewData.GetViewShell()->GetViewFrame();
    if( pViewFrm->HasChildWindow( nWinId ) )
    {
        if( SfxChildWindow* pChild = pViewFrm->GetChildWindow( nWinId ) )
            if( vcl::Window* pWin = pChild->GetWindow() )
                if( pWin->IsVisible() )
                    return pWin;
        {
            auto xController = pChild->GetController();
            if (xController)
            {
                if (weld::Window *pRet = xController->getDialog())
                {
                    if (pRet->get_visible())
                        return pRet;
                }
            }
        }
    }

    // fall back to standard dialog parent
    return ScDocShell::GetActiveDialogParent();
    vcl::Window* pWin = ScDocShell::GetActiveDialogParent();
    return pWin ? pWin->GetFrameWeld() : nullptr;
}

ScConversionParam::ScConversionParam( ScConversionType eConvType ) :
diff --git a/sd/inc/Outliner.hxx b/sd/inc/Outliner.hxx
index 5f4056f..47c3b5d 100644
--- a/sd/inc/Outliner.hxx
+++ b/sd/inc/Outliner.hxx
@@ -30,6 +30,10 @@ class SdrObject;
class SdrTextObj;
class SdDrawDocument;

namespace weld {
class Window;
}

namespace sd {

class View;
@@ -516,7 +520,7 @@ private:
        that the otherwise non-modal search or spell dialogs, if visible, are
        locked, too.
    */
    VclPtr<vcl::Window> GetMessageBoxParent();
    weld::Window* GetMessageBoxParent();
};

#endif
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index a98ad3c..a91d5f7 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -1205,8 +1205,8 @@ void SdOutliner::ShowEndOfSearchDialog()
        aString = SdResId(STR_END_SPELLING);

    // Show the message in an info box that is modal with respect to the whole application.
    VclPtr<vcl::Window> xParent(GetMessageBoxParent());
    std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(xParent ? xParent->GetFrameWeld() : nullptr,
    weld::Window* pParent = GetMessageBoxParent();
    std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
                                                  VclMessageType::Info, VclButtonsType::Ok, aString));
    xInfoBox->run();
}
@@ -1246,8 +1246,8 @@ bool SdOutliner::ShowWrapArroundDialog()

    // Pop up question box that asks the user whether to wrap around.
    // The dialog is made modal with respect to the whole application.
    VclPtr<vcl::Window> xParent(GetMessageBoxParent());
    std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(xParent ? xParent->GetFrameWeld() : nullptr,
    weld::Window* pParent = GetMessageBoxParent();
    std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent,
                                                   VclMessageType::Question, VclButtonsType::YesNo, SdResId(pStringId)));
    sal_uInt16 nBoxResult = xQueryBox->run();

@@ -1691,7 +1691,7 @@ bool SdOutliner::ConvertNextDocument()
    return !mbEndOfSearch;
}

VclPtr<vcl::Window> SdOutliner::GetMessageBoxParent()
weld::Window* SdOutliner::GetMessageBoxParent()
{
    // We assume that the parent of the given message box is NULL, i.e. it is
    // modal with respect to the top application window. However, this
@@ -1699,7 +1699,7 @@ VclPtr<vcl::Window> SdOutliner::GetMessageBoxParent()
    // while the message box is being shown. We also have to take into
    // account that we are called during a spell check and the search dialog
    // is not available.
    vcl::Window* pSearchDialog = nullptr;
    weld::Window* pSearchDialog = nullptr;
    SfxChildWindow* pChildWindow = nullptr;
    switch (meMode)
    {
@@ -1720,13 +1720,17 @@ VclPtr<vcl::Window> SdOutliner::GetMessageBoxParent()
    }

    if (pChildWindow != nullptr)
        pSearchDialog = pChildWindow->GetWindow();
    {
        auto xController = pChildWindow->GetController();
        pSearchDialog = xController ? xController->getDialog() : nullptr;
    }

    if (pSearchDialog)
        return pSearchDialog;

    std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
    return pViewShell->GetActiveWindow();
    auto pWin = pViewShell->GetActiveWindow();
    return pWin ? pWin->GetFrameWeld() : nullptr;
}

//===== SdOutliner::Implementation ==============================================
diff --git a/sfx2/source/appl/appinit.cxx b/sfx2/source/appl/appinit.cxx
index 5432007..89e1ea9 100644
--- a/sfx2/source/appl/appinit.cxx
+++ b/sfx2/source/appl/appinit.cxx
@@ -142,7 +142,7 @@ Sequence< OUString > SAL_CALL SfxTerminateListener_Impl::getSupportedServiceName
}


typedef bool ( *PFunc_getSpecialCharsForEdit)( vcl::Window const * i_pParent, const vcl::Font& i_rFont, OUString& o_rOutString );
typedef bool (*PFunc_getSpecialCharsForEdit)(weld::Widget* i_pParent, const vcl::Font& i_rFont, OUString& o_rOutString);


// Lazy binding of the GetSpecialCharsForEdit function as it resides in
@@ -155,11 +155,11 @@ extern "C" { static void thisModule() {} }

#else

extern "C" bool GetSpecialCharsForEdit( vcl::Window const * i_pParent, const vcl::Font& i_rFont, OUString& o_rOutString );
extern "C" bool GetSpecialCharsForEdit(weld::Widget* i_pParent, const vcl::Font& i_rFont, OUString& o_rOutString);

#endif

static OUString SfxGetSpecialCharsForEdit(vcl::Window* pParent, const vcl::Font& rFont)
static OUString SfxGetSpecialCharsForEdit(weld::Widget* pParent, const vcl::Font& rFont)
{
    static bool bDetermineFunction = false;
    static PFunc_getSpecialCharsForEdit pfunc_getSpecialCharsForEdit = nullptr;
diff --git a/sfx2/source/dialog/basedlgs.cxx b/sfx2/source/dialog/basedlgs.cxx
index 5dc2067..0d4da9e 100644
--- a/sfx2/source/dialog/basedlgs.cxx
+++ b/sfx2/source/dialog/basedlgs.cxx
@@ -423,9 +423,12 @@ void SfxModelessDialogController::Init(SfxBindings *pBindinx, SfxChildWindow *pC
    If a ModelessDialog is enabled its ViewFrame will be activated.
    This is necessary by PluginInFrames.
*/
IMPL_LINK_NOARG(SfxDialogController, FocusInHdl, weld::Widget&, void)
IMPL_LINK_NOARG(SfxDialogController, FocusChangeHdl, weld::Widget&, void)
{
    Activate();
    if (m_xDialog->has_toplevel_focus())
        Activate();
    else
        Deactivate();
}

void SfxModelessDialogController::Activate()
@@ -436,11 +439,6 @@ void SfxModelessDialogController::Activate()
    m_xImpl->pMgr->Activate_Impl();
}

IMPL_LINK_NOARG(SfxDialogController, FocusOutHdl, weld::Widget&, void)
{
    Deactivate();
}

void SfxModelessDialogController::Deactivate()
{
    if (!m_xImpl)
@@ -713,8 +711,7 @@ SfxDialogController::SfxDialogController(weld::Widget* pParent, const OUString& 
    : GenericDialogController(pParent, rUIFile, rDialogId)
{
    m_xDialog->SetInstallLOKNotifierHdl(LINK(this, SfxDialogController, InstallLOKNotifierHdl));
    m_xDialog->connect_focus_in(LINK(this, SfxDialogController, FocusInHdl));
    m_xDialog->connect_focus_out(LINK(this, SfxDialogController, FocusOutHdl));
    m_xDialog->connect_toplevel_focus_changed(LINK(this, SfxDialogController, FocusChangeHdl));
}

IMPL_STATIC_LINK_NOARG(SfxDialogController, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*)
diff --git a/solenv/bin/native-code.py b/solenv/bin/native-code.py
index 4696341..2a1782b 100755
--- a/solenv/bin/native-code.py
+++ b/solenv/bin/native-code.py
@@ -476,7 +476,6 @@ custom_widgets = [
    'SdPageObjsTLB',
    'SearchBox',
    'SearchResultsBox',
    'SentenceEditWindow',
    'ShowNupOrderWindow',
    'ShowNupOrderWindow',
    'SidebarDialControl',
diff --git a/svx/source/dialog/SpellDialogChildWindow.cxx b/svx/source/dialog/SpellDialogChildWindow.cxx
index 51bd2fc..ae82769 100644
--- a/svx/source/dialog/SpellDialogChildWindow.cxx
+++ b/svx/source/dialog/SpellDialogChildWindow.cxx
@@ -32,10 +32,10 @@ SpellDialogChildWindow::SpellDialogChildWindow (
    : SfxChildWindow (_pParent, nId)
{
    SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
    m_xAbstractSpellDialog = pFact->CreateSvxSpellDialog(_pParent,
    m_xAbstractSpellDialog = pFact->CreateSvxSpellDialog(_pParent->GetFrameWeld(),
                                            pBindings,
                                            this );
    SetWindow( m_xAbstractSpellDialog->GetWindow() );
    SetController(m_xAbstractSpellDialog->GetController());
    SetHideNotDelete(true);
}

@@ -54,7 +54,7 @@ void SpellDialogChildWindow::InvalidateSpellDialog()
{
    OSL_ASSERT (m_xAbstractSpellDialog);
    if (m_xAbstractSpellDialog)
        m_xAbstractSpellDialog->Invalidate();
        m_xAbstractSpellDialog->InvalidateDialog();
}

bool SpellDialogChildWindow::HasAutoCorrection()
diff --git a/svx/source/dialog/rubydialog.cxx b/svx/source/dialog/rubydialog.cxx
index 7856b12..5f0a6e5 100644
--- a/svx/source/dialog/rubydialog.cxx
+++ b/svx/source/dialog/rubydialog.cxx
@@ -280,9 +280,9 @@ void SvxRubyDialog::Close()
{
    if (IsClosing())
        return;
    SfxViewShell* pViewShell = SfxViewShell::Current();
    if (pViewShell)
        pViewShell->GetViewFrame()->ToggleChildWindow(SID_RUBY_DIALOG);
    SfxViewFrame* pViewFrame = SfxViewFrame::Current();
    if (pViewFrame)
        pViewFrame->ToggleChildWindow(SID_RUBY_DIALOG);
}

void SvxRubyDialog::Activate()
diff --git a/svx/source/dialog/srchdlg.cxx b/svx/source/dialog/srchdlg.cxx
index 7911163..48dbc88 100644
--- a/svx/source/dialog/srchdlg.cxx
+++ b/svx/source/dialog/srchdlg.cxx
@@ -523,9 +523,9 @@ void SvxSearchDialog::Close()
    rBindings.GetDispatcher()->Execute( FID_SEARCH_OFF, SfxCallMode::SLOT, ppArgs );
    rBindings.Invalidate(SID_SEARCH_DLG);

    SfxViewShell* pViewShell = SfxViewShell::Current();
    if (pViewShell)
        pViewShell->GetViewFrame()->ToggleChildWindow(SID_SEARCH_DLG);
    SfxViewFrame* pViewFrame = SfxViewFrame::Current();
    if (pViewFrame)
        pViewFrame->ToggleChildWindow(SID_SEARCH_DLG);
}

TransliterationFlags SvxSearchDialog::GetTransliterationFlags() const
diff --git a/sw/source/uibase/dialog/SwSpellDialogChildWindow.cxx b/sw/source/uibase/dialog/SwSpellDialogChildWindow.cxx
index d8c927c..918d484 100644
--- a/sw/source/uibase/dialog/SwSpellDialogChildWindow.cxx
+++ b/sw/source/uibase/dialog/SwSpellDialogChildWindow.cxx
@@ -383,7 +383,7 @@ The code below would only be part of the solution.
            if(m_pSpellState->m_xStartRange.is())
            {
                LockFocusNotification( true );
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetWindow()->GetFrameWeld(),
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetController()->getDialog(),
                                                                                        VclMessageType::Question, VclButtonsType::YesNo, SwResId(STR_QUERY_SPELL_CONTINUE)));
                sal_uInt16 nRet = xBox->run();
                if (RET_YES == nRet)
@@ -411,10 +411,10 @@ The code below would only be part of the solution.
        {
            LockFocusNotification( true );
            OUString sInfo( SwResId( bNoDictionaryAvailable ? STR_DICTIONARY_UNAVAILABLE : STR_SPELLING_COMPLETED ) );
            vcl::Window* pThisWindow = GetWindow();
            auto xSpellController = GetController();
            // #i84610#
            std::unique_ptr<weld::MessageDialog> xBox(
                Application::CreateMessageDialog( pThisWindow->GetFrameWeld(),
                Application::CreateMessageDialog( xSpellController->getDialog(),
                                                  VclMessageType::Info,
                                                  VclButtonsType::Ok,
                                                  sInfo ) );
@@ -422,8 +422,7 @@ The code below would only be part of the solution.
            LockFocusNotification( false );
            // take care that the now valid selection is stored
            LoseFocus();
            if( pThisWindow )
                pThisWindow->GrabFocus();
            xSpellController->getDialog()->grab_focus();
        }
    }
    return aRet;
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index f5f86da2..ceff007 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -695,9 +695,9 @@ public:

void SalInstanceWidget::HandleEventListener(VclWindowEvent& rEvent)
{
    if (rEvent.GetId() == VclEventId::WindowGetFocus || rEvent.GetId() == VclEventId::WindowActivate)
    if (rEvent.GetId() == VclEventId::WindowGetFocus)
        m_aFocusInHdl.Call(*this);
    else if (rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::WindowDeactivate)
    else if (rEvent.GetId() == VclEventId::WindowLoseFocus)
        m_aFocusOutHdl.Call(*this);
    else if (rEvent.GetId() == VclEventId::WindowResize)
        m_aSizeAllocateHdl.Call(m_xWidget->GetSizePixel());
@@ -1140,6 +1140,22 @@ public:
        return *m_xWindow->GetSystemData();
    }

    virtual void connect_toplevel_focus_changed(const Link<weld::Widget&, void>& rLink) override
    {
        ensure_event_listener();
        weld::Window::connect_toplevel_focus_changed(rLink);
    }

    virtual void HandleEventListener(VclWindowEvent& rEvent) override
    {
        if (rEvent.GetId() == VclEventId::WindowActivate || rEvent.GetId() == VclEventId::WindowDeactivate)
        {
            signal_toplevel_focus_changed();
            return;
        }
        SalInstanceContainer::HandleEventListener(rEvent);
    }

    virtual ~SalInstanceWindow() override
    {
        clear_child_help(m_xWindow);
@@ -1899,6 +1915,7 @@ public:
        m_xMenuButton->SetSelectHdl(LINK(this, SalInstanceMenuButton, MenuSelectHdl));
        if (PopupMenu* pMenu = m_xMenuButton->GetPopupMenu())
        {
            pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics);
            const auto nCount = pMenu->GetItemCount();
            m_nLastId = nCount ? pMenu->GetItemId(nCount-1) : 0;
        }
@@ -1953,6 +1970,12 @@ public:
        pMenu->RemoveItem(pMenu->GetItemPos(pMenu->GetItemId(rId)));
    }

    virtual void clear() override
    {
        PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
        pMenu->Clear();
    }

    virtual void set_item_active(const OString& rIdent, bool bActive) override
    {
        PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
@@ -1965,6 +1988,12 @@ public:
        pMenu->SetItemText(pMenu->GetItemId(rIdent), rText);
    }

    virtual OUString get_item_label(const OString& rIdent) const override
    {
        PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
        return pMenu->GetItemText(pMenu->GetItemId(rIdent));
    }

    virtual void set_item_visible(const OString& rIdent, bool bShow) override
    {
        PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx
index a1b1af2..de5f7a1 100644
--- a/vcl/source/control/edit.cxx
+++ b/vcl/source/control/edit.cxx
@@ -1467,7 +1467,7 @@ bool Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
            if ( pImplFncGetSpecialChars )
            {
                Selection aSaveSel = GetSelection(); // if someone changes the selection in Get/LoseFocus, e.g. URL bar
                OUString aChars = pImplFncGetSpecialChars( this, GetFont() );
                OUString aChars = pImplFncGetSpecialChars( GetFrameWeld(), GetFont() );
                SetSelection( aSaveSel );
                if ( !aChars.isEmpty() )
                {
@@ -2028,7 +2028,7 @@ void Edit::Command( const CommandEvent& rCEvt )
        }
        else if (sCommand == "specialchar" && pImplFncGetSpecialChars)
        {
            OUString aChars = pImplFncGetSpecialChars( this, GetFont() );
            OUString aChars = pImplFncGetSpecialChars(GetFrameWeld(), GetFont());
            SetSelection( aSaveSel );
            if (!aChars.isEmpty())
            {
diff --git a/vcl/source/edit/vclmedit.cxx b/vcl/source/edit/vclmedit.cxx
index 1419602..4d2ebb3 100644
--- a/vcl/source/edit/vclmedit.cxx
+++ b/vcl/source/edit/vclmedit.cxx
@@ -713,7 +713,7 @@ void TextWindow::KeyInput( const KeyEvent& rKEvent )
        {
            // to maintain the selection
            mbActivePopup = true;
            OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() );
            OUString aChars = Edit::GetGetSpecialCharsFunction()(GetFrameWeld(), GetFont());
            if (!aChars.isEmpty())
            {
                mpExtTextView->InsertText( aChars );
@@ -827,7 +827,7 @@ void TextWindow::Command( const CommandEvent& rCEvt )
        }
        else if (sCommand == "specialchar")
        {
            OUString aChars = Edit::GetGetSpecialCharsFunction()( this, GetFont() );
            OUString aChars = Edit::GetGetSpecialCharsFunction()(GetFrameWeld(), GetFont());
            if (!aChars.isEmpty())
            {
                mpExtTextView->InsertText( aChars );
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 764cb78..d92b36a 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -2422,7 +2422,7 @@ public:
                     bool bCheck)
    {
        GtkWidget* pImage = nullptr;
        if (pIconName)
        if (pIconName && !pIconName->isEmpty())
        {
            GdkPixbuf* pixbuf = load_icon_by_name(*pIconName);
            if (!pixbuf)
@@ -2498,6 +2498,12 @@ public:
        gtk_menu_item_set_label(m_aMap[rIdent], MapToGtkAccelerator(rText).getStr());
    }

    OUString get_item_label(const OString& rIdent) const
    {
        const gchar* pText = gtk_menu_item_get_label(m_aMap.find(rIdent)->second);
        return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8);
    }

    void set_item_help_id(const OString& rIdent, const OString& rHelpId)
    {
        set_help_id(GTK_WIDGET(m_aMap[rIdent]), rHelpId);
@@ -2635,18 +2641,27 @@ class GtkInstanceWindow : public GtkInstanceContainer, public virtual weld::Wind
private:
    GtkWindow* m_pWindow;
    rtl::Reference<SalGtkXWindow> m_xWindow; //uno api
    gulong m_nToplevelFocusChangedSignalId;

    static void help_pressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer widget)
    {
        GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget);
        pThis->help();
    }

    static void signalToplevelFocusChanged(GtkWindow*, GParamSpec*, gpointer widget)
    {
        GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget);
        pThis->signal_toplevel_focus_changed();
    }

protected:
    void help();
public:
    GtkInstanceWindow(GtkWindow* pWindow, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
        : GtkInstanceContainer(GTK_CONTAINER(pWindow), pBuilder, bTakeOwnership)
        , m_pWindow(pWindow)
        , m_nToplevelFocusChangedSignalId(0)
    {
        //hook up F1 to show help
        GtkAccelGroup *pGroup = gtk_accel_group_new();
@@ -2802,8 +2817,31 @@ public:
        return ImplWindowStateToStr(aData);
    }

    virtual void connect_toplevel_focus_changed(const Link<weld::Widget&, void>& rLink) override
    {
        assert(!m_nToplevelFocusChangedSignalId);
        m_nToplevelFocusChangedSignalId = g_signal_connect(m_pWindow, "notify::has-toplevel-focus", G_CALLBACK(signalToplevelFocusChanged), this);
        weld::Window::connect_toplevel_focus_changed(rLink);
    }

    virtual void disable_notify_events() override
    {
        if (m_nToplevelFocusChangedSignalId)
            g_signal_handler_block(m_pWidget, m_nToplevelFocusChangedSignalId);
        GtkInstanceContainer::disable_notify_events();
    }

    virtual void enable_notify_events() override
    {
        GtkInstanceContainer::enable_notify_events();
        if (m_nToplevelFocusChangedSignalId)
            g_signal_handler_unblock(m_pWidget, m_nToplevelFocusChangedSignalId);
    }

    virtual ~GtkInstanceWindow() override
    {
        if (m_nToplevelFocusChangedSignalId)
            g_signal_handler_disconnect(m_pWindow, m_nToplevelFocusChangedSignalId);
        if (m_xWindow.is())
            m_xWindow->clear();
    }
@@ -5215,6 +5253,11 @@ public:
        MenuHelper::remove_item(rId);
    }

    virtual void clear() override
    {
        clear_items();
    }

    virtual void set_item_active(const OString& rIdent, bool bActive) override
    {
        MenuHelper::set_item_active(rIdent, bActive);
@@ -5230,6 +5273,11 @@ public:
        MenuHelper::set_item_label(rIdent, rLabel);
    }

    virtual OUString get_item_label(const OString& rIdent) const override
    {
        return MenuHelper::get_item_label(rIdent);
    }

    virtual void set_item_visible(const OString& rIdent, bool bVisible) override
    {
        MenuHelper::set_item_visible(rIdent, bVisible);