lok: sc: overlays and edit view misplaced by other view actions

The edit view, the cell cursor and the cell selection overlays become
misplaced when another user inserts, deletes or resizes a row.

The same is true for columns.

The solution takes care of the current tab each view is
displaying and of undo/redo actions.

Change-Id: I24c94f774f3b18028c9356a904e1b14b07c5c61a
Reviewed-on: https://gerrit.libreoffice.org/40016
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Marco Cecchetti <mrcekets@gmail.com>
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index 8f6ba1f..b5b7f1a 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -621,6 +621,9 @@ public:
    SC_DLLPUBLIC SAL_WARN_UNUSED_RESULT bool MoveSticky( SCCOL aDeltaX, SCROW aDeltaY, SCTAB aDeltaZ,
            ScRange& rErrorRange );

    SC_DLLPUBLIC void IncColIfNotLessThan(SCCOL nStartCol, SCCOL nOffset);
    SC_DLLPUBLIC void IncRowIfNotLessThan(SCROW nStartRow, SCROW nOffset);

    SC_DLLPUBLIC void ExtendTo( const ScRange& rRange );
    SC_DLLPUBLIC bool Intersects( const ScRange& rRange ) const;    // do two ranges intersect?

diff --git a/sc/inc/markarr.hxx b/sc/inc/markarr.hxx
index 548d023..4b538d9 100644
--- a/sc/inc/markarr.hxx
+++ b/sc/inc/markarr.hxx
@@ -60,6 +60,9 @@ public:
    /// Including current row, may return -1 if bUp and not found
    SCROW   GetNextMarked( SCROW nRow, bool bUp ) const;
    SCROW   GetMarkEnd( SCROW nRow, bool bUp ) const;

    void    Shift( SCROW nStartRow, long nOffset );
    void    Intersect( const ScMarkArray& rOther );
};

class ScMarkArrayIter                   // iterate over selected range
diff --git a/sc/inc/markdata.hxx b/sc/inc/markdata.hxx
index 51f63a4..2638710 100644
--- a/sc/inc/markdata.hxx
+++ b/sc/inc/markdata.hxx
@@ -142,6 +142,9 @@ public:
    void        InsertTab( SCTAB nTab );
    void        DeleteTab( SCTAB nTab );

    void        ShiftCols(SCCOL nStartCol, long nColOffset);
    void        ShiftRows(SCROW nStartRow, long nRowOffset);

    // Generate envelopes if multimarked and fills the passed ScRange object with
    // the smallest range that includes the marked area plus its envelopes.
    void        GetSelectionCover( ScRange& rRange );
diff --git a/sc/inc/markmulti.hxx b/sc/inc/markmulti.hxx
index 6ada78c..cf68a40 100644
--- a/sc/inc/markmulti.hxx
+++ b/sc/inc/markmulti.hxx
@@ -63,6 +63,8 @@ public:
    void Clear();
    void MarkAllCols( SCROW nStartRow, SCROW nEndRow );
    bool HasAnyMarks() const;
    void ShiftCols(SCCOL nStartCol, long nColOffset);
    void ShiftRows(SCROW nStartRow, long nRowOffset);

    // For faster access from within ScMarkData, instead of creating
    // ScMultiSelIter with ScFlatBoolRowSegments bottleneck.
diff --git a/sc/source/core/data/markarr.cxx b/sc/source/core/data/markarr.cxx
index 248ddd0..81c8f94 100644
--- a/sc/source/core/data/markarr.cxx
+++ b/sc/source/core/data/markarr.cxx
@@ -172,10 +172,10 @@ void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, bool bMarked )
                }
            }
            else
        {
            {
                nInsert = 0;
                ni = 0;
        }
            }

            SCSIZE nj = ni;     // stop position of range to replace
            while ( nj < nCount && pData[nj].nRow <= nEndRow )
@@ -369,6 +369,119 @@ SCROW ScMarkArray::GetMarkEnd( SCROW nRow, bool bUp ) const
    return nRet;
}

void ScMarkArray::Shift(SCROW nStartRow, long nOffset)
{
    if (!pData || nOffset == 0 || nStartRow > MAXROW)
        return;

    for (size_t i=0; i < nCount; ++i)
    {
        auto& rEntry = pData[i];

        if (rEntry.nRow < nStartRow)
            continue;
        rEntry.nRow += nOffset;
        if (rEntry.nRow < 0)
        {
            rEntry.nRow = 0;
        }
        else if (rEntry.nRow > MAXROW)
        {
            rEntry.nRow = MAXROW;
        }
    }
}

void ScMarkArray::Intersect(const ScMarkArray& rOther)
{
    if (!pData || !rOther.pData)
        return;

    size_t i = 0;
    size_t j = 0;

    std::vector<ScMarkEntry> aEntryArray;
    aEntryArray.reserve(std::max(nCount, rOther.nCount));

    while (i < nCount && j < rOther.nCount)
    {
        const auto& rEntry = pData[i];
        const auto& rOtherEntry = rOther.pData[j];

        if (rEntry.bMarked != rOtherEntry.bMarked)
        {
            if (!rOtherEntry.bMarked)
            {
                aEntryArray.push_back(rOther.pData[j++]);
                while (i < nCount && pData[i].nRow <= rOtherEntry.nRow)
                    ++i;
            }
            else // rEntry not marked
            {
                aEntryArray.push_back(pData[i++]);
                while (j < rOther.nCount && rOther.pData[j].nRow <= rEntry.nRow)
                    ++j;
            }
        }
        else // rEntry.bMarked == rOtherEntry.bMarked
        {
            if (rEntry.bMarked) // both marked
            {
                if (rEntry.nRow <= rOtherEntry.nRow)
                {
                    aEntryArray.push_back(pData[i++]); // upper row
                    if (rEntry.nRow == rOtherEntry.nRow)
                        ++j;
                }
                else
                {
                    aEntryArray.push_back(rOther.pData[j++]); // upper row
                }
            }
            else // both not marked
            {
                if (rEntry.nRow <= rOtherEntry.nRow)
                {
                    aEntryArray.push_back(rOther.pData[j++]); // lower row
                    while (i < nCount && pData[i].nRow <= rOtherEntry.nRow)
                        ++i;
                }
                else
                {
                    aEntryArray.push_back(pData[i++]); // lower row
                    while (j < rOther.nCount && rOther.pData[j].nRow <= rEntry.nRow)
                        ++j;
                }
            }
        }
    }

    OSL_ENSURE(i == nCount || j == rOther.nCount, "Unexpected case.");

    if (i == nCount)
    {
        for (; j < rOther.nCount; ++j)
        {
            aEntryArray.push_back(rOther.pData[j]);
        }
    }
    else // j == rOther.nCount
    {
        for (; i < nCount; ++i)
        {
            aEntryArray.push_back(pData[i]);
        }
    }

    size_t nSize = aEntryArray.size();
    OSL_ENSURE(nSize > 0, "Unexpected case.");

    pData.reset(new ScMarkEntry[nSize]);
    memcpy(pData.get(), &(aEntryArray[0]), nSize * sizeof(ScMarkEntry));
    nCount = nLimit = nSize;
}


//  -------------- Iterator ----------------------------------------------

ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx
index 8c94f19..93a66f8 100644
--- a/sc/source/core/data/markdata.cxx
+++ b/sc/source/core/data/markdata.cxx
@@ -623,6 +623,33 @@ void ScMarkData::DeleteTab( SCTAB nTab )
    maTabMarked.swap(tabMarked);
}

void ScMarkData::ShiftCols(SCCOL nStartCol, long nColOffset)
{
    if (bMarked)
    {
        aMarkRange.IncColIfNotLessThan(nStartCol, nColOffset);
    }
    else if (bMultiMarked)
    {
        aMultiSel.ShiftCols(nStartCol, nColOffset);
        aMultiRange.IncColIfNotLessThan(nStartCol, nColOffset);
    }
}

void ScMarkData::ShiftRows(SCROW nStartRow, long nRowOffset)
{
    if (bMarked)
    {
        aMarkRange.IncRowIfNotLessThan(nStartRow, nRowOffset);
    }
    else if (bMultiMarked)
    {
        aMultiSel.ShiftRows(nStartRow, nRowOffset);
        aMultiRange.IncRowIfNotLessThan(nStartRow, nRowOffset);
    }

}

static void lcl_AddRanges(ScRange& rRangeDest, const ScRange& rNewRange )
{
    SCCOL nStartCol = rNewRange.aStart.Col();
diff --git a/sc/source/core/data/markmulti.cxx b/sc/source/core/data/markmulti.cxx
index 091c91e..d8ac507 100644
--- a/sc/source/core/data/markmulti.cxx
+++ b/sc/source/core/data/markmulti.cxx
@@ -296,6 +296,80 @@ bool ScMultiSel::HasAnyMarks() const
    return false;
}

void ScMultiSel::ShiftCols(SCCOL nStartCol, long nColOffset)
{
    if (nStartCol > MAXCOL)
        return;

    ScMultiSel aNewMultiSel(*this);
    Clear();

    if (nColOffset < 0)
    {
        // columns that would be moved on the left of nStartCol must be removed
        const SCCOL nEndPos = nStartCol - nColOffset;
        for (SCCOL nSearchPos = nStartCol; nSearchPos < nEndPos; ++nSearchPos)
        {
            const auto& aColIt = aNewMultiSel.aMultiSelContainer.find(nSearchPos);
            if (aColIt != aNewMultiSel.aMultiSelContainer.end())
            {
                aNewMultiSel.aMultiSelContainer.erase(aColIt);
            }
        }
    }

    MapType::iterator aDestEnd = aMultiSelContainer.end();
    MapType::iterator aDestIter = aDestEnd;
    for (const auto& aSourcePair : aNewMultiSel.aMultiSelContainer)
    {
        SCCOL nCol = aSourcePair.first;
        if (aSourcePair.first >= nStartCol)
        {
            nCol += nColOffset;
            if (nCol < 0)
                nCol = 0;
            else if (nCol > MAXCOL)
                nCol = MAXCOL;
        }
        // correct hint is always aDestEnd as keys come in ascending order
        // Amortized constant time operation as we always give the correct hint
        aDestIter = aMultiSelContainer.emplace_hint( aDestEnd, nCol, ScMarkArray() );
        aSourcePair.second.CopyMarksTo(aDestIter->second);
    }
    aNewMultiSel.aRowSel.CopyMarksTo(aRowSel);

    if (nColOffset > 0 && nStartCol > 0)
    {
        // insert nColOffset new columns, and select their cells if they are selected
        // both in the old column at nStartPos and in the previous column
        const auto& aPrevPosIt = aNewMultiSel.aMultiSelContainer.find(nStartCol - 1);
        if (aPrevPosIt != aNewMultiSel.aMultiSelContainer.end())
        {
            const auto& aStartPosIt = aNewMultiSel.aMultiSelContainer.find(nStartCol);
            if (aStartPosIt != aNewMultiSel.aMultiSelContainer.end())
            {
                MapType::iterator aNewColIt = aMultiSelContainer.emplace_hint(aDestEnd, nStartCol, ScMarkArray());
                aStartPosIt->second.CopyMarksTo(aNewColIt->second);
                aNewColIt->second.Intersect(aPrevPosIt->second);
                for (long i = 1; i < nColOffset; ++i)
                {
                    aDestIter = aMultiSelContainer.emplace_hint(aDestEnd, nStartCol + i, ScMarkArray());
                    aNewColIt->second.CopyMarksTo(aDestIter->second);
                }
            }
        }
    }
}

void ScMultiSel::ShiftRows(SCROW nStartRow, long nRowOffset)
{
    for (auto& aPair: aMultiSelContainer)
    {
        aPair.second.Shift(nStartRow, nRowOffset);
    }
    aRowSel.Shift(nStartRow, nRowOffset);
}

const ScMarkArray& ScMultiSel::GetRowSelArray() const
{
    return aRowSel;
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx
index 9899044..e8c5ed4 100644
--- a/sc/source/core/tool/address.cxx
+++ b/sc/source/core/tool/address.cxx
@@ -2382,6 +2382,46 @@ bool ScRange::MoveSticky( SCCOL dx, SCROW dy, SCTAB dz, ScRange& rErrorRange )
    return b1 && b2;
}

void ScRange::IncColIfNotLessThan(SCCOL nStartCol, SCCOL nOffset)
{
    if (aStart.Col() >= nStartCol)
    {
        aStart.IncCol(nOffset);
        if (aStart.Col() < 0)
            aStart.SetCol(0);
        else if(aStart.Col() > MAXCOL)
            aStart.SetCol(MAXCOL);
    }
    if (aEnd.Col() >= nStartCol)
    {
        aEnd.IncCol(nOffset);
        if (aEnd.Col() < 0)
            aEnd.SetCol(0);
        else if(aEnd.Col() > MAXCOL)
            aEnd.SetCol(MAXCOL);
    }
}

void ScRange::IncRowIfNotLessThan(SCROW nStartRow, SCROW nOffset)
{
    if (aStart.Row() >= nStartRow)
    {
        aStart.IncRow(nOffset);
        if (aStart.Row() < 0)
            aStart.SetRow(0);
        else if(aStart.Row() > MAXROW)
            aStart.SetRow(MAXROW);
    }
    if (aEnd.Row() >= nStartRow)
    {
        aEnd.IncRow(nOffset);
        if (aEnd.Row() < 0)
            aEnd.SetRow(0);
        else if(aEnd.Row() > MAXROW)
            aEnd.SetRow(MAXROW);
    }
}

void ScRange::IncEndColSticky( SCCOL nDelta )
{
    SCCOL nCol = aEnd.Col();
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
index a3df618..5a0436f 100644
--- a/sc/source/ui/app/inputhdl.cxx
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -2590,6 +2590,10 @@ static void lcl_SelectionToEnd( EditView* pView )

void ScInputHandler::EnterHandler( ScEnterMode nBlockMode )
{
    if (!mbDocumentDisposing && comphelper::LibreOfficeKit::isActive()
        && pActiveViewSh != SfxViewShell::Current())
        return;

    // Macro calls for validity can cause a lot of problems, so inhibit
    // nested calls of EnterHandler().
    if (bInEnterHandler) return;
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index c9abf98..7a85a36 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -2132,6 +2132,24 @@ bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, 
            rDocShell.ErrorMessage(STR_INSERT_FULL);        // column/row full
    }

    // The cursor position needs to be modified earlier than updating
    // any enabled edit view which is triggered by SetDocumentModified below.
    if (bSuccess)
    {
        bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER);
        bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER );

        if (bInsertCols)
        {
            pViewSh->OnLOKInsertDeleteColumn(rRange.aStart.Col(), 1);
        }

        if (bInsertRows)
        {
            pViewSh->OnLOKInsertDeleteRow(rRange.aStart.Row(), 1);
        }
    }

    aModificator.SetDocumentModified();

    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
@@ -2658,6 +2676,21 @@ bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, 
        }
    }

    // The cursor position needs to be modified earlier than updating
    // any enabled edit view which is triggered by SetDocumentModified below.
    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    if (pViewSh)
    {
        if (eCmd == DEL_DELCOLS)
        {
            pViewSh->OnLOKInsertDeleteColumn(rRange.aStart.Col(), -1);
        }
        if (eCmd == DEL_DELROWS)
        {
            pViewSh->OnLOKInsertDeleteRow(rRange.aStart.Row(), -1);
        }
    }

    aModificator.SetDocumentModified();

    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx
index 93df48d..bd1288d 100644
--- a/sc/source/ui/inc/viewdata.hxx
+++ b/sc/source/ui/inc/viewdata.hxx
@@ -298,8 +298,11 @@ public:
    SCROW           GetPosY( ScVSplitPos eWhich ) const     { return pThisTab->nPosY[eWhich]; }
    SCCOL           GetCurX() const                         { return pThisTab->nCurX; }
    SCROW           GetCurY() const                         { return pThisTab->nCurY; }
    SCCOL           GetCurXForTab( SCTAB nTabIndex ) const;
    SCROW           GetCurYForTab( SCTAB nTabIndex ) const;
    SCCOL           GetOldCurX() const;
    SCROW           GetOldCurY() const;

    ScSplitMode     GetHSplitMode() const                   { return pThisTab->eHSplitMode; }
    ScSplitMode     GetVSplitMode() const                   { return pThisTab->eVSplitMode; }
    long            GetHSplitPos() const                    { return pThisTab->nHSplitPos; }
@@ -317,6 +320,8 @@ public:
    void            SetPosY( ScVSplitPos eWhich, SCROW nNewPosY );
    void            SetCurX( SCCOL nNewCurX )                       { pThisTab->nCurX = nNewCurX; }
    void            SetCurY( SCROW nNewCurY )                       { pThisTab->nCurY = nNewCurY; }
    void            SetCurXForTab( SCCOL nNewCurX, SCTAB nTabIndex );
    void            SetCurYForTab( SCCOL nNewCurY, SCTAB nTabIndex );
    void            SetOldCursor( SCCOL nNewX, SCROW nNewY );
    void            ResetOldCursor();
    void            SetHSplitMode( ScSplitMode eMode )              { pThisTab->eHSplitMode = eMode; }
diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx
index 507d6ad..20ed2bc 100644
--- a/sc/source/ui/inc/viewfunc.hxx
+++ b/sc/source/ui/inc/viewfunc.hxx
@@ -322,6 +322,10 @@ public:
                                     std::vector<VclPtr<Edit> >& aEdits,
                                     sal_uInt16 aColLength );
    void            UpdateSelectionArea( const ScMarkData& rSel, ScPatternAttr* pAttr = nullptr );

    void            OnLOKInsertDeleteColumn(SCCOL nStartCol, long nOffset);
    void            OnLOKInsertDeleteRow(SCROW nStartRow, long nOffset);

                                                // Internal helper functions
protected:
    static void     UpdateLineAttrs( ::editeng::SvxBorderLine&        rLine,
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index 5ca8efeba..3b7de1a 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -156,6 +156,7 @@ void ScUndoInsertCells::DoChange( const bool bUndo )

    // refresh of merged cells has to be after inserting/deleting

    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
    switch (eCmd)
    {
        case INS_INSROWS_BEFORE:
@@ -163,12 +164,19 @@ void ScUndoInsertCells::DoChange( const bool bUndo )
        case INS_CELLSDOWN:
            for( i=0; i<nCount; i++ )
            {

                if (bUndo)
                    rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
                else
                    rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));

                if (pViewShell)
                {
                    const long nSign = bUndo ? -1 : 1;
                    pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
                }
            }
            break;
        case INS_INSCOLS_BEFORE:
@@ -182,6 +190,12 @@ void ScUndoInsertCells::DoChange( const bool bUndo )
                else
                    rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
                    aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));

                if (pViewShell)
                {
                    const long nSign = bUndo ? -1 : 1;
                    pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
                }
            }
            break;
        default:
@@ -207,7 +221,7 @@ void ScUndoInsertCells::DoChange( const bool bUndo )
    // Undo for displaced attributes?

    PaintPartFlags nPaint = PaintPartFlags::Grid;
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();

    switch (eCmd)
    {
        case INS_INSROWS_BEFORE:
@@ -380,6 +394,8 @@ void ScUndoDeleteCells::DoChange( const bool bUndo )
    else
        SetChangeTrack();

    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();

    switch (eCmd)
    {
        case DEL_DELROWS:
@@ -392,6 +408,12 @@ void ScUndoDeleteCells::DoChange( const bool bUndo )
                else
                    rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));

                if (pViewShell)
                {
                    const long nSign = bUndo ? 1 : -1;
                    pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
                }
            }
            break;
        case DEL_DELCOLS:
@@ -404,6 +426,12 @@ void ScUndoDeleteCells::DoChange( const bool bUndo )
                else
                    rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
                    aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));

                if (pViewShell)
                {
                    const long nSign = bUndo ? 1 : -1;
                    pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
                }
            }
            break;
        default:
@@ -502,6 +530,20 @@ void ScUndoDeleteCells::DoChange( const bool bUndo )

    pDocShell->PostDataChanged();
    //  CellContentChanged comes with the selection

    if (pViewShell)
    {
        if (comphelper::LibreOfficeKit::isActive())
        {
            if (eCmd == DEL_DELCOLS || eCmd == DEL_CELLSLEFT)
                ScTabViewShell::notifyAllViewsHeaderInvalidation("column",  pViewShell->GetViewData().GetTabNo());

            if (eCmd == DEL_DELROWS || eCmd == DEL_CELLSUP)
                ScTabViewShell::notifyAllViewsHeaderInvalidation("row",  pViewShell->GetViewData().GetTabNo());
        }

    }

}

void ScUndoDeleteCells::Undo()
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
index 244aec9..5f15c43 100644
--- a/sc/source/ui/view/tabvwsh4.cxx
+++ b/sc/source/ui/view/tabvwsh4.cxx
@@ -1746,6 +1746,14 @@ ScTabViewShell::~ScTabViewShell()
    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");

    // all to NULL, in case the TabView-dtor tries to access them
    //! (should not really! ??!?!)
    if (mpInputHandler)
        mpInputHandler->SetDocumentDisposing(true);
    // We end edit mode, before destroying the input handler and the edit engine
    // and before end listening (in order to call ScTabViewShell::KillEditView())
    mpInputHandler->EnterHandler();

    ScDocShell* pDocSh = GetViewData().GetDocShell();
    EndListening(*pDocSh);
    EndListening(*GetViewFrame());
@@ -1756,11 +1764,6 @@ ScTabViewShell::~ScTabViewShell()
    RemoveSubShell();           // all
    SetWindow(nullptr);

    // all to NULL, in case the TabView-dtor tries to access them
    //! (should not really! ??!?!)
    if (mpInputHandler)
        mpInputHandler->SetDocumentDisposing(true);

    DELETEZ(pFontworkBarShell);
    DELETEZ(pExtrusionBarShell);
    DELETEZ(pCellShell);
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index d978ef8..92647ac 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -971,6 +971,38 @@ void ScViewData::ResetOldCursor()
    pThisTab->mbOldCursorValid = false;
}

SCCOL ScViewData::GetCurXForTab( SCTAB nTabIndex ) const
{
    if (!ValidTab(nTabIndex) || !(nTabIndex < static_cast<SCTAB>(maTabData.size())))
        return -1;

    return maTabData[nTabIndex]->nCurX;
}

SCROW ScViewData::GetCurYForTab( SCTAB nTabIndex ) const
{
    if (!ValidTab(nTabIndex) || !(nTabIndex < static_cast<SCTAB>(maTabData.size())))
            return -1;

    return maTabData[nTabIndex]->nCurY;
}

void ScViewData::SetCurXForTab( SCCOL nNewCurX, SCTAB nTabIndex )
{
    if (!ValidTab(nTabIndex) || !(nTabIndex < static_cast<SCTAB>(maTabData.size())))
            return;

    maTabData[nTabIndex]->nCurX = nNewCurX;
}

void ScViewData::SetCurYForTab( SCCOL nNewCurY, SCTAB nTabIndex )
{
    if (!ValidTab(nTabIndex) || !(nTabIndex < static_cast<SCTAB>(maTabData.size())))
            return;

    maTabData[nTabIndex]->nCurY = nNewCurY;
}

tools::Rectangle ScViewData::GetEditArea( ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY,
                                    vcl::Window* pWin, const ScPatternAttr* pPattern,
                                    bool bForceToTop )
@@ -984,10 +1016,6 @@ void ScViewData::SetEditEngine( ScSplitPos eWhich,
                                ScEditEngineDefaulter* pNewEngine,
                                vcl::Window* pWin, SCCOL nNewX, SCROW nNewY )
{
    if (comphelper::LibreOfficeKit::isActive()
        && GetViewShell() != SfxViewShell::Current())
        return;

    bool bLayoutRTL = pDoc->IsLayoutRTL( nTabNo );
    ScHSplitPos eHWhich = WhichH(eWhich);

@@ -1023,7 +1051,8 @@ void ScViewData::SetEditEngine( ScSplitPos eWhich,
    }

    // add windows from other views
    if (comphelper::LibreOfficeKit::isActive())
    if (!bWasThere && comphelper::LibreOfficeKit::isActive())
    //if (comphelper::LibreOfficeKit::isActive())
    {
        ScTabViewShell* pThisViewShell = GetViewShell();
        SCTAB nThisTabNo = GetTabNo();
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index 3a33dcb..5eae272 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -1465,6 +1465,103 @@ void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
        pHdl->ForgetLastPattern();
}


void ScViewFunc::OnLOKInsertDeleteColumn(SCCOL nStartCol, long nOffset)
{
    if (!comphelper::LibreOfficeKit::isActive() || nOffset == 0)
        return;

    SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        {
            // if we remove a column the cursor position  and the current selection
            // in other views could need to be moved on the left by one column.
            if (pTabViewShell != this)
            {
                if (pTabViewShell->getPart() == nCurrentTabIndex)
                {
                    SCCOL nX = pTabViewShell->GetViewData().GetCurX();
                    if (nX > nStartCol || (nX == nStartCol && nOffset > 0))
                    {
                        SCROW nY = pTabViewShell->GetViewData().GetCurY();
                        pTabViewShell->SetCursor(nX + nOffset, nY);
                    }

                    ScMarkData aMultiMark( pTabViewShell->GetViewData().GetMarkData() );
                    aMultiMark.SetMarking( false );
                    aMultiMark.MarkToMulti();
                    if (aMultiMark.IsMultiMarked())
                    {
                        aMultiMark.ShiftCols(nStartCol, nOffset);
                        pTabViewShell->SetMarkData(aMultiMark);
                    }
                }
                else
                {
                    SCROW nX = pTabViewShell->GetViewData().GetCurXForTab(nCurrentTabIndex);
                    if (nX > nStartCol || (nX == nStartCol && nOffset > 0))
                    {
                        pTabViewShell->GetViewData().SetCurXForTab(nX + nOffset, nCurrentTabIndex);
                    }
                }
            }
        }
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}

void ScViewFunc::OnLOKInsertDeleteRow(SCROW nStartRow, long nOffset)
{
    if (!comphelper::LibreOfficeKit::isActive() || nOffset == 0)
        return;

    SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        {
            // if we remove a row the cursor position and the current selection
            // in other views could need to be moved up by one row.
            if (pTabViewShell != this)
            {
                if (pTabViewShell->getPart() == nCurrentTabIndex)
                {
                    SCROW nY = pTabViewShell->GetViewData().GetCurY();
                    if (nY > nStartRow || (nY == nStartRow && nOffset > 0))
                    {
                        SCCOL nX = pTabViewShell->GetViewData().GetCurX();
                        pTabViewShell->SetCursor(nX, nY + nOffset);
                    }

                    ScMarkData aMultiMark( pTabViewShell->GetViewData().GetMarkData() );
                    aMultiMark.SetMarking( false );
                    aMultiMark.MarkToMulti();
                    if (aMultiMark.IsMultiMarked())
                    {
                        aMultiMark.ShiftRows(nStartRow, nOffset);
                        pTabViewShell->SetMarkData(aMultiMark);
                    }
                }
                else
                {
                    SCROW nY = pTabViewShell->GetViewData().GetCurYForTab(nCurrentTabIndex);
                    if (nY >= nStartRow || (nY == nStartRow && nOffset > 0))
                    {
                        pTabViewShell->GetViewData().SetCurYForTab(nY + nOffset, nCurrentTabIndex);
                    }
                }
            }
        }
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}

//  insert cells - undo OK

bool ScViewFunc::InsertCells( InsCellCmd eCmd, bool bRecord, bool bPartOfPaste )