/* -*- 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 <comphelper/string.hxx>
#include <comphelper/lok.hxx>
#include <scitems.hxx>
#include <editeng/eeitem.hxx>
#include <i18nutil/unicode.hxx>
#include <i18nutil/transliteration.hxx>
 
#include <svx/clipfmtitem.hxx>
#include <svx/svxdlg.hxx>
#include <editeng/contouritem.hxx>
#include <editeng/outliner.hxx>
#include <editeng/crossedoutitem.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editview.hxx>
#include <editeng/escapementitem.hxx>
#include <editeng/flditem.hxx>
#include <editeng/flstitem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/urlfieldhelper.hxx>
#include <editeng/editund2.hxx>
#include <svx/hlnkitem.hxx>
#include <vcl/EnumContext.hxx>
#include <editeng/postitem.hxx>
#include <editeng/scriptsetitem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/wghtitem.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/namedcolor.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <svtools/cliplistener.hxx>
#include <svl/whiter.hxx>
#include <sot/formats.hxx>
#include <vcl/transfer.hxx>
#include <vcl/unohelp2.hxx>
#include <svl/stritem.hxx>
#include <editeng/colritem.hxx>
 
#include <editsh.hxx>
#include <global.hxx>
#include <appoptio.hxx>
#include <scmod.hxx>
#include <sc.hrc>
#include <inputhdl.hxx>
#include <viewutil.hxx>
#include <viewdata.hxx>
#include <document.hxx>
#include <reffind.hxx>
#include <tabvwsh.hxx>
#include <editutil.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <gridwin.hxx>
 
#define ShellClass_ScEditShell
#include <scslots.hxx>
 
#include <scui_def.hxx>
#include <scabstdlg.hxx>
#include <memory>
 
using namespace ::com::sun::star;
 
 
SFX_IMPL_INTERFACE(ScEditShell, SfxShell)
 
void ScEditShell::InitInterface_Impl()
{
    GetStaticInterface()->RegisterPopupMenu(u"celledit"_ustr);
}
 
ScEditShell::ScEditShell(EditView* pView, ScViewData& rData) :
    pEditView       (pView),
    rViewData       (rData),
    bPastePossible  (false),
    bIsInsertMode   (true)
{
    SetPool( pEditView->getEditEngine().GetEmptyItemSet().GetPool() );
    SetUndoManager( &pEditView->getEditEngine().GetUndoManager() );
    SetName(u"EditCell"_ustr);
    SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::EditCell));
}
 
ScEditShell::~ScEditShell()
{
    if ( mxClipEvtLstnr.is() )
    {
        mxClipEvtLstnr->RemoveListener( rViewData.GetActiveWin() );
 
        //  The listener may just now be waiting for the SolarMutex and call the link
        //  afterwards, in spite of RemoveListener. So the link has to be reset, too.
        mxClipEvtLstnr->ClearCallbackLink();
    }
}
 
ScInputHandler* ScEditShell::GetMyInputHdl()
{
    return ScModule::get()->GetInputHdl(rViewData.GetViewShell());
}
 
void ScEditShell::SetEditView(EditView* pView)
{
    pEditView = pView;
    pEditView->SetInsertMode( bIsInsertMode );
    SetPool( pEditView->getEditEngine().GetEmptyItemSet().GetPool() );
    SetUndoManager( &pEditView->getEditEngine().GetUndoManager() );
}
 
static void lcl_RemoveAttribs( EditView& rEditView )
{
    ScEditEngineDefaulter* pEngine = static_cast<ScEditEngineDefaulter*>(&rEditView.getEditEngine());
 
    bool bOld = pEngine->SetUpdateLayout(false);
 
    OUString aName = ScResId( STR_UNDO_DELETECONTENTS );
    ViewShellId nViewShellId(-1);
    if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
        nViewShellId = pViewSh->GetViewShellId();
    pEngine->GetUndoManager().EnterListAction( aName, aName, 0, nViewShellId );
 
    rEditView.RemoveAttribs(true);
    pEngine->RepeatDefaults();      // paragraph attributes from cell formats must be preserved
 
    pEngine->GetUndoManager().LeaveListAction();
 
    pEngine->SetUpdateLayout(bOld);
}
 
static void lclInsertCharacter( EditView* pTableView, EditView* pTopView, sal_Unicode cChar )
{
    OUString aString( cChar );
    if( pTableView )
        pTableView->InsertText( aString );
    if( pTopView )
        pTopView->InsertText( aString );
}
 
void ScEditShell::Execute( SfxRequest& rReq )
{
    const SfxItemSet*   pReqArgs    = rReq.GetArgs();
    sal_uInt16              nSlot   = rReq.GetSlot();
    SfxBindings&        rBindings   = rViewData.GetBindings();
 
    ScInputHandler* pHdl = GetMyInputHdl();
    OSL_ENSURE(pHdl,"no ScInputHandler");
 
    EditView* pTopView   = pHdl->GetTopView();      // Has thee input cell the focus?
    EditView* pTableView = pHdl->GetTableView();
 
    OSL_ENSURE(pTableView,"no EditView :-(");
    /* #i91683# No EditView if spell-check dialog is active and positioned on
     * an error and user immediately (without double click or F2) selected a
     * text portion of that cell with the mouse and wanted to modify it. */
    /* FIXME: Bailing out only cures the symptom and prevents a crash, no edit
     * action is possible. A real fix somehow would need to create a valid
     * EditView from the spell-check view. */
    if (!pTableView)
        return;
 
    EditEngine& rEngine = pTableView->getEditEngine();
 
    pHdl->DataChanging();
    bool bSetSelIsRef = false;
    bool bSetModified = true;
 
    switch ( nSlot )
    {
        case SID_ATTR_INSERT:
        case FID_INS_CELL_CONTENTS: // Insert taste, while defined as Acc
            bIsInsertMode = !pTableView->IsInsertMode();
            pTableView->SetInsertMode( bIsInsertMode );
            if (pTopView)
                pTopView->SetInsertMode( bIsInsertMode );
            rBindings.Invalidate( SID_ATTR_INSERT );
            break;
 
        case SID_THES:
            {
                OUString aReplaceText;
                const SfxStringItem* pItem2 = rReq.GetArg(FN_PARAM_THES_WORD_REPLACE);
                if (pItem2)
                    aReplaceText = pItem2->GetValue();
                if (!aReplaceText.isEmpty())
                    ReplaceTextWithSynonym( *pEditView, aReplaceText );
            }
            break;
 
        case SID_COPY:
            pTableView->Copy();
            bSetModified = false;
            break;
 
        case SID_CUT:
            pTableView->Cut();
            if (pTopView)
                pTopView->DeleteSelected();
            break;
 
        case SID_PASTE:
        {
            EVControlBits nControl = pTableView->GetControlWord();
            if (pTopView)
            {
                pTopView->Paste();
                pTableView->SetControlWord(nControl | EVControlBits::SINGLELINEPASTE);
            }
 
            pTableView->PasteSpecial();
            pTableView->SetControlWord(nControl);
        }
        break;
 
        case SID_DELETE:
            pTableView->DeleteSelected();
            if (pTopView)
                pTopView->DeleteSelected();
            break;
 
        case SID_CELL_FORMAT_RESET:                 // "Standard"
            lcl_RemoveAttribs( *pTableView );
            if ( pTopView )
                lcl_RemoveAttribs( *pTopView );
            break;
 
        case SID_CLIPBOARD_FORMAT_ITEMS:
            {
                SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
                const SfxPoolItem* pItem;
                if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
                    if (auto pIntItem = dynamic_cast<const SfxUInt32Item*>( pItem))
                        nFormat = static_cast<SotClipboardFormatId>(pIntItem->GetValue());
 
                if ( nFormat != SotClipboardFormatId::NONE )
                {
                    if (SotClipboardFormatId::STRING == nFormat)
                        pTableView->Paste();
                    else
                        pTableView->PasteSpecial();
 
                    if (pTopView)
                        pTopView->Paste();
                }
            }
            break;
 
        case SID_PASTE_SPECIAL:
            {
                SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
                ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(rViewData.GetDialogParent()));
                SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
                pDlg->Insert( SotClipboardFormatId::STRING, OUString() );
                pDlg->Insert( SotClipboardFormatId::RTF,    OUString() );
                pDlg->Insert( SotClipboardFormatId::RICHTEXT,    OUString() );
                // Do not offer SotClipboardFormatId::STRING_TSVC for
                // in-cell paste.
 
                TransferableDataHelper aDataHelper(
                    TransferableDataHelper::CreateFromSystemClipboard( rViewData.GetActiveWin() ) );
 
                nFormat = pDlg->GetFormat( aDataHelper.GetTransferable() );
                pDlg.disposeAndClear();
 
                // while the dialog was open, edit mode may have been stopped
                if (!ScModule::get()->IsInputMode())
                    return;
 
                if (nFormat != SotClipboardFormatId::NONE)
                {
                    if (SotClipboardFormatId::STRING == nFormat)
                        pTableView->Paste();
                    else
                        pTableView->PasteSpecial();
 
                    if (pTopView)
                        pTopView->Paste();
                }
 
                if (vcl::Window* pViewWindow = pTopView ? pTopView->GetWindow() : nullptr)
                    pViewWindow->GrabFocus();
            }
            break;
 
        case SID_PASTE_UNFORMATTED:
            {
                pTableView->Paste();
 
                if (pTopView)
                {
                    pTopView->Paste();
                    if (vcl::Window* pViewWindow = pTopView->GetWindow())
                        pViewWindow->GrabFocus();
                }
            }
            break;
 
        case SID_SELECTALL:
            {
                sal_Int32 nPar = rEngine.GetParagraphCount();
                if (nPar)
                {
                    sal_Int32 nLen = rEngine.GetTextLen(nPar-1);
                    pTableView->SetSelection(ESelection(0,0,nPar-1,nLen));
                    if (pTopView)
                        pTopView->SetSelection(ESelection(0,0,nPar-1,nLen));
                    rBindings.Invalidate( SID_ATTR_CHAR_FONT );
                    rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
                    rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
                    rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
                    rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
                    rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
                    rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
                    rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
                    rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
                    rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
                    rBindings.Invalidate( SID_SET_SUB_SCRIPT );
                }
            }
            return;
        case SID_UNICODE_NOTATION_TOGGLE:
            {
                EditView* pActiveView = pHdl->GetActiveView();
                if( pActiveView )
                {
                    ESelection aSel( pActiveView->GetSelection() );
                    OUString sInput(aSel.HasRange() ? pActiveView->GetSelected()
                                                    : rEngine.GetText());
 
                    if (aSel.start.nIndex > aSel.end.nIndex)
                        aSel.end.nIndex = aSel.start.nIndex;
 
                    //calculate a valid end-position by reading logical characters
                    sal_Int32 nUtf16Pos=0;
                    while ((nUtf16Pos < sInput.getLength()) && (nUtf16Pos < aSel.end.nIndex))
                    {
                        sInput.iterateCodePoints(&nUtf16Pos);
                        if (nUtf16Pos > aSel.end.nIndex)
                            aSel.end.nIndex = nUtf16Pos;
                    }
 
                    ToggleUnicodeCodepoint aToggle;
                    while( nUtf16Pos && aToggle.AllowMoreInput( sInput[nUtf16Pos-1]) )
                        --nUtf16Pos;
                    OUString sReplacement = aToggle.ReplacementString();
                    if( !sReplacement.isEmpty() )
                    {
                        aSel.start.nIndex = aSel.end.nIndex - aToggle.StringToReplace().getLength();
                        pTableView->SetSelection( aSel );
                        pTableView->InsertText(sReplacement, true);
                        if( pTopView )
                        {
                            pTopView->SetSelection( aSel );
                            pTopView->InsertText(sReplacement, true);
                        }
                    }
                }
            }
            break;
 
        case SID_CHARMAP:
            {
                SvtScriptType nScript = pTableView->GetSelectedScriptType();
                sal_uInt16 nFontWhich = ( nScript == SvtScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK :
                                ( ( nScript == SvtScriptType::COMPLEX ) ? EE_CHAR_FONTINFO_CTL :
                                                                        EE_CHAR_FONTINFO );
                auto const attribs = pTableView->GetAttribs();
                const SvxFontItem& rItem = static_cast<const SvxFontItem&>(
                            attribs.Get(nFontWhich));
 
                OUString aString;
                std::shared_ptr<SvxFontItem> aNewItem(std::make_shared<SvxFontItem>(EE_CHAR_FONTINFO));
 
                const SfxItemSet *pArgs = rReq.GetArgs();
                const SfxPoolItem* pItem = nullptr;
                if( pArgs )
                    pArgs->GetItemState(SID_CHARMAP, false, &pItem);
 
                if ( pItem )
                {
                    aString = static_cast<const SfxStringItem*>(pItem)->GetValue();
                    const SfxStringItem* pFontItem = pArgs->GetItemIfSet( SID_ATTR_SPECIALCHAR, false);
                    if ( pFontItem )
                    {
                        const OUString& aFontName(pFontItem->GetValue());
                        vcl::Font aFont(aFontName, Size(1,1)); // Size just because CTOR
                        // tdf#125054 see comment in drtxob.cxx, same ID
                        aNewItem = std::make_shared<SvxFontItem>(
                            aFont.GetFamilyTypeMaybeAskConfig(), aFont.GetFamilyName(),
                            aFont.GetStyleName(), aFont.GetPitchMaybeAskConfig(),
                            aFont.GetCharSet(), ATTR_FONT);
                    }
                    else
                    {
                        aNewItem.reset(rItem.Clone());
                    }
 
                    // tdf#125054 force Item to correct intended ID
                    aNewItem->SetWhich(EE_CHAR_FONTINFO);
                }
                else
                {
                    ScViewUtil::ExecuteCharMap(rItem, *rViewData.GetViewShell());
 
                    // while the dialog was open, edit mode may have been stopped
                    if (!ScModule::get()->IsInputMode())
                        return;
                }
 
                if ( !aString.isEmpty() )
                {
                    //  if string contains WEAK characters, set all fonts
                    SvtScriptType nSetScript;
                    ScDocument& rDoc = rViewData.GetDocument();
                    if ( rDoc.HasStringWeakCharacters( aString ) )
                        nSetScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
                    else
                        nSetScript = rDoc.GetStringScriptType( aString );
 
                    SfxItemSet aSet( pTableView->GetEmptyItemSet() );
                    SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, GetPool() );
                    aSetItem.PutItemForScriptType( nSetScript, *aNewItem );
                    aSet.Put( aSetItem.GetItemSet(), false );
 
                    // SetAttribs on the View selects a word, when nothing is selected
                    pTableView->getEditEngine().QuickSetAttribs( aSet, pTableView->GetSelection() );
                    pTableView->InsertText(aString);
                    if (pTopView)
                        pTopView->InsertText(aString);
 
                    SfxStringItem aStringItem( SID_CHARMAP, aString );
                    SfxStringItem aFontItem( SID_ATTR_SPECIALCHAR, aNewItem->GetFamilyName() );
                    rReq.AppendItem( aFontItem );
                    rReq.AppendItem( aStringItem );
                    rReq.Done();
 
                }
 
                if (vcl::Window* pViewWindow = pTopView ? pTopView->GetWindow() : nullptr)
                    pViewWindow->GrabFocus();
            }
            break;
 
        case FID_INSERT_NAME:
            {
                ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
 
                ScopedVclPtr<AbstractScNamePasteDlg> pDlg(pFact->CreateScNamePasteDlg(rViewData.GetDialogParent(), rViewData.GetDocShell()));
                short nRet = pDlg->Execute();
                // pDlg is needed below
 
                // while the dialog was open, edit mode may have been stopped
                if (!ScModule::get()->IsInputMode())
                    return;
 
                if ( nRet == BTN_PASTE_NAME )
                {
                    std::vector<OUString> aNames = pDlg->GetSelectedNames();
                    if (!aNames.empty())
                    {
                        OUStringBuffer aBuffer;
                        for (const auto& rName : aNames)
                        {
                            aBuffer.append(rName + " ");
                        }
                        const OUString s = aBuffer.makeStringAndClear();
                        pTableView->InsertText(s);
                        if (pTopView)
                            pTopView->InsertText(s);
                    }
                }
                pDlg.disposeAndClear();
 
                if (vcl::Window* pViewWindow = pTopView ? pTopView->GetWindow() : nullptr)
                    pViewWindow->GrabFocus();
            }
            break;
 
        case SID_CHAR_DLG_EFFECT:
        case SID_CHAR_DLG:
            {
                SfxItemSet aAttrs( pTableView->GetAttribs() );
 
                SfxObjectShell* pObjSh = rViewData.GetSfxDocShell();
 
                ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
 
                ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScCharDlg(
                    rViewData.GetDialogParent(), &aAttrs, pObjSh, false));
                if (nSlot == SID_CHAR_DLG_EFFECT)
                {
                    pDlg->SetCurPageId(u"fonteffects"_ustr);
                }
                short nRet = pDlg->Execute();
                // pDlg is needed below
 
                // while the dialog was open, edit mode may have been stopped
                if (!ScModule::get()->IsInputMode())
                    return;
 
                if ( nRet == RET_OK )
                {
                    const SfxItemSet* pOut = pDlg->GetOutputItemSet();
                    pTableView->SetAttribs( *pOut );
                }
            }
            break;
 
        case SID_TOGGLE_REL:
            {
                auto PaMToStringIndex = [](const OUString& s, EPaM pam)
                {
                    sal_Int32 index = 0;
                    for (; pam.nPara > 0; --pam.nPara)
                    {
                        index = s.indexOf('\n', index) + 1; // becomes 0 on "not found"
                        if (index <= 0)
                            return s.getLength();
                    }
                    index += pam.nIndex;
                    return std::min(index, s.getLength());
                };
                auto StringIndexToPaM = [](const OUString& s, sal_Int32 index)
                {
                    EPaM pam;
                    for (sal_Int32 i = 0; i < index; ++i)
                    {
                        if (s[i] == '\n')
                        {
                            ++pam.nPara;
                            pam.nIndex = 0;
                        }
                        else
                        {
                            ++pam.nIndex;
                        }
                    }
                    return pam;
                };
 
                OUString aText = rEngine.GetText(LINEEND_LF);
                ESelection aSel = pEditView->GetSelection(); // current View
                sal_Int32 nStart = PaMToStringIndex(aText, aSel.start);
                sal_Int32 nEnd = PaMToStringIndex(aText, aSel.end);
 
                ScDocument& rDoc = rViewData.GetDocument();
                ScRefFinder aFinder(aText, rViewData.GetCurPos(), rDoc, rDoc.GetAddressConvention());
                aFinder.ToggleRel(nStart, nEnd);
                if (aFinder.GetFound())
                {
                    const OUString& aNew = aFinder.GetText();
                    ESelection aNewSel(StringIndexToPaM(aNew, aFinder.GetSelStart()));
                    aNewSel.end = StringIndexToPaM(aNew, aFinder.GetSelEnd());
                    rEngine.SetText( aNew );
                    pTableView->SetSelection( aNewSel );
                    if ( pTopView )
                    {
                        pTopView->getEditEngine().SetText( aNew );
                        pTopView->SetSelection( aNewSel );
                    }
 
                    // reference is being selected -> do not overwrite when typing
                    bSetSelIsRef = true;
                }
            }
            break;
 
        case SID_HYPERLINK_SETLINK:
            if( pReqArgs )
            {
                const SfxPoolItem* pItem;
                if ( pReqArgs->GetItemState( SID_HYPERLINK_SETLINK, true, &pItem ) == SfxItemState::SET )
                {
                    const SvxHyperlinkItem* pHyper = static_cast<const SvxHyperlinkItem*>(pItem);
                    const OUString& rName     = pHyper->GetName();
                    const OUString& rURL      = pHyper->GetURL();
                    const OUString& rTarget   = pHyper->GetTargetFrame();
                    SvxLinkInsertMode eMode = pHyper->GetInsertMode();
 
                    bool bCellLinksOnly
                        = (ScModule::get()->GetAppOptions().GetLinksInsertedLikeMSExcel()
                          && rViewData.GetSfxDocShell()->GetMedium()->GetFilter()->IsMSOFormat())
                          || comphelper::LibreOfficeKit::isActive();
 
                    bool bDone = false;
                    if ( (eMode == HLINK_DEFAULT || eMode == HLINK_FIELD) && !bCellLinksOnly )
                    {
                        std::unique_ptr<const SvxFieldData> aSvxFieldDataPtr(GetURLField());
                        const SvxURLField* pURLField(static_cast<const SvxURLField*>(aSvxFieldDataPtr.get()));
                        if ( pURLField )
                        {
                            // select old field
 
                            ESelection aSel = pTableView->GetSelection();
                            aSel.Adjust();
                            aSel.end.nPara = aSel.start.nPara;
                            aSel.end.nIndex = aSel.start.nIndex + 1;
                            pTableView->SetSelection( aSel );
 
                            // insert new field
 
                            SvxURLField aURLField( rURL, rName, SvxURLFormat::Repr );
                            aURLField.SetTargetFrame( rTarget );
                            SvxFieldItem aURLItem( aURLField, EE_FEATURE_FIELD );
                            pTableView->InsertField( aURLItem );
                            pTableView->SetSelection( aSel );       // select inserted field
 
                            // now also fields in the Top-View
 
                            if ( pTopView )
                            {
                                aSel = pTopView->GetSelection();
                                aSel.end.nPara = aSel.start.nPara;
                                aSel.end.nIndex = aSel.start.nIndex + 1;
                                pTopView->SetSelection( aSel );
                                pTopView->InsertField( aURLItem );
                                pTopView->SetSelection( aSel );     // select inserted field
                            }
 
                            bDone = true;
                        }
                    }
 
                    if (!bDone)
                    {
                        if (bCellLinksOnly)
                        {
                            sal_Int32 nPar = rEngine.GetParagraphCount();
                            if (nPar)
                            {
                                sal_Int32 nLen = rEngine.GetTextLen(nPar - 1);
                                pTableView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
                                if (pTopView)
                                    pTopView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
                            }
                        }
                        rViewData.GetViewShell()->
                            InsertURL( rName, rURL, rTarget, static_cast<sal_uInt16>(eMode) );
 
                        // when "Button", the InsertURL in ViewShell turns the EditShell  off
                        // thus the immediate return statement
                        return;
                    }
                }
            }
            break;
        case SID_INSERT_HYPERLINK:
            {
                rViewData.GetViewShell()->GetViewFrame().GetDispatcher()->Execute(
                    SID_HYPERLINK_DIALOG);
            }
        break;
        case SID_EDIT_HYPERLINK:
            {
                // Ensure the field is selected first
                pEditView->SelectFieldAtCursor();
                rViewData.GetViewShell()->GetViewFrame().GetDispatcher()->Execute(
                    SID_HYPERLINK_DIALOG);
            }
        break;
        case SID_COPY_HYPERLINK_LOCATION:
            {
                const SvxFieldItem* pFieldItem
                    = pEditView->GetFieldAtSelection(/*AlsoCheckBeforeCursor=*/true);
                const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr;
                if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
                {
                    uno::Reference<datatransfer::clipboard::XClipboard> xClipboard
                        = pEditView->GetClipboard();
                    vcl::unohelper::TextDataObject::CopyStringTo(pURLField->GetURL(), xClipboard, SfxViewShell::Current());
                }
            }
        break;
        case SID_REMOVE_HYPERLINK:
            {
                URLFieldHelper::RemoveURLField(*pEditView);
            }
        break;
 
        case FN_INSERT_SOFT_HYPHEN:
            lclInsertCharacter( pTableView, pTopView, CHAR_SHY );
        break;
        case FN_INSERT_HARDHYPHEN:
            lclInsertCharacter( pTableView, pTopView, CHAR_NBHY );
        break;
        case FN_INSERT_HARD_SPACE:
            lclInsertCharacter( pTableView, pTopView, CHAR_NBSP );
        break;
        case FN_INSERT_NNBSP:
            lclInsertCharacter( pTableView, pTopView, CHAR_NNBSP );
        break;
        case SID_INSERT_RLM:
            lclInsertCharacter( pTableView, pTopView, CHAR_RLM );
        break;
        case SID_INSERT_LRM:
            lclInsertCharacter( pTableView, pTopView, CHAR_LRM );
        break;
        case SID_INSERT_ZWSP:
            lclInsertCharacter( pTableView, pTopView, CHAR_ZWSP );
        break;
        case SID_INSERT_WJ:
            lclInsertCharacter( pTableView, pTopView, CHAR_WJ );
        break;
        case SID_INSERT_FIELD_SHEET:
        {
            SvxTableField aField(rViewData.CurrentTabForData());
            SvxFieldItem aItem(aField, EE_FEATURE_FIELD);
            pTableView->InsertField(aItem);
        }
        break;
        case SID_INSERT_FIELD_TITLE:
        {
            SvxFileField aField;
            SvxFieldItem aItem(aField, EE_FEATURE_FIELD);
            pTableView->InsertField(aItem);
        }
        break;
        case SID_INSERT_FIELD_DATE_VAR:
        {
            SvxDateField aField;
            SvxFieldItem aItem(aField, EE_FEATURE_FIELD);
            pTableView->InsertField(aItem);
        }
        break;
    }
 
    pHdl->DataChanged(false, bSetModified);
    if (bSetSelIsRef)
        pHdl->SetSelIsRef(true);
}
 
static void lcl_DisableAll( SfxItemSet& rSet )    // disable all slots
{
    SfxWhichIter aIter( rSet );
    sal_uInt16 nWhich = aIter.FirstWhich();
    while (nWhich)
    {
        rSet.DisableItem( nWhich );
        nWhich = aIter.NextWhich();
    }
}
 
void ScEditShell::GetState( SfxItemSet& rSet )
{
    // When deactivating the view, edit mode is stopped, but the EditShell is left active
    // (a shell can't be removed from within Deactivate). In that state, the EditView isn't inserted
    // into the EditEngine, so it can have an invalid selection and must not be used.
    ScInputHandler* pHdl = GetMyInputHdl();
    if ( !rViewData.HasEditView( rViewData.GetActivePart() ) )
    {
        lcl_DisableAll( rSet );
 
        // Some items are actually useful and still applicable when in formula building mode: enable
        if (pHdl && pHdl->IsFormulaMode())
        {
            rSet.ClearItem(SID_TOGGLE_REL); //  F4 Cycle Cell Reference Types
            rSet.ClearItem(SID_CHARMAP); // Insert Special Characters
        }
        return;
    }
 
    EditView* pActiveView = pHdl ? pHdl->GetActiveView() : pEditView;
 
    SfxWhichIter aIter( rSet );
    sal_uInt16 nWhich = aIter.FirstWhich();
    while (nWhich)
    {
        switch (nWhich)
        {
            case SID_ATTR_INSERT:   // Status row
                {
                    if ( pActiveView )
                        rSet.Put( SfxBoolItem( nWhich, pActiveView->IsInsertMode() ) );
                    else
                    {
                        // Here the code used to pass the value 42 and it used
                        // to "work" without warnings because the SfxBoolItem
                        // was based on 'sal_Bool', which is actually 'unsigned
                        // char'. But now it uses actual 'bool', and passing 42
                        // for a 'bool' parameter causes a warning at least with
                        // MSVC.  So use 'true'. I really really hope there is
                        // not code somewhere that retrieves this "boolean" item
                        // and checks it value for the magic value 42...
                        rSet.Put( SfxBoolItem( nWhich,  true) );
                    }
                }
                break;
 
            case SID_HYPERLINK_GETLINK:
                {
                    SvxHyperlinkItem aHLinkItem;
                    aHLinkItem.SetShowName(false);
                    bool bCellLinksOnly
                        = (ScModule::get()->GetAppOptions().GetLinksInsertedLikeMSExcel()
                          && rViewData.GetSfxDocShell()->GetMedium()->GetFilter()->IsMSOFormat())
                          || comphelper::LibreOfficeKit::isActive();
                    std::unique_ptr<const SvxFieldData> aSvxFieldDataPtr(GetURLField());
                    const SvxURLField* pURLField(static_cast<const SvxURLField*>(aSvxFieldDataPtr.get()));
                    if (!bCellLinksOnly)
                    {
                        if (pURLField)
                        {
                            aHLinkItem.SetName(pURLField->GetRepresentation());
                            aHLinkItem.SetURL(pURLField->GetURL());
                            aHLinkItem.SetTargetFrame(pURLField->GetTargetFrame());
                        }
                        else if (pActiveView)
                        {
                            // use selected text as name for urls
                            OUString sReturn = pActiveView->GetSelected();
                            sReturn = sReturn.copy(
                                0, std::min(sReturn.getLength(), static_cast<sal_Int32>(255)));
                            aHLinkItem.SetName(comphelper::string::stripEnd(sReturn, ' '));
                        }
                    }
                    else
                    {
                        if (!pURLField)
                        {
                            aSvxFieldDataPtr = GetFirstURLFieldFromCell();
                            pURLField = static_cast<const SvxURLField*>(aSvxFieldDataPtr.get());
                        }
                        if (pURLField)
                        {
                            aHLinkItem.SetURL(pURLField->GetURL());
                            aHLinkItem.SetTargetFrame(pURLField->GetTargetFrame());
                        }
                        ScDocument& rDoc = rViewData.GetDocument();
                        SCCOL nPosX = rViewData.GetCurX();
                        SCROW nPosY = rViewData.GetCurY();
                        SCTAB nTab = rViewData.CurrentTabForData();
                        aHLinkItem.SetName(rDoc.GetString(nPosX, nPosY, nTab));
                    }
                    rSet.Put(aHLinkItem);
                }
                break;
 
            case SID_INSERT_HYPERLINK:
                {
                    // Disable insert hyperlink if no text is selected or cursor is at a URL field
                    ESelection aSel( pActiveView->GetSelection() );
                    if (!aSel.HasRange() || URLFieldHelper::IsCursorAtURLField(*pEditView,
                                                            /*AlsoCheckBeforeCursor=*/true))
                        rSet.DisableItem (nWhich);
                }
                break;
 
            case SID_EDIT_HYPERLINK:
            case SID_COPY_HYPERLINK_LOCATION:
            case SID_REMOVE_HYPERLINK:
                {
                    if (!URLFieldHelper::IsCursorAtURLField(*pEditView,
                                                            /*AlsoCheckBeforeCursor=*/true))
                        rSet.DisableItem (nWhich);
                }
                break;
 
            case SID_TRANSLITERATE_HALFWIDTH:
            case SID_TRANSLITERATE_FULLWIDTH:
            case SID_TRANSLITERATE_HIRAGANA:
            case SID_TRANSLITERATE_KATAKANA:
            case SID_INSERT_RLM:
            case SID_INSERT_LRM:
                ScViewUtil::HideDisabledSlot( rSet, rViewData.GetBindings(), nWhich );
            break;
 
            case SID_THES:
                {
                    OUString        aStatusVal;
                    LanguageType    nLang = LANGUAGE_NONE;
                    bool bIsLookUpWord = pActiveView &&
                        GetStatusValueForThesaurusFromContext(aStatusVal, nLang, *pActiveView);
                    rSet.Put( SfxStringItem( SID_THES, aStatusVal ) );
 
                    // disable thesaurus context menu entry if there is nothing to look up
                    bool bCanDoThesaurus = ScModule::HasThesaurusLanguage( nLang );
                    if (!bIsLookUpWord || !bCanDoThesaurus)
                        rSet.DisableItem( SID_THES );
                }
                break;
            case SID_INSERT_FIELD_SHEET:
            case SID_INSERT_FIELD_TITLE:
            case SID_INSERT_FIELD_DATE_VAR:
            break;
            case SID_COPY:
            case SID_CUT:
                if (GetObjectShell() && GetObjectShell()->isContentExtractionLocked())
                {
                    rSet.DisableItem(SID_COPY);
                    rSet.DisableItem(SID_CUT);
                }
                break;
 
        }
        nWhich = aIter.NextWhich();
    }
}
 
std::unique_ptr<const SvxFieldData> ScEditShell::GetURLField()
{
    ScInputHandler* pHdl = GetMyInputHdl();
    EditView* pActiveView = pHdl ? pHdl->GetActiveView() : pEditView;
    if (!pActiveView)
        return std::unique_ptr<const SvxFieldData>();
 
    const SvxFieldData* pField = pActiveView->GetFieldUnderMouseOrInSelectionOrAtCursor();
    if (auto pURLField = dynamic_cast<const SvxURLField*>(pField))
        return pURLField->Clone();
 
    return std::unique_ptr<const SvxFieldData>();
}
 
std::unique_ptr<const SvxFieldData> ScEditShell::GetFirstURLFieldFromCell()
{
    EditEngine& rEditEngine = GetEditView()->getEditEngine();
    sal_Int32 nParaCount = rEditEngine.GetParagraphCount();
    for (sal_Int32 nPara = 0; nPara < nParaCount; ++nPara)
    {
        ESelection aSel(nPara, 0);
        std::vector<sal_Int32> aPosList;
        rEditEngine.GetPortions(nPara, aPosList);
        for (const auto& rPos : aPosList)
        {
            aSel.end.nIndex = rPos;
 
            SfxItemSet aEditSet(rEditEngine.GetAttribs(aSel));
            if (aSel.start.nIndex + 1 == aSel.end.nIndex)
            {
                // test if the character is a text field
                if (const SvxFieldItem* pItem = aEditSet.GetItemIfSet(EE_FEATURE_FIELD, false))
                {
                    const SvxFieldData* pField = pItem->GetField();
                    if (const SvxURLField* pUrlField = dynamic_cast<const SvxURLField*>(pField))
                    {
                        return pUrlField->Clone();
                    }
                }
            }
            aSel.start.nIndex = aSel.end.nIndex;
        }
    }
 
    return std::unique_ptr<const SvxFieldData>();
}
 
IMPL_LINK( ScEditShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
{
    bPastePossible = ( pDataHelper->HasFormat( SotClipboardFormatId::STRING )
            || pDataHelper->HasFormat( SotClipboardFormatId::RTF )
            || pDataHelper->HasFormat( SotClipboardFormatId::RICHTEXT ));
 
    SfxBindings& rBindings = rViewData.GetBindings();
    rBindings.Invalidate( SID_PASTE );
    rBindings.Invalidate( SID_PASTE_SPECIAL );
    rBindings.Invalidate( SID_PASTE_UNFORMATTED );
    rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS );
}
 
void ScEditShell::GetClipState( SfxItemSet& rSet )
{
    // Do not offer SotClipboardFormatId::STRING_TSVC for in-cell paste.
 
    if ( !mxClipEvtLstnr.is() )
    {
        // create listener
        mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, ScEditShell, ClipboardChanged ) );
        vcl::Window* pWin = rViewData.GetActiveWin();
        mxClipEvtLstnr->AddListener( pWin );
 
        // get initial state
        TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( rViewData.GetActiveWin() ) );
        bPastePossible = ( aDataHelper.HasFormat( SotClipboardFormatId::STRING )
                || aDataHelper.HasFormat( SotClipboardFormatId::RTF )
                || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) );
    }
 
    SfxWhichIter aIter( rSet );
    sal_uInt16 nWhich = aIter.FirstWhich();
    while (nWhich)
    {
        switch (nWhich)
        {
            case SID_PASTE:
            case SID_PASTE_SPECIAL:
            case SID_PASTE_UNFORMATTED:
                if( !bPastePossible )
                    rSet.DisableItem( nWhich );
                break;
            case SID_CLIPBOARD_FORMAT_ITEMS:
                if( bPastePossible )
                {
                    SvxClipboardFormatItem aFormats( SID_CLIPBOARD_FORMAT_ITEMS );
                    TransferableDataHelper aDataHelper(
                            TransferableDataHelper::CreateFromSystemClipboard( rViewData.GetActiveWin() ) );
 
                    if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
                        aFormats.AddClipbrdFormat( SotClipboardFormatId::STRING );
                    if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
                        aFormats.AddClipbrdFormat( SotClipboardFormatId::RTF );
 
                    rSet.Put( aFormats );
                }
                else
                    rSet.DisableItem( nWhich );
                break;
        }
        nWhich = aIter.NextWhich();
    }
}
 
static void lcl_InvalidateUnder( SfxBindings& rBindings )
{
    rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
    rBindings.Invalidate( SID_ULINE_VAL_NONE );
    rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
    rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
    rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
}
 
void ScEditShell::ExecuteAttr(SfxRequest& rReq)
{
    SfxItemSet          aSet( pEditView->GetEmptyItemSet() );
    SfxBindings&        rBindings   = rViewData.GetBindings();
    const SfxItemSet*   pArgs       = rReq.GetArgs();
    sal_uInt16              nSlot       = rReq.GetSlot();
 
    switch ( nSlot )
    {
        case SID_ATTR_CHAR_FONTHEIGHT:
        case SID_ATTR_CHAR_FONT:
            {
                if (pArgs)
                {
                    // #i78017 establish the same behaviour as in Writer
                    SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
                    if (nSlot == SID_ATTR_CHAR_FONT)
                    {
                        nScript = pEditView->GetSelectedScriptType();
                        if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
                    }
 
                    SfxItemPool& rPool = GetPool();
                    SvxScriptSetItem aSetItem( nSlot, rPool );
                    sal_uInt16 nWhich = rPool.GetWhichIDFromSlotID( nSlot );
                    aSetItem.PutItemForScriptType( nScript, pArgs->Get( nWhich ) );
 
                    aSet.Put( aSetItem.GetItemSet(), false );
                }
            }
            break;
 
        case SID_ATTR_CHAR_COLOR:
        case SID_ATTR_CHAR_BACK_COLOR:
            {
                if (pArgs)
                {
                    aSet.Put( pArgs->Get( pArgs->GetPool()->GetWhichIDFromSlotID( nSlot ) ) );
                    rBindings.Invalidate( nSlot );
                }
                else
                {
                    const sal_uInt16 nEEWhich = GetPool().GetWhichIDFromSlotID(nSlot);
                    const std::optional<NamedColor> oColor
                        = rViewData.GetDocShell()->GetRecentColor(nSlot);
                    if (oColor.has_value())
                    {
                        const model::ComplexColor aCol = (*oColor).getComplexColor();
                        aSet.Put(SvxColorItem(aCol.getFinalColor(), aCol, nEEWhich));
                    }
                }
            }
            break;
 
        //  Toggles
 
        case SID_ATTR_CHAR_WEIGHT:
            {
                // #i78017 establish the same behaviour as in Writer
                SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
 
                SfxItemPool& rPool = GetPool();
 
                bool bOld = false;
                SvxScriptSetItem aOldSetItem( nSlot, rPool );
                aOldSetItem.GetItemSet().Put( pEditView->GetAttribs(), false );
                const SfxPoolItem* pCore = aOldSetItem.GetItemOfScript( nScript );
                if ( pCore && static_cast<const SvxWeightItem*>(pCore)->GetWeight() > WEIGHT_NORMAL )
                    bOld = true;
 
                SvxScriptSetItem aSetItem( nSlot, rPool );
                aSetItem.PutItemForScriptType( nScript,
                            SvxWeightItem( bOld ? WEIGHT_NORMAL : WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
                aSet.Put( aSetItem.GetItemSet(), false );
 
                rBindings.Invalidate( nSlot );
            }
            break;
 
        case SID_ATTR_CHAR_POSTURE:
            {
                // #i78017 establish the same behaviour as in Writer
                SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
 
                SfxItemPool& rPool = GetPool();
 
                bool bOld = false;
                SvxScriptSetItem aOldSetItem( nSlot, rPool );
                aOldSetItem.GetItemSet().Put( pEditView->GetAttribs(), false );
                const SfxPoolItem* pCore = aOldSetItem.GetItemOfScript( nScript );
                if ( pCore && static_cast<const SvxPostureItem*>(pCore)->GetValue() != ITALIC_NONE )
                    bOld = true;
 
                SvxScriptSetItem aSetItem( nSlot, rPool );
                aSetItem.PutItemForScriptType( nScript,
                            SvxPostureItem( bOld ? ITALIC_NONE : ITALIC_NORMAL, EE_CHAR_ITALIC ) );
                aSet.Put( aSetItem.GetItemSet(), false );
 
                rBindings.Invalidate( nSlot );
            }
            break;
 
        case SID_ULINE_VAL_NONE:
            aSet.Put( SvxUnderlineItem( LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
            lcl_InvalidateUnder( rBindings );
            break;
 
        case SID_ATTR_CHAR_UNDERLINE:
        case SID_ULINE_VAL_SINGLE:
        case SID_ULINE_VAL_DOUBLE:
        case SID_ULINE_VAL_DOTTED:
            {
                FontLineStyle eOld = pEditView->GetAttribs().Get(EE_CHAR_UNDERLINE).GetLineStyle();
                FontLineStyle eNew = eOld;
                switch (nSlot)
                {
                    case SID_ATTR_CHAR_UNDERLINE:
                        if ( pArgs )
                        {
                            const SvxTextLineItem& rTextLineItem = static_cast< const SvxTextLineItem& >( pArgs->Get( pArgs->GetPool()->GetWhichIDFromSlotID(nSlot) ) );
                            eNew = rTextLineItem.GetLineStyle();
                        }
                        else
                        {
                            eNew = ( eOld != LINESTYLE_NONE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
                        }
                        break;
                    case SID_ULINE_VAL_SINGLE:
                        eNew = ( eOld == LINESTYLE_SINGLE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
                        break;
                    case SID_ULINE_VAL_DOUBLE:
                        eNew = ( eOld == LINESTYLE_DOUBLE ) ? LINESTYLE_NONE : LINESTYLE_DOUBLE;
                        break;
                    case SID_ULINE_VAL_DOTTED:
                        eNew = ( eOld == LINESTYLE_DOTTED ) ? LINESTYLE_NONE : LINESTYLE_DOTTED;
                        break;
                }
                aSet.Put( SvxUnderlineItem( eNew, EE_CHAR_UNDERLINE ) );
                lcl_InvalidateUnder( rBindings );
            }
            break;
 
        case SID_ATTR_CHAR_OVERLINE:
            {
                FontLineStyle eOld = pEditView->GetAttribs().Get(EE_CHAR_OVERLINE).GetLineStyle();
                FontLineStyle eNew = ( eOld != LINESTYLE_NONE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
                aSet.Put( SvxOverlineItem( eNew, EE_CHAR_OVERLINE ) );
                rBindings.Invalidate( nSlot );
            }
            break;
 
        case SID_ATTR_CHAR_STRIKEOUT:
            {
                bool bOld = pEditView->GetAttribs().Get(EE_CHAR_STRIKEOUT).GetValue() != STRIKEOUT_NONE;
                aSet.Put( SvxCrossedOutItem( bOld ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT ) );
                rBindings.Invalidate( nSlot );
            }
            break;
 
        case SID_ATTR_CHAR_SHADOWED:
            {
                bool bOld = pEditView->GetAttribs().Get(EE_CHAR_SHADOW).GetValue();
                aSet.Put( SvxShadowedItem( !bOld, EE_CHAR_SHADOW ) );
                rBindings.Invalidate( nSlot );
            }
            break;
 
        case SID_ATTR_CHAR_CONTOUR:
            {
                bool bOld = pEditView->GetAttribs().Get(EE_CHAR_OUTLINE).GetValue();
                aSet.Put( SvxContourItem( !bOld, EE_CHAR_OUTLINE ) );
                rBindings.Invalidate( nSlot );
            }
            break;
 
        case SID_SET_SUPER_SCRIPT:
            {
                SvxEscapement eOld = pEditView->GetAttribs().Get(EE_CHAR_ESCAPEMENT).GetEscapement();
                SvxEscapement eNew = (eOld == SvxEscapement::Superscript) ?
                                        SvxEscapement::Off : SvxEscapement::Superscript;
                aSet.Put( SvxEscapementItem( eNew, EE_CHAR_ESCAPEMENT ) );
                rBindings.Invalidate( nSlot );
            }
            break;
        case SID_SET_SUB_SCRIPT:
            {
                SvxEscapement eOld = pEditView->GetAttribs().Get(EE_CHAR_ESCAPEMENT).GetEscapement();
                SvxEscapement eNew = (eOld == SvxEscapement::Subscript) ?
                                        SvxEscapement::Off : SvxEscapement::Subscript;
                aSet.Put( SvxEscapementItem( eNew, EE_CHAR_ESCAPEMENT ) );
                rBindings.Invalidate( nSlot );
            }
            break;
        case SID_ATTR_CHAR_KERNING:
            {
                if(pArgs)
                {
                    aSet.Put ( pArgs->Get(pArgs->GetPool()->GetWhichIDFromSlotID(nSlot)));
                    rBindings.Invalidate( nSlot );
                }
            }
            break;
 
        case SID_GROW_FONT_SIZE:
        case SID_SHRINK_FONT_SIZE:
            {
                SfxObjectShell* pObjSh = SfxObjectShell::Current();
                const SvxFontListItem* pFontListItem = (pObjSh ? pObjSh->GetItem(SID_ATTR_CHAR_FONTLIST) : nullptr);
                const FontList* pFontList = pFontListItem ? pFontListItem->GetFontList() : nullptr;
                pEditView->ChangeFontSize( nSlot == SID_GROW_FONT_SIZE, pFontList );
                rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
            }
            break;
    }
 
    // apply
 
    EditEngine& rEngine = pEditView->getEditEngine();
    bool bOld = rEngine.SetUpdateLayout(false);
 
    pEditView->SetAttribs( aSet );
 
    rEngine.SetUpdateLayout(bOld);
    pEditView->Invalidate();
 
    ScInputHandler* pHdl = GetMyInputHdl();
    pHdl->SetModified();
 
    rReq.Done();
}
 
void ScEditShell::GetAttrState(SfxItemSet &rSet)
{
    if ( !rViewData.HasEditView( rViewData.GetActivePart() ) )
    {
        lcl_DisableAll( rSet );
        return;
    }
 
    SfxItemSet aAttribs = pEditView->GetAttribs();
    rSet.Put( aAttribs );
 
    //  choose font info according to selection script type
 
    SvtScriptType nScript = pEditView->GetSelectedScriptType();
    if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
 
    // #i55929# input-language-dependent script type (depends on input language if nothing selected)
    SvtScriptType nInputScript = nScript;
    if ( !pEditView->GetSelection().HasRange() )
    {
        LanguageType nInputLang = rViewData.GetActiveWin()->GetInputLanguage();
        if (nInputLang != LANGUAGE_DONTKNOW && nInputLang != LANGUAGE_SYSTEM)
            nInputScript = SvtLanguageOptions::GetScriptTypeOfLanguage( nInputLang );
    }
 
    // #i55929# according to spec, nInputScript is used for font and font height only
    if ( rSet.GetItemState( EE_CHAR_FONTINFO ) != SfxItemState::UNKNOWN )
        ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_FONTINFO, nInputScript );
    if ( rSet.GetItemState( EE_CHAR_FONTHEIGHT ) != SfxItemState::UNKNOWN )
        ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_FONTHEIGHT, nInputScript );
    if ( rSet.GetItemState( EE_CHAR_WEIGHT ) != SfxItemState::UNKNOWN )
        ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_WEIGHT, nScript );
    if ( rSet.GetItemState( EE_CHAR_ITALIC ) != SfxItemState::UNKNOWN )
        ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_ITALIC, nScript );
 
    // underline
    SfxItemState eState = aAttribs.GetItemState( EE_CHAR_UNDERLINE );
    if ( eState == SfxItemState::INVALID )
    {
        rSet.InvalidateItem( SID_ULINE_VAL_NONE );
        rSet.InvalidateItem( SID_ULINE_VAL_SINGLE );
        rSet.InvalidateItem( SID_ULINE_VAL_DOUBLE );
        rSet.InvalidateItem( SID_ULINE_VAL_DOTTED );
    }
    else
    {
        FontLineStyle eUnderline = aAttribs.Get(EE_CHAR_UNDERLINE).GetLineStyle();
        rSet.Put(SfxBoolItem(SID_ULINE_VAL_SINGLE, eUnderline == LINESTYLE_SINGLE));
        rSet.Put(SfxBoolItem(SID_ULINE_VAL_DOUBLE, eUnderline == LINESTYLE_DOUBLE));
        rSet.Put(SfxBoolItem(SID_ULINE_VAL_DOTTED, eUnderline == LINESTYLE_DOTTED));
        rSet.Put(SfxBoolItem(SID_ULINE_VAL_NONE, eUnderline == LINESTYLE_NONE));
    }
 
    //! Testing whether brace highlighting is active !!!!
    ScInputHandler* pHdl = GetMyInputHdl();
    if ( pHdl && pHdl->IsFormulaMode() )
        rSet.ClearItem( EE_CHAR_WEIGHT );   // Highlighted brace not here
 
    SvxEscapement eEsc = aAttribs.Get(EE_CHAR_ESCAPEMENT).GetEscapement();
    rSet.Put(SfxBoolItem(SID_SET_SUPER_SCRIPT, eEsc == SvxEscapement::Superscript));
    rSet.Put(SfxBoolItem(SID_SET_SUB_SCRIPT, eEsc == SvxEscapement::Subscript));
    rViewData.GetBindings().Invalidate( SID_SET_SUPER_SCRIPT );
    rViewData.GetBindings().Invalidate( SID_SET_SUB_SCRIPT );
 
    eState = aAttribs.GetItemState( EE_CHAR_KERNING );
    rViewData.GetBindings().Invalidate( SID_ATTR_CHAR_KERNING );
    if ( eState == SfxItemState::INVALID )
    {
        rSet.InvalidateItem(EE_CHAR_KERNING);
    }
}
 
OUString ScEditShell::GetSelectionText( bool bWholeWord )
{
    OUString aStrSelection;
 
    if ( rViewData.HasEditView( rViewData.GetActivePart() ) )
    {
        if ( bWholeWord )
        {
            EditEngine& rEngine = pEditView->getEditEngine();
            ESelection  aSel = pEditView->GetSelection();
            OUString    aStrCurrentDelimiters = rEngine.GetWordDelimiters();
 
            rEngine.SetWordDelimiters(u" .,;\"'"_ustr);
            aStrSelection = rEngine.GetWord(aSel.end);
            rEngine.SetWordDelimiters( aStrCurrentDelimiters );
        }
        else
        {
            aStrSelection = pEditView->GetSelected();
        }
    }
 
    return aStrSelection;
}
 
void ScEditShell::ExecuteUndo(const SfxRequest& rReq)
{
    //  Undo must be handled here because it's called for both EditViews
 
    ScInputHandler* pHdl = GetMyInputHdl();
    OSL_ENSURE(pHdl,"no ScInputHandler");
    EditView* pTopView   = pHdl->GetTopView();
    EditView* pTableView = pHdl->GetTableView();
    OSL_ENSURE(pTableView,"no EditView");
 
    pHdl->DataChanging();
 
    const SfxItemSet* pReqArgs = rReq.GetArgs();
    sal_uInt16 nSlot = rReq.GetSlot();
    switch ( nSlot )
    {
        case SID_UNDO:
        case SID_REDO:
            {
                bool bIsUndo = ( nSlot == SID_UNDO );
 
                sal_uInt16 nCount = 1;
                const SfxPoolItem* pItem;
                if ( pReqArgs && pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
                    nCount = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
 
                for (sal_uInt16 i=0; i<nCount; i++)
                {
                    if ( bIsUndo )
                    {
                        pTableView->Undo();
                        if (pTopView)
                            pTopView->Undo();
                    }
                    else
                    {
                        pTableView->Redo();
                        if (pTopView)
                            pTopView->Redo();
                    }
                }
            }
            break;
    }
    rViewData.GetBindings().InvalidateAll(false);
 
    pHdl->DataChanged();
}
 
void ScEditShell::GetUndoState(SfxItemSet &rSet)
{
    //  Undo state is taken from normal ViewFrame state function
 
    SfxViewFrame& rViewFrm = rViewData.GetViewShell()->GetViewFrame();
    if ( GetUndoManager() )
    {
        SfxWhichIter aIter(rSet);
        sal_uInt16 nWhich = aIter.FirstWhich();
        while( nWhich )
        {
            rViewFrm.GetSlotState( nWhich, nullptr, &rSet );
            nWhich = aIter.NextWhich();
        }
    }
 
    //  disable if no action in input line EditView
 
    ScInputHandler* pHdl = GetMyInputHdl();
    OSL_ENSURE(pHdl,"no ScInputHandler");
    EditView* pTopView = pHdl->GetTopView();
    if (pTopView)
    {
        SfxUndoManager& rTopMgr = pTopView->getEditEngine().GetUndoManager();
        if ( rTopMgr.GetUndoActionCount() == 0 )
            rSet.DisableItem( SID_UNDO );
        if ( rTopMgr.GetRedoActionCount() == 0 )
            rSet.DisableItem( SID_REDO );
    }
}
 
void ScEditShell::ExecuteTrans( const SfxRequest& rReq )
{
    TransliterationFlags nType = ScViewUtil::GetTransliterationType( rReq.GetSlot() );
    if ( nType == TransliterationFlags::NONE )
        return;
 
    ScInputHandler* pHdl = GetMyInputHdl();
    assert(pHdl && "no ScInputHandler");
 
    EditView* pTopView   = pHdl->GetTopView();
    EditView* pTableView = pHdl->GetTableView();
    assert(pTableView && "no EditView");
 
    pHdl->DataChanging();
 
    pTableView->TransliterateText( nType );
    if (pTopView)
        pTopView->TransliterateText( nType );
 
    pHdl->DataChanged();
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'Execute' is required to be utilized.

V530 The return value of function 'Execute' is required to be utilized.

V530 The return value of function 'GetSlotState' is required to be utilized.