Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/editeng/source/editeng/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 59 kB image not shown  

Quelle  editview.cxx   Sprache: C

 
/* -*- 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 <memory>
#include <vcl/image.hxx>

#include <com/sun/star/i18n/WordType.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>

#include <i18nlangtag/languagetag.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <svl/languageoptions.hxx>
#include <svtools/ctrltool.hxx>
#include <svtools/langtab.hxx>
#include <tools/stream.hxx>

#include <svl/srchitem.hxx>

#include "impedit.hxx"
#include <comphelper/propertyvalue.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editview.hxx>
#include <editeng/flditem.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/langitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/eerdll.hxx>
#include <eerdll2.hxx>
#include <editeng/editrids.hrc>
#include <editeng.hxx>
#include <i18nlangtag/lang.h>
#include <vcl/window.hxx>
#include <editeng/acorrcfg.hxx>
#include <editeng/unolingu.hxx>
#include <unotools/lingucfg.hxx>

#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/linguistic2/XDictionary.hpp>
#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
#include <linguistic/lngprops.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/lokhelper.hxx>
#include <osl/diagnose.h>
#include <boost/property_tree/json_parser.hpp>

#include <com/sun/star/lang/XServiceInfo.hpp>

using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::beans;


// static
LanguageType EditView::CheckLanguage(
        const OUString &rText,
        const Reference< linguistic2::XSpellChecker1 >& xSpell,
        const Reference< linguistic2::XLanguageGuessing >& xLangGuess,
        bool bIsParaText )
{
    LanguageType nLang = LANGUAGE_NONE;
    if (bIsParaText)    // check longer texts with language-guessing...
    {
        if (!xLangGuess.is())
            return nLang;

        LanguageTag aGuessTag( xLangGuess->guessPrimaryLanguage( rText, 0, rText.getLength()) );

        // If the result from language guessing does not provide a 'Country'
        // part, try to get it by looking up the locale setting of the office,
        // "Tools/Options - Languages and Locales - General: Locale setting", if
        // the language matches.
        if ( aGuessTag.getCountry().isEmpty() )
        {
            const LanguageTag& rAppLocaleTag = Application::GetSettings().GetLanguageTag();
            if (rAppLocaleTag.getLanguage() == aGuessTag.getLanguage())
                nLang = rAppLocaleTag.getLanguageType();
        }
        if (nLang == LANGUAGE_NONE) // language not found by looking up the system language...
            nLang = aGuessTag.makeFallback().getLanguageType();     // best known locale match
        if (nLang == LANGUAGE_SYSTEM)
            nLang = Application::GetSettings().GetLanguageTag().getLanguageType();
        if (nLang == LANGUAGE_DONTKNOW)
            nLang = LANGUAGE_NONE;
    }
    else    // check single word
    {
        if (!xSpell.is())
            return nLang;


        // build list of languages to check

        LanguageType aLangList[4];
        const AllSettings& rSettings  = Application::GetSettings();
        SvtLinguOptions aLinguOpt;
        SvtLinguConfig().GetOptions( aLinguOpt );
        // The default document language from "Tools/Options - Languages and Locales - General: Western"
        aLangList[0] = MsLangId::resolveSystemLanguageByScriptType( aLinguOpt.nDefaultLanguage,
                css::i18n::ScriptType::LATIN);
        // The one from "Tools/Options - Languages and Locales - General: User interface"
        aLangList[1] = rSettings.GetUILanguageTag().getLanguageType();
        // The one from "Tools/Options - Languages and Locales - General: Locale setting"
        aLangList[2] = rSettings.GetLanguageTag().getLanguageType();
        // en-US
        aLangList[3] = LANGUAGE_ENGLISH_US;
#if OSL_DEBUG_LEVEL >= 2
        lang::Locale a0( LanguageTag::convertToLocale( aLangList[0] ) );
        lang::Locale a1( LanguageTag::convertToLocale( aLangList[1] ) );
        lang::Locale a2( LanguageTag::convertToLocale( aLangList[2] ) );
        lang::Locale a3( LanguageTag::convertToLocale( aLangList[3] ) );
#endif

        for (const LanguageType& nTmpLang : aLangList)
        {
            if (nTmpLang != LANGUAGE_NONE  &&  nTmpLang != LANGUAGE_DONTKNOW)
            {
                if (xSpell->hasLanguage( static_cast<sal_uInt16>(nTmpLang) ) &&
                    xSpell->isValid( rText, static_cast<sal_uInt16>(nTmpLang), Sequence< PropertyValue >() ))
                {
                    nLang = nTmpLang;
                    break;
                }
            }
        }
    }

    return nLang;
}

EditViewCallbacks::~EditViewCallbacks()
{
}

EditView::EditView(EditEngine& rEditEngine, vcl::Window* pWindow)
    : mpImpEditView(new ImpEditView(this, rEditEngine, pWindow))
{
    getImpl().mbReadOnly = getImpl().mbReadOnly || SfxViewShell::IsCurrentLokViewReadOnly();
}

EditView::~EditView()
{
}

void EditView::setEditViewCallbacks(EditViewCallbacks* pEditViewCallbacks)
{
    getImpl().setEditViewCallbacks(pEditViewCallbacks);
}

EditViewCallbacks* EditView::getEditViewCallbacks() const
{
    return getImpl().getEditViewCallbacks();
}

ImpEditEngine& EditView::getImpEditEngine() const
{
    return getImpl().getImpEditEngine();
}

EditEngine& EditView::getEditEngine() const
{
    return getImpl().getEditEngine();
}

tools::Rectangle EditView::GetInvalidateRect() const
{
    if (!getImpl().DoInvalidateMore())
        return getImpl().maOutputArea;
    else
    {
        tools::Rectangle aRect(getImpl().maOutputArea);
        tools::Long nMore = getImpl().GetOutputDevice().PixelToLogic( Size( getImpl().GetInvalidateMore(), 0 ) ).Width();
        aRect.AdjustLeft( -nMore );
        aRect.AdjustRight(nMore );
        aRect.AdjustTop( -nMore );
        aRect.AdjustBottom(nMore );
        return aRect;
    }
}

namespace {

tools::Rectangle lcl_negateRectX(const tools::Rectangle& rRect)
{
    return tools::Rectangle(-rRect.Right(), rRect.Top(), -rRect.Left(), rRect.Bottom());
}

}

void EditView::InvalidateWindow(const tools::Rectangle& rClipRect)
{
    LOKEditViewHistory::Update();
    bool bNegativeX = IsNegativeX();
    if (EditViewCallbacks* pEditViewCallbacks = getImpl().getEditViewCallbacks())
    {
        // do not invalidate and trigger a global repaint, but forward
        // the need for change to the applied EditViewCallback, can e.g.
        // be used to visualize the active edit text in an OverlayObject
        pEditViewCallbacks->EditViewInvalidate(bNegativeX ? lcl_negateRectX(rClipRect) : rClipRect);
    }
    else
    {
        // classic mode: invalidate and trigger full repaint
        // of the changed area
        GetWindow()->Invalidate(bNegativeX ? lcl_negateRectX(rClipRect) : rClipRect);
    }
}

void EditView::InvalidateOtherViewWindows( const tools::Rectangle& rInvRect )
{
    if (comphelper::LibreOfficeKit::isActive())
    {
        bool bNegativeX = IsNegativeX();
        for (auto& pWin : getImpl().maOutWindowSet)
        {
            if (pWin)
            {
                if (!pWin->InvalidateByForeignEditView(this))
                    pWin->Invalidate( bNegativeX ? lcl_negateRectX(rInvRect) : rInvRect );
            }
        }
    }
}

void EditView::Invalidate()
{
    const tools::Rectangle aInvRect = GetInvalidateRect();

    LOKEditViewHistory::Update();
    getImpl().InvalidateAtWindow(aInvRect);
    InvalidateOtherViewWindows(aInvRect);
}

void EditView::SetReadOnly( bool bReadOnly )
{
    getImpl().mbReadOnly = bReadOnly || SfxViewShell::IsCurrentLokViewReadOnly();
}

bool EditView::IsReadOnly() const
{
    return getImpl().mbReadOnly;
}

void EditView::SetSelection( const ESelection& rESel )
{
    // If someone has just left an empty attribute, and then the outliner manipulates the
    // selection, call the CursorMoved method so that empty attributes get cleaned up.
    if ( !HasSelection() )
    {
        // tdf#113591 Get node from EditDoc, as the selection might have a pointer to an
        // already deleted node.
        const ContentNode* pNode(getEditEngine().GetEditDoc().GetEndPaM().GetNode());
        if (nullptr != pNode)
            pNode->checkAndDeleteEmptyAttribs();
    }
    EditSelection aNewSelection(getImpEditEngine().CreateNormalizedSel(rESel));

    // If the selection is manipulated after a KeyInput:
    getEditEngine().CheckIdleFormatter();

    // Selection may not start/end at an invisible paragraph:
    const ParaPortion* pPortion = getEditEngine().FindParaPortion( aNewSelection.Min().GetNode() );
    if ( !pPortion->IsVisible() )
    {
        pPortion = getEditEngine().GetPrevVisPortion( pPortion );
        ContentNode* pNode = pPortion ? pPortion->GetNode() : getEditEngine().GetEditDoc().GetObject( 0 );
        aNewSelection.Min() = EditPaM( pNode, pNode->Len() );
    }
    pPortion = getEditEngine().FindParaPortion( aNewSelection.Max().GetNode() );
    if ( !pPortion->IsVisible() )
    {
        pPortion = getEditEngine().GetPrevVisPortion( pPortion );
        ContentNode* pNode = pPortion ? pPortion->GetNode() : getEditEngine().GetEditDoc().GetObject( 0 );
        aNewSelection.Max() = EditPaM( pNode, pNode->Len() );
    }

    getImpl().DrawSelectionXOR();
    getImpl().SetEditSelection( aNewSelection );
    getImpl().DrawSelectionXOR();
    bool bGotoCursor = getImpl().DoAutoScroll();

    // comments section in Writer:
    // don't scroll to the selection if it is
    // out of visible area of comment canvas.
    if (HasSelection())
        ShowCursor( bGotoCursor );
}

ESelection EditView::GetSelection() const
{
    return getEditEngine().CreateESelection(getImpl().GetEditSelection());
}

bool EditView::HasSelection() const
{
    return getImpl().HasSelection();
}

bool EditView::IsSelectionFullPara() const
{
    return getImpl().IsSelectionFullPara();
}

bool EditView::IsSelectionWithinSinglePara() const
{
    return getImpl().IsSelectionInSinglePara();
}

bool EditView::IsSelectionAtPoint(const Point& rPointPixel)
{
    return getImpl().IsSelectionAtPoint(rPointPixel);
}

void EditView::DeleteSelected()
{
    getImpl().DeleteSelected();
}

SvtScriptType EditView::GetSelectedScriptType() const
{
    return getEditEngine().GetScriptType( getImpl().GetEditSelection() );
}

void EditView::GetSelectionRectangles(std::vector<tools::Rectangle>& rLogicRectsconst
{
    return getImpl().GetSelectionRectangles(getImpl().GetEditSelection(), rLogicRects);
}

#if ENABLE_YRS
void EditView::YrsGetSelectionRectangles(
    ::std::vector<::std::pair<OUString, ::std::vector<tools::Rectangle>>>& rLogicRects) const
{
    for (auto const& it : getImpl().m_PeerCursors)
    {
        rLogicRects.push_back({it.second.first, {}});
        EditSelection const sel{getEditEngine().getImpl().CreateSel(it.second.second)};
        if (sel.HasRange())
        {
            getImpl().GetSelectionRectangles(sel, rLogicRects.back().second);
        }
        else
        {
            ParaPortion const& rParaPortion{getEditEngine().GetParaPortions().getRef(it.second.second.start.nPara)};
            auto const oCursor{getImpl().ImplGetCursorRectAndMaybeScroll(sel.Min(), rParaPortion, false)};
            if (oCursor)
            {
                auto const rect{std::get<0>(*oCursor)};
                rLogicRects.back().second.push_back(rect);
            }
        }
    }
}

bool EditView::YrsWriteEECursor(YTransaction *const pTxn, Branch const& rArray, YOutput const*const pCurrent)
{
    return getEditEngine().GetEditDoc().YrsWriteEECursor(pTxn, rArray, pCurrent, getImpl().GetEditSelection());
}

void EditView::YrsApplyEECursor(OString const& rPeerId, OUString const& rAuthor,
    ::std::pair<int64_t, int64_t> const point,
    ::std::optional<::std::pair<int64_t, int64_t>> const oMark)
{
    ::std::optional<EditSelection> const oSel{getEditEngine().GetEditDoc().YrsReadEECursor(point, oMark)};
    if (!oSel)
    {
        SAL_INFO("editeng.yrs""YRS ignoring invalid cursor position");
        return;
    }
    ESelection const esel{getEditEngine().getImpl().CreateESel(*oSel)};
    getImpl().m_PeerCursors[rPeerId] = {rAuthor, esel};
}

bool EditView::YrsDelEECursor(OString const& rId)
{
    return getImpl().m_PeerCursors.erase(rId) != 0;
}
#endif

Point EditView::CalculateTextPaintStartPosition() const
{
    return getImpEditEngine().CalculateTextPaintStartPosition(getImpl());
}

void EditView::Paint( const tools::Rectangle& rRect, OutputDevice* pTargetDevice )
{
    getImpEditEngine().Paint(&getImpl(), rRect, pTargetDevice);
}

void EditView::setEditEngine(EditEngine& rEditEngine)
{
    getImpl().mpEditEngine = &rEditEngine;
    EditSelection aStartSel( getEditEngine().GetEditDoc().GetStartPaM() );
    getImpl().SetEditSelection( aStartSel );
}

void EditView::SetWindow(vcl::Window* pWindow)
{
    getImpl().mpOutputWindow = pWindow;
    getImpEditEngine().GetSelEngine().Reset();
}

vcl::Window* EditView::GetWindow() const
{
    return getImpl().mpOutputWindow;
}

OutputDevice& EditView::GetOutputDevice() const
{
    return getImpl().GetOutputDevice();
}

LanguageType EditView::GetInputLanguage() const
{
    // it might make sense to add this to getEditViewCallbacks
    if (const vcl::Window* pWindow = GetWindow())
        return pWindow->GetInputLanguage();
    return LANGUAGE_DONTKNOW;
}

bool EditView::HasOtherViewWindow( vcl::Window* pWin )
{
    OutWindowSet& rOutWindowSet = getImpl().maOutWindowSet;
    auto found = std::find(rOutWindowSet.begin(), rOutWindowSet.end(), pWin);
    return (found != rOutWindowSet.end());
}

bool EditView::AddOtherViewWindow( vcl::Window* pWin )
{
    if (HasOtherViewWindow(pWin))
        return false;
    getImpl().maOutWindowSet.emplace_back(pWin);
    return true;
}

bool EditView::RemoveOtherViewWindow( vcl::Window* pWin )
{
    OutWindowSet& rOutWindowSet = getImpl().maOutWindowSet;
    auto found = std::find(rOutWindowSet.begin(), rOutWindowSet.end(), pWin);
    if (found == rOutWindowSet.end())
        return false;
    rOutWindowSet.erase(found);
    return true;
}

void EditView::SetVisArea( const tools::Rectangle& rRect )
{
    getImpl().SetVisDocStartPos( rRect.TopLeft() );
}

tools::Rectangle EditView::GetVisArea() const
{
    return getImpl().GetVisDocArea();
}

void EditView::SetOutputArea( const tools::Rectangle& rRect )
{
    getImpl().SetOutputArea( rRect );

    // the rest here only if it is an API call:
    getImpl().CalcAnchorPoint();
    if (getImpEditEngine().GetStatus().AutoPageSize() )
        getImpl().RecalcOutputArea();
    getImpl().ShowCursor( falsefalse );
}

const tools::Rectangle& EditView::GetOutputArea() const
{
    return getImpl().GetOutputArea();
}

PointerStyle EditView::GetPointer() const
{
    return getImpl().GetPointer();
}

vcl::Cursor* EditView::GetCursor() const
{
    return getImpl().GetCursor();
}

void EditView::InsertText( const OUString& rStr, bool bSelect, bool bLOKShowSelect )
{

    EditEngine& rEditEngine = getEditEngine();

    if (bLOKShowSelect)
        getImpl().DrawSelectionXOR();

    EditPaM aPaM1;
    if ( bSelect )
    {
        EditSelection aTmpSel( getImpl().GetEditSelection() );
        aTmpSel.Adjust(rEditEngine.GetEditDoc());
        aPaM1 = aTmpSel.Min();
    }

    rEditEngine.UndoActionStart( EDITUNDO_INSERT );
    EditPaM aPaM2(rEditEngine.InsertText( getImpl().GetEditSelection(), rStr ) );
    rEditEngine.UndoActionEnd();

    if ( bSelect )
    {
        DBG_ASSERT( !aPaM1.DbgIsBuggy(rEditEngine.GetEditDoc()), "Insert: PaM broken" );
        getImpl().SetEditSelection( EditSelection( aPaM1, aPaM2 ) );
    }
    else
        getImpl().SetEditSelection( EditSelection( aPaM2, aPaM2 ) );

    if (bLOKShowSelect)
        rEditEngine.FormatAndLayout( this );
}

bool EditView::PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window const * pFrameWin )
{
    return getImpl().PostKeyEvent( rKeyEvent, pFrameWin );
}

bool EditView::MouseButtonUp( const MouseEvent& rMouseEvent )
{
    return getImpl().MouseButtonUp( rMouseEvent );
}

void EditView::ReleaseMouse()
{
    return getImpl().ReleaseMouse();
}

bool EditView::MouseButtonDown( const MouseEvent& rMouseEvent )
{
    return getImpl().MouseButtonDown( rMouseEvent );
}

bool EditView::MouseMove( const MouseEvent& rMouseEvent )
{
    return getImpl().MouseMove( rMouseEvent );
}

bool EditView::Command(const CommandEvent& rCEvt)
{
    return getImpl().Command(rCEvt);
}

void EditView::SetBroadcastLOKViewCursor(bool bSet)
{
    getImpl().SetBroadcastLOKViewCursor(bSet);
}

tools::Rectangle EditView::GetEditCursor() const
{
    return getImpl().GetEditCursor();
}

void EditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor, bool bActivate )
{
    if (!getEditEngine().HasView(this))
        return;

    // The control word is more important:
    if ( !getImpl().DoAutoScroll() )
        bGotoCursor = false;
    getImpl().ShowCursor( bGotoCursor, bForceVisCursor );

    if (getImpl().mpViewShell && !bActivate)
    {
        if (!getImpl().mpOutputWindow)
            return;
        VclPtr<vcl::Window> pParent = getImpl().mpOutputWindow->GetParentWithLOKNotifier();
        if (pParent && pParent->GetLOKWindowId() != 0)
            return;

        static const OString aPayload = OString::boolean(true);
        getImpl().mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, aPayload);
        getImpl().mpViewShell->NotifyOtherViews(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible"_ostr, aPayload);
    }
}

void EditView::HideCursor(bool bDeactivate)
{
    getImpl().GetCursor()->Hide();

    if (getImpl().mpViewShell && !bDeactivate)
    {
        if (!getImpl().mpOutputWindow)
            return;
        VclPtr<vcl::Window> pParent = getImpl().mpOutputWindow->GetParentWithLOKNotifier();
        if (pParent && pParent->GetLOKWindowId() != 0)
            return;

        OString aPayload = OString::boolean(false);
        getImpl().mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, aPayload);
        getImpl().mpViewShell->NotifyOtherViews(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible"_ostr, aPayload);
    }
}

bool EditView::IsCursorVisible() const { return getImpl().GetCursor()->IsVisible(); }

::Pair EditView::Scroll( tools::Long ndX, tools::Long ndY, ScrollRangeCheck nRangeCheck )
{
    return getImpl().Scroll( ndX, ndY, nRangeCheck );
}

const SfxItemSet& EditView::GetEmptyItemSet() const
{
    return getEditEngine().GetEmptyItemSet();
}

void EditView::SetAttribs( const SfxItemSet& rSet )
{
    DBG_ASSERT(!getImpl().maEditSelection.IsInvalid(), "Blind Selection in...");

    getImpl().DrawSelectionXOR();
    getEditEngine().SetAttribs( getImpl().GetEditSelection(), rSet, SetAttribsMode::WholeWord );
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout( this );
}

void EditView::RemoveAttribsKeepLanguages( bool bRemoveParaAttribs )
{

    getImpl().DrawSelectionXOR();
    getEditEngine().UndoActionStart( EDITUNDO_RESETATTRIBS );
    EditSelection aSelection( getImpl().GetEditSelection() );

    for (sal_uInt16 nWID = EE_ITEMS_START; nWID <= EE_ITEMS_END; ++nWID)
    {
        bool bIsLang =  EE_CHAR_LANGUAGE     == nWID ||
                        EE_CHAR_LANGUAGE_CJK == nWID ||
                        EE_CHAR_LANGUAGE_CTL == nWID;
        if (!bIsLang)
            getEditEngine().RemoveCharAttribs( aSelection, bRemoveParaAttribs, nWID );
    }

    getEditEngine().UndoActionEnd();
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout( this );
}

void EditView::RemoveAttribs( bool bRemoveParaAttribs, sal_uInt16 nWhich )
{
    RemoveAttribs(bRemoveParaAttribs ? EERemoveParaAttribsMode::RemoveAll
            : EERemoveParaAttribsMode::RemoveCharItems, nWhich);
}

void EditView::RemoveAttribs( EERemoveParaAttribsMode eMode, sal_uInt16 nWhich )
{
    getImpl().DrawSelectionXOR();
    getEditEngine().UndoActionStart( EDITUNDO_RESETATTRIBS );
    getEditEngine().RemoveCharAttribs( getImpl().GetEditSelection(), eMode, nWhich  );
    getEditEngine().UndoActionEnd();
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout( this );
}

void EditView::RemoveCharAttribs( sal_Int32 nPara, sal_uInt16 nWhich )
{
    getEditEngine().UndoActionStart( EDITUNDO_RESETATTRIBS );
    getEditEngine().RemoveCharAttribs( nPara, nWhich );
    getEditEngine().UndoActionEnd();
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout( this );
}

SfxItemSet EditView::GetAttribs()
{
    DBG_ASSERT(!getImpl().maEditSelection.IsInvalid(), "Blind Selection in...");
    return getImpEditEngine().GetAttribs( getImpl().GetEditSelection() );
}

void EditView::Undo()
{
    getEditEngine().Undo( this );
}

void EditView::Redo()
{
    getEditEngine().Redo( this );
}

ErrCode EditView::Read( SvStream& rInput, EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs )
{
    EditSelection aOldSel( getImpl().GetEditSelection() );
    getImpl().DrawSelectionXOR();
    getImpEditEngine().UndoActionStart( EDITUNDO_READ );
    EditPaM aEndPaM = getImpEditEngine().Read( rInput, u""_ustr, eFormat, aOldSel, pHTTPHeaderAttrs );
    getImpEditEngine().UndoActionEnd();
    EditSelection aNewSel( aEndPaM, aEndPaM );

    getImpl().SetEditSelection( aNewSel );
    bool bGotoCursor = getImpl().DoAutoScroll();
    ShowCursor( bGotoCursor );

    return rInput.GetError();
}

OString EditView::GetSimpleHtml() const
{
    return getImpl().getEditEngine().mpImpEditEngine->GetSimpleHtml();
}

void EditView::Cut()
{
    Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
    getImpl().CutCopy( aClipBoard, true );
}

Reference<css::datatransfer::clipboard::XClipboard> EditView::GetClipboard() const
{
    return getImpl().GetClipboard();
}

css::uno::Reference< css::datatransfer::XTransferable > EditView::GetTransferable() const
{
    uno::Reference< datatransfer::XTransferable > xData = getEditEngine().CreateTransferable( getImpl().GetEditSelection() );
    return xData;
}

void EditView::Copy()
{
    Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
    getImpl().CutCopy( aClipBoard, false );
}

void EditView::Paste()
{
    Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
    getImpl().Paste( aClipBoard );
}

void EditView::PasteSpecial(SotClipboardFormatId format)
{
    Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
    getImpl().Paste(aClipBoard, true, format );
}

Point EditView::GetWindowPosTopLeft( sal_Int32 nParagraph )
{
    Point aDocPos(getEditEngine().GetDocPosTopLeft(nParagraph));
    return getImpl().GetWindowPos( aDocPos );
}

void EditView::SetSelectionMode( EESelectionMode eMode )
{
    getImpl().SetSelectionMode( eMode );
}

OUString EditView::GetSelected() const
{
    return getImpEditEngine().GetSelected( getImpl().GetEditSelection() );
}

void EditView::MoveParagraphs( Range aParagraphs, sal_Int32 nNewPos )
{
    getImpEditEngine().UndoActionStart( EDITUNDO_MOVEPARAS );
    getImpEditEngine().MoveParagraphs( aParagraphs, nNewPos, this );
    getImpEditEngine().UndoActionEnd();
}

void EditView::MoveParagraphs( tools::Long nDiff )
{
    ESelection aSel = GetSelection();
    Range aRange( aSel.start.nPara, aSel.end.nPara );
    aRange.Normalize();
    tools::Long nDest = ( nDiff > 0  ? aRange.Max() : aRange.Min() ) + nDiff;
    if ( nDiff > 0 )
        nDest++;
    DBG_ASSERT( ( nDest >= 0 ) && ( nDest <= getEditEngine().GetParagraphCount() ), "MoveParagraphs - wrong Parameters!" );
    MoveParagraphs( aRange, sal::static_int_cast< sal_Int32 >( nDest ) );
}

void EditView::SetBackgroundColor( const Color& rColor )
{
    getImpl().SetBackgroundColor( rColor );
    getEditEngine().SetBackgroundColor( rColor );
}

Color const & EditView::GetBackgroundColor() const
{
    return getImpl().GetBackgroundColor();
}

void EditView::RegisterViewShell(OutlinerViewShell* pViewShell)
{
    getImpl().RegisterViewShell(pViewShell);
}

void EditView::RegisterOtherShell(OutlinerViewShell* pOtherShell)
{
    getImpl().RegisterOtherShell(pOtherShell);
}

void EditView::SetControlWord( EVControlBits nWord )
{
    getImpl().mnControl = nWord;
}

EVControlBits EditView::GetControlWord() const
{
    return getImpl().mnControl;
}

std::unique_ptr<EditTextObject> EditView::CreateTextObject()
{
    return getImpEditEngine().CreateTextObject( getImpl().GetEditSelection() );
}

void EditView::InsertText( const EditTextObject& rTextObject )
{
    getImpl().DrawSelectionXOR();

    getEditEngine().UndoActionStart( EDITUNDO_INSERT );
    EditSelection aTextSel(getEditEngine().InsertText(rTextObject, getImpl().GetEditSelection()));
    getEditEngine().UndoActionEnd();

    aTextSel.Min() = aTextSel.Max();    // Selection not retained.
    getImpl().SetEditSelection( aTextSel );
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout( this );
}

void EditView::InsertText( css::uno::Reference< css::datatransfer::XTransferable > const & xDataObj, const OUString& rBaseURL, bool bUseSpecial )
{
    getEditEngine().UndoActionStart( EDITUNDO_INSERT );
    getImpl().DeleteSelected();
    EditSelection aTextSel =
        getEditEngine().InsertText(xDataObj, rBaseURL, getImpl().GetEditSelection().Max(), bUseSpecial);
    getEditEngine().UndoActionEnd();

    aTextSel.Min() = aTextSel.Max();    // Selection not retained.
    getImpl().SetEditSelection( aTextSel );
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout( this );
}

bool EditView::SetEditEngineUpdateLayout( bool bUpdate )
{
    return getImpEditEngine().SetUpdateLayout( bUpdate, this );
}

void EditView::ForceLayoutCalculation()
{
    getImpEditEngine().SetUpdateLayout( truethistrue );
}

SfxStyleSheet* EditView::GetStyleSheet()
{
    EditSelection aSel( getImpl().GetEditSelection() );
    aSel.Adjust(getEditEngine().GetEditDoc());
    sal_Int32 nStartPara = getEditEngine().GetEditDoc().GetPos( aSel.Min().GetNode() );
    sal_Int32 nEndPara = getEditEngine().GetEditDoc().GetPos( aSel.Max().GetNode() );

    SfxStyleSheet* pStyle = nullptr;
    for ( sal_Int32 n = nStartPara; n <= nEndPara; n++ )
    {
        SfxStyleSheet* pTmpStyle = getEditEngine().GetStyleSheet( n );
        if ( ( n != nStartPara ) && ( pStyle != pTmpStyle ) )
            return nullptr;    // Not unique.
        pStyle = pTmpStyle;
    }
    return pStyle;
}

const SfxStyleSheet* EditView::GetStyleSheet() const
{
    return const_cast< EditView* >( this )->GetStyleSheet();
}

bool EditView::IsInsertMode() const
{
    return getImpl().IsInsertMode();
}

void EditView::SetInsertMode( bool bInsert )
{
    getImpl().SetInsertMode( bInsert );
}

void EditView::SetAnchorMode( EEAnchorMode eMode )
{
    getImpl().SetAnchorMode( eMode );
}

EEAnchorMode EditView::GetAnchorMode() const
{
    return getImpl().GetAnchorMode();
}

void EditView::TransliterateText( TransliterationFlags nTransliterationMode )
{
    EditSelection aOldSel( getImpl().GetEditSelection() );
    EditSelection aNewSel = getEditEngine().TransliterateText( getImpl().GetEditSelection(), nTransliterationMode );
    if ( aNewSel != aOldSel )
    {
        getImpl().DrawSelectionXOR();
        getImpl().SetEditSelection( aNewSel );
        getImpl().DrawSelectionXOR();
    }
}

void EditView::CompleteAutoCorrect( vcl::Window const * pFrameWin )
{
    if ( !HasSelection() && getImpEditEngine().GetStatus().DoAutoCorrect() )
    {
        getImpl().DrawSelectionXOR();
        EditSelection aSel = getImpl().GetEditSelection();
        aSel = getEditEngine().EndOfWord( aSel.Max() );
        aSel = getImpEditEngine().AutoCorrect( aSel, 0, !IsInsertMode(), pFrameWin );
        getImpl().SetEditSelection( aSel );
        if (getEditEngine().IsModified())
            getEditEngine().FormatAndLayout( this );
    }
}

EESpellState EditView::StartSpeller(weld::Widget* pDialogParent, bool bMultipleDoc)
{
    if (!getImpEditEngine().GetSpeller().is())
        return EESpellState::NoSpeller;

    return getImpEditEngine().Spell(this, pDialogParent, bMultipleDoc);
}

EESpellState EditView::StartThesaurus(weld::Widget* pDialogParent)
{
    if (!getImpEditEngine().GetSpeller().is())
        return EESpellState::NoSpeller;

    return getImpEditEngine().StartThesaurus(this, pDialogParent);
}

void EditView::StartTextConversion(weld::Widget* pDialogParent,
        LanguageType nSrcLang, LanguageType nDestLang, const vcl::Font *pDestFont,
        sal_Int32 nOptions, bool bIsInteractive, bool bMultipleDoc )
{
    getImpEditEngine().Convert(this, pDialogParent, nSrcLang, nDestLang, pDestFont, nOptions, bIsInteractive, bMultipleDoc);
}

sal_Int32 EditView::StartSearchAndReplace( const SvxSearchItem& rSearchItem )
{
    return getImpEditEngine().StartSearchAndReplace( this, rSearchItem );
}

bool EditView::IsCursorAtWrongSpelledWord()
{
    bool bIsWrong = false;
    if ( !HasSelection() )
    {
        EditPaM aPaM = getImpl().GetEditSelection().Max();
        bIsWrong = getImpl().IsWrongSpelledWord( aPaM, false/*bMarkIfWrong*/ );
    }
    return bIsWrong;
}

bool EditView::IsWrongSpelledWordAtPos( const Point& rPosPixel, bool bMarkIfWrong )
{
    Point aPos(getImpl().GetOutputDevice().PixelToLogic(rPosPixel));
    aPos = getImpl().GetDocPos( aPos );
    EditPaM aPaM = getEditEngine().GetPaM(aPos, false);
    return getImpl().IsWrongSpelledWord( aPaM , bMarkIfWrong );
}

static void LOKSendSpellPopupMenu(const weld::Menu& rMenu, LanguageType nGuessLangWord,
                                  LanguageType nGuessLangPara, sal_uInt16 nSuggestions)
{
    if (!comphelper::LibreOfficeKit::isActive())
        return;

    // Generate the menu structure and send it to the client code.
    SfxViewShell* pViewShell = SfxViewShell::Current();
    if (!pViewShell)
        return;

    boost::property_tree::ptree aMenu;

    boost::property_tree::ptree aItemTree;
    if (nSuggestions)
    {
        for(int i = 0; i < nSuggestions; ++i)
        {
            OUString sItemId = OUString::number(MN_ALTSTART + i);
            OUString sText = rMenu.get_label(sItemId);
            aItemTree.put("text", sText.toUtf8().getStr());
            aItemTree.put("type""command");
            OUString sCommandString = ".uno:SpellCheckApplySuggestion?ApplyRule:string=Spelling_" + sText;
            aItemTree.put("command", sCommandString.toUtf8().getStr());
            aItemTree.put("enabled", rMenu.get_sensitive(sItemId));
            aMenu.push_back(std::make_pair("", aItemTree));
            aItemTree.clear();
        }

        aItemTree.put("type""separator");
        aMenu.push_back(std::make_pair("", aItemTree));
        aItemTree.clear();
    }

    // First we need to set item commands for the context menu.
    OUString aTmpWord( SvtLanguageTable::GetLanguageString( nGuessLangWord ) );
    OUString aTmpPara( SvtLanguageTable::GetLanguageString( nGuessLangPara ) );

    aItemTree.put("text", rMenu.get_label(u"ignore"_ustr).toUtf8().getStr());
    aItemTree.put("type""command");
    aItemTree.put("command"".uno:SpellCheckIgnoreAll?Type:string=Spelling");
    aItemTree.put("enabled", rMenu.get_sensitive(u"ignore"_ustr));
    aMenu.push_back(std::make_pair("", aItemTree));
    aItemTree.clear();

    aItemTree.put("type""separator");
    aMenu.push_back(std::make_pair("", aItemTree));
    aItemTree.clear();

    aItemTree.put("text", rMenu.get_label(u"wordlanguage"_ustr).toUtf8().getStr());
    aItemTree.put("type""command");
    OUString sCommandString = ".uno:LanguageStatus?Language:string=Current_" + aTmpWord;
    aItemTree.put("command", sCommandString.toUtf8().getStr());
    aItemTree.put("enabled", rMenu.get_sensitive(u"wordlanguage"_ustr));
    aMenu.push_back(std::make_pair("", aItemTree));
    aItemTree.clear();

    aItemTree.put("text", rMenu.get_label(u"paralanguage"_ustr).toUtf8().getStr());
    aItemTree.put("type""command");
    sCommandString = ".uno:LanguageStatus?Language:string=Paragraph_" + aTmpPara;
    aItemTree.put("command", sCommandString.toUtf8().getStr());
    aItemTree.put("enabled", rMenu.get_sensitive(u"paralanguage"_ustr));
    aMenu.push_back(std::make_pair("", aItemTree));
    aItemTree.clear();

    boost::property_tree::ptree aRoot;
    aRoot.add_child("menu", aMenu);

    std::stringstream aStream;
    boost::property_tree::write_json(aStream, aRoot, true);
    pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, OString(aStream.str()));
}

bool EditView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbackInfo&,void> &rCallBack)
{
    OutputDevice& rDevice = getImpl().GetOutputDevice();
    Point aPos(rDevice.PixelToLogic(rPosPixel));
    aPos = getImpl().GetDocPos( aPos );
    EditPaM aPaM = getEditEngine().GetPaM(aPos, false);
    Reference< linguistic2::XSpellChecker1 >  xSpeller(getImpEditEngine().GetSpeller());
    ESelection aOldSel = GetSelection();
    if ( !(xSpeller.is() && getImpl().IsWrongSpelledWord( aPaM, true )) )
        return false;

    // PaMtoEditCursor returns Logical units
    tools::Rectangle aTempRect = getImpEditEngine().PaMtoEditCursor(aPaM, CursorFlags{ .bTextOnly = true });
    // GetWindowPos works in Logical units
    aTempRect = getImpl().GetWindowPos(aTempRect);
    // Convert to pixels
    aTempRect = rDevice.LogicToPixel(aTempRect);

    weld::Widget* pPopupParent = getImpl().GetPopupParent(aTempRect);
    std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, u"editeng/ui/spellmenu.ui"_ustr));
    std::unique_ptr<weld::Menu> xPopupMenu(xBuilder->weld_menu(u"editviewspellmenu"_ustr));
    std::unique_ptr<weld::Menu> xInsertMenu(xBuilder->weld_menu(u"insertmenu"_ustr)); // add word to user-dictionaries
    std::unique_ptr<weld::Menu> xAutoMenu(xBuilder->weld_menu(u"automenu"_ustr));

    EditPaM aPaM2( aPaM );
    aPaM2.SetIndex( aPaM2.GetIndex()+1 );

    // Are there any replace suggestions?
    OUString aSelected( GetSelected() );

    // restrict the maximal number of suggestions displayed
    // in the context menu.
    // Note: That could of course be done by clipping the
    // resulting sequence but the current third party
    // implementations result differs greatly if the number of
    // suggestions to be returned gets changed. Statistically
    // it gets much better if told to return e.g. only 7 strings
    // than returning e.g. 16 suggestions and using only the
    // first 7. Thus we hand down the value to use to that
    // implementation here by providing an additional parameter.
    Sequence< PropertyValue > aPropVals { comphelper::makePropertyValue(UPN_MAX_NUMBER_OF_SUGGESTIONS, sal_Int16(7)) };

    // Are there any replace suggestions?
    Reference< linguistic2::XSpellAlternatives >  xSpellAlt =
            xSpeller->spell( aSelected, static_cast<sal_uInt16>(getImpEditEngine().GetLanguage( aPaM2 ).nLang), aPropVals );

    Reference< linguistic2::XLanguageGuessing >  xLangGuesser( EditDLL::Get().GetGlobalData()->GetLanguageGuesser() );

    // check if text might belong to a different language...
    LanguageType nGuessLangWord = LANGUAGE_NONE;
    LanguageType nGuessLangPara = LANGUAGE_NONE;
    if (xSpellAlt.is() && xLangGuesser.is())
    {
        OUString aParaText;
        ContentNode *pNode = aPaM.GetNode();
        if (pNode)
        {
            aParaText = pNode->GetString();
        }
        else
        {
            OSL_FAIL( "content node is NULL" );
        }

        nGuessLangWord = CheckLanguage( xSpellAlt->getWord(), xSpeller, xLangGuesser, false );
        nGuessLangPara = CheckLanguage( aParaText, xSpeller, xLangGuesser, true );
    }
    if (nGuessLangWord != LANGUAGE_NONE || nGuessLangPara != LANGUAGE_NONE)
    {
        // make sure LANGUAGE_NONE gets not used as menu entry
        if (nGuessLangWord == LANGUAGE_NONE)
            nGuessLangWord = nGuessLangPara;
        if (nGuessLangPara == LANGUAGE_NONE)
            nGuessLangPara = nGuessLangWord;

        xPopupMenu->append_separator(u"separator1"_ustr);
        OUString aTmpWord( SvtLanguageTable::GetLanguageString( nGuessLangWord ) );
        OUString aTmpPara( SvtLanguageTable::GetLanguageString( nGuessLangPara ) );
        OUString aWordStr( EditResId( RID_STR_WORD ) );
        aWordStr = aWordStr.replaceFirst( "%x", aTmpWord );
        OUString aParaStr( EditResId( RID_STR_PARAGRAPH ) );
        aParaStr = aParaStr.replaceFirst( "%x", aTmpPara );
        xPopupMenu->append(u"wordlanguage"_ustr, aWordStr);
        xPopupMenu->append(u"paralanguage"_ustr, aParaStr);
    }

    // Replace suggestions...
    Sequence< OUString > aAlt;
    if (xSpellAlt.is())
        aAlt = xSpellAlt->getAlternatives();
    const OUString *pAlt = aAlt.getConstArray();
    sal_uInt16 nWords = static_cast<sal_uInt16>(aAlt.getLength());
    if ( nWords )
    {
        for ( sal_uInt16 nW = 0; nW < nWords; nW++ )
        {
            OUString aAlternate( pAlt[nW] );
            OUString sId(OUString::number(MN_ALTSTART + nW));
            xPopupMenu->insert(nW, sId, aAlternate, nullptr, nullptr, nullptr, TRISTATE_INDET);
            xAutoMenu->append(sId, aAlternate);
        }
        xPopupMenu->insert_separator(nWords, u"separator2"_ustr);
    }
    else
    {
        xAutoMenu.reset();
        xPopupMenu->remove(u"autocorrect"_ustr);
    }

    SvtLinguConfig aCfg;

    Reference< linguistic2::XSearchableDictionaryList >  xDicList( LinguMgr::GetDictionaryList() );
    Sequence< Reference< linguistic2::XDictionary >  > aDics;
    if (xDicList.is())
    {
        const Reference< linguistic2::XDictionary >  *pDic = nullptr;
        // add the default positive dictionary to dic-list (if not already done).
        // This is to ensure that there is at least one dictionary to which
        // words could be added.
        uno::Reference< linguistic2::XDictionary >  xDic( LinguMgr::GetStandardDic() );
        if (xDic.is())
            xDic->setActive( true );

        aDics = xDicList->getDictionaries();
        pDic  = aDics.getConstArray();
        LanguageType nCheckedLanguage = getImpEditEngine().GetLanguage( aPaM2 ).nLang;
        sal_uInt16 nDicCount = static_cast<sal_uInt16>(aDics.getLength());
        for (sal_uInt16 i = 0; i < nDicCount; i++)
        {
            uno::Reference< linguistic2::XDictionary >  xDicTmp = pDic[i];
            if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp)
                continue;

            uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
            LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
            if( xDicTmp->isActive()
                &&  xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
                && (nCheckedLanguage == nActLanguage || LANGUAGE_NONE == nActLanguage )
                && (!xStor.is() || !xStor->isReadonly()) )
            {
                OUString sImage;

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

                if (sImage.isEmpty())
                {
                    xInsertMenu->append(OUString::number(MN_DICTSTART + i), xDicTmp->getName());
                }
                else
                {
                    Image aImage(sImage);
                    ScopedVclPtr<VirtualDevice> xVirDev(pPopupParent->create_virtual_device());
                    Size aSize(aImage.GetSizePixel());
                    xVirDev->SetOutputSizePixel(aSize);
                    xVirDev->DrawImage(Point(0, 0), aImage);
                    xInsertMenu->append(OUString::number(MN_DICTSTART + i), xDicTmp->getName(), *xVirDev);
                }
                getImpl().maDicNameSingle = xDicTmp->getName();
            }
        }
    }

    if (xInsertMenu->n_children() != 1)
        xPopupMenu->remove(u"add"_ustr);
    if (xInsertMenu->n_children() < 2)
    {
        xInsertMenu.reset();
        xPopupMenu->remove(u"insert"_ustr);
    }

    //tdf#106123 store and restore the EditPaM around the menu Execute
    //because the loss of focus in the current editeng causes writer
    //annotations to save their contents, making the pContent of the
    //current EditPams invalid
    EPaM aP = getImpEditEngine().CreateEPaM(aPaM);
    EPaM aP2 = getImpEditEngine().CreateEPaM(aPaM2);

    if (comphelper::LibreOfficeKit::isActive())
    {
        xPopupMenu->remove(u"autocorrect"_ustr);
        xPopupMenu->remove(u"autocorrectdlg"_ustr);

        LOKSendSpellPopupMenu(*xPopupMenu, nGuessLangWord, nGuessLangPara, nWords);
        return true;
    }

    OUString sId = xPopupMenu->popup_at_rect(pPopupParent, aTempRect);

    aPaM2 = getImpEditEngine().CreateEditPaM(aP2);
    aPaM = getImpEditEngine().CreateEditPaM(aP);

    if (sId == "ignore")
    {
        OUString aWord = getImpl().SpellIgnoreWord();
        SpellCallbackInfo aInf( SpellCallbackCommand::IGNOREWORD, aWord );
        rCallBack.Call(aInf);
        SetSelection( aOldSel );
    }
    else if (sId == "wordlanguage" || sId == "paralanguage")
    {
        LanguageType nLangToUse = (sId == "wordlanguage") ? nGuessLangWord : nGuessLangPara;
        SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse );

        SfxItemSet aAttrs = getEditEngine().GetEmptyItemSet();
        if (nScriptType == SvtScriptType::LATIN)
            aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE ) );
        if (nScriptType == SvtScriptType::COMPLEX)
            aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CTL ) );
        if (nScriptType == SvtScriptType::ASIAN)
            aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CJK ) );
        if (sId == "paralanguage")
        {
            ESelection aSel = GetSelection();
            aSel.start.nIndex = 0;
            aSel.end.nIndex = EE_TEXTPOS_MAX;
            SetSelection( aSel );
        }
        SetAttribs( aAttrs );
        getImpEditEngine().StartOnlineSpellTimer();

        SpellCallbackInfo aInf((sId == "wordlanguage") ? SpellCallbackCommand::WORDLANGUAGE : SpellCallbackCommand::PARALANGUAGE);
        rCallBack.Call(aInf);
        SetSelection( aOldSel );
    }
    else if (sId == "check")
    {
        SpellCallbackInfo aInf( SpellCallbackCommand::STARTSPELLDLG, OUString() );
        rCallBack.Call(aInf);
    }
    else if (sId == "autocorrectdlg")
    {
        SpellCallbackInfo aInf( SpellCallbackCommand::AUTOCORRECT_OPTIONS, OUString() );
        rCallBack.Call(aInf);
    }
    else if ( sId.toInt32() >= MN_DICTSTART || sId == "add")
    {
        OUString aDicName;
        if (sId.toInt32() >= MN_DICTSTART)
        {
            assert(xInsertMenu && "this case only occurs when xInsertMenu exists");
            // strip_mnemonic is necessary to retrieve the correct dictionary name
            aDicName = pPopupParent->strip_mnemonic(xInsertMenu->get_label(sId));
        }
        else
            aDicName = getImpl().maDicNameSingle;

        uno::Reference< linguistic2::XDictionary >      xDic;
        if (xDicList.is())
            xDic = xDicList->getDictionaryByName( aDicName );

        if (xDic.is())
            xDic->add( aSelected, false, OUString() );
        // save modified user-dictionary if it is persistent
        Reference< frame::XStorable >  xSavDic( xDic, UNO_QUERY );
        if (xSavDic.is())
            xSavDic->store();

        aPaM.GetNode()->GetWrongList()->ResetInvalidRange(0, aPaM.GetNode()->Len());
        getImpEditEngine().StartOnlineSpellTimer();

        SpellCallbackInfo aInf( SpellCallbackCommand::ADDTODICTIONARY, aSelected );
        rCallBack.Call(aInf);
        SetSelection( aOldSel );
    }
    else if ( sId.toInt32() >= MN_AUTOSTART )
    {
        DBG_ASSERT(sId.toInt32() - MN_AUTOSTART < aAlt.getLength(), "index out of range");
        OUString aWord = pAlt[sId.toInt32() - MN_AUTOSTART];
        SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get().GetAutoCorrect();
        if ( pAutoCorrect )
            pAutoCorrect->PutText( aSelected, aWord, getImpEditEngine().GetLanguage( aPaM2 ).nLang );
        InsertText( aWord );
    }
    else if ( sId.toInt32() >= MN_ALTSTART )  // Replace
    {
        DBG_ASSERT(sId.toInt32() - MN_ALTSTART < aAlt.getLength(), "index out of range");
        OUString aWord = pAlt[sId.toInt32() - MN_ALTSTART];
        InsertText( aWord );
    }
    else
    {
        SetSelection( aOldSel );
    }
    return true;
}

OUString EditView::SpellIgnoreWord()
{
    return getImpl().SpellIgnoreWord();
}

void EditView::SelectCurrentWord( sal_Int16 nWordType )
{
    EditSelection aCurSel( getImpl().GetEditSelection() );
    getImpl().DrawSelectionXOR();
    aCurSel = getEditEngine().SelectWord(EditSelection(aCurSel.Max()), nWordType);
    getImpl().SetEditSelection( aCurSel );
    getImpl().DrawSelectionXOR();
    ShowCursor( truefalse );
}

void EditView::InsertParaBreak()
{
    getEditEngine().UndoActionStart(EDITUNDO_INSERT);
    getImpl().DeleteSelected();
    EditPaM aPaM(getEditEngine().InsertParaBreak(getImpl().GetEditSelection()));
    getEditEngine().UndoActionEnd();
    getImpl().SetEditSelection(EditSelection(aPaM, aPaM));
    if (getEditEngine().IsUpdateLayout())
        getEditEngine().FormatAndLayout(this);
}

void EditView::InsertField( const SvxFieldItem& rFld )
{
    EditEngine& rEditEngine = getImpl().getEditEngine();
    getImpl().DrawSelectionXOR();
    rEditEngine.UndoActionStart( EDITUNDO_INSERT );
    EditPaM aPaM(rEditEngine.InsertField(getImpl().GetEditSelection(), rFld));
    rEditEngine.UndoActionEnd();
    getImpl().SetEditSelection( EditSelection( aPaM, aPaM ) );
    rEditEngine.UpdateFields();
    if (rEditEngine.IsUpdateLayout())
        rEditEngine.FormatAndLayout( this );
}

const SvxFieldItem* EditView::GetFieldUnderMousePointer() const
{
    sal_Int32 nPara;
    sal_Int32 nPos;
    return GetFieldUnderMousePointer( nPara, nPos );
}

const SvxFieldItem* EditView::GetField( const Point& rPos, sal_Int32* pPara, sal_Int32* pPos ) const
{
    return getImpl().GetField( rPos, pPara, pPos );
}

const SvxFieldItem* EditView::GetFieldUnderMousePointer( sal_Int32& nPara, sal_Int32& nPos ) const
{
    Point aPos;
    if (EditViewCallbacks* pEditViewCallbacks = getImpl().getEditViewCallbacks())
        aPos = pEditViewCallbacks->EditViewPointerPosPixel();
    else
        aPos = getImpl().GetWindow()->GetPointerPosPixel();
    OutputDevice& rDevice = getImpl().GetOutputDevice();
    aPos = rDevice.PixelToLogic(aPos);
    return GetField( aPos, &nPara, &nPos );
}

const SvxFieldItem* EditView::GetFieldAtSelection(bool bAlsoCheckBeforeCursor) const
{
    bool* pIsBeforeCursor = bAlsoCheckBeforeCursor ? &bAlsoCheckBeforeCursor : nullptr;
    return GetFieldAtSelection(pIsBeforeCursor);
}

// If pIsBeforeCursor != nullptr, the position before the cursor will also be checked for a field
// and pIsBeforeCursor will return true if that fallback field is returned.
// If no field is returned, the value in pIsBeforeCursor is meaningless.
const SvxFieldItem* EditView::GetFieldAtSelection(bool* pIsBeforeCursor) const
{
    // a field is a dummy character - so it cannot span nodes or be a selection larger than 1
    EditSelection aSel( getImpl().GetEditSelection() );
    if (aSel.Min().GetNode() != aSel.Max().GetNode())
        return nullptr;

    // normalize: min < max
    aSel.Adjust(getEditEngine().GetEditDoc());

    const sal_Int32 nMinIndex =  aSel.Min().GetIndex();
    const sal_Int32 nMaxIndex =  aSel.Max().GetIndex();
    if (nMaxIndex > nMinIndex + 1)
        return nullptr;

    // Only when cursor is in font of field, no selection,
    // or only selecting field
    bool bAlsoCheckBeforeCursor = false;
    if (pIsBeforeCursor)
    {
        *pIsBeforeCursor = false;
        bAlsoCheckBeforeCursor = nMaxIndex == nMinIndex;
    }
    const SvxFieldItem* pFoundBeforeCursor = nullptr;
    const CharAttribList::AttribsType& rAttrs = aSel.Min().GetNode()->GetCharAttribs().GetAttribs();
    for (const auto& rAttr: rAttrs)
    {
        if (rAttr->Which() == EE_FEATURE_FIELD)
        {
            DBG_ASSERT(dynamic_cast<const SvxFieldItem*>(rAttr->GetItem()), "No FieldItem...");
            if (rAttr->GetStart() == nMinIndex)
                return static_cast<const SvxFieldItem*>(rAttr->GetItem());

            // perhaps the cursor is behind the field?
            if (nMinIndex && rAttr->GetStart() == nMinIndex - 1)
                pFoundBeforeCursor = static_cast<const SvxFieldItem*>(rAttr->GetItem());
        }
    }
    if (bAlsoCheckBeforeCursor)
    {
        *pIsBeforeCursor = /*(bool)*/pFoundBeforeCursor;
        return pFoundBeforeCursor;
    }
    return nullptr;
}

void EditView::SelectFieldAtCursor()
{
    bool bIsBeforeCursor = false;
    const SvxFieldItem* pFieldItem = GetFieldAtSelection(&bIsBeforeCursor);
    if (!pFieldItem)
        return;

    // Make sure the whole field is selected
    // A field is represented by a dummy character - so it cannot be a selection larger than 1
    ESelection aSel = GetSelection();
    if (!aSel.HasRange()) // not yet selected
    {
        if (bIsBeforeCursor)
        {
            assert (aSel.start.nIndex);
            --aSel.start.nIndex;
        }
        else
            aSel.end.nIndex++;
        SetSelection(aSel);
    }
    else
        assert(std::abs(aSel.start.nIndex - aSel.end.nIndex) == 1);
}

const SvxFieldData* EditView::GetFieldUnderMouseOrInSelectionOrAtCursor(bool bAlsoCheckBeforeCursor) const
{
    const SvxFieldItem* pFieldItem = GetFieldUnderMousePointer();
    if (!pFieldItem)
        pFieldItem = GetFieldAtSelection(bAlsoCheckBeforeCursor);

    return pFieldItem ? pFieldItem->GetField() : nullptr;
}

sal_Int32 EditView::countFieldsOffsetSum(sal_Int32 nPara, sal_Int32 nPos, bool bCanOverflow) const
{
    int nOffset = 0;

    for (int nCurrentPara = 0; nCurrentPara <= nPara; nCurrentPara++)
    {
        std::vector<EFieldInfo> aFieldInfos = getEditEngine().GetFieldInfo( nCurrentPara );
        for (const EFieldInfo& rFieldInfo : aFieldInfos)
        {
            bool bLastPara = nCurrentPara == nPara;
            sal_Int32 nFieldPos = rFieldInfo.aPosition.nIndex;

            if (bLastPara && nFieldPos >= nPos)
                break;

            sal_Int32 nFieldLen = rFieldInfo.aCurrentText.getLength();

            // position in the middle of a field
            if (!bCanOverflow && bLastPara && nFieldPos + nFieldLen > nPos)
                nFieldLen = nPos - nFieldPos;

            nOffset += nFieldLen - 1;
        }
    }

    return nOffset;
}

sal_Int32 EditView::GetPosNoField(sal_Int32 nPara, sal_Int32 nPos) const
{
    sal_Int32 nOffset = countFieldsOffsetSum(nPara, nPos, false);
    assert(nPos >= nOffset);
    return nPos - nOffset;
}

sal_Int32 EditView::GetPosWithField(sal_Int32 nPara, sal_Int32 nPos) const
{
    sal_Int32 nOffset = countFieldsOffsetSum(nPara, nPos, true);
    return nPos + nOffset;
}

void EditView::SetInvalidateMore( sal_uInt16 nPixel )
{
    getImpl().SetInvalidateMore( nPixel );
}

sal_uInt16 EditView::GetInvalidateMore() const
{
    return getImpl().GetInvalidateMore();
}

static void ChangeFontSizeImpl( EditView* pEditView, bool bGrow, const ESelection& rSel, const FontList* pFontList )
{
    pEditView->SetSelection( rSel );

    SfxItemSet aSet( pEditView->GetAttribs() );
    if( EditView::ChangeFontSize( bGrow, aSet, pFontList ) )
    {
        SfxItemSet aNewSet( pEditView->GetEmptyItemSet() );
        aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT ) );
        aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CJK ) );
        aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CTL ) );
        pEditView->SetAttribs( aNewSet );
    }
}

void EditView::ChangeFontSize( bool bGrow, const FontList* pFontList )
{

    EditEngine& rEditEngine = getEditEngine();

    ESelection aSel( GetSelection() );
    ESelection aOldSelection( aSel );
    aSel.Adjust();

    if( !aSel.HasRange() )
    {
        aSel = rEditEngine.GetWord( aSel, css::i18n::WordType::DICTIONARY_WORD );
    }

    if( aSel.HasRange() )
    {
        for( sal_Int32 nPara = aSel.start.nPara; nPara <= aSel.end.nPara; nPara++ )
        {
            std::vector<sal_Int32> aPortions;
            rEditEngine.GetPortions( nPara, aPortions );

            if( aPortions.empty() )
                aPortions.push_back( rEditEngine.GetTextLen(nPara) );

            const sal_Int32 nBeginPos = (nPara == aSel.start.nPara) ? aSel.start.nIndex : 0;
            const sal_Int32 nEndPos = (nPara == aSel.end.nPara) ? aSel.end.nIndex : EE_TEXTPOS_MAX;

            for ( size_t nPos = 0; nPos < aPortions.size(); ++nPos )
            {
                sal_Int32 nPortionEnd   = aPortions[ nPos ];
                sal_Int32 nPortionStart = nPos > 0 ? aPortions[ nPos - 1 ] : 0;

                if( (nPortionEnd < nBeginPos) || (nPortionStart > nEndPos) )
                    continue;

                if( nPortionStart < nBeginPos )
                    nPortionStart = nBeginPos;
                if( nPortionEnd > nEndPos )
                    nPortionEnd = nEndPos;

                if( nPortionStart == nPortionEnd )
                    continue;

                ESelection aPortionSel( nPara, nPortionStart, nPara, nPortionEnd );
                ChangeFontSizeImpl( this, bGrow, aPortionSel, pFontList );
            }
        }
    }
    else
    {
        ChangeFontSizeImpl( this, bGrow, aSel, pFontList );
    }

    SetSelection( aOldSelection );
}

bool EditView::ChangeFontSize( bool bGrow, SfxItemSet& rSet, const FontList* pFontList )
{
    if (!pFontList)
        return false;

    static const sal_uInt16 gFontSizeWichMap[] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL, 0 };
    bool bRet = false;

    const sal_uInt16* pWhich = gFontSizeWichMap;
    while( *pWhich )
    {
        SvxFontHeightItem aFontHeightItem( static_cast<const SvxFontHeightItem&>(rSet.Get( *pWhich )) );
        tools::Long nHeight = aFontHeightItem.GetHeight();
        const MapUnit eUnit = rSet.GetPool()->GetMetric( *pWhich );
        nHeight = OutputDevice::LogicToLogic(nHeight * 10, eUnit, MapUnit::MapPoint);

        const int* pAry = FontList::GetStdSizeAry();

        if( bGrow )
        {
            while( *pAry )
            {
                if( *pAry > nHeight )
                {
                    nHeight = *pAry;
                    break;
                }
                pAry++;
            }

            if( *pAry == 0 )
            {
                nHeight += (nHeight + 5) / 10;
                if( nHeight > 9999 )
                    nHeight = 9999;
            }

        }
        else if( *pAry )
        {
            bool bFound = false;
            if( *pAry < nHeight )
            {
                pAry++;
                while( *pAry )
                {
                    if( *pAry >= nHeight )
                    {
                        nHeight = pAry[-1];
                        bFound = true;
                        break;
                    }
                    pAry++;
                }
            }

            if( !bFound )
            {
                nHeight -= (nHeight + 5) / 10;
                if( nHeight < 2 )
                    nHeight = 2;
            }
        }

        if( (nHeight >= 2) && (nHeight <= 9999 ) )
        {
            nHeight = OutputDevice::LogicToLogic( nHeight, MapUnit::MapPoint, eUnit  ) / 10;

            if( nHeight != static_cast<tools::Long>(aFontHeightItem.GetHeight()) )
            {
                aFontHeightItem.SetHeight( nHeight );
                rSet.Put( aFontHeightItem.CloneSetWhich(*pWhich) );
                bRet = true;
            }
        }
        pWhich++;
    }
    return bRet;
}

OUString EditView::GetSurroundingText() const
{
    EditSelection aSel( getImpl().GetEditSelection() );
    aSel.Adjust(getEditEngine().GetEditDoc());

    if( HasSelection() )
    {
        OUString aStr = getEditEngine().GetSelected(aSel);

        // Stop reconversion if the selected text includes a line break.
        if ( aStr.indexOf( 0x0A ) == -1 )
          return aStr;
        else
          return OUString();
    }
    else
    {
        aSel.Min().SetIndex( 0 );
        aSel.Max().SetIndex( aSel.Max().GetNode()->Len() );
        return getEditEngine().GetSelected(aSel);
    }
}

Selection EditView::GetSurroundingTextSelection() const
{
    ESelection aSelection( GetSelection() );
    aSelection.Adjust();

    if( HasSelection() )
    {
        EditSelection aSel( getImpl().GetEditSelection() );
        aSel.Adjust(getEditEngine().GetEditDoc());
        OUString aStr = getEditEngine().GetSelected(aSel);

        // Stop reconversion if the selected text includes a line break.
        if ( aStr.indexOf( 0x0A ) == -1 )
            return Selection(0, aSelection.end.nIndex - aSelection.start.nIndex);
        else
            return Selection( 0, 0 );
    }
    else
    {
        return Selection(aSelection.start.nIndex, aSelection.end.nIndex);
    }
}

bool EditView::DeleteSurroundingText(const Selection& rRange)
{
    ESelection aSel(GetSelection());
    aSel.end.nPara = aSel.start.nPara;
    aSel.start.nIndex = rRange.Min();
    aSel.end.nIndex = rRange.Max();
    SetSelection(aSel);
    DeleteSelected();
    return true;
}

void EditView::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool bClearMark)
{
    Point aDocPos(getImpl().GetDocPos(rPosition));
    EditPaM aPaM = getEditEngine().GetPaM(aDocPos);
    EditSelection aSelection(getImpl().GetEditSelection());

    // Explicitly create or delete the selection.
    if (bClearMark)
    {
        getImpl().DeselectAll();
        aSelection = getImpl().GetEditSelection();
    }
    else
        getImpl().CreateAnchor();

    if (bPoint)
        aSelection.Max() = aPaM;
    else
        aSelection.Min() = aPaM;

    if (getImpl().GetEditSelection().Min() != aSelection.Min())
    {
        const ContentNode* pNode(getImpl().GetEditSelection().Min().GetNode());
        if (nullptr != pNode)
            pNode->checkAndDeleteEmptyAttribs();
    }

    getImpl().DrawSelectionXOR(aSelection);
    if (getImpl().GetEditSelection() != aSelection)
        getImpl().SetEditSelection(aSelection);
    ShowCursor(/*bGotoCursor=*/false);
}

void EditView::DrawSelectionXOR(OutlinerViewShell* pOtherShell)
{
    getImpl().RegisterOtherShell(pOtherShell);
    getImpl().DrawSelectionXOR();
    getImpl().RegisterOtherShell(nullptr);
}

void EditView::InitLOKSpecialPositioning(MapUnit eUnit,
                                         const tools::Rectangle& rOutputArea,
                                         const Point& rVisDocStartPos)
{
    getImpl().InitLOKSpecialPositioning(eUnit, rOutputArea, rVisDocStartPos);
}

void EditView::SetLOKSpecialOutputArea(const tools::Rectangle& rOutputArea)
{
    getImpl().SetLOKSpecialOutputArea(rOutputArea);
}

const tools::Rectangle & EditView::GetLOKSpecialOutputArea() const
{
    return getImpl().GetLOKSpecialOutputArea();
}

void EditView::SetLOKSpecialVisArea(const tools::Rectangle& rVisArea)
{
    getImpl().SetLOKSpecialVisArea(rVisArea);
}

tools::Rectangle EditView::GetLOKSpecialVisArea() const
{
    return getImpl().GetLOKSpecialVisArea();
}

bool EditView::HasLOKSpecialPositioning() const
{
    return getImpl().HasLOKSpecialPositioning();
}

void EditView::SetLOKSpecialFlags(LOKSpecialFlags eFlags)
{
    getImpl().SetLOKSpecialFlags(eFlags);
}

void EditView::SuppressLOKMessages(bool bSet)
{
    getImpl().SuppressLOKMessages(bSet);
}

bool EditView::IsSuppressLOKMessages() const
{
    return getImpl().IsSuppressLOKMessages();
}

void EditView::SetNegativeX(bool bSet)
{
    getImpl().SetNegativeX(bSet);
}

bool EditView::IsNegativeX() const
{
    return getImpl().IsNegativeX();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=96 G=95

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.