2520 lines
81 KiB
C++
2520 lines
81 KiB
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 <utility>
|
|
#include <vcl/virdev.hxx>
|
|
#include <editeng/boxitem.hxx>
|
|
#include <sfx2/app.hxx>
|
|
#include <comphelper/lok.hxx>
|
|
#include <osl/diagnose.h>
|
|
|
|
#include <undoblk.hxx>
|
|
#include <undoutil.hxx>
|
|
#include <document.hxx>
|
|
#include <patattr.hxx>
|
|
#include <docsh.hxx>
|
|
#include <tabvwsh.hxx>
|
|
#include <rangenam.hxx>
|
|
#include <rangeutl.hxx>
|
|
#include <stlpool.hxx>
|
|
#include <stlsheet.hxx>
|
|
#include <globstr.hrc>
|
|
#include <scresid.hxx>
|
|
#include <global.hxx>
|
|
#include <target.hxx>
|
|
#include <docpool.hxx>
|
|
#include <docfunc.hxx>
|
|
#include <attrib.hxx>
|
|
#include <chgtrack.hxx>
|
|
#include <transobj.hxx>
|
|
#include <refundo.hxx>
|
|
#include <undoolk.hxx>
|
|
#include <clipparam.hxx>
|
|
#include <rowheightcontext.hxx>
|
|
#include <refupdatecontext.hxx>
|
|
#include <validat.hxx>
|
|
#include <gridwin.hxx>
|
|
#include <columnspanset.hxx>
|
|
|
|
#include <memory>
|
|
#include <set>
|
|
|
|
// TODO:
|
|
/*A*/ // SetOptimalHeight on Document, if no View
|
|
/*B*/ // linked sheets
|
|
/*C*/ // ScArea
|
|
//? // check later
|
|
|
|
ScUndoInsertCells::ScUndoInsertCells( ScDocShell* pNewDocShell,
|
|
const ScRange& rRange,
|
|
SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
|
|
InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData,
|
|
bool bNewPartOfPaste ) :
|
|
ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
|
|
aEffRange( rRange ),
|
|
nCount( nNewCount ),
|
|
pTabs( std::move(pNewTabs) ),
|
|
pScenarios( std::move(pNewScenarios) ),
|
|
eCmd( eNewCmd ),
|
|
bPartOfPaste( bNewPartOfPaste )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER) // whole row?
|
|
{
|
|
aEffRange.aStart.SetCol(0);
|
|
aEffRange.aEnd.SetCol(rDoc.MaxCol());
|
|
}
|
|
|
|
if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER) // whole column?
|
|
{
|
|
aEffRange.aStart.SetRow(0);
|
|
aEffRange.aEnd.SetRow(rDoc.MaxRow());
|
|
}
|
|
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoInsertCells::~ScUndoInsertCells()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoInsertCells::GetComment() const
|
|
{
|
|
return ScResId( pPasteUndo ? STR_UNDO_PASTE : STR_UNDO_INSERTCELLS );
|
|
}
|
|
|
|
bool ScUndoInsertCells::Merge( SfxUndoAction* pNextAction )
|
|
{
|
|
// If a paste undo action has already been added, append (detective) action there.
|
|
if ( pPasteUndo )
|
|
return pPasteUndo->Merge( pNextAction );
|
|
|
|
if ( bPartOfPaste )
|
|
if ( auto pWrapper = dynamic_cast<ScUndoWrapper*>( pNextAction) )
|
|
{
|
|
if (dynamic_cast<const ScUndoPaste*>(pWrapper->GetWrappedUndo()))
|
|
{
|
|
// Store paste action if this is part of paste with inserting cells.
|
|
// A list action isn't used because Repeat wouldn't work (insert wrong cells).
|
|
|
|
// Pass ownership of the wrapped SfxUndoAction* to pPasteUndO
|
|
pPasteUndo = pWrapper->ReleaseWrappedUndo();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Call base class for detective handling
|
|
return ScMoveUndo::Merge( pNextAction );
|
|
}
|
|
|
|
void ScUndoInsertCells::SetChangeTrack()
|
|
{
|
|
ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
{
|
|
pChangeTrack->AppendInsert( aEffRange );
|
|
nEndChangeAction = pChangeTrack->GetActionMax();
|
|
}
|
|
else
|
|
nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoInsertCells::DoChange( const bool bUndo )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
SCTAB i;
|
|
|
|
if ( bUndo )
|
|
{
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
|
|
}
|
|
else
|
|
SetChangeTrack();
|
|
|
|
// refresh of merged cells has to be after inserting/deleting
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
switch (eCmd)
|
|
{
|
|
case INS_INSROWS_BEFORE:
|
|
case INS_INSROWS_AFTER:
|
|
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 tools::Long nSign = bUndo ? -1 : 1;
|
|
pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
|
|
}
|
|
}
|
|
break;
|
|
case INS_INSCOLS_BEFORE:
|
|
case INS_INSCOLS_AFTER:
|
|
case INS_CELLSRIGHT:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
if (bUndo)
|
|
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));
|
|
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 tools::Long nSign = bUndo ? -1 : 1;
|
|
pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// added to avoid warnings
|
|
}
|
|
}
|
|
|
|
ScRange aWorkRange( aEffRange );
|
|
if ( eCmd == INS_CELLSRIGHT ) // only "shift right" requires refresh of the moved area
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol());
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
|
|
aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged ) )
|
|
{
|
|
SCCOL nEndCol = aWorkRange.aEnd.Col();
|
|
SCROW nEndRow = aWorkRange.aEnd.Row();
|
|
rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
|
|
}
|
|
}
|
|
|
|
// Undo for displaced attributes?
|
|
|
|
PaintPartFlags nPaint = PaintPartFlags::Grid;
|
|
|
|
switch (eCmd)
|
|
{
|
|
case INS_INSROWS_BEFORE:
|
|
case INS_INSROWS_AFTER:
|
|
nPaint |= PaintPartFlags::Left;
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
break;
|
|
case INS_CELLSDOWN:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
|
|
{
|
|
aWorkRange.aStart.SetCol(0);
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol());
|
|
nPaint |= PaintPartFlags::Left;
|
|
}
|
|
}
|
|
break;
|
|
case INS_INSCOLS_BEFORE:
|
|
case INS_INSCOLS_AFTER:
|
|
nPaint |= PaintPartFlags::Top; // top bar
|
|
[[fallthrough]];
|
|
case INS_CELLSRIGHT:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
|
|
if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i]) )
|
|
{ // AdjustDraw does not paint PaintPartFlags::Top,
|
|
aWorkRange.aStart.SetCol(0); // thus solved like this
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
nPaint |= PaintPartFlags::Left;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// added to avoid warnings
|
|
}
|
|
}
|
|
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
|
|
aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint );
|
|
}
|
|
pDocShell->PostDataChanged();
|
|
if (!pViewShell)
|
|
return;
|
|
|
|
pViewShell->CellContentChanged();
|
|
|
|
if (!comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
|
|
SCTAB nTab = pViewShell->GetViewData().GetTabNo();
|
|
bool bColsAffected = (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT);
|
|
bool bRowsAffected = (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN);
|
|
|
|
if (bColsAffected)
|
|
ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
|
|
|
|
if (bRowsAffected)
|
|
ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
|
|
|
|
ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
|
|
pViewShell,
|
|
bColsAffected, bRowsAffected,
|
|
true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
|
|
true /* bGroups */, nTab);
|
|
}
|
|
|
|
void ScUndoInsertCells::Undo()
|
|
{
|
|
if ( pPasteUndo )
|
|
pPasteUndo->Undo(); // undo paste first
|
|
|
|
weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
|
|
BeginUndo();
|
|
DoChange( true );
|
|
EndUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
for (SCTAB i = 0; i < nCount; ++i)
|
|
rDoc.SetDrawPageSize(pTabs[i]);
|
|
}
|
|
|
|
void ScUndoInsertCells::Redo()
|
|
{
|
|
weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
|
|
BeginRedo();
|
|
DoChange( false );
|
|
EndRedo();
|
|
|
|
if ( pPasteUndo )
|
|
pPasteUndo->Redo(); // redo paste last
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
for (SCTAB i = 0; i < nCount; ++i)
|
|
rDoc.SetDrawPageSize(pTabs[i]);
|
|
}
|
|
|
|
void ScUndoInsertCells::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr)
|
|
{
|
|
if ( pPasteUndo )
|
|
{
|
|
// Repeat for paste with inserting cells is handled completely
|
|
// by the Paste undo action
|
|
|
|
pPasteUndo->Repeat( rTarget );
|
|
}
|
|
else
|
|
static_cast<ScTabViewTarget&>(rTarget).GetViewShell()->InsertCells( eCmd );
|
|
}
|
|
}
|
|
|
|
bool ScUndoInsertCells::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoDeleteCells::ScUndoDeleteCells( ScDocShell* pNewDocShell,
|
|
const ScRange& rRange,
|
|
SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
|
|
DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
|
|
ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
|
|
aEffRange( rRange ),
|
|
nCount( nNewCount ),
|
|
pTabs( std::move(pNewTabs) ),
|
|
pScenarios( std::move(pNewScenarios) ),
|
|
eCmd( eNewCmd )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
if (eCmd == DelCellCmd::Rows) // whole row?
|
|
{
|
|
aEffRange.aStart.SetCol(0);
|
|
aEffRange.aEnd.SetCol(rDoc.MaxCol());
|
|
}
|
|
|
|
if (eCmd == DelCellCmd::Cols) // whole column?
|
|
{
|
|
aEffRange.aStart.SetRow(0);
|
|
aEffRange.aEnd.SetRow(rDoc.MaxRow());
|
|
}
|
|
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoDeleteCells::~ScUndoDeleteCells()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoDeleteCells::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_DELETECELLS ); // "Delete"
|
|
}
|
|
|
|
void ScUndoDeleteCells::SetChangeTrack()
|
|
{
|
|
ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->AppendDeleteRange( aEffRange, pRefUndoDoc.get(),
|
|
nStartChangeAction, nEndChangeAction );
|
|
else
|
|
nStartChangeAction = nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoDeleteCells::DoChange( const bool bUndo )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
SCTAB i;
|
|
|
|
if ( bUndo )
|
|
{
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
|
|
}
|
|
else
|
|
SetChangeTrack();
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
|
|
switch (eCmd)
|
|
{
|
|
case DelCellCmd::Rows:
|
|
case DelCellCmd::CellsUp:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
if (bUndo)
|
|
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));
|
|
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 tools::Long nSign = bUndo ? 1 : -1;
|
|
pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
|
|
}
|
|
}
|
|
break;
|
|
case DelCellCmd::Cols:
|
|
case DelCellCmd::CellsLeft:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
if (bUndo)
|
|
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));
|
|
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 tools::Long nSign = bUndo ? 1 : -1;
|
|
pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// added to avoid warnings
|
|
}
|
|
}
|
|
|
|
// if Undo, restore references
|
|
for( i=0; i<nCount && bUndo; i++ )
|
|
{
|
|
pRefUndoDoc->CopyToDocument(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
|
|
InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, rDoc);
|
|
}
|
|
|
|
ScRange aWorkRange( aEffRange );
|
|
if ( eCmd == DelCellCmd::CellsLeft ) // only "shift left" requires refresh of the moved area
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol());
|
|
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
|
|
aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
|
|
{
|
|
// #i51445# old merge flag attributes must be deleted also for single cells,
|
|
// not only for whole columns/rows
|
|
|
|
if ( !bUndo )
|
|
{
|
|
if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol());
|
|
if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
ScMarkData aMarkData(rDoc.GetSheetLimits());
|
|
aMarkData.SelectOneTable( aWorkRange.aStart.Tab() );
|
|
ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
|
|
aPattern.GetItemSet().Put( ScMergeFlagAttr() );
|
|
rDoc.ApplyPatternArea( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(),
|
|
aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(),
|
|
aMarkData, aPattern );
|
|
}
|
|
|
|
SCCOL nEndCol = aWorkRange.aEnd.Col();
|
|
SCROW nEndRow = aWorkRange.aEnd.Row();
|
|
rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
|
|
}
|
|
}
|
|
|
|
// paint
|
|
PaintPartFlags nPaint = PaintPartFlags::Grid;
|
|
switch (eCmd)
|
|
{
|
|
case DelCellCmd::Rows:
|
|
nPaint |= PaintPartFlags::Left;
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
break;
|
|
case DelCellCmd::CellsUp:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
|
|
{
|
|
aWorkRange.aStart.SetCol(0);
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol());
|
|
nPaint |= PaintPartFlags::Left;
|
|
}
|
|
}
|
|
break;
|
|
case DelCellCmd::Cols:
|
|
nPaint |= PaintPartFlags::Top; // top bar
|
|
[[fallthrough]];
|
|
case DelCellCmd::CellsLeft:
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
|
|
if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ) )
|
|
{
|
|
aWorkRange.aStart.SetCol(0);
|
|
aWorkRange.aEnd.SetRow(rDoc.MaxRow());
|
|
nPaint |= PaintPartFlags::Left;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// added to avoid warnings
|
|
}
|
|
}
|
|
|
|
for( i=0; i<nCount; i++ )
|
|
{
|
|
pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
|
|
aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint, SC_PF_LINES );
|
|
}
|
|
// Selection not until EndUndo
|
|
|
|
pDocShell->PostDataChanged();
|
|
// CellContentChanged comes with the selection
|
|
|
|
if (!pViewShell)
|
|
return;
|
|
|
|
if (!comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
|
|
SCTAB nTab = pViewShell->GetViewData().GetTabNo();
|
|
bool bColsAffected = (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft);
|
|
bool bRowsAffected = (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp);
|
|
|
|
if (bColsAffected)
|
|
ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
|
|
|
|
if (bRowsAffected)
|
|
ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
|
|
|
|
ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
|
|
pViewShell,
|
|
bColsAffected, bRowsAffected,
|
|
true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
|
|
true /* bGroups */, nTab);
|
|
|
|
}
|
|
|
|
void ScUndoDeleteCells::Undo()
|
|
{
|
|
weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
|
|
BeginUndo();
|
|
DoChange( true );
|
|
EndUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
// Now that DBData have been restored in ScMoveUndo::EndUndo() via its
|
|
// pRefUndoDoc we can apply the AutoFilter buttons.
|
|
// Add one row for cases undoing deletion right above a cut AutoFilter
|
|
// range so the buttons are removed.
|
|
SCROW nRefreshEndRow = std::min<SCROW>( aEffRange.aEnd.Row() + 1, rDoc.MaxRow());
|
|
for (SCTAB i=0; i < nCount; ++i)
|
|
{
|
|
rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
|
|
aEffRange.aEnd.Col(), nRefreshEndRow, pTabs[i]);
|
|
}
|
|
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
|
|
// Selection not until EndUndo
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
{
|
|
for( SCTAB i=0; i<nCount; i++ )
|
|
{
|
|
pViewShell->MarkRange( ScRange(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i]) );
|
|
}
|
|
}
|
|
|
|
for (SCTAB i = 0; i < nCount; ++i)
|
|
rDoc.SetDrawPageSize(pTabs[i]);
|
|
}
|
|
|
|
void ScUndoDeleteCells::Redo()
|
|
{
|
|
weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
|
|
BeginRedo();
|
|
DoChange( false);
|
|
EndRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
for (SCTAB i=0; i < nCount; ++i)
|
|
{
|
|
rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
|
|
aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]);
|
|
}
|
|
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
pViewShell->DoneBlockMode(); // current way
|
|
|
|
for (SCTAB i = 0; i < nCount; ++i)
|
|
rDoc.SetDrawPageSize(pTabs[i]);
|
|
}
|
|
|
|
void ScUndoDeleteCells::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
|
|
pViewTarget->GetViewShell()->DeleteCells( eCmd );
|
|
}
|
|
|
|
bool ScUndoDeleteCells::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
// delete cells in multiselection
|
|
ScUndoDeleteMulti::ScUndoDeleteMulti(
|
|
ScDocShell* pNewDocShell,
|
|
bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab,
|
|
std::vector<sc::ColRowSpan>&& rSpans,
|
|
ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
|
|
ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
|
|
mbRows(bNewRows),
|
|
mbRefresh(bNeedsRefresh),
|
|
nTab( nNewTab ),
|
|
maSpans(std::move(rSpans))
|
|
{
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoDeleteMulti::~ScUndoDeleteMulti()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoDeleteMulti::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_DELETECELLS ); // like DeleteCells
|
|
}
|
|
|
|
void ScUndoDeleteMulti::DoChange() const
|
|
{
|
|
SCCOL nStartCol;
|
|
SCROW nStartRow;
|
|
PaintPartFlags nPaint;
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
if (mbRows)
|
|
{
|
|
nStartCol = 0;
|
|
nStartRow = static_cast<SCROW>(maSpans[0].mnStart);
|
|
nPaint = PaintPartFlags::Grid | PaintPartFlags::Left;
|
|
}
|
|
else
|
|
{
|
|
nStartCol = static_cast<SCCOL>(maSpans[0].mnStart);
|
|
nStartRow = 0;
|
|
nPaint = PaintPartFlags::Grid | PaintPartFlags::Top;
|
|
}
|
|
|
|
if (mbRefresh)
|
|
{
|
|
SCCOL nEndCol = rDoc.MaxCol();
|
|
SCROW nEndRow = rDoc.MaxRow();
|
|
rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
|
|
rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
|
|
}
|
|
|
|
pDocShell->PostPaint( nStartCol, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, nPaint );
|
|
pDocShell->PostDataChanged();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
|
|
ShowTable( nTab );
|
|
}
|
|
|
|
void ScUndoDeleteMulti::SetChangeTrack()
|
|
{
|
|
ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
nStartChangeAction = pChangeTrack->GetActionMax() + 1;
|
|
ScRange aRange( 0, 0, nTab, 0, 0, nTab );
|
|
if (mbRows)
|
|
aRange.aEnd.SetCol( rDoc.MaxCol() );
|
|
else
|
|
aRange.aEnd.SetRow( rDoc.MaxRow() );
|
|
// delete in reverse
|
|
std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
|
|
for (; ri != riEnd; ++ri)
|
|
{
|
|
SCCOLROW nEnd = ri->mnEnd;
|
|
SCCOLROW nStart = ri->mnStart;
|
|
if (mbRows)
|
|
{
|
|
aRange.aStart.SetRow( nStart );
|
|
aRange.aEnd.SetRow( nEnd );
|
|
}
|
|
else
|
|
{
|
|
aRange.aStart.SetCol( static_cast<SCCOL>(nStart) );
|
|
aRange.aEnd.SetCol( static_cast<SCCOL>(nEnd) );
|
|
}
|
|
sal_uLong nDummyStart;
|
|
pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
|
|
nDummyStart, nEndChangeAction );
|
|
}
|
|
}
|
|
else
|
|
nStartChangeAction = nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoDeleteMulti::Undo()
|
|
{
|
|
weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
// reverse delete -> forward insert
|
|
for (const auto& rSpan : maSpans)
|
|
{
|
|
SCCOLROW nStart = rSpan.mnStart;
|
|
SCCOLROW nEnd = rSpan.mnEnd;
|
|
if (mbRows)
|
|
rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
|
|
else
|
|
rDoc.InsertCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
|
|
}
|
|
|
|
for (const auto& rSpan : maSpans)
|
|
{
|
|
SCCOLROW nStart = rSpan.mnStart;
|
|
SCCOLROW nEnd = rSpan.mnEnd;
|
|
if (mbRows)
|
|
pRefUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::ALL, false, rDoc);
|
|
else
|
|
pRefUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart),0,nTab,
|
|
static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL, false, rDoc);
|
|
}
|
|
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
|
|
|
|
DoChange();
|
|
|
|
//! redrawing the selection is not possible at the moment
|
|
//! since no data for selection exist
|
|
|
|
EndUndo();
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
}
|
|
|
|
void ScUndoDeleteMulti::Redo()
|
|
{
|
|
weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
// reverse delete
|
|
std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
|
|
for (; ri != riEnd; ++ri)
|
|
{
|
|
SCCOLROW nEnd = ri->mnEnd;
|
|
SCCOLROW nStart = ri->mnStart;
|
|
if (mbRows)
|
|
rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
|
|
else
|
|
rDoc.DeleteCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
|
|
}
|
|
|
|
SetChangeTrack();
|
|
|
|
DoChange();
|
|
|
|
EndRedo();
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
}
|
|
|
|
void ScUndoDeleteMulti::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
// if single selection
|
|
if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
pTabViewTarget->GetViewShell()->DeleteCells( DelCellCmd::Rows );
|
|
}
|
|
|
|
bool ScUndoDeleteMulti::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoCut::ScUndoCut(ScDocShell* pNewDocShell, const ScRange& aRange, const ScAddress& aOldEnd,
|
|
const ScMarkData& rMark, ScDocumentUniquePtr pNewUndoDoc)
|
|
: ScBlockUndo(pNewDocShell, ScRange(aRange.aStart, aOldEnd), SC_UNDO_AUTOHEIGHT)
|
|
, aMarkData(rMark)
|
|
, pUndoDoc(std::move(pNewUndoDoc))
|
|
, aExtendedRange(aRange)
|
|
{
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoCut::~ScUndoCut()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoCut::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_CUT ); // "cut"
|
|
}
|
|
|
|
void ScUndoCut::SetChangeTrack()
|
|
{
|
|
ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
|
|
nStartChangeAction, nEndChangeAction, SC_CACM_CUT );
|
|
else
|
|
nStartChangeAction = nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoCut::DoChange( const bool bUndo )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
sal_uInt16 nExtFlags = 0;
|
|
|
|
// do not undo/redo objects and note captions, they are handled via drawing undo
|
|
InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
|
|
|
|
if (bUndo) // only for Undo
|
|
{
|
|
// all sheets - CopyToDocument skips those that don't exist in pUndoDoc
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
ScRange aCopyRange = aExtendedRange;
|
|
aCopyRange.aStart.SetTab(0);
|
|
aCopyRange.aEnd.SetTab(nTabCount-1);
|
|
pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, false, rDoc);
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
|
|
|
|
BroadcastChanges(aCopyRange);
|
|
}
|
|
else // only for Redo
|
|
{
|
|
pDocShell->UpdatePaintExt( nExtFlags, aExtendedRange );
|
|
rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
|
|
aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), aMarkData, nUndoFlags );
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
|
|
/*A*/ pDocShell->PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags );
|
|
|
|
if ( !bUndo ) // draw redo after updating row heights
|
|
RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
|
|
|
|
pDocShell->PostDataChanged();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
}
|
|
|
|
void ScUndoCut::Undo()
|
|
{
|
|
BeginUndo();
|
|
DoChange( true );
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoCut::Redo()
|
|
{
|
|
BeginRedo();
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
|
|
DoChange( false );
|
|
EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoCut::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
pViewTarget->GetViewShell()->CutToClip();
|
|
}
|
|
|
|
bool ScUndoCut::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoPaste::ScUndoPaste( ScDocShell* pNewDocShell, const ScRangeList& rRanges,
|
|
const ScMarkData& rMark,
|
|
ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
|
|
InsertDeleteFlags nNewFlags,
|
|
std::unique_ptr<ScRefUndoData> pRefData,
|
|
bool bRedoIsFilled, const ScUndoPasteOptions* pOptions ) :
|
|
ScMultiBlockUndo( pNewDocShell, rRanges ),
|
|
aMarkData( rMark ),
|
|
pUndoDoc( std::move(pNewUndoDoc) ),
|
|
pRedoDoc( std::move(pNewRedoDoc) ),
|
|
nFlags( nNewFlags ),
|
|
pRefUndoData( std::move(pRefData) ),
|
|
bRedoFilled( bRedoIsFilled )
|
|
{
|
|
if ( pRefUndoData )
|
|
pRefUndoData->DeleteUnchanged( &pDocShell->GetDocument() );
|
|
|
|
if ( pOptions )
|
|
aPasteOptions = *pOptions; // used only for Repeat
|
|
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoPaste::~ScUndoPaste()
|
|
{
|
|
pUndoDoc.reset();
|
|
pRedoDoc.reset();
|
|
pRefUndoData.reset();
|
|
pRefRedoData.reset();
|
|
}
|
|
|
|
OUString ScUndoPaste::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_PASTE ); // "paste"
|
|
}
|
|
|
|
void ScUndoPaste::SetChangeTrack()
|
|
{
|
|
ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
|
|
if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
|
|
{
|
|
for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
|
|
{
|
|
pChangeTrack->AppendContentRange(maBlockRanges[i], pUndoDoc.get(),
|
|
nStartChangeAction, nEndChangeAction, SC_CACM_PASTE );
|
|
}
|
|
}
|
|
else
|
|
nStartChangeAction = nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoPaste::DoChange(bool bUndo)
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
// RefUndoData for redo is created before first undo
|
|
// (with DeleteUnchanged after the DoUndo call)
|
|
bool bCreateRedoData = ( bUndo && pRefUndoData && !pRefRedoData );
|
|
if ( bCreateRedoData )
|
|
pRefRedoData.reset( new ScRefUndoData( &rDoc ) );
|
|
|
|
ScRefUndoData* pWorkRefData = bUndo ? pRefUndoData.get() : pRefRedoData.get();
|
|
|
|
// Always back-up either all or none of the content for Undo
|
|
InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE;
|
|
if (nFlags & InsertDeleteFlags::CONTENTS)
|
|
nUndoFlags |= InsertDeleteFlags::CONTENTS;
|
|
if (nFlags & InsertDeleteFlags::ATTRIB)
|
|
nUndoFlags |= InsertDeleteFlags::ATTRIB;
|
|
|
|
// do not undo/redo objects and note captions, they are handled via drawing undo
|
|
nUndoFlags &= ~InsertDeleteFlags::OBJECTS;
|
|
nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
|
|
|
|
bool bPaintAll = false;
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
if ( bUndo && !bRedoFilled )
|
|
{
|
|
if (!pRedoDoc)
|
|
{
|
|
bool bColInfo = true;
|
|
bool bRowInfo = true;
|
|
for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
|
|
{
|
|
const ScRange& r = maBlockRanges[i];
|
|
bColInfo &= (r.aStart.Row() == 0 && r.aEnd.Row() == rDoc.MaxRow());
|
|
bRowInfo &= (r.aStart.Col() == 0 && r.aEnd.Col() == rDoc.MaxCol());
|
|
if (!bColInfo && !bRowInfo)
|
|
break;
|
|
}
|
|
|
|
pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
|
|
pRedoDoc->InitUndoSelected( rDoc, aMarkData, bColInfo, bRowInfo );
|
|
}
|
|
// read "redo" data from the document in the first undo
|
|
// all sheets - CopyToDocument skips those that don't exist in pRedoDoc
|
|
for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
|
|
{
|
|
ScRange aCopyRange = maBlockRanges[i];
|
|
aCopyRange.aStart.SetTab(0);
|
|
aCopyRange.aEnd.SetTab(nTabCount-1);
|
|
rDoc.CopyToDocument(aCopyRange, nUndoFlags, false, *pRedoDoc);
|
|
bRedoFilled = true;
|
|
}
|
|
}
|
|
|
|
sal_uInt16 nExtFlags = 0;
|
|
pDocShell->UpdatePaintExt(nExtFlags, maBlockRanges.Combine());
|
|
|
|
rDoc.ForgetNoteCaptions(maBlockRanges, false);
|
|
aMarkData.MarkToMulti();
|
|
rDoc.DeleteSelection(nUndoFlags, aMarkData, false); // no broadcasting here
|
|
for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
|
|
rDoc.BroadcastCells(maBlockRanges[i], SfxHintId::ScDataChanged);
|
|
|
|
aMarkData.MarkToSimple();
|
|
|
|
SCTAB nFirstSelected = aMarkData.GetFirstSelected();
|
|
|
|
if ( !bUndo && pRedoDoc ) // Redo: UndoToDocument before handling RefData
|
|
{
|
|
for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
|
|
{
|
|
ScRange aRange = maBlockRanges[i];
|
|
aRange.aStart.SetTab(nFirstSelected);
|
|
aRange.aEnd.SetTab(nFirstSelected);
|
|
pRedoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
|
|
for (const auto& rTab : aMarkData)
|
|
{
|
|
if (rTab >= nTabCount)
|
|
break;
|
|
|
|
if (rTab == nFirstSelected)
|
|
continue;
|
|
|
|
aRange.aStart.SetTab(rTab);
|
|
aRange.aEnd.SetTab(rTab);
|
|
pRedoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pWorkRefData)
|
|
{
|
|
pWorkRefData->DoUndo( &rDoc, true ); // true = bSetChartRangeLists for SetChartListenerCollection
|
|
if (!maBlockRanges.empty() &&
|
|
rDoc.RefreshAutoFilter(0, 0, rDoc.MaxCol(), rDoc.MaxRow(), maBlockRanges[0].aStart.Tab()))
|
|
bPaintAll = true;
|
|
}
|
|
|
|
if ( bCreateRedoData && pRefRedoData )
|
|
pRefRedoData->DeleteUnchanged( &rDoc );
|
|
|
|
if (bUndo) // Undo: UndoToDocument after handling RefData
|
|
{
|
|
for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
|
|
{
|
|
ScRange aRange = maBlockRanges[i];
|
|
for (const auto& rTab : aMarkData)
|
|
{
|
|
if (rTab >= nTabCount)
|
|
break;
|
|
aRange.aStart.SetTab(rTab);
|
|
aRange.aEnd.SetTab(rTab);
|
|
pUndoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bUndo )
|
|
{
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
|
|
}
|
|
else
|
|
SetChangeTrack();
|
|
|
|
ScRangeList aDrawRanges(maBlockRanges);
|
|
PaintPartFlags nPaint = PaintPartFlags::Grid;
|
|
|
|
// For sheet geometry invalidation.
|
|
bool bColsAffected = false;
|
|
bool bRowsAffected = false;
|
|
|
|
for (size_t i = 0, n = aDrawRanges.size(); i < n; ++i)
|
|
{
|
|
ScRange& rDrawRange = aDrawRanges[i];
|
|
rDoc.ExtendMerge(rDrawRange, true); // only needed for single sheet (text/rtf etc.)
|
|
ScRangeList aRangeList(rDrawRange);
|
|
ScMarkData aData(rDoc.GetSheetLimits(), aRangeList);
|
|
if (bPaintAll)
|
|
{
|
|
rDrawRange.aStart.SetCol(0);
|
|
rDrawRange.aStart.SetRow(0);
|
|
rDrawRange.aEnd.SetCol(rDoc.MaxCol());
|
|
rDrawRange.aEnd.SetRow(rDoc.MaxRow());
|
|
nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
|
|
if (pViewShell)
|
|
pViewShell->AdjustBlockHeight(false, &aData);
|
|
}
|
|
else
|
|
{
|
|
if (maBlockRanges[i].aStart.Row() == 0 && maBlockRanges[i].aEnd.Row() == rDoc.MaxRow()) // whole column
|
|
{
|
|
nPaint |= PaintPartFlags::Top;
|
|
rDrawRange.aEnd.SetCol(rDoc.MaxCol());
|
|
bColsAffected = true;
|
|
}
|
|
if (maBlockRanges[i].aStart.Col() == 0 && maBlockRanges[i].aEnd.Col() == rDoc.MaxCol()) // whole row
|
|
{
|
|
nPaint |= PaintPartFlags::Left;
|
|
rDrawRange.aEnd.SetRow(rDoc.MaxRow());
|
|
bRowsAffected = true;
|
|
}
|
|
if (pViewShell && pViewShell->AdjustBlockHeight(false, &aData))
|
|
{
|
|
rDrawRange.aStart.SetCol(0);
|
|
rDrawRange.aStart.SetRow(0);
|
|
rDrawRange.aEnd.SetCol(rDoc.MaxCol());
|
|
rDrawRange.aEnd.SetRow(rDoc.MaxRow());
|
|
nPaint |= PaintPartFlags::Left;
|
|
}
|
|
pDocShell->UpdatePaintExt(nExtFlags, rDrawRange);
|
|
}
|
|
}
|
|
|
|
if ( !bUndo ) // draw redo after updating row heights
|
|
RedoSdrUndoAction(mpDrawUndo.get());
|
|
|
|
pDocShell->PostPaint(aDrawRanges, nPaint, nExtFlags);
|
|
|
|
pDocShell->PostDataChanged();
|
|
if (!pViewShell)
|
|
return;
|
|
|
|
pViewShell->CellContentChanged();
|
|
|
|
if (bColsAffected || bRowsAffected)
|
|
ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
|
|
pViewShell,
|
|
bColsAffected, bRowsAffected,
|
|
true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
|
|
true /* bGroups */, aDrawRanges[0].aStart.Tab());
|
|
}
|
|
|
|
void ScUndoPaste::Undo()
|
|
{
|
|
BeginUndo();
|
|
DoChange(true);
|
|
if (!maBlockRanges.empty())
|
|
ShowTable(maBlockRanges.front());
|
|
EndUndo();
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
}
|
|
|
|
void ScUndoPaste::Redo()
|
|
{
|
|
BeginRedo();
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
|
|
DoChange( false );
|
|
EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
|
|
EndRedo();
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
}
|
|
|
|
void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget);
|
|
if (!pViewTarget)
|
|
return;
|
|
|
|
ScTabViewShell* pViewSh = pViewTarget->GetViewShell();
|
|
// keep a reference in case the clipboard is changed during PasteFromClip
|
|
const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pViewSh->GetViewData().GetActiveWin()));
|
|
if (pOwnClip)
|
|
{
|
|
pViewSh->PasteFromClip( nFlags, pOwnClip->GetDocument(),
|
|
aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose,
|
|
aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE,
|
|
true ); // allow warning dialog
|
|
}
|
|
}
|
|
|
|
bool ScUndoPaste::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoDragDrop::ScUndoDragDrop( ScDocShell* pNewDocShell,
|
|
const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut,
|
|
ScDocumentUniquePtr pUndoDocument, bool bScenario ) :
|
|
ScMoveUndo( pNewDocShell, std::move(pUndoDocument), nullptr ),
|
|
mnPaintExtFlags( 0 ),
|
|
aSrcRange( rRange ),
|
|
bCut( bNewCut ),
|
|
bKeepScenarioFlags( bScenario )
|
|
{
|
|
ScAddress aDestEnd(aNewDestPos);
|
|
aDestEnd.IncRow(aSrcRange.aEnd.Row() - aSrcRange.aStart.Row());
|
|
aDestEnd.IncCol(aSrcRange.aEnd.Col() - aSrcRange.aStart.Col());
|
|
aDestEnd.IncTab(aSrcRange.aEnd.Tab() - aSrcRange.aStart.Tab());
|
|
|
|
bool bIncludeFiltered = bCut;
|
|
if ( !bIncludeFiltered )
|
|
{
|
|
// find number of non-filtered rows
|
|
SCROW nPastedCount = pDocShell->GetDocument().CountNonFilteredRows(
|
|
aSrcRange.aStart.Row(), aSrcRange.aEnd.Row(), aSrcRange.aStart.Tab());
|
|
|
|
if ( nPastedCount == 0 )
|
|
nPastedCount = 1;
|
|
aDestEnd.SetRow( aNewDestPos.Row() + nPastedCount - 1 );
|
|
}
|
|
|
|
aDestRange.aStart = aNewDestPos;
|
|
aDestRange.aEnd = aDestEnd;
|
|
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoDragDrop::~ScUndoDragDrop()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoDragDrop::GetComment() const
|
|
{ // "Move" : "Copy"
|
|
return bCut ?
|
|
ScResId( STR_UNDO_MOVE ) :
|
|
ScResId( STR_UNDO_COPY );
|
|
}
|
|
|
|
void ScUndoDragDrop::SetChangeTrack()
|
|
{
|
|
ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
{
|
|
if ( bCut )
|
|
{
|
|
nStartChangeAction = pChangeTrack->GetActionMax() + 1;
|
|
pChangeTrack->AppendMove( aSrcRange, aDestRange, pRefUndoDoc.get() );
|
|
nEndChangeAction = pChangeTrack->GetActionMax();
|
|
}
|
|
else
|
|
pChangeTrack->AppendContentRange( aDestRange, pRefUndoDoc.get(),
|
|
nStartChangeAction, nEndChangeAction );
|
|
}
|
|
else
|
|
nStartChangeAction = nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const
|
|
{
|
|
PaintPartFlags nPaint = PaintPartFlags::Grid;
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
if (pViewShell)
|
|
{
|
|
ScopedVclPtrInstance< VirtualDevice > pVirtDev;
|
|
ScViewData& rViewData = pViewShell->GetViewData();
|
|
sc::RowHeightContext aCxt(
|
|
rDoc.MaxRow(), rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomX(), rViewData.GetZoomY(),
|
|
pVirtDev);
|
|
|
|
if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab(), true))
|
|
{
|
|
// tdf#76183: recalculate objects' positions
|
|
rDoc.SetDrawPageSize(aRange.aStart.Tab());
|
|
aRange.aStart.SetCol(0);
|
|
aRange.aEnd.SetCol(rDoc.MaxCol());
|
|
aRange.aEnd.SetRow(rDoc.MaxRow());
|
|
nPaint |= PaintPartFlags::Left;
|
|
}
|
|
}
|
|
|
|
if ( bKeepScenarioFlags )
|
|
{
|
|
// Copy scenario -> also paint scenario boarder
|
|
aRange.aStart.SetCol(0);
|
|
aRange.aStart.SetRow(0);
|
|
aRange.aEnd.SetCol(rDoc.MaxCol());
|
|
aRange.aEnd.SetRow(rDoc.MaxRow());
|
|
}
|
|
|
|
// column/row info (width/height) included if whole columns/rows were copied
|
|
if ( aSrcRange.aStart.Col() == 0 && aSrcRange.aEnd.Col() == rDoc.MaxCol() )
|
|
{
|
|
nPaint |= PaintPartFlags::Left;
|
|
aRange.aEnd.SetRow(rDoc.MaxRow());
|
|
}
|
|
if ( aSrcRange.aStart.Row() == 0 && aSrcRange.aEnd.Row() == rDoc.MaxRow() )
|
|
{
|
|
nPaint |= PaintPartFlags::Top;
|
|
aRange.aEnd.SetCol(rDoc.MaxCol());
|
|
}
|
|
|
|
pDocShell->PostPaint( aRange, nPaint, nExtFlags );
|
|
}
|
|
|
|
void ScUndoDragDrop::DoUndo( ScRange aRange )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
|
|
|
|
// Database range before data, so that the Autofilter button match up in ExtendMerge
|
|
|
|
ScRange aPaintRange = aRange;
|
|
rDoc.ExtendMerge( aPaintRange ); // before deleting
|
|
|
|
pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
|
|
|
|
// do not undo objects and note captions, they are handled via drawing undo
|
|
InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
|
|
|
|
// Additionally discard/forget caption ownership during deletion, as
|
|
// Drag&Drop is a special case in that the Undo holds captions of the
|
|
// transferred target range, which would get deleted and
|
|
// SdrGroupUndo::Undo() would attempt to access invalidated captions and
|
|
// crash, tdf#92995
|
|
InsertDeleteFlags nDelFlags = nUndoFlags | InsertDeleteFlags::FORGETCAPTIONS;
|
|
|
|
rDoc.DeleteAreaTab( aRange, nDelFlags );
|
|
pRefUndoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
|
|
if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
|
|
rDoc.ExtendMerge( aRange, true );
|
|
|
|
aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) );
|
|
aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) );
|
|
|
|
pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
|
|
maPaintRanges.Join(aPaintRange);
|
|
|
|
if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell())
|
|
{
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Col(), true);
|
|
pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Row(), false);
|
|
}
|
|
|
|
ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
|
|
pTabViewShell,
|
|
true /* bColumns */, true /* bRows */,
|
|
true /* bSizes */, true /* bHidden */, true /* bFiltered */,
|
|
true /* bGroups */, aPaintRange.aStart.Tab());
|
|
}
|
|
|
|
}
|
|
|
|
void ScUndoDragDrop::Undo()
|
|
{
|
|
mnPaintExtFlags = 0;
|
|
maPaintRanges.RemoveAll();
|
|
|
|
BeginUndo();
|
|
|
|
if (bCut)
|
|
{
|
|
// During undo, we move cells from aDestRange to aSrcRange.
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
|
|
SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
|
|
SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
|
|
|
|
sc::RefUpdateContext aCxt(rDoc);
|
|
aCxt.meMode = URM_MOVE;
|
|
aCxt.maRange = aSrcRange;
|
|
aCxt.mnColDelta = nColDelta;
|
|
aCxt.mnRowDelta = nRowDelta;
|
|
aCxt.mnTabDelta = nTabDelta;
|
|
|
|
// Global range names.
|
|
ScRangeName* pName = rDoc.GetRangeName();
|
|
if (pName)
|
|
pName->UpdateReference(aCxt);
|
|
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
|
|
{
|
|
// Sheet-local range names.
|
|
pName = rDoc.GetRangeName(nTab);
|
|
if (pName)
|
|
pName->UpdateReference(aCxt, nTab);
|
|
}
|
|
|
|
ScValidationDataList* pValidList = rDoc.GetValidationList();
|
|
if (pValidList)
|
|
{
|
|
// Update the references of validation entries.
|
|
pValidList->UpdateReference(aCxt);
|
|
}
|
|
|
|
DoUndo(aDestRange);
|
|
DoUndo(aSrcRange);
|
|
|
|
rDoc.BroadcastCells(aSrcRange, SfxHintId::ScDataChanged, false);
|
|
}
|
|
else
|
|
DoUndo(aDestRange);
|
|
|
|
for (size_t i = 0; i < maPaintRanges.size(); ++i)
|
|
{
|
|
const ScRange& r = maPaintRanges[i];
|
|
PaintArea(r, mnPaintExtFlags);
|
|
}
|
|
|
|
EndUndo();
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
}
|
|
|
|
void ScUndoDragDrop::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
|
|
|
|
EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
|
|
|
|
// do not undo/redo objects and note captions, they are handled via drawing undo
|
|
constexpr InsertDeleteFlags nRedoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
|
|
|
|
/* TODO: Redoing note captions is quite tricky due to the fact that a
|
|
helper clip document is used. While (re-)pasting the contents to the
|
|
destination area, the original pointers to the captions created while
|
|
dropping have to be restored. A simple CopyFromClip() would create new
|
|
caption objects that are not tracked by drawing undo, and the captions
|
|
restored by drawing redo would live without cell note objects pointing
|
|
to them. So, first, CopyToClip() and CopyFromClip() are called without
|
|
cloning the caption objects. This leads to cell notes pointing to the
|
|
wrong captions from source area that will be removed by drawing redo
|
|
later. Second, the pointers to the new captions have to be restored.
|
|
Sadly, currently these pointers are not stored anywhere but in the list
|
|
of drawing undo actions. */
|
|
|
|
SCTAB nTab;
|
|
ScMarkData aSourceMark(rDoc.GetSheetLimits());
|
|
for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
|
|
aSourceMark.SelectTable( nTab, true );
|
|
|
|
// do not clone objects and note captions into clipdoc (see above)
|
|
// but at least copy notes
|
|
ScClipParam aClipParam(aSrcRange, bCut);
|
|
rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bKeepScenarioFlags, false);
|
|
|
|
if (bCut)
|
|
{
|
|
ScRange aSrcPaintRange = aSrcRange;
|
|
rDoc.ExtendMerge( aSrcPaintRange ); // before deleting
|
|
sal_uInt16 nExtFlags = 0;
|
|
pDocShell->UpdatePaintExt( nExtFlags, aSrcPaintRange );
|
|
rDoc.DeleteAreaTab( aSrcRange, nRedoFlags );
|
|
PaintArea( aSrcPaintRange, nExtFlags );
|
|
}
|
|
|
|
ScMarkData aDestMark(rDoc.GetSheetLimits());
|
|
for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
|
|
aDestMark.SelectTable( nTab, true );
|
|
|
|
bool bIncludeFiltered = bCut;
|
|
// TODO: restore old note captions instead of cloning new captions...
|
|
rDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, nullptr, pClipDoc.get(), true, false, bIncludeFiltered );
|
|
|
|
if (bCut)
|
|
for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
|
|
rDoc.RefreshAutoFilter( aSrcRange.aStart.Col(), aSrcRange.aStart.Row(),
|
|
aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row(), nTab );
|
|
|
|
// skipped rows and merged cells don't mix
|
|
if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
|
|
pDocShell->GetDocFunc().UnmergeCells( aDestRange, false, nullptr );
|
|
|
|
for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
|
|
{
|
|
SCCOL nEndCol = aDestRange.aEnd.Col();
|
|
SCROW nEndRow = aDestRange.aEnd.Row();
|
|
rDoc.ExtendMerge( aDestRange.aStart.Col(), aDestRange.aStart.Row(),
|
|
nEndCol, nEndRow, nTab, true );
|
|
PaintArea( ScRange( aDestRange.aStart.Col(), aDestRange.aStart.Row(), nTab,
|
|
nEndCol, nEndRow, nTab ), 0 );
|
|
}
|
|
|
|
SetChangeTrack();
|
|
|
|
pClipDoc.reset();
|
|
ShowTable( aDestRange.aStart.Tab() );
|
|
|
|
RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
|
|
EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
|
|
|
|
EndRedo();
|
|
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
|
|
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
SCCOL nStartCol = aDestRange.aStart.Col();
|
|
SCROW nStartRow = aDestRange.aStart.Row();
|
|
if (bCut)
|
|
{
|
|
nStartCol = std::min(nStartCol, aSrcRange.aStart.Col());
|
|
nStartRow = std::min(nStartRow, aSrcRange.aStart.Row());
|
|
}
|
|
|
|
if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell())
|
|
{
|
|
pTabViewShell->OnLOKSetWidthOrHeight(nStartCol, true);
|
|
pTabViewShell->OnLOKSetWidthOrHeight(nStartRow, false);
|
|
|
|
SCTAB nStartTab = aDestRange.aStart.Tab();
|
|
SCTAB nEndTab = aDestRange.aEnd.Tab();
|
|
if (bCut)
|
|
{
|
|
nStartTab = std::min(nStartTab, aSrcRange.aStart.Tab());
|
|
nEndTab = std::max(nEndTab, aSrcRange.aEnd.Tab());
|
|
}
|
|
for (nTab = nStartTab; nTab <= nEndTab; ++nTab)
|
|
{
|
|
ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
|
|
pTabViewShell, true /* bColumns */, true /* bRows */,
|
|
true /* bSizes */, true /* bHidden */, true /* bFiltered */, true /* bGroups */,
|
|
nTab);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScUndoDragDrop::Repeat(SfxRepeatTarget& /* rTarget */)
|
|
{
|
|
}
|
|
|
|
bool ScUndoDragDrop::CanRepeat(SfxRepeatTarget& /* rTarget */) const
|
|
{
|
|
return false; // not possible
|
|
}
|
|
|
|
// Insert list containing range names
|
|
// (Insert|Name|Insert =>[List])
|
|
ScUndoListNames::ScUndoListNames(ScDocShell* pNewDocShell, const ScRange& rRange,
|
|
ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc)
|
|
: ScBlockUndo(pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT)
|
|
, xUndoDoc(std::move(pNewUndoDoc))
|
|
, xRedoDoc(std::move(pNewRedoDoc))
|
|
{
|
|
}
|
|
|
|
OUString ScUndoListNames::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_LISTNAMES );
|
|
}
|
|
|
|
void ScUndoListNames::DoChange( ScDocument* pSrcDoc ) const
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL );
|
|
pSrcDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL, false, rDoc);
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
|
|
pDocShell->PostDataChanged();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
}
|
|
|
|
void ScUndoListNames::Undo()
|
|
{
|
|
BeginUndo();
|
|
DoChange(xUndoDoc.get());
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoListNames::Redo()
|
|
{
|
|
BeginRedo();
|
|
DoChange(xRedoDoc.get());
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoListNames::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
|
|
pTabViewTarget->GetViewShell()->InsertNameList();
|
|
}
|
|
|
|
bool ScUndoListNames::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoConditionalFormat::ScUndoConditionalFormat(ScDocShell* pNewDocShell, SCTAB nTab):
|
|
ScSimpleUndo( pNewDocShell ),
|
|
mnTab(nTab),
|
|
mpUndoDoc(createUndoRedoData())
|
|
{
|
|
}
|
|
|
|
ScUndoConditionalFormat::~ScUndoConditionalFormat()
|
|
{
|
|
}
|
|
|
|
ScDocumentUniquePtr ScUndoConditionalFormat::createUndoRedoData()
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScDocumentUniquePtr pUndoRedoDoc(new ScDocument(SCDOCMODE_UNDO));
|
|
pUndoRedoDoc->InitUndo(rDoc, mnTab, mnTab);
|
|
if (const auto* pList = rDoc.GetCondFormList(mnTab))
|
|
pUndoRedoDoc->SetCondFormList(new ScConditionalFormatList(*pUndoRedoDoc, *pList), mnTab);
|
|
return pUndoRedoDoc;
|
|
}
|
|
|
|
OUString ScUndoConditionalFormat::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_CONDFORMAT );
|
|
}
|
|
|
|
void ScUndoConditionalFormat::Undo()
|
|
{
|
|
DoChange(mpUndoDoc.get());
|
|
}
|
|
|
|
void ScUndoConditionalFormat::Redo()
|
|
{
|
|
DoChange(mpRedoDoc.get());
|
|
}
|
|
|
|
void ScUndoConditionalFormat::DoChange(ScDocument* pSrcDoc)
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
// Restore all conditional formats in the tab. This is simpler and more reliable, than
|
|
// restoring formats in a specific range, and then trying to join selectively the restored
|
|
// formats with the other formats in the tab, to get the correct state.
|
|
ScRangeList aCombinedRange;
|
|
if (const auto* pOldList = rDoc.GetCondFormList(mnTab))
|
|
{
|
|
aCombinedRange = pOldList->GetCombinedRange();
|
|
// Clear all existing CF keys from cells' attributes
|
|
for (auto& pFormat : *pOldList)
|
|
rDoc.RemoveCondFormatData(aCombinedRange, mnTab, pFormat->GetKey());
|
|
}
|
|
|
|
if (const auto* pNewList = pSrcDoc->GetCondFormList(mnTab))
|
|
{
|
|
for (const auto& cond : *pNewList)
|
|
{
|
|
// Restore the CF keys to cell attributes
|
|
rDoc.AddCondFormatData(cond->GetRange(), mnTab, cond->GetKey());
|
|
for (const auto& range : cond->GetRange())
|
|
aCombinedRange.Join(range);
|
|
}
|
|
rDoc.SetCondFormList(new ScConditionalFormatList(rDoc, *pNewList), mnTab);
|
|
}
|
|
else
|
|
{
|
|
rDoc.SetCondFormList(nullptr, mnTab);
|
|
}
|
|
pDocShell->PostPaint(aCombinedRange, PaintPartFlags::Grid);
|
|
pDocShell->PostDataChanged();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
}
|
|
|
|
void ScUndoConditionalFormat::Repeat(SfxRepeatTarget& )
|
|
{
|
|
}
|
|
|
|
bool ScUndoConditionalFormat::CanRepeat(SfxRepeatTarget& ) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ScUndoConditionalFormatList::ScUndoConditionalFormatList(ScDocShell* pNewDocShell,
|
|
ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab):
|
|
ScSimpleUndo( pNewDocShell ),
|
|
mpUndoDoc(std::move(pUndoDoc)),
|
|
mpRedoDoc(std::move(pRedoDoc)),
|
|
mnTab(nTab)
|
|
{
|
|
}
|
|
|
|
ScUndoConditionalFormatList::~ScUndoConditionalFormatList()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoConditionalFormatList::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_CONDFORMAT_LIST );
|
|
}
|
|
|
|
void ScUndoConditionalFormatList::Undo()
|
|
{
|
|
DoChange(mpUndoDoc.get());
|
|
}
|
|
|
|
void ScUndoConditionalFormatList::Redo()
|
|
{
|
|
DoChange(mpRedoDoc.get());
|
|
}
|
|
|
|
void ScUndoConditionalFormatList::DoChange(const ScDocument* pSrcDoc)
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
if (pSrcDoc == mpUndoDoc.get())
|
|
{
|
|
mpRedoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
|
|
mpUndoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
|
|
}
|
|
else
|
|
{
|
|
mpUndoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
|
|
mpRedoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
|
|
}
|
|
rDoc.SetCondFormList(new ScConditionalFormatList(rDoc, *pSrcDoc->GetCondFormList(mnTab)), mnTab);
|
|
|
|
pDocShell->PostPaintGridAll();
|
|
pDocShell->PostDataChanged();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
}
|
|
|
|
void ScUndoConditionalFormatList::Repeat(SfxRepeatTarget& )
|
|
{
|
|
}
|
|
|
|
bool ScUndoConditionalFormatList::CanRepeat(SfxRepeatTarget& ) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ScUndoUseScenario::ScUndoUseScenario( ScDocShell* pNewDocShell,
|
|
const ScMarkData& rMark,
|
|
/*C*/ const ScArea& rDestArea,
|
|
ScDocumentUniquePtr pNewUndoDoc,
|
|
OUString aNewName ) :
|
|
ScSimpleUndo( pNewDocShell ),
|
|
pUndoDoc( std::move(pNewUndoDoc) ),
|
|
aMarkData( rMark ),
|
|
aName(std::move( aNewName ))
|
|
{
|
|
aRange.aStart.SetCol(rDestArea.nColStart);
|
|
aRange.aStart.SetRow(rDestArea.nRowStart);
|
|
aRange.aStart.SetTab(rDestArea.nTab);
|
|
aRange.aEnd.SetCol(rDestArea.nColEnd);
|
|
aRange.aEnd.SetRow(rDestArea.nRowEnd);
|
|
aRange.aEnd.SetTab(rDestArea.nTab);
|
|
}
|
|
|
|
ScUndoUseScenario::~ScUndoUseScenario()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoUseScenario::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_USESCENARIO );
|
|
}
|
|
|
|
void ScUndoUseScenario::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
{
|
|
pViewShell->DoneBlockMode();
|
|
pViewShell->InitOwnBlockMode( aRange );
|
|
}
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
rDoc.DeleteSelection( InsertDeleteFlags::ALL, aMarkData );
|
|
pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, true, rDoc, &aMarkData);
|
|
|
|
// scenario table
|
|
bool bFrame = false;
|
|
SCTAB nTab = aRange.aStart.Tab();
|
|
SCTAB nEndTab = nTab;
|
|
while ( pUndoDoc->HasTable(nEndTab+1) && pUndoDoc->IsScenario(nEndTab+1) )
|
|
++nEndTab;
|
|
for (SCTAB i = nTab+1; i<=nEndTab; i++)
|
|
{
|
|
// Flags always
|
|
OUString aComment;
|
|
Color aColor;
|
|
ScScenarioFlags nScenFlags;
|
|
pUndoDoc->GetScenarioData( i, aComment, aColor, nScenFlags );
|
|
rDoc.SetScenarioData( i, aComment, aColor, nScenFlags );
|
|
bool bActive = pUndoDoc->IsActiveScenario( i );
|
|
rDoc.SetActiveScenario( i, bActive );
|
|
// For copy-back scenario also consider content
|
|
if ( nScenFlags & ScScenarioFlags::TwoWay )
|
|
{
|
|
rDoc.DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), i, InsertDeleteFlags::ALL );
|
|
pUndoDoc->CopyToDocument(0,0,i, rDoc.MaxCol(),rDoc.MaxRow(),i, InsertDeleteFlags::ALL,false, rDoc);
|
|
}
|
|
if ( nScenFlags & ScScenarioFlags::ShowFrame )
|
|
bFrame = true;
|
|
}
|
|
|
|
// if visible borders, then paint all
|
|
if (bFrame)
|
|
pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Extras );
|
|
else
|
|
pDocShell->PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras );
|
|
pDocShell->PostDataChanged();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
|
|
ShowTable( aRange.aStart.Tab() );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoUseScenario::Redo()
|
|
{
|
|
SCTAB nTab = aRange.aStart.Tab();
|
|
BeginRedo();
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
{
|
|
pViewShell->SetTabNo( nTab );
|
|
pViewShell->DoneBlockMode();
|
|
pViewShell->InitOwnBlockMode( aRange );
|
|
}
|
|
|
|
pDocShell->UseScenario( nTab, aName, false );
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoUseScenario::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
{
|
|
OUString aTemp = aName;
|
|
pViewTarget->GetViewShell()->UseScenario(aTemp);
|
|
}
|
|
}
|
|
|
|
bool ScUndoUseScenario::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
{
|
|
ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
|
|
return !rViewData.GetDocument().IsScenario( rViewData.GetTabNo() );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ScUndoSelectionStyle::ScUndoSelectionStyle( ScDocShell* pNewDocShell,
|
|
const ScMarkData& rMark,
|
|
const ScRange& rRange,
|
|
OUString aName,
|
|
ScDocumentUniquePtr pNewUndoDoc ) :
|
|
ScSimpleUndo( pNewDocShell ),
|
|
aMarkData( rMark ),
|
|
pUndoDoc( std::move(pNewUndoDoc) ),
|
|
aStyleName(std::move( aName )),
|
|
aRange( rRange )
|
|
{
|
|
aMarkData.MarkToMulti();
|
|
}
|
|
|
|
ScUndoSelectionStyle::~ScUndoSelectionStyle()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoSelectionStyle::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_APPLYCELLSTYLE );
|
|
}
|
|
|
|
void ScUndoSelectionStyle::DoChange( const bool bUndo )
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
SetViewMarkData( aMarkData );
|
|
|
|
ScRange aWorkRange( aRange );
|
|
if ( rDoc.HasAttrib( aWorkRange, HasAttrFlags::Merged ) ) // Merged cells?
|
|
rDoc.ExtendMerge( aWorkRange, true );
|
|
|
|
sal_uInt16 nExtFlags = 0;
|
|
pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
|
|
|
|
if (bUndo) // if Undo then push back all old data again
|
|
{
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
ScRange aCopyRange = aWorkRange;
|
|
aCopyRange.aStart.SetTab(0);
|
|
aCopyRange.aEnd.SetTab(nTabCount-1);
|
|
pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
|
|
}
|
|
else // if Redo, then reapply style
|
|
{
|
|
ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
|
|
ScStyleSheet* pStyleSheet =
|
|
static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) );
|
|
if (!pStyleSheet)
|
|
{
|
|
OSL_FAIL("StyleSheet not found");
|
|
return;
|
|
}
|
|
rDoc.ApplySelectionStyle( *pStyleSheet, aMarkData );
|
|
}
|
|
|
|
pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
|
|
/*A*/ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
|
|
|
|
ShowTable( aWorkRange.aStart.Tab() );
|
|
}
|
|
|
|
void ScUndoSelectionStyle::Undo()
|
|
{
|
|
BeginUndo();
|
|
DoChange( true );
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoSelectionStyle::Redo()
|
|
{
|
|
BeginRedo();
|
|
DoChange( false );
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoSelectionStyle::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (dynamic_cast<const ScTabViewTarget*>( &rTarget) == nullptr)
|
|
return;
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
|
|
ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( pStlPool->
|
|
Find( aStyleName, SfxStyleFamily::Para ));
|
|
if (!pStyleSheet)
|
|
{
|
|
OSL_FAIL("StyleSheet not found");
|
|
return;
|
|
}
|
|
|
|
ScTabViewShell& rViewShell = *static_cast<ScTabViewTarget&>(rTarget).GetViewShell();
|
|
rViewShell.SetStyleSheetToMarked( pStyleSheet );
|
|
}
|
|
|
|
bool ScUndoSelectionStyle::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoEnterMatrix::ScUndoEnterMatrix( ScDocShell* pNewDocShell, const ScRange& rArea,
|
|
ScDocumentUniquePtr pNewUndoDoc, OUString aForm ) :
|
|
ScBlockUndo( pNewDocShell, rArea, SC_UNDO_SIMPLE ),
|
|
pUndoDoc( std::move(pNewUndoDoc) ),
|
|
aFormula(std::move( aForm ))
|
|
{
|
|
SetChangeTrack();
|
|
}
|
|
|
|
ScUndoEnterMatrix::~ScUndoEnterMatrix()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoEnterMatrix::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_ENTERMATRIX );
|
|
}
|
|
|
|
void ScUndoEnterMatrix::SetChangeTrack()
|
|
{
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
|
|
nStartChangeAction, nEndChangeAction );
|
|
else
|
|
nStartChangeAction = nEndChangeAction = 0;
|
|
}
|
|
|
|
void ScUndoEnterMatrix::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
|
|
pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
|
|
pDocShell->PostDataChanged();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
if (pViewShell)
|
|
pViewShell->CellContentChanged();
|
|
|
|
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
|
|
if ( pChangeTrack )
|
|
pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoEnterMatrix::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
|
|
ScMarkData aDestMark(rDoc.GetSheetLimits());
|
|
aDestMark.SelectOneTable( aBlockRange.aStart.Tab() );
|
|
aDestMark.SetMarkArea( aBlockRange );
|
|
|
|
rDoc.InsertMatrixFormula( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
|
|
aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(),
|
|
aDestMark, aFormula );
|
|
|
|
SetChangeTrack();
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoEnterMatrix::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
|
|
{
|
|
OUString aTemp = aFormula;
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
pTabViewTarget->GetViewShell()->EnterMatrix(aTemp, rDoc.GetGrammar());
|
|
}
|
|
}
|
|
|
|
bool ScUndoEnterMatrix::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
static ScRange lcl_GetMultiMarkRange( const ScMarkData& rMark )
|
|
{
|
|
OSL_ENSURE( rMark.IsMultiMarked(), "wrong mark type" );
|
|
return rMark.GetMultiMarkArea();
|
|
}
|
|
|
|
ScUndoIndent::ScUndoIndent( ScDocShell* pNewDocShell, const ScMarkData& rMark,
|
|
ScDocumentUniquePtr pNewUndoDoc, bool bIncrement ) :
|
|
ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
|
|
aMarkData( rMark ),
|
|
pUndoDoc( std::move(pNewUndoDoc) ),
|
|
bIsIncrement( bIncrement )
|
|
{
|
|
}
|
|
|
|
ScUndoIndent::~ScUndoIndent()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoIndent::GetComment() const
|
|
{
|
|
TranslateId pId = bIsIncrement ? STR_UNDO_INC_INDENT : STR_UNDO_DEC_INDENT;
|
|
return ScResId(pId);
|
|
}
|
|
|
|
void ScUndoIndent::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
ScRange aCopyRange = aBlockRange;
|
|
aCopyRange.aStart.SetTab(0);
|
|
aCopyRange.aEnd.SetTab(nTabCount-1);
|
|
pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoIndent::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
rDoc.ChangeSelectionIndent( bIsIncrement, aMarkData );
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoIndent::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
pViewTarget->GetViewShell()->ChangeIndent( bIsIncrement );
|
|
}
|
|
|
|
bool ScUndoIndent::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoTransliterate::ScUndoTransliterate( ScDocShell* pNewDocShell, const ScMarkData& rMark,
|
|
ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType ) :
|
|
ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
|
|
aMarkData( rMark ),
|
|
pUndoDoc( std::move(pNewUndoDoc) ),
|
|
nTransliterationType( nType )
|
|
{
|
|
}
|
|
|
|
ScUndoTransliterate::~ScUndoTransliterate()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoTransliterate::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_TRANSLITERATE );
|
|
}
|
|
|
|
void ScUndoTransliterate::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
ScRange aCopyRange = aBlockRange;
|
|
aCopyRange.aStart.SetTab(0);
|
|
aCopyRange.aEnd.SetTab(nTabCount-1);
|
|
pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, rDoc, &aMarkData);
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoTransliterate::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
rDoc.TransliterateText( aMarkData, nTransliterationType );
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoTransliterate::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
pViewTarget->GetViewShell()->TransliterateText( nTransliterationType );
|
|
}
|
|
|
|
bool ScUndoTransliterate::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoClearItems::ScUndoClearItems( ScDocShell* pNewDocShell, const ScMarkData& rMark,
|
|
ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW ) :
|
|
ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
|
|
aMarkData( rMark ),
|
|
pUndoDoc( std::move(pNewUndoDoc) )
|
|
{
|
|
assert(pW && "ScUndoClearItems: Which-Pointer is Null");
|
|
|
|
sal_uInt16 nCount = 0;
|
|
while ( pW[nCount] )
|
|
++nCount;
|
|
pWhich.reset( new sal_uInt16[nCount+1] );
|
|
for (sal_uInt16 i=0; i<=nCount; i++)
|
|
pWhich[i] = pW[i];
|
|
}
|
|
|
|
ScUndoClearItems::~ScUndoClearItems()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoClearItems::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_DELETECONTENTS );
|
|
}
|
|
|
|
void ScUndoClearItems::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoClearItems::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
rDoc.ClearSelectionItems( pWhich.get(), aMarkData );
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoClearItems::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
{
|
|
ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
|
|
rViewData.GetDocFunc().ClearItems( rViewData.GetMarkData(), pWhich.get(), false );
|
|
}
|
|
}
|
|
|
|
bool ScUndoClearItems::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
// remove all line breaks of a table
|
|
ScUndoRemoveBreaks::ScUndoRemoveBreaks( ScDocShell* pNewDocShell,
|
|
SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc ) :
|
|
ScSimpleUndo( pNewDocShell ),
|
|
nTab( nNewTab ),
|
|
pUndoDoc( std::move(pNewUndoDoc) )
|
|
{
|
|
}
|
|
|
|
ScUndoRemoveBreaks::~ScUndoRemoveBreaks()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoRemoveBreaks::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_REMOVEBREAKS );
|
|
}
|
|
|
|
void ScUndoRemoveBreaks::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
|
|
pUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, rDoc);
|
|
if (pViewShell)
|
|
pViewShell->UpdatePageBreakData( true );
|
|
pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoRemoveBreaks::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
|
|
rDoc.RemoveManualBreaks(nTab);
|
|
rDoc.UpdatePageBreaks(nTab);
|
|
if (pViewShell)
|
|
pViewShell->UpdatePageBreakData( true );
|
|
pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoRemoveBreaks::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
{
|
|
ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
|
|
rViewShell.RemoveManualBreaks();
|
|
}
|
|
}
|
|
|
|
bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
|
|
const ScCellMergeOption& rOption, ScDocumentUniquePtr pNewUndoDoc ) :
|
|
ScBlockUndo( pNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ),
|
|
pUndoDoc( std::move(pNewUndoDoc) )
|
|
{
|
|
maOptions.push_back( rOption);
|
|
}
|
|
|
|
ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
|
|
const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc ) :
|
|
ScBlockUndo( pNewDocShell, rRange, SC_UNDO_SIMPLE ),
|
|
pUndoDoc( std::move(pNewUndoDoc) )
|
|
{
|
|
}
|
|
|
|
ScUndoRemoveMerge::~ScUndoRemoveMerge()
|
|
{
|
|
}
|
|
|
|
OUString ScUndoRemoveMerge::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_REMERGE ); // "remove merge"
|
|
}
|
|
|
|
ScDocument* ScUndoRemoveMerge::GetUndoDoc()
|
|
{
|
|
return pUndoDoc.get();
|
|
}
|
|
|
|
void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption )
|
|
{
|
|
maOptions.push_back( rOption);
|
|
}
|
|
|
|
void ScUndoRemoveMerge::Undo()
|
|
{
|
|
using ::std::set;
|
|
|
|
SetCurTab();
|
|
BeginUndo();
|
|
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
for (const auto & rOption : maOptions)
|
|
{
|
|
for (const auto& rTab : rOption.maTabs)
|
|
{
|
|
OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!");
|
|
if (!pUndoDoc)
|
|
continue;
|
|
// There is no need to extend merge area because it's already been extended.
|
|
ScRange aRange = rOption.getSingleRange(rTab);
|
|
rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB);
|
|
pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc);
|
|
|
|
bool bDidPaint = false;
|
|
if ( pViewShell )
|
|
{
|
|
pViewShell->SetTabNo(rTab);
|
|
bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
|
|
}
|
|
if (!bDidPaint)
|
|
ScUndoUtil::PaintMore(pDocShell, aRange);
|
|
}
|
|
}
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoRemoveMerge::Redo()
|
|
{
|
|
using ::std::set;
|
|
|
|
SetCurTab();
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
|
|
|
|
for (const auto & rOption : maOptions)
|
|
{
|
|
for (const SCTAB nTab : rOption.maTabs)
|
|
{
|
|
// There is no need to extend merge area because it's already been extended.
|
|
ScRange aRange = rOption.getSingleRange(nTab);
|
|
|
|
const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
|
|
ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
|
|
aPattern.GetItemSet().Put( rDefAttr );
|
|
rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow,
|
|
rOption.mnEndCol, rOption.mnEndRow, nTab,
|
|
aPattern );
|
|
|
|
rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow,
|
|
rOption.mnEndCol, rOption.mnEndRow, nTab,
|
|
ScMF::Hor | ScMF::Ver );
|
|
|
|
rDoc.ExtendMerge(aRange, true);
|
|
|
|
// Paint
|
|
|
|
bool bDidPaint = false;
|
|
if ( pViewShell )
|
|
{
|
|
pViewShell->SetTabNo(nTab);
|
|
bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
|
|
}
|
|
if (!bDidPaint)
|
|
ScUndoUtil::PaintMore(pDocShell, aRange);
|
|
}
|
|
}
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoRemoveMerge::Repeat(SfxRepeatTarget& rTarget)
|
|
{
|
|
if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
|
|
pViewTarget->GetViewShell()->RemoveMerge();
|
|
}
|
|
|
|
bool ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const
|
|
{
|
|
return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
|
|
}
|
|
|
|
void ScUndoRemoveMerge::SetCurTab()
|
|
{
|
|
SCTAB nCurTab = ScDocShell::GetCurTab();
|
|
aBlockRange.aStart.SetTab(nCurTab);
|
|
aBlockRange.aEnd.SetTab(nCurTab);
|
|
}
|
|
|
|
/** set only border, for ScRangeList (StarOne) */
|
|
static ScRange lcl_TotalRange( const ScRangeList& rRanges )
|
|
{
|
|
ScRange aTotal;
|
|
if ( !rRanges.empty() )
|
|
{
|
|
aTotal = rRanges[ 0 ];
|
|
for ( size_t i = 1, nCount = rRanges.size(); i < nCount; ++i )
|
|
{
|
|
ScRange const & rRange = rRanges[ i ];
|
|
if (rRange.aStart.Col() < aTotal.aStart.Col()) aTotal.aStart.SetCol(rRange.aStart.Col());
|
|
if (rRange.aStart.Row() < aTotal.aStart.Row()) aTotal.aStart.SetRow(rRange.aStart.Row());
|
|
if (rRange.aStart.Tab() < aTotal.aStart.Tab()) aTotal.aStart.SetTab(rRange.aStart.Tab());
|
|
if (rRange.aEnd.Col() > aTotal.aEnd.Col() ) aTotal.aEnd.SetCol( rRange.aEnd.Col() );
|
|
if (rRange.aEnd.Row() > aTotal.aEnd.Row() ) aTotal.aEnd.SetRow( rRange.aEnd.Row() );
|
|
if (rRange.aEnd.Tab() > aTotal.aEnd.Tab() ) aTotal.aEnd.SetTab(rRange.aEnd.Tab() );
|
|
}
|
|
}
|
|
return aTotal;
|
|
}
|
|
|
|
ScUndoBorder::ScUndoBorder(ScDocShell* pNewDocShell,
|
|
const ScRangeList& rRangeList, ScDocumentUniquePtr pNewUndoDoc,
|
|
const SvxBoxItem& rNewOuter, const SvxBoxInfoItem& rNewInner)
|
|
: ScBlockUndo(pNewDocShell, lcl_TotalRange(rRangeList), SC_UNDO_SIMPLE)
|
|
, xUndoDoc(std::move(pNewUndoDoc))
|
|
{
|
|
xRanges.reset(new ScRangeList(rRangeList));
|
|
xOuter.reset(new SvxBoxItem(rNewOuter));
|
|
xInner.reset(new SvxBoxInfoItem(rNewInner));
|
|
}
|
|
|
|
OUString ScUndoBorder::GetComment() const
|
|
{
|
|
return ScResId( STR_UNDO_SELATTRLINES ); //! own string?
|
|
}
|
|
|
|
void ScUndoBorder::Undo()
|
|
{
|
|
BeginUndo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument();
|
|
ScMarkData aMarkData(rDoc.GetSheetLimits());
|
|
aMarkData.MarkFromRangeList(*xRanges, false);
|
|
xUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
|
|
pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndUndo();
|
|
}
|
|
|
|
void ScUndoBorder::Redo()
|
|
{
|
|
BeginRedo();
|
|
|
|
ScDocument& rDoc = pDocShell->GetDocument(); // call function at docfunc
|
|
size_t nCount = xRanges->size();
|
|
for (size_t i = 0; i < nCount; ++i )
|
|
{
|
|
ScRange const & rRange = (*xRanges)[i];
|
|
SCTAB nTab = rRange.aStart.Tab();
|
|
|
|
ScMarkData aMark(rDoc.GetSheetLimits());
|
|
aMark.SetMarkArea( rRange );
|
|
aMark.SelectTable( nTab, true );
|
|
|
|
rDoc.ApplySelectionFrame(aMark, *xOuter, xInner.get());
|
|
}
|
|
for (size_t i = 0; i < nCount; ++i)
|
|
pDocShell->PostPaint( (*xRanges)[i], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
|
|
|
|
EndRedo();
|
|
}
|
|
|
|
void ScUndoBorder::Repeat(SfxRepeatTarget& /* rTarget */)
|
|
{
|
|
//TODO later (when the function has moved from cellsuno to docfunc)
|
|
}
|
|
|
|
bool ScUndoBorder::CanRepeat(SfxRepeatTarget& /* rTarget */) const
|
|
{
|
|
return false; // See above
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|