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

Quelle  viewdata.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 <scitems.hxx>
#include <editeng/eeitem.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/unit_conversion.hxx>
#include <o3tl/string_view.hxx>
#include <sfx2/lokhelper.hxx>
#include <sfx2/viewfrm.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/brushitem.hxx>
#include <svtools/colorcfg.hxx>
#include <editeng/editview.hxx>
#include <editeng/editstat.hxx>
#include <editeng/outliner.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/justifyitem.hxx>

#include <vcl/svapp.hxx>
#include <rtl/math.hxx>
#include <sal/log.hxx>

#include <viewdata.hxx>
#include <scmod.hxx>
#include <global.hxx>
#include <document.hxx>
#include <drwlayer.hxx>
#include <attrib.hxx>
#include <tabview.hxx>
#include <tabvwsh.hxx>
#include <docpool.hxx>
#include <docsh.hxx>
#include <patattr.hxx>
#include <editutil.hxx>
#include <scextopt.hxx>
#include <miscuno.hxx>
#include <unonames.hxx>
#include <inputopt.hxx>
#include <inputhdl.hxx>
#include <inputwin.hxx>
#include <viewutil.hxx>
#include <markdata.hxx>
#include <ViewSettingsSequenceDefines.hxx>
#include <gridwin.hxx>
#include <transobj.hxx>
#include <clipparam.hxx>
#include <comphelper/flagguard.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>

#include <vcl/uitest/logger.hxx>
#include <vcl/uitest/eventdescription.hxx>

#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/document/NamedPropertyValues.hpp>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>

using namespace com::sun::star;

#define SC_GROWY_SMALL_EXTRA    100
#define SC_GROWY_BIG_EXTRA      200

constexpr OUString TAG_TABBARWIDTH = u"tw:"_ustr;

namespace {

void lcl_LOKRemoveWindow(ScTabViewShell* pTabViewShell, ScSplitPos eWhich)
{
    if (comphelper::LibreOfficeKit::isActive())
    {
        auto lRemoveWindows =
                [pTabViewShell, eWhich] (ScTabViewShell* pOtherViewShell)
                { pOtherViewShell->RemoveWindowFromForeignEditView(pTabViewShell, eWhich); };

        SfxLokHelper::forEachOtherView(pTabViewShell, lRemoveWindows);
    }
}

// anonymous namespace

namespace {

void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
{
    EventDescription aDescription;
    aDescription.aID = "grid_window";
    aDescription.aAction = rAction;
    aDescription.aParameters = std::move(aParameters);
    aDescription.aParent = "MainWindow";
    aDescription.aKeyWord = "ScGridWinUIObject";

    UITestLogger::getInstance().logEvent(aDescription);
}
}

const ScPositionHelper::index_type ScPositionHelper::null; // definition

bool ScPositionHelper::Comp::operator() (const value_type& rValue1, const value_type& rValue2) const
{
    if (rValue1.first == null || rValue2.first == null)
    {
        return rValue1.second < rValue2.second;
    }
    else
    {
        return rValue1.first < rValue2.first;
    }
}

ScPositionHelper::ScPositionHelper(const ScDocument *pDoc, bool bColumn)
    : MAX_INDEX(bColumn ? (pDoc ? pDoc->MaxCol() : -1) : MAXTILEDROW)
{
    mData.insert(std::make_pair(-1, 0));
}

void ScPositionHelper::setDocument(const ScDocument& rDoc, bool bColumn)
{
    MAX_INDEX = bColumn ? rDoc.MaxCol() : MAXTILEDROW;
}

void ScPositionHelper::insert(index_type nIndex, tools::Long nPos)
{
    if (nIndex < 0) return;
    SAL_INFO("sc.lok.poshelper""ScPositionHelper::insert: nIndex: "
            << nIndex << ", nPos: " << nPos << ", size: " << mData.size());
    value_type aValue = std::make_pair(nIndex, nPos);
    mData.erase(aValue);
    mData.insert(aValue);
    SAL_INFO("sc.lok.poshelper",
            "ScPositionHelper::insert: after insert: size: " << mData.size());
}

void ScPositionHelper::removeByIndex(index_type nIndex)
{
    if (nIndex < 0)
        return;
    SAL_INFO("sc.lok.poshelper""ScPositionHelper::remove: nIndex: " << nIndex
            << ", size: " << mData.size());
    auto it = mData.find(std::make_pair(nIndex, 0));
    if (it == mData.end()) return;
    mData.erase(it);
    SAL_INFO("sc.lok.poshelper",
            "ScPositionHelper::remove: after erase: size: " << mData.size());
}

void ScPositionHelper::invalidateByIndex(index_type nIndex)
{
    SAL_INFO("sc.lok.poshelper""ScPositionHelper::invalidate: nIndex: " << nIndex);
    if (nIndex < 0)
    {
        mData.clear();
        mData.insert(std::make_pair(-1, 0));
    }
    else
    {
        auto it = mData.lower_bound(std::make_pair(nIndex, 0));
        mData.erase(it, mData.end());
    }
}

void ScPositionHelper::invalidateByPosition(tools::Long nPos)
{
    SAL_INFO("sc.lok.poshelper""ScPositionHelper::invalidate: nPos: " << nPos);
    if (nPos <= 0)
    {
        mData.clear();
        mData.insert(std::make_pair(-1, 0));
    }
    else
    {
        auto it = mData.lower_bound(std::make_pair(null, nPos));
        mData.erase(it, mData.end());
    }
}

const ScPositionHelper::value_type&
ScPositionHelper::getNearestByIndex(index_type nIndex) const
{
    SAL_INFO("sc.lok.poshelper",
            "ScPositionHelper::getNearest: nIndex: " << nIndex << ", size: " << mData.size());
    auto posUB = mData.upper_bound(std::make_pair(nIndex, 0));
    if (posUB == mData.begin())
    {
        return *posUB;
    }

    auto posLB = std::prev(posUB);
    // coverity[copy_paste_error : FALSE] - posUB is correct
    if (posUB == mData.end())
    {
        return *posLB;
    }

    tools::Long nDiffUB = posUB->first - nIndex;
    tools::Long nDiffLB = posLB->first - nIndex;
    if (nDiffUB < -nDiffLB)
    {
        return *posUB;
    }
    else
    {
        return *posLB;
    }
}

const ScPositionHelper::value_type&
ScPositionHelper::getNearestByPosition(tools::Long nPos) const
{
    SAL_INFO("sc.lok.poshelper",
            "ScPositionHelper::getNearest: nPos: " << nPos << ", size: " << mData.size());
    auto posUB = mData.upper_bound(std::make_pair(null, nPos));

    if (posUB == mData.begin())
    {
        return *posUB;
    }

    auto posLB = std::prev(posUB);
    // coverity[copy_paste_error : FALSE] - posUB is correct
    if (posUB == mData.end())
    {
        return *posLB;
    }

    tools::Long nDiffUB = posUB->second - nPos;
    tools::Long nDiffLB = posLB->second - nPos;

    if (nDiffUB < -nDiffLB)
    {
        return *posUB;
    }
    else
    {
        return *posLB;
    }
}

tools::Long ScPositionHelper::getPosition(index_type nIndex) const
{
    auto it = mData.find(std::make_pair(nIndex, 0));
    if (it == mData.end()) return -1;
    return it->second;
}

tools::Long ScPositionHelper::computePosition(index_type nIndex, const std::function<long (index_type)>& getSizePx)
{
    assert(MAX_INDEX > 0);
    if (nIndex < 0) nIndex = 0;
    if (nIndex > MAX_INDEX) nIndex = MAX_INDEX;

    const auto& rNearest = getNearestByIndex(nIndex);
    index_type nStartIndex = rNearest.first;
    tools::Long nTotalPixels = rNearest.second;

    if (nStartIndex < nIndex)
    {
        for (index_type nIdx = nStartIndex + 1; nIdx <= nIndex; ++nIdx)
        {
            nTotalPixels += getSizePx(nIdx);
        }
    }
    else
    {
        for (index_type nIdx = nStartIndex; nIdx > nIndex; --nIdx)
        {
            nTotalPixels -= getSizePx(nIdx);
        }
    }
    return nTotalPixels;
}

ScBoundsProvider::ScBoundsProvider(const ScViewData &rView, SCTAB nT, bool bColHeader)
    : rDoc(rView.GetDocument())
    , nTab(nT)
    , bColumnHeader(bColHeader)
    , MAX_INDEX(bColHeader ? rDoc.MaxCol() : MAXTILEDROW)
    , mfPPTX(rView.GetPPTX())
    , mfPPTY(rView.GetPPTY())
    , nFirstIndex(-1)
    , nSecondIndex(-1)
    , nFirstPositionPx(-1)
    , nSecondPositionPx(-1)
{}

void ScBoundsProvider::GetStartIndexAndPosition(SCCOL& nIndex, tools::LongnPosition) const
{
    assert(bColumnHeader);
    nIndex = nFirstIndex;
    nPosition = nFirstPositionPx;
}

void ScBoundsProvider::GetEndIndexAndPosition(SCCOL& nIndex, tools::Long& nPosition) const
{
    assert(bColumnHeader);
    nIndex = nSecondIndex;
    nPosition = nSecondPositionPx;
}

void ScBoundsProvider::GetStartIndexAndPosition(SCROW& nIndex, tools::LongnPosition) const
{
    assert(!bColumnHeader);
    nIndex = nFirstIndex;
    nPosition = nFirstPositionPx;
}

void ScBoundsProvider::GetEndIndexAndPosition(SCROW& nIndex, tools::Long& nPosition) const
{
    assert(!bColumnHeader);
    nIndex = nSecondIndex;
    nPosition = nSecondPositionPx;
}

tools::Long ScBoundsProvider::GetSize(index_type nIndex) const
{
    const sal_uInt16 nSize = bColumnHeader ? rDoc.GetColWidth(nIndex, nTab) : rDoc.GetRowHeight(nIndex, nTab);
    return ScViewData::ToPixel(nSize, bColumnHeader ? mfPPTX : mfPPTY);
}

void ScBoundsProvider::GetIndexAndPos(index_type nNearestIndex, tools::Long nNearestPosition,
                    tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition,
                    bool bTowards, tools::Long nDiff)
{
    if (nDiff > 0) // nBound < nNearestPosition
        GeIndexBackwards(nNearestIndex, nNearestPosition, nBound,
                         nFoundIndex, nPosition, bTowards);
    else
        GetIndexTowards(nNearestIndex, nNearestPosition, nBound,
                        nFoundIndex, nPosition, bTowards);
}

void ScBoundsProvider::Compute(
            value_type aFirstNearest, value_type aSecondNearest,
            tools::Long nFirstBound, tools::Long nSecondBound)
{
    SAL_INFO("sc.lok.header""BoundsProvider: nFirstBound: " << nFirstBound
            << ", nSecondBound: " << nSecondBound);

    tools::Long nFirstDiff = aFirstNearest.second - nFirstBound;
    tools::Long nSecondDiff = aSecondNearest.second - nSecondBound;
    SAL_INFO("sc.lok.header""BoundsProvider: rTopNearest: index: " << aFirstNearest.first
            << ", pos: " << aFirstNearest.second << ", diff: " << nFirstDiff);
    SAL_INFO("sc.lok.header""BoundsProvider: rBottomNearest: index: " << aSecondNearest.first
            << ", pos: " << aSecondNearest.second << ", diff: " << nSecondDiff);

    bool bReverse = (std::abs(nFirstDiff) >= std::abs(nSecondDiff));

    if(bReverse)
    {
        std::swap(aFirstNearest, aSecondNearest);
        std::swap(nFirstBound, nSecondBound);
        std::swap(nFirstDiff, nSecondDiff);
    }

    index_type nNearestIndex = aFirstNearest.first;
    tools::Long nNearestPosition = aFirstNearest.second;
    SAL_INFO("sc.lok.header""BoundsProvider: nearest to first bound: nNearestIndex: "
            << nNearestIndex << ", nNearestPosition: " << nNearestPosition);

    GetIndexAndPos(nNearestIndex, nNearestPosition, nFirstBound,
                   nFirstIndex, nFirstPositionPx, !bReverse, nFirstDiff);
    SAL_INFO("sc.lok.header""BoundsProvider: nFirstIndex: " << nFirstIndex
            << ", nFirstPositionPx: " << nFirstPositionPx);

    if (std::abs(nSecondDiff) < std::abs(nSecondBound - nFirstPositionPx))
    {
        nNearestIndex = aSecondNearest.first;
        nNearestPosition = aSecondNearest.second;
    }
    else
    {
        nNearestPosition = nFirstPositionPx;
        nNearestIndex = nFirstIndex;
        nSecondDiff = !bReverse ? -1 : 1;
    }
    SAL_INFO("sc.lok.header""BoundsProvider: nearest to second bound: nNearestIndex: "
            << nNearestIndex << ", nNearestPosition: " << nNearestPosition
            << ", diff: " << nSecondDiff);

    GetIndexAndPos(nNearestIndex, nNearestPosition, nSecondBound,
                   nSecondIndex, nSecondPositionPx, bReverse, nSecondDiff);
    SAL_INFO("sc.lok.header""BoundsProvider: nSecondIndex: " << nSecondIndex
            << ", nSecondPositionPx: " << nSecondPositionPx);

    if (bReverse)
    {
        std::swap(nFirstIndex, nSecondIndex);
        std::swap(nFirstPositionPx, nSecondPositionPx);
    }
}

void ScBoundsProvider::EnlargeStartBy(tools::Long nOffset)
{
    const index_type nNewFirstIndex =
            std::max(static_cast<index_type>(-1),
                     static_cast<index_type>(nFirstIndex - nOffset));
    for (index_type nIndex = nFirstIndex; nIndex > nNewFirstIndex; --nIndex)
    {
        const tools::Long nSizePx = GetSize(nIndex);
        nFirstPositionPx -= nSizePx;
    }
    nFirstIndex = nNewFirstIndex;
    SAL_INFO("sc.lok.header""BoundsProvider: added offset: nFirstIndex: " << nFirstIndex
            << ", nFirstPositionPx: " << nFirstPositionPx);
}

void ScBoundsProvider::EnlargeEndBy(tools::Long nOffset)
{
    const index_type nNewSecondIndex = std::min(MAX_INDEX, static_cast<index_type>(nSecondIndex + nOffset));
    for (index_type nIndex = nSecondIndex + 1; nIndex <= nNewSecondIndex; ++nIndex)
    {
        const tools::Long nSizePx = GetSize(nIndex);
        nSecondPositionPx += nSizePx;
    }
    nSecondIndex = nNewSecondIndex;
    SAL_INFO("sc.lok.header""BoundsProvider: added offset: nSecondIndex: " << nSecondIndex
            << ", nSecondPositionPx: " << nSecondPositionPx);
}

void ScBoundsProvider::GeIndexBackwards(
            index_type nNearestIndex, tools::Long nNearestPosition,
            tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition, bool bTowards)
{
    nFoundIndex = -1;
    for (index_type nIndex = nNearestIndex; nIndex >= 0; --nIndex)
    {
        if (nBound >= nNearestPosition)
        {
            nFoundIndex = nIndex; // last index whose nPosition is less than nBound
            nPosition = nNearestPosition;
            break;
        }

        const tools::Long nSizePx = GetSize(nIndex);
        nNearestPosition -= nSizePx;
    }
    if (!bTowards && nFoundIndex != -1)
    {
        nFoundIndex += 1;
        nPosition += GetSize(nFoundIndex);
    }
}

void ScBoundsProvider::GetIndexTowards(
            index_type nNearestIndex, tools::Long nNearestPositionPx,
            tools::Long nBoundPx, index_type& nFoundIndex, tools::Long& nPosition, bool bTowards)
{
    nFoundIndex = -2;
    if (bColumnHeader)
    {
        for (index_type nIndex = nNearestIndex + 1; nIndex <= MAX_INDEX; ++nIndex)
        {
            const sal_uInt16 nSize = rDoc.GetColWidth(nIndex, nTab);
            const tools::Long nSizePx = ScViewData::ToPixel(nSize, mfPPTX);
            nNearestPositionPx += nSizePx;

            if (nNearestPositionPx > nBoundPx)
            {
                nFoundIndex = nIndex; // first index whose nPosition is greater than nBoundPx
                nPosition = nNearestPositionPx;
                break;
            }
        }
    }
    else
    {
        SCROW nFoundRow = rDoc.GetRowForHeightPixels(nTab, nNearestIndex, nNearestPositionPx, nBoundPx, mfPPTY);
        if (nFoundRow != -1)
        {
            nFoundIndex = nFoundRow; // first index whose nPosition is greater than nBound
            nPosition = nNearestPositionPx;
        }
    }
    if (nFoundIndex == -2)
    {
        nFoundIndex = MAX_INDEX;
        nPosition = nNearestPositionPx;
    }
    else if (bTowards)
    {
        nPosition -= GetSize(nFoundIndex);
        nFoundIndex -= 1;
    }
}

ScViewDataTable::ScViewDataTable(const ScDocument *pDoc) :
                eZoomType( SvxZoomType::PERCENT ),
                aZoomX( 1,1 ),
                aZoomY( 1,1 ),
                aPageZoomX( 3,5 ),              // Page-Default: 60%
                aPageZoomY( 3,5 ),
                nHSplitPos( 0 ),
                nVSplitPos( 0 ),
                eHSplitMode( SC_SPLIT_NONE ),
                eVSplitMode( SC_SPLIT_NONE ),
                eWhichActive( SC_SPLIT_BOTTOMLEFT ),
                nFixPosX( 0 ),
                nFixPosY( 0 ),
                nCurX( 0 ),
                nCurY( 0 ),
                nOldCurX( 0 ),
                nOldCurY( 0 ),
                aWidthHelper(pDoc, true),
                aHeightHelper(pDoc, false),
                nMaxTiledCol( 20 ),
                nMaxTiledRow( 50 ),
                bShowGrid( true ),
                mbOldCursorValid( false )
{
    nPosX[0]=nPosX[1]=0;
    nPosY[0]=nPosY[1]=0;
    nTPosX[0]=nTPosX[1]=0;
    nTPosY[0]=nTPosY[1]=0;
    nMPosX[0]=nMPosX[1]=0;
    nMPosY[0]=nMPosY[1]=0;
    nPixPosX[0]=nPixPosX[1]=0;
    nPixPosY[0]=nPixPosY[1]=0;
}

void ScViewDataTable::InitData(const ScDocument& rDoc)
{
    aWidthHelper.setDocument(rDoc, true);
    aHeightHelper.setDocument(rDoc, false);
}

void ScViewDataTable::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& ;rSettings, const ScViewData& rViewData, SCTAB nTab) const
{
    rSettings.realloc(SC_TABLE_VIEWSETTINGS_COUNT);
    beans::PropertyValue* pSettings = rSettings.getArray();

    ScSplitMode eExHSplitMode = eHSplitMode;
    ScSplitMode eExVSplitMode = eVSplitMode;
    SCCOL nExFixPosX = nFixPosX;
    SCROW nExFixPosY = nFixPosY;
    tools::Long nExHSplitPos = nHSplitPos;
    tools::Long nExVSplitPos = nVSplitPos;

    if (comphelper::LibreOfficeKit::isActive())
    {
        rViewData.OverrideWithLOKFreeze(eExHSplitMode, eExVSplitMode,
                                        nExFixPosX, nExFixPosY,
                                        nExHSplitPos, nExVSplitPos, nTab);
    }

    pSettings[SC_CURSOR_X].Name = SC_CURSORPOSITIONX;
    pSettings[SC_CURSOR_X].Value <<= sal_Int32(nCurX);
    pSettings[SC_CURSOR_Y].Name = SC_CURSORPOSITIONY;
    pSettings[SC_CURSOR_Y].Value <<= sal_Int32(nCurY);

    // Write freezepan data only when freeze pans are set
    if(nExFixPosX != 0 || nExFixPosY != 0 || nExHSplitPos != 0 || nExVSplitPos != 0)
    {
        pSettings[SC_HORIZONTAL_SPLIT_MODE].Name = SC_HORIZONTALSPLITMODE;
        pSettings[SC_HORIZONTAL_SPLIT_MODE].Value <<= sal_Int16(eExHSplitMode);
        pSettings[SC_VERTICAL_SPLIT_MODE].Name = SC_VERTICALSPLITMODE;
        pSettings[SC_VERTICAL_SPLIT_MODE].Value <<= sal_Int16(eExVSplitMode);
        pSettings[SC_HORIZONTAL_SPLIT_POSITION].Name = SC_HORIZONTALSPLITPOSITION;
        if (eExHSplitMode == SC_SPLIT_FIX)
            pSettings[SC_HORIZONTAL_SPLIT_POSITION].Value <<= sal_Int32(nExFixPosX);
        else
            pSettings[SC_HORIZONTAL_SPLIT_POSITION].Value <<= sal_Int32(nExHSplitPos);
        pSettings[SC_VERTICAL_SPLIT_POSITION].Name = SC_VERTICALSPLITPOSITION;
        if (eExVSplitMode == SC_SPLIT_FIX)
            pSettings[SC_VERTICAL_SPLIT_POSITION].Value <<= sal_Int32(nExFixPosY);
        else
            pSettings[SC_VERTICAL_SPLIT_POSITION].Value <<= sal_Int32(nExVSplitPos);
    }

    // Prevent writing odd settings that would make crash versions that
    // don't apply SanitizeWhichActive() when reading the settings.
    // See tdf#117093
    const ScSplitPos eActiveSplitRange = SanitizeWhichActive();
    // And point out to give us a chance to inspect weird things (if anyone
    // remembers what s/he did).
    assert(eWhichActive == eActiveSplitRange);
    pSettings[SC_ACTIVE_SPLIT_RANGE].Name = SC_ACTIVESPLITRANGE;
    pSettings[SC_ACTIVE_SPLIT_RANGE].Value <<= sal_Int16(eActiveSplitRange);
    pSettings[SC_POSITION_LEFT].Name = SC_POSITIONLEFT;
    pSettings[SC_POSITION_LEFT].Value <<= sal_Int32(nPosX[SC_SPLIT_LEFT]);
    pSettings[SC_POSITION_RIGHT].Name = SC_POSITIONRIGHT;
    pSettings[SC_POSITION_RIGHT].Value <<= sal_Int32(nPosX[SC_SPLIT_RIGHT]);
    pSettings[SC_POSITION_TOP].Name = SC_POSITIONTOP;
    pSettings[SC_POSITION_TOP].Value <<= sal_Int32(nPosY[SC_SPLIT_TOP]);
    pSettings[SC_POSITION_BOTTOM].Name = SC_POSITIONBOTTOM;
    pSettings[SC_POSITION_BOTTOM].Value <<= sal_Int32(nPosY[SC_SPLIT_BOTTOM]);

    sal_Int32 nZoomValue = tools::Long(aZoomY * 100);
    sal_Int32 nPageZoomValue = tools::Long(aPageZoomY * 100);
    pSettings[SC_TABLE_ZOOM_TYPE].Name = SC_ZOOMTYPE;
    pSettings[SC_TABLE_ZOOM_TYPE].Value <<= sal_Int16(eZoomType);
    pSettings[SC_TABLE_ZOOM_VALUE].Name = SC_ZOOMVALUE;
    pSettings[SC_TABLE_ZOOM_VALUE].Value <<= nZoomValue;
    pSettings[SC_TABLE_PAGE_VIEW_ZOOM_VALUE].Name = SC_PAGEVIEWZOOMVALUE;
    pSettings[SC_TABLE_PAGE_VIEW_ZOOM_VALUE].Value <<= nPageZoomValue;

    pSettings[SC_TABLE_SHOWGRID].Name = SC_UNO_SHOWGRID;
    pSettings[SC_TABLE_SHOWGRID].Value <<= bShowGrid;

    // Common SdrModel processing
    rViewData.GetDocument().GetDrawLayer()->WriteUserDataSequence(rSettings);
}

void ScViewDataTable::ReadUserDataSequence(const uno::Sequence <beans::PropertyValue>&&nbsp;aSettings, ScViewData& rViewData, SCTAB nTab, bool& rHasZoom )
{
    rHasZoom = false;

    sal_Int32 nTemp32(0);
    sal_Int16 nTemp16(0);
    sal_Int32 nTempPosV(0);
    sal_Int32 nTempPosH(0);
    sal_Int32 nTempPosVTw(0);
    sal_Int32 nTempPosHTw(0);
    bool bHasVSplitInTwips = false;
    bool bHasHSplitInTwips = false;
    for (const auto& rSetting : aSettings)
    {
        OUString sName(rSetting.Name);
        if (sName == SC_CURSORPOSITIONX)
        {
            rSetting.Value >>= nTemp32;
            nCurX = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
        }
        else if (sName == SC_CURSORPOSITIONY)
        {
            rSetting.Value >>= nTemp32;
            nCurY = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
        }
        else if (sName == SC_HORIZONTALSPLITMODE)
        {
            if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitMode::SC_SPLIT_MODE_MAX_ENUM)
                eHSplitMode = static_cast<ScSplitMode>(nTemp16);
        }
        else if (sName == SC_VERTICALSPLITMODE)
        {
            if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitMode::SC_SPLIT_MODE_MAX_ENUM)
                eVSplitMode = static_cast<ScSplitMode>(nTemp16);
        }
        else if (sName == SC_HORIZONTALSPLITPOSITION)
        {
            rSetting.Value >>= nTempPosH;
            bHasHSplitInTwips = false;
        }
        else if (sName == SC_VERTICALSPLITPOSITION)
        {
            rSetting.Value >>= nTempPosV;
            bHasVSplitInTwips = false;
        }
        else if (sName == SC_HORIZONTALSPLITPOSITION_TWIPS)
        {
            rSetting.Value >>= nTempPosHTw;
            bHasHSplitInTwips = true;
        }
        else if (sName == SC_VERTICALSPLITPOSITION_TWIPS)
        {
            rSetting.Value >>= nTempPosVTw;
            bHasVSplitInTwips = true;
        }
        else if (sName == SC_ACTIVESPLITRANGE)
        {
            if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitPos::SC_SPLIT_POS_MAX_ENUM)
                eWhichActive = static_cast<ScSplitPos>(nTemp16);
        }
        else if (sName == SC_POSITIONLEFT)
        {
            rSetting.Value >>= nTemp32;
            nPosX[SC_SPLIT_LEFT] = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
        }
        else if (sName == SC_POSITIONRIGHT)
        {
            rSetting.Value >>= nTemp32;
            nPosX[SC_SPLIT_RIGHT] = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
        }
        else if (sName == SC_POSITIONTOP)
        {
            rSetting.Value >>= nTemp32;
            nPosY[SC_SPLIT_TOP] = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
        }
        else if (sName == SC_POSITIONBOTTOM)
        {
            rSetting.Value >>= nTemp32;
            nPosY[SC_SPLIT_BOTTOM] = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
        }
        else if (sName == SC_ZOOMTYPE)
        {
            rSetting.Value >>= nTemp16;
            eZoomType = SvxZoomType(nTemp16);
            rHasZoom = true;        // set if there is any zoom information
        }
        else if (sName == SC_ZOOMVALUE)
        {
            rSetting.Value >>= nTemp32;
            Fraction aZoom(nTemp32, 100);
            aZoomX = aZoomY = aZoom;
            rHasZoom = true;
        }
        else if (sName == SC_PAGEVIEWZOOMVALUE)
        {
            rSetting.Value >>= nTemp32;
            Fraction aZoom(nTemp32, 100);
            aPageZoomX = aPageZoomY = aZoom;
            rHasZoom = true;
        }
        else if (sName == SC_UNO_SHOWGRID)
        {
            rSetting.Value >>= bShowGrid;
        }
        else if (sName == SC_TABLESELECTED)
        {
            bool bSelected = false;
            rSetting.Value >>= bSelected;
            rViewData.GetMarkData().SelectTable( nTab, bSelected );
        }
        else if (sName == SC_UNONAME_TABCOLOR)
        {
            // There are documents out there that have their tab color defined as a view setting.
            Color aColor = COL_AUTO;
            rSetting.Value >>= aColor;
            if (aColor != COL_AUTO)
            {
                ScDocument& rDoc = rViewData.GetDocument();
                rDoc.SetTabBgColor(nTab, aColor);
            }
        }
        // Fallback to common SdrModel processing
        else rViewData.GetDocument().GetDrawLayer()->ReadUserDataSequenceValue(&rSetting);
    }

    if (eHSplitMode == SC_SPLIT_FIX)
        nFixPosX = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>( bHasHSplitInTwips ? nTempPosHTw : nTempPosH ));
    else
        nHSplitPos = bHasHSplitInTwips ? static_cast< tools::Long >( nTempPosHTw * rViewData.GetPPTX() ) : nTempPosH;

    if (eVSplitMode == SC_SPLIT_FIX)
        nFixPosY = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>( bHasVSplitInTwips ? nTempPosVTw : nTempPosV ));
    else
        nVSplitPos = bHasVSplitInTwips ? static_cast< tools::Long >( nTempPosVTw * rViewData.GetPPTY() ) : nTempPosV;

    eWhichActive = SanitizeWhichActive();
}

ScSplitPos ScViewDataTable::SanitizeWhichActive() const
{
    if ((WhichH(eWhichActive) == SC_SPLIT_RIGHT && eHSplitMode == SC_SPLIT_NONE) ||
            (WhichV(eWhichActive) == SC_SPLIT_TOP && eVSplitMode == SC_SPLIT_NONE))
    {
        SAL_WARN("sc.ui","ScViewDataTable::SanitizeWhichActive - bad eWhichActive " << eWhichActive);
        // The default always initialized grid window is SC_SPLIT_BOTTOMLEFT.
        return SC_SPLIT_BOTTOMLEFT;
    }
    return eWhichActive;
}

ScViewData::ScViewData(ScDocShell& rDocSh, ScTabViewShell* pViewSh) :
        nPPTX(0.0),
        nPPTY(0.0),
        mrDocShell   ( rDocSh ),
        mrDoc       (rDocSh.GetDocument()),
        maMarkData  (mrDoc.GetSheetLimits()),
        maHighlightData (mrDoc.GetSheetLimits()),
        pView       ( pViewSh ),
        maOptions   (mrDoc.GetViewOptions()),
        pSpellingView ( nullptr ),
        aLogicMode  ( MapUnit::Map100thMM ),
        eDefZoomType( SvxZoomType::PERCENT ),
        aDefZoomX   ( 1,1 ),
        aDefZoomY   ( 1,1 ),
        aDefPageZoomX( 3,5 ),
        aDefPageZoomY( 3,5 ),
        eRefType    ( SC_REFTYPE_NONE ),
        nTabNo      ( 0 ),
        nRefTabNo   ( 0 ),
        nRefStartX(0),
        nRefStartY(0),
        nRefStartZ(0),
        nRefEndX(0),
        nRefEndY(0),
        nRefEndZ(0),
        nFillStartX(0),
        nFillStartY(0),
        nFillEndX(0),
        nFillEndY(0),
        nPasteFlags ( ScPasteFlags::NONE ),
        eEditActivePart( SC_SPLIT_BOTTOMLEFT ),
        nFillMode   ( ScFillMode::NONE ),
        eEditAdjust ( SvxAdjust::Left ),
        bActive     ( true ),                   // how to initialize?
        bIsRefMode  ( false ),
        bDelMarkValid( false ),
        bPagebreak  ( false ),
        bSelCtrlMouseClick( false ),
        bMoveArea ( false ),
        bEditHighlight ( false ),
        bGrowing (false),
        nFormulaBarLines(1),
        m_nLOKPageUpDownOffset( 0 )
{
    maMarkData.SelectOneTable(0); // Sync with nTabNo

    aScrSize = Size( o3tl::convert(STD_COL_WIDTH * OLE_STD_CELLS_X, o3tl::Length::twip, o3tl::Length::px),
                    o3tl::convert(mrDoc.GetSheetOptimalMinRowHeight(nTabNo) * OLE_STD_CELLS_Y,
                                  o3tl::Length::twip, o3tl::Length::px));
    maTabData.emplace_back( new ScViewDataTable(nullptr) );
    pThisTab = maTabData[nTabNo].get();

    nEditEndCol = nEditStartCol = nEditCol = 0;
    nEditEndRow = nEditRow = 0;
    nTabStartCol = SC_TABSTART_NONE;

    // don't show hidden tables
    if (!mrDoc.IsVisible(nTabNo))
    {
        while (!mrDoc.IsVisible(nTabNo) && mrDoc.HasTable(nTabNo + 1))
        {
            ++nTabNo;
            maTabData.emplace_back(nullptr);
        }
        maTabData[nTabNo].reset( new ScViewDataTable(nullptr) );
        pThisTab = maTabData[nTabNo].get();
    }

    SCTAB nTableCount = mrDoc.GetTableCount();
    EnsureTabDataSize(nTableCount);

    for (auto& xTabData : maTabData)
    {
        if (xTabData)
            xTabData->InitData(mrDoc);
    }

    CalcPPT();
}

ScViewData::~ScViewData() COVERITY_NOEXCEPT_FALSE
{
    KillEditView();
}

ScDBFunc* ScViewData::GetView() const { return pView; }

void ScViewData::UpdateCurrentTab()
{
    assert(0 <= nTabNo && o3tl::make_unsigned(nTabNo) < maTabData.size());
    pThisTab = maTabData[nTabNo].get();
    while (!pThisTab)
    {
        if (nTabNo > 0)
            pThisTab = maTabData[--nTabNo].get();
        else
        {
            maTabData[0].reset(new ScViewDataTable(&mrDoc));
            pThisTab = maTabData[0].get();
        }
    }
}

void ScViewData::InsertTab( SCTAB nTab )
{
    if( nTab >= static_cast<SCTAB>(maTabData.size()))
        maTabData.resize(nTab+1);
    else
        maTabData.insert( maTabData.begin() + nTab, nullptr );
    CreateTabData( nTab );

    UpdateCurrentTab();
    maMarkData.InsertTab(nTab);

    collectUIInformation({{}}, u"InsertTab"_ustr);
}

void ScViewData::InsertTabs( SCTAB nTab, SCTAB nNewSheets )
{
    if (nTab >= static_cast<SCTAB>(maTabData.size()))
        maTabData.resize(nTab+nNewSheets);
    else
    {
        // insert nNewSheets new tables at position nTab
        auto prevSize = maTabData.size();
        maTabData.resize(prevSize + nNewSheets);
        std::move_backward(maTabData.begin() + nTab, maTabData.begin() + prevSize, maTabData.end());
    }
    for (SCTAB i = nTab; i < nTab + nNewSheets; ++i)
    {
        CreateTabData( i );
        maMarkData.InsertTab(i);
    }
    UpdateCurrentTab();
}

void ScViewData::DeleteTab( SCTAB nTab )
{
    assert(nTab < static_cast<SCTAB>(maTabData.size()));
    maTabData.erase(maTabData.begin() + nTab);

    if (o3tl::make_unsigned(nTabNo) >= maTabData.size())
    {
        EnsureTabDataSize(1);
        nTabNo = maTabData.size() - 1;
    }
    UpdateCurrentTab();
    maMarkData.DeleteTab(nTab);
}

void ScViewData::DeleteTabs( SCTAB nTab, SCTAB nSheets )
{
    for (SCTAB i = 0; i < nSheets; ++i)
    {
        maMarkData.DeleteTab(nTab + i);
    }
    maTabData.erase(maTabData.begin() + nTab, maTabData.begin()+ nTab+nSheets);
    if (o3tl::make_unsigned(nTabNo) >= maTabData.size())
    {
        EnsureTabDataSize(1);
        nTabNo = maTabData.size() - 1;
    }
    UpdateCurrentTab();
}

void ScViewData::CopyTab( SCTAB nSrcTab, SCTAB nDestTab )
{
    if (nDestTab==SC_TAB_APPEND)
        nDestTab = mrDoc.GetTableCount() - 1;   // something had to have been copied

    if (nDestTab > MAXTAB)
    {
        OSL_FAIL("too many sheets");
        return;
    }

    if (nSrcTab >= static_cast<SCTAB>(maTabData.size()))
        OSL_FAIL("pTabData out of bounds, FIX IT");

    EnsureTabDataSize(nDestTab + 1);

    if ( maTabData[nSrcTab] )
        maTabData.emplace(maTabData.begin() + nDestTab, new ScViewDataTable( *maTabData[nSrcTab] ));
    else
        maTabData.insert(maTabData.begin() + nDestTab, nullptr);

    UpdateCurrentTab();
    maMarkData.InsertTab(nDestTab);
}

void ScViewData::MoveTab( SCTAB nSrcTab, SCTAB nDestTab )
{
    if (nDestTab==SC_TAB_APPEND)
        nDestTab = mrDoc.GetTableCount() - 1;
    std::unique_ptr<ScViewDataTable> pTab;
    if (nSrcTab < static_cast<SCTAB>(maTabData.size()))
    {
        pTab = std::move(maTabData[nSrcTab]);
        maTabData.erase( maTabData.begin() + nSrcTab );
    }

    if (nDestTab < static_cast<SCTAB>(maTabData.size()))
        maTabData.insert( maTabData.begin() + nDestTab, std::move(pTab) );
    else
    {
        EnsureTabDataSize(nDestTab + 1);
        maTabData[nDestTab] = std::move(pTab);
    }

    UpdateCurrentTab();
    maMarkData.DeleteTab(nSrcTab);
    maMarkData.InsertTab(nDestTab); // adapted if needed
}

void ScViewData::CreateTabData( std::vector< SCTAB >& rvTabs )
{
    for ( const auto& rTab : rvTabs )
        CreateTabData(rTab);
}

void ScViewData::SetZoomType( SvxZoomType eNew, std::vector< SCTAB >& tabs )
{
    bool bAll = tabs.empty();

    if ( !bAll ) // create associated table data
        CreateTabData( tabs );

    if ( bAll )
    {
        for ( auto & i: maTabData )
        {
            if ( i )
                i->eZoomType = eNew;
        }
        eDefZoomType = eNew;
    }
    else
    {
        for ( const SCTAB& i : tabs )
        {
            if ( i < static_cast<SCTAB>(maTabData.size()) && maTabData[i] )
                maTabData[i]->eZoomType = eNew;
        }
    }
}

void ScViewData::SetZoomType( SvxZoomType eNew, bool bAll )
{
    std::vector< SCTAB > vTabs; // Empty for all tabs
    if ( !bAll ) // get selected tabs
    {
        ScMarkData::const_iterator itr = maMarkData.begin(), itrEnd = maMarkData.end();
        vTabs.insert(vTabs.begin(), itr, itrEnd);
    }
    SetZoomType( eNew, vTabs );
}

void ScViewData::SetZoom( const Fraction& rNewX, const Fraction& rNewY, std::vector< SCTAB >& tabs )
{
    bool bAll = tabs.empty();
    if ( !bAll ) // create associated table data
        CreateTabData( tabs );

    // sanity check - we shouldn't need something this low / big
    SAL_WARN_IF(rNewX < Fraction(1, 100) || rNewX > Fraction(100, 1), "sc.viewdata",
                "fraction rNewX not sensible: " << static_cast<double>(rNewX));
    SAL_WARN_IF(rNewY < Fraction(1, 100) || rNewY > Fraction(100, 1), "sc.viewdata",
                "fraction rNewY not sensible: " << static_cast<double>(rNewY));

    if ( bAll )
    {
        for ( auto & i: maTabData )
        {
            if ( i )
            {
                if ( bPagebreak )
                {
                    i->aPageZoomX = rNewX;
                    i->aPageZoomY = rNewY;
                }
                else
                {
                    i->aZoomX = rNewX;
                    i->aZoomY = rNewY;
                }
            }
        }
        if ( bPagebreak )
        {
            aDefPageZoomX = rNewX;
            aDefPageZoomY = rNewY;
        }
        else
        {
            aDefZoomX = rNewX;
            aDefZoomY = rNewY;
        }
    }
    else
    {
        for ( const SCTAB& i : tabs )
        {
            if ( i < static_cast<SCTAB>(maTabData.size()) && maTabData[i] )
            {
                if ( bPagebreak )
                {
                    maTabData[i]->aPageZoomX = rNewX;
                    maTabData[i]->aPageZoomY = rNewY;
                }
                else
                {
                    maTabData[i]->aZoomX = rNewX;
                    maTabData[i]->aZoomY = rNewY;
                }
            }
        }
    }
    RefreshZoom();
}

void ScViewData::SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll )
{
    std::vector< SCTAB > vTabs;
    if ( !bAll ) // get selected tabs
    {
        ScMarkData::const_iterator itr = maMarkData.begin(), itrEnd = maMarkData.end();
        vTabs.insert(vTabs.begin(), itr, itrEnd);
    }
    SetZoom( rNewX, rNewY, vTabs );
}

void ScViewData::SetShowGrid( bool bShow )
{
    CreateSelectedTabData();
    maTabData[nTabNo]->bShowGrid = bShow;
}

void ScViewData::RefreshZoom()
{
    // recalculate zoom-dependent values (only for current sheet)

    CalcPPT();
    RecalcPixPos();
    aScenButSize = Size(0,0);
    aLogicMode.SetScaleX( GetZoomX() );
    aLogicMode.SetScaleY( GetZoomY() );
}

void ScViewData::SetPagebreakMode( bool bSet )
{
    bPagebreak = bSet;

    RefreshZoom();
}

ScMarkType ScViewData::GetSimpleArea( ScRange & rRange, ScMarkData & rNewMark ) const
{
    ScMarkType eMarkType = SC_MARK_NONE;

    if ( rNewMark.IsMarked() || rNewMark.IsMultiMarked() )
    {
        if ( rNewMark.IsMultiMarked() )
            rNewMark.MarkToSimple();

        if ( rNewMark.IsMarked() && !rNewMark.IsMultiMarked() )
        {
            rRange = rNewMark.GetMarkArea();
            if (ScViewUtil::HasFiltered(rRange, GetDocument()))
                eMarkType = SC_MARK_SIMPLE_FILTERED;
            else
                eMarkType = SC_MARK_SIMPLE;
        }
        else
            eMarkType = SC_MARK_MULTI;
    }
    if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
    {
        if (eMarkType == SC_MARK_NONE)
            eMarkType = SC_MARK_SIMPLE;
        const ScPatternAttr* pMarkPattern = mrDoc.GetPattern(GetCurX(), GetCurY(), GetTabNo());
        const ScMergeAttr* pMergeItem = nullptr;
        if (pMarkPattern && pMarkPattern->GetItemSet().GetItemState(ATTR_MERGE, false, &pMergeItem) == SfxItemState::SET)
        {
            SCROW nRow = pMergeItem->GetRowMerge();
            SCCOL nCol = pMergeItem->GetColMerge();
            if ( nRow < 1 || nCol < 1 )
            {
                // This kind of cells do exist. Not sure if that is intended or a bug.
                rRange = ScRange(GetCurX(), GetCurY(), GetTabNo());
            }
            else
            {
                rRange = ScRange(GetCurX(), GetCurY(), GetTabNo(),
                                GetCurX() + nCol - 1, GetCurY() + nRow - 1, GetTabNo());
                if ( ScViewUtil::HasFiltered(rRange, GetDocument()) )
                    eMarkType = SC_MARK_SIMPLE_FILTERED;
            }
        }
        else
            rRange = ScRange(GetCurX(), GetCurY(), GetTabNo());
    }
    return eMarkType;
}

ScMarkType ScViewData::GetSimpleArea( SCCOL& rStartCol, SCROW& rStartRow, SCTAB& rStartTab,
                                SCCOL& rEndCol, SCROW& rEndRow, SCTAB& rEndTab ) const
{
    //  parameter bMergeMark is no longer needed: The view's selection is never modified
    //  (a local copy is used), and a multi selection that adds to a single range can always
    //  be treated like a single selection (GetSimpleArea isn't used in selection
    //  handling itself)

    ScRange aRange;
    ScMarkData aNewMark(maMarkData);       // use a local copy for MarkToSimple
    ScMarkType eMarkType = GetSimpleArea( aRange, aNewMark);
    aRange.GetVars( rStartCol, rStartRow, rStartTab, rEndCol, rEndRow, rEndTab);
    return eMarkType;
}

ScMarkType ScViewData::GetSimpleArea( ScRange& rRange ) const
{
    //  parameter bMergeMark is no longer needed, see above

    ScMarkData aNewMark(maMarkData);       // use a local copy for MarkToSimple
    return GetSimpleArea( rRange, aNewMark);
}

void ScViewData::GetMultiArea( ScRangeListRef& rRange ) const
{
    //  parameter bMergeMark is no longer needed, see GetSimpleArea

    ScMarkData aNewMark(maMarkData);       // use a local copy for MarkToSimple

    bool bMulti = aNewMark.IsMultiMarked();
    if (bMulti)
    {
        aNewMark.MarkToSimple();
        bMulti = aNewMark.IsMultiMarked();
    }
    if (bMulti)
    {
        rRange = new ScRangeList;
        aNewMark.FillRangeListWithMarks( rRange.get(), false );
    }
    else
    {
        ScRange aSimple;
        GetSimpleArea(aSimple);
        rRange = new ScRangeList(aSimple);
    }
}

bool ScViewData::SimpleColMarked()
{
    SCCOL nStartCol;
    SCROW nStartRow;
    SCTAB nStartTab;
    SCCOL nEndCol;
    SCROW nEndRow;
    SCTAB nEndTab;
    if (GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
        if (nStartRow == 0 && nEndRow == mrDoc.MaxRow())
            return true;

    return false;
}

bool ScViewData::SimpleRowMarked()
{
    SCCOL nStartCol;
    SCROW nStartRow;
    SCTAB nStartTab;
    SCCOL nEndCol;
    SCROW nEndRow;
    SCTAB nEndTab;
    if (GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
        if (nStartCol == 0 && nEndCol == mrDoc.MaxCol())
            return true;

    return false;
}

bool ScViewData::IsMultiMarked() const
{
    // Test for "real" multi selection, calling MarkToSimple on a local copy,
    // and taking filtered in simple area marks into account.

    ScRange aDummy;
    ScMarkType eType = GetSimpleArea(aDummy);
    return (eType & SC_MARK_SIMPLE) != SC_MARK_SIMPLE;
}

bool ScViewData::SelectionForbidsPaste( ScDocument* pClipDoc )
{
    if (!pClipDoc)
    {
        // Same as checkDestRanges() in sc/source/ui/view/cellsh.cxx but
        // different return details.

        vcl::Window* pWin = GetActiveWin();
        if (!pWin)
            // No window doesn't mean paste would be forbidden.
            return false;

        const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
        if (!pOwnClip)
            // Foreign content does not get repeatedly replicated.
            return false;

        pClipDoc = pOwnClip->GetDocument();
        if (!pClipDoc)
            // No clipdoc doesn't mean paste would be forbidden.
            return false;
    }

    const ScRange aSrcRange = pClipDoc->GetClipParam().getWholeRange();
    const SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
    const SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;

    return SelectionForbidsPaste( nColSize, nRowSize);
}

bool ScViewData::SelectionForbidsPaste( SCCOL nSrcCols, SCROW nSrcRows )
{
    ScRange aSelRange( ScAddress::UNINITIALIZED );
    ScMarkType eMarkType = GetSimpleArea( aSelRange);

    if (eMarkType == SC_MARK_MULTI)
        // Not because of DOOM.
        return false;

    if (aSelRange.aEnd.Row() - aSelRange.aStart.Row() + 1 == nSrcRows)
        // This also covers entire col(s) copied to be pasted on entire cols.
        return false;

    if (aSelRange.aEnd.Col() - aSelRange.aStart.Col() + 1 == nSrcCols)
        // This also covers entire row(s) copied to be pasted on entire rows.
        return false;

    return SelectionFillDOOM( aSelRange);
}

bool ScViewData::SelectionForbidsCellFill()
{
    ScRange aSelRange( ScAddress::UNINITIALIZED );
    ScMarkType eMarkType = GetSimpleArea( aSelRange);
    return eMarkType != SC_MARK_MULTI && SelectionFillDOOM( aSelRange);
}

// static
bool ScViewData::SelectionFillDOOM( const ScRange& rRange )
{
    // Assume that more than 23 full columns (23M cells) will not be
    // successful... Even with only 10 bytes per cell that would already be
    // 230MB, formula cells would be 100 bytes and more per cell.
    // rows * columns > 23m => rows > 23m / columns
    // to not overflow in case number of available columns or rows would be
    // arbitrarily increased.
    // We could refine this and take some actual cell size into account,
    // evaluate available memory and what not, but...
    const sal_Int32 kMax = 23 * 1024 * 1024;    // current MAXROWCOUNT1 is 1024*1024=1048576
    return (rRange.aEnd.Row() - rRange.aStart.Row() + 1) > (kMax / (rRange.aEnd.Col() - rRange.aStart.Col() + 1));
}

void ScViewData::SetFillMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
{
    nFillMode   = ScFillMode::FILL;
    nFillStartX = nStartCol;
    nFillStartY = nStartRow;
    nFillEndX   = nEndCol;
    nFillEndY   = nEndRow;
}

void ScViewData::SetDragMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
                                ScFillMode nMode )
{
    nFillMode   = nMode;
    nFillStartX = nStartCol;
    nFillStartY = nStartRow;
    nFillEndX   = nEndCol;
    nFillEndY   = nEndRow;
}

void ScViewData::ResetFillMode()
{
    nFillMode   = ScFillMode::NONE;
}

void ScViewData::GetFillData( SCCOL& rStartCol, SCROW& rStartRow,
                                SCCOL& rEndCol, SCROW& rEndRow )
{
    rStartCol = nFillStartX;
    rStartRow = nFillStartY;
    rEndCol   = nFillEndX;
    rEndRow   = nFillEndY;
}

SCCOL ScViewData::GetOldCurX() const
{
    if (pThisTab->mbOldCursorValid)
        return pThisTab->nOldCurX;
    else
        return pThisTab->nCurX;
}

SCROW ScViewData::GetOldCurY() const
{
    if (pThisTab->mbOldCursorValid)
        return pThisTab->nOldCurY;
    else
        return pThisTab->nCurY;
}

void ScViewData::SetOldCursor( SCCOL nNewX, SCROW nNewY )
{
    pThisTab->nOldCurX = nNewX;
    pThisTab->nOldCurY = nNewY;
    pThisTab->mbOldCursorValid = true;
}

void ScViewData::ResetOldCursor()
{
    pThisTab->mbOldCursorValid = false;
}

SCCOL ScViewData::GetPosX( ScHSplitPos eWhich, SCTAB nForTab ) const
{
    if (comphelper::LibreOfficeKit::isActive())
        return 0;

    if (nForTab == -1)
        return pThisTab->nPosX[eWhich];

    if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
        return -1;

    return maTabData[nForTab]->nPosX[eWhich];
}

SCROW ScViewData::GetPosY( ScVSplitPos eWhich, SCTAB nForTab ) const
{
    if (comphelper::LibreOfficeKit::isActive())
        return 0;

    if (nForTab == -1)
        return pThisTab->nPosY[eWhich];

    if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
        return -1;

    return maTabData[nForTab]->nPosY[eWhich];
}

ScViewDataTable* ScViewData::FetchTableData(SCTAB nTabIndex) const
{
    if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
        return nullptr;
    ScViewDataTable* pRet = maTabData[nTabIndex].get();
    SAL_WARN_IF(!pRet, "sc.viewdata""ScViewData::FetchTableData: hidden sheet = " << nTabIndex);
    return pRet;
}

SCCOL ScViewData::GetCurXForTab( SCTAB nTabIndex ) const
{
    ScViewDataTable* pTabData = FetchTableData(nTabIndex);
    return pTabData ? pTabData->nCurX : -1;
}

SCROW ScViewData::GetCurYForTab( SCTAB nTabIndex ) const
{
    ScViewDataTable* pTabData = FetchTableData(nTabIndex);
    return pTabData ? pTabData->nCurY : -1;
}

void ScViewData::SetCurXForTab( SCCOL nNewCurX, SCTAB nTabIndex )
{
    if (ScViewDataTable* pTabData = FetchTableData(nTabIndex))
        pTabData->nCurX = nNewCurX;
}

void ScViewData::SetCurYForTab( SCCOL nNewCurY, SCTAB nTabIndex )
{
    if (ScViewDataTable* pTabData = FetchTableData(nTabIndex))
        pTabData->nCurY = nNewCurY;
}

void ScViewData::SetMaxTiledCol( SCCOL nNewMaxCol )
{
    nNewMaxCol = std::clamp(nNewMaxCol, SCCOL(0), mrDoc.MaxCol());

    const SCTAB nTab = GetTabNo();
    auto GetColWidthPx = [this, nTab](SCCOL nCol) {
        const sal_uInt16 nSize = this->mrDoc.GetColWidth(nCol, nTab);
        const tools::Long nSizePx = ScViewData::ToPixel(nSize, nPPTX);
        return nSizePx;
    };

    tools::Long nTotalPixels = GetLOKWidthHelper().computePosition(nNewMaxCol, GetColWidthPx);

    SAL_INFO("sc.lok.docsize""ScViewData::SetMaxTiledCol: nNewMaxCol: "
            << nNewMaxCol << ", nTotalPixels: " << nTotalPixels);

    GetLOKWidthHelper().removeByIndex(pThisTab->nMaxTiledCol);
    GetLOKWidthHelper().insert(nNewMaxCol, nTotalPixels);

    pThisTab->nMaxTiledCol = nNewMaxCol;
}

void ScViewData::SetMaxTiledRow( SCROW nNewMaxRow )
{
    if (nNewMaxRow < 0)
        nNewMaxRow = 0;
    if (nNewMaxRow > MAXTILEDROW)
        nNewMaxRow = MAXTILEDROW;

    const SCTAB nTab = GetTabNo();
    auto GetRowHeightPx = [this, nTab](SCROW nRow) {
        const sal_uInt16 nSize = this->mrDoc.GetRowHeight(nRow, nTab);
        const tools::Long nSizePx = ScViewData::ToPixel(nSize, nPPTY);
        return nSizePx;
    };

    tools::Long nTotalPixels = GetLOKHeightHelper().computePosition(nNewMaxRow, GetRowHeightPx);

    SAL_INFO("sc.lok.docsize""ScViewData::SetMaxTiledRow: nNewMaxRow: "
            << nNewMaxRow << ", nTotalPixels: " << nTotalPixels);

    GetLOKHeightHelper().removeByIndex(pThisTab->nMaxTiledRow);
    GetLOKHeightHelper().insert(nNewMaxRow, nTotalPixels);

    pThisTab->nMaxTiledRow = nNewMaxRow;
}

tools::Rectangle ScViewData::GetEditArea( ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY,
                                          vcl::Window* pWin, const ScPatternAttr* pPattern,
                                          bool bForceToTop, bool bInPrintTwips )
{
    Point aCellTopLeft = bInPrintTwips ?
            GetPrintTwipsPos(nPosX, nPosY) : GetScrPos(nPosX, nPosY, eWhich, true);
    return ScEditUtil(mrDoc, nPosX, nPosY, nTabNo, aCellTopLeft,
                        pWin->GetOutDev(), nPPTX, nPPTY, GetZoomX(), GetZoomY(), bInPrintTwips ).
                            GetEditArea( pPattern, bForceToTop );
}

namespace {

void notifyCellCursorAt(const ScTabViewShell* pViewShell, SCCOL nCol, SCROW nRow,
                        const tools::Rectangle& rCursor)
{
    std::stringstream ss;
    ss << rCursor.getX() << ", " << rCursor.getY() << ", " << rCursor.GetWidth() << ", "
       << rCursor.GetHeight() << ", " << nCol << ", " << nRow;

    pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_CURSOR, ss.str().c_str());
    SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle",
                                   ss.str().c_str());
}

}

void ScViewData::SetEditEngine( ScSplitPos eWhich,
                                ScEditEngineDefaulter& rNewEngine,
                                vcl::Window* pWin, SCCOL nNewX, SCROW nNewY )
{
    bool bLayoutRTL = mrDoc.IsLayoutRTL(nTabNo);
    ScHSplitPos eHWhich = WhichH(eWhich);
    ScVSplitPos eVWhich = WhichV(eWhich);
    bool bLOKActive = comphelper::LibreOfficeKit::isActive();
    bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
            comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
    bool bLOKLayoutRTL = bLOKActive && bLayoutRTL;

    bool bWasThere = false;
    if (pEditView[eWhich])
    {
        //  if the view is already there don't call anything that changes the cursor position
        if (bEditActive[eWhich])
        {
            bWasThere = true;
        }
        else
        {
            lcl_LOKRemoveWindow(GetViewShell(), eWhich);
            pEditView[eWhich]->setEditEngine(rNewEngine);
        }

        if (pEditView[eWhich]->GetWindow() != pWin)
        {
            lcl_LOKRemoveWindow(GetViewShell(), eWhich);
            pEditView[eWhich]->SetWindow(pWin);
            OSL_FAIL("EditView Window has changed");
        }
    }
    else
    {
        pEditView[eWhich].reset(new EditView(rNewEngine, pWin));

        if (bLOKActive)
        {
            // We can broadcast the view-cursor message in print-twips for all views.
            pEditView[eWhich]->SetBroadcastLOKViewCursor(bLOKPrintTwips);
            pEditView[eWhich]->RegisterViewShell(pView);
        }
    }

    // add windows from other views
    if (!bWasThere && bLOKActive)
    {
        ScTabViewShell* pThisViewShell = GetViewShell();
        SCTAB nThisTabNo = GetTabNo();
        auto lAddWindows =
                [pThisViewShell, nThisTabNo, eWhich] (ScTabViewShell* pOtherViewShell)
                {
                    ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
                    SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
                    if (nThisTabNo == nOtherTabNo)
                        pOtherViewShell->AddWindowToForeignEditView(pThisViewShell, eWhich);
                };

        SfxLokHelper::forEachOtherView(pThisViewShell, lAddWindows);
    }

    // if view is gone then during IdleFormat sometimes a cursor is drawn

    EEControlBits nEC = rNewEngine.GetControlWord();
    rNewEngine.SetControlWord(nEC & ~EEControlBits::DOIDLEFORMAT);

    EVControlBits nVC = pEditView[eWhich]->GetControlWord();
    pEditView[eWhich]->SetControlWord(nVC & ~EVControlBits::AUTOSCROLL);

    bEditActive[eWhich] = true;

    const ScPatternAttr* pPattern = mrDoc.GetPattern(nNewX, nNewY, nTabNo);
    if (!pPattern)
    {
        SAL_WARN("sc.viewdata""No Pattern Found for: Col: " << nNewX << ", Row: " << nNewY << ", Tab: " << nTabNo);
        pPattern = &mrDoc.getCellAttributeHelper().getDefaultCellAttribute();
    }
    SvxCellHorJustify eJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();

    bool bBreak = ( eJust == SvxCellHorJustify::Block ) ||
                    pPattern->GetItem(ATTR_LINEBREAK).GetValue();

    bool bAsianVertical = rNewEngine.IsEffectivelyVertical();     // set by InputHandler

    tools::Rectangle aPixRect = ScEditUtil(mrDoc, nNewX, nNewY, nTabNo, GetScrPos(nNewX, nNewY, eWhich),
                                        pWin->GetOutDev(), nPPTX,nPPTY,GetZoomX(),GetZoomY() ).
                                            GetEditArea( pPattern, true );

    tools::Rectangle aPTwipsRect;
    if (bLOKPrintTwips)
    {
        aPTwipsRect = ScEditUtil(mrDoc, nNewX, nNewY, nTabNo, GetPrintTwipsPos(nNewX, nNewY),
                                 pWin->GetOutDev(), nPPTX, nPPTY, GetZoomX(), GetZoomY(), true /* bInPrintTwips */).
                                        GetEditArea(pPattern, true);
    }

    //  when right-aligned, leave space for the cursor
    //  in vertical mode, editing is always right-aligned
    if ( GetEditAdjust() == SvxAdjust::Right || bAsianVertical )
    {
        aPixRect.AdjustRight(1 );
        if (bLOKPrintTwips)
            aPTwipsRect.AdjustRight(o3tl::convert(1, o3tl::Length::px, o3tl::Length::twip));
    }

    if (bLOKPrintTwips)
    {
        if (!pEditView[eWhich]->HasLOKSpecialPositioning())
            pEditView[eWhich]->InitLOKSpecialPositioning(MapUnit::MapTwip, aPTwipsRect, Point());
        else
            pEditView[eWhich]->SetLOKSpecialOutputArea(aPTwipsRect);
    }

    if (bLOKActive && pEditView[eWhich]->HasLOKSpecialPositioning())
        pEditView[eWhich]->SetLOKSpecialFlags(bLOKLayoutRTL ? LOKSpecialFlags::LayoutRTL : LOKSpecialFlags::NONE);

    tools::Rectangle aOutputArea = pWin->PixelToLogic( aPixRect, GetLogicMode() );
    pEditView[eWhich]->SetOutputArea( aOutputArea );

    if (bLOKPrintTwips)
        notifyCellCursorAt(GetViewShell(), nNewX, nNewY, aPTwipsRect);

    ScModule* pScMod = ScModule::get();
    if ( bActive && eWhich == GetActivePart() )
    {
        // keep the part that has the active edit view available after
        // switching sheets or reference input on a different part
        eEditActivePart = eWhich;

        //  modify members nEditCol etc. only if also extending for needed area
        nEditCol = nNewX;
        nEditRow = nNewY;
        const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
        nEditEndCol = nEditCol;
        if (pMergeAttr->GetColMerge() > 1)
            nEditEndCol += pMergeAttr->GetColMerge() - 1;
        nEditEndRow = nEditRow;
        if (pMergeAttr->GetRowMerge() > 1)
            nEditEndRow += pMergeAttr->GetRowMerge() - 1;
        nEditStartCol = nEditCol;

        //  For growing use only the alignment value from the attribute, numbers
        //  (existing or started) with default alignment extend to the right.
        bool bGrowCentered = ( eJust == SvxCellHorJustify::Center );
        bool bGrowToLeft = ( eJust == SvxCellHorJustify::Right );      // visual left
        bool bLOKRTLInvert = (bLOKActive && bLayoutRTL);
        if ( bAsianVertical )
            bGrowCentered = bGrowToLeft = false;   // keep old behavior for asian mode

        tools::Long nSizeXPix, nSizeXPTwips = 0;

        const tools::Long nGridWidthPx = pView->GetGridWidth(eHWhich);
        const tools::Long nGridHeightPx = pView->GetGridHeight(eVWhich);
        tools::Long nGridWidthTwips = 0, nGridHeightTwips = 0;
        if (bLOKPrintTwips)
        {
            Size aGridSize(nGridWidthPx, nGridHeightPx);
            const MapMode& rWinMapMode = GetLogicMode();
            aGridSize = OutputDevice::LogicToLogic(
                pWin->PixelToLogic(aGridSize, rWinMapMode),
                rWinMapMode, MapMode(MapUnit::MapTwip));
            nGridWidthTwips = aGridSize.Width();
            nGridHeightTwips = aGridSize.Height();
        }

        if (bBreak && !bAsianVertical)
        {
            nSizeXPix = aPixRect.GetWidth();    // papersize -> no horizontal scrolling
            if (bLOKPrintTwips)
                nSizeXPTwips = aPTwipsRect.GetWidth();
        }
        else
        {
            OSL_ENSURE(pView,"no View for EditView");

            if ( bGrowCentered )
            {
                //  growing into both directions until one edge is reached
                //! should be limited to whole cells in both directions
                tools::Long nLeft = aPixRect.Left();
                tools::Long nRight = nGridWidthPx - aPixRect.Right();
                nSizeXPix = aPixRect.GetWidth() + 2 * std::min( nLeft, nRight );
                if (bLOKPrintTwips)
                {
                    tools::Long nLeftPTwips = aPTwipsRect.Left();
                    tools::Long nRightPTwips = nGridWidthTwips - aPTwipsRect.Right();
                    nSizeXPTwips = aPTwipsRect.GetWidth() + 2 * std::min(nLeftPTwips, nRightPTwips);
                }
            }
            else if ( (bGrowToLeft && !bLOKRTLInvert) || (!bGrowToLeft && bLOKRTLInvert) )
            {
                nSizeXPix = aPixRect.Right();   // space that's available in the window when growing to the left
                if (bLOKPrintTwips)
                    nSizeXPTwips = aPTwipsRect.Right();
            }
            else
            {
                nSizeXPix = nGridWidthPx - aPixRect.Left();
                if (bLOKPrintTwips)
                    nSizeXPTwips = nGridWidthTwips - aPTwipsRect.Left();
            }

            if ( nSizeXPix <= 0 )
            {
                nSizeXPix = aPixRect.GetWidth();    // editing outside to the right of the window -> keep cell width
                if (bLOKPrintTwips)
                    nSizeXPTwips = aPTwipsRect.GetWidth();
            }
        }
        OSL_ENSURE(pView,"no View for EditView");
        tools::Long nSizeYPix = nGridHeightPx - aPixRect.Top();
        tools::Long nSizeYPTwips = bLOKPrintTwips ? (nGridHeightTwips - aPTwipsRect.Top()) : 0;

        if ( nSizeYPix <= 0 )
        {
            nSizeYPix = aPixRect.GetHeight();   // editing outside below the window -> keep cell height
            if (bLOKPrintTwips)
                nSizeYPTwips = aPTwipsRect.GetHeight();
        }

        Size aPaperSize = pView->GetActiveWin()->PixelToLogic( Size( nSizeXPix, nSizeYPix ), GetLogicMode() );
        Size aPaperSizePTwips(nSizeXPTwips, nSizeYPTwips);
        // In the LOK case the following code can make the cell background and visible area larger
        // than needed which makes selecting the adjacent right cell impossible in some cases.
        if (bBreak && !bAsianVertical && pScMod->GetInputOptions().GetTextWysiwyg() && !bLOKActive)
        {
            //  if text is formatted for printer, use the exact same paper width
            //  (and same line breaks) as for output.

            Fraction aFract(1,1);
            constexpr auto HMM_PER_TWIPS = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
            tools::Rectangle aUtilRect = ScEditUtil(mrDoc, nNewX, nNewY, nTabNo, Point(0, 0), pWin->GetOutDev(),
                                    HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( pPattern, false );
            aPaperSize.setWidth( aUtilRect.GetWidth() );
            if (bLOKPrintTwips)
            {
                aPaperSizePTwips.setWidth(o3tl::convert(aUtilRect.GetWidth(), o3tl::Length::mm100, o3tl::Length::twip));
            }
        }

        rNewEngine.SetPaperSize( aPaperSize );
        if (bLOKPrintTwips)
            rNewEngine.SetLOKSpecialPaperSize(aPaperSizePTwips);

        // sichtbarer Ausschnitt
        Size aPaper = rNewEngine.GetPaperSize();
        tools::Rectangle aVis = pEditView[eWhich]->GetVisArea();
        tools::Rectangle aVisPTwips;
        if (bLOKPrintTwips)
            aVisPTwips = pEditView[eWhich]->GetLOKSpecialVisArea();

        tools::Long nDiff = aVis.Right() - aVis.Left();
        tools::Long nDiffPTwips = bLOKPrintTwips ? (aVisPTwips.Right() - aVisPTwips.Left()) : 0;
        if ( GetEditAdjust() == SvxAdjust::Right )
        {
            aVis.SetRight( aPaper.Width() - 1 );
            if (bLOKPrintTwips)
                aVisPTwips.SetRight( aPaperSizePTwips.Width() - 1 );
            bMoveArea = !bLayoutRTL;
        }
        else if ( GetEditAdjust() == SvxAdjust::Center )
        {
            aVis.SetRight( ( aPaper.Width() - 1 + nDiff ) / 2 );
            if (bLOKPrintTwips)
                aVisPTwips.SetRight( ( aPaperSizePTwips.Width() - 1 + nDiffPTwips ) / 2 );
            bMoveArea = true;   // always
        }
        else
        {
            aVis.SetRight( nDiff );
            if (bLOKPrintTwips)
                aVisPTwips.SetRight(nDiffPTwips);
            bMoveArea = bLayoutRTL;
        }
        aVis.SetLeft( aVis.Right() - nDiff );
        if (bLOKPrintTwips)
            aVisPTwips.SetLeft(aVisPTwips.Right() - nDiffPTwips);
        // #i49561# Important note:
        // The set offset of the visible area of the EditView for centered and
        // right alignment in horizontal layout is consider by instances of
        // class <ScEditObjectViewForwarder> in its methods <LogicToPixel(..)>
        // and <PixelToLogic(..)>. This is needed for the correct visibility
        // of paragraphs in edit mode at the accessibility API.
        pEditView[eWhich]->SetVisArea(aVis);
        if (bLOKPrintTwips)
            pEditView[eWhich]->SetLOKSpecialVisArea(aVisPTwips);
        //  UpdateMode has been disabled in ScInputHandler::StartTable
        //  must be enabled before EditGrowY (GetTextHeight)
        rNewEngine.SetUpdateLayout( true );

        rNewEngine.SetStatusEventHdl( LINK( this, ScViewData, EditEngineHdl ) );

        EditGrowY( true );      // adjust to existing text content
        EditGrowX();

        Point aDocPos = pEditView[eWhich]->GetWindowPosTopLeft(0);
        if (aDocPos.Y() < aOutputArea.Top())
            pEditView[eWhich]->Scroll( 0, aOutputArea.Top() - aDocPos.Y() );
    }

                                                    // here bEditActive needs to be set already
                                                    // (due to Map-Mode during Paint)
    if (!bWasThere)
        rNewEngine.InsertView(pEditView[eWhich].get());

    //      background color of the cell
    Color aBackCol = pPattern->GetItem(ATTR_BACKGROUND).GetColor();

    if ( aBackCol.IsTransparent() )
    {
        aBackCol = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
    }
    pEditView[eWhich]->SetBackgroundColor( aBackCol );

    if (comphelper::LibreOfficeKit::isActive())
    {
        // now only needed when not CEOO (CellEditOnOverlay)
        //  needed?
        //  needed, if position changed
        pEditView[eWhich]->Invalidate();
    }
}

IMPL_LINK( ScViewData, EditEngineHdl, EditStatus&, rStatus, void )
{
    EditStatusFlags nStatus = rStatus.GetStatusWord();
    if (nStatus & (EditStatusFlags::HSCROLL | EditStatusFlags::TextHeightChanged | EditStatusFlags::TEXTWIDTHCHANGED | EditStatusFlags::CURSOROUT))
    {
        EditGrowY();
        EditGrowX();

        if (nStatus & EditStatusFlags::CURSOROUT)
        {
            ScSplitPos eWhich = GetActivePart();
            if (pEditView[eWhich])
                pEditView[eWhich]->ShowCursor(false);
        }
    }
}

void ScViewData::EditGrowX()
{
    // It is insane to call EditGrowX while the output area is already growing.
    // That could occur because of the call to SetDefaultItem later.
    // We end up with wrong start/end edit columns and the changes
    // to the output area performed by the inner call to this method are
    // useless since they are discarded by the outer call.
    if (bGrowing)
        return;

    comphelper::FlagRestorationGuard aFlagGuard(bGrowing, true);

    bool bLOKActive = comphelper::LibreOfficeKit::isActive();
    bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
            comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);

    ScDocument& rLocalDoc = GetDocument();

    ScSplitPos eWhich = GetActivePart();
    ScHSplitPos eHWhich = WhichH(eWhich);
    EditView* pCurView = pEditView[eWhich].get();

    if ( !pCurView || !bEditActive[eWhich])
        return;

    bool bLayoutRTL = rLocalDoc.IsLayoutRTL( nTabNo );

    ScEditEngineDefaulter* pEngine = static_cast<ScEditEngineDefaulter*>(&pCurView->getEditEngine());
    vcl::Window* pWin = pCurView->GetWindow();

    // Get the left- and right-most column positions.
    SCCOL nLeft = GetPosX(eHWhich);
    SCCOL nRight = nLeft + VisibleCellsX(eHWhich);

    Size        aSize = pEngine->GetPaperSize();
    Size aSizePTwips;
    if (bLOKPrintTwips)
        aSizePTwips = pEngine->GetLOKSpecialPaperSize();

    tools::Rectangle   aArea = pCurView->GetOutputArea();
    tools::Rectangle aAreaPTwips;
    if (bLOKPrintTwips)
        aAreaPTwips = pCurView->GetLOKSpecialOutputArea();

    tools::Long        nOldRight = aArea.Right();

    // Margin is already included in the original width.
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.24 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.