/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * 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 .
*/
if (!maRowManualBreaks.empty())
{ // Copy all breaks up to nStartRow (non-inclusive).
::std::set<SCROW>::iterator itr1 = maRowManualBreaks.lower_bound(nStartRow);
::std::set<SCROW> aNewBreaks(maRowManualBreaks.begin(), itr1);
// Copy all breaks from nStartRow (inclusive) to the last element, // but add nSize to each value.
::std::set<SCROW>::iterator itr2 = maRowManualBreaks.end(); for (; itr1 != itr2; ++itr1)
aNewBreaks.insert(static_cast<SCROW>(*itr1 + nSize));
if (!maRowManualBreaks.empty())
{ // Erase all manual breaks between nStartRow and nStartRow + nSize - 1 (inclusive).
std::set<SCROW>::iterator itr1 = maRowManualBreaks.lower_bound(nStartRow);
std::set<SCROW>::iterator itr2 = maRowManualBreaks.upper_bound(static_cast<SCROW>(nStartRow + nSize - 1));
maRowManualBreaks.erase(itr1, itr2);
// Copy all breaks from the 1st element up to nStartRow to the new container.
itr1 = maRowManualBreaks.lower_bound(nStartRow);
::std::set<SCROW> aNewBreaks(maRowManualBreaks.begin(), itr1);
// Copy all breaks from nStartRow to the last element, but subtract each value by nSize.
itr2 = maRowManualBreaks.end(); for (; itr1 != itr2; ++itr1)
aNewBreaks.insert(static_cast<SCROW>(*itr1 - nSize));
maRowManualBreaks.swap(aNewBreaks);
}
}
{ // scope for bulk broadcast
ScBulkBroadcast aBulkBroadcast( rDocument.GetBASM(), SfxHintId::ScDataChanged); for (SCCOL j=nStartCol; j<=ClampToAllocatedColumns(nEndCol); j++)
aCol[j].DeleteRow(nStartRow, nSize, pGroupPos);
}
auto range = GetAllocatedColumnsRange( rDocument.MaxCol() - static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() ); for (auto it = range.rbegin(); it != range.rend(); ++it ) if (! aCol[*it].TestInsertCol(nStartRow, nEndRow)) returnfalse;
returntrue;
}
void ScTable::InsertCol( const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
{ if (nStartRow==0 && nEndRow==rDocument.MaxRow())
{ if (mpColWidth && mpColFlags)
{
mpColWidth->InsertPreservingSize(nStartCol, nSize, STD_COL_WIDTH); // The inserted columns have the same widths as the columns, which were selected for insert. for (SCSIZE i=0; i < std::min(rDocument.MaxCol()-nSize-nStartCol, nSize); ++i)
mpColWidth->SetValue(nStartCol + i, mpColWidth->GetValue(nStartCol+i+nSize));
mpColFlags->InsertPreservingSize(nStartCol, nSize, CRFlags::NONE);
} if (pOutlineTable)
pOutlineTable->InsertCol( nStartCol, nSize );
if (!maColManualBreaks.empty())
{ // Copy all breaks up to nStartCol (non-inclusive).
::std::set<SCCOL>::iterator itr1 = maColManualBreaks.lower_bound(nStartCol);
::std::set<SCCOL> aNewBreaks(maColManualBreaks.begin(), itr1);
// Copy all breaks from nStartCol (inclusive) to the last element, // but add nSize to each value.
::std::set<SCCOL>::iterator itr2 = maColManualBreaks.end(); for (; itr1 != itr2; ++itr1)
aNewBreaks.insert(static_cast<SCCOL>(*itr1 + nSize));
maColManualBreaks.swap(aNewBreaks);
}
}
// Make sure there are enough columns at the end.
CreateColumnIfNotExists(std::min<SCCOL>(rDocument.MaxCol(), std::max(nStartCol, aCol.size()) + nSize - 1 )); if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
{ // Move existing columns back, this will swap last empty columns in the inserted place. for (SCCOL nCol = aCol.size() - 1 - nSize; nCol >= nStartCol; --nCol)
aCol[nCol].SwapCol(aCol[nCol+nSize]);
} else
{ for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol < aCol.size(); i++)
aCol[aCol.size() - 1 - nSize - i].MoveTo(nStartRow, nEndRow, aCol[aCol.size() - 1 - i]);
}
if (!maColManualBreaks.empty())
{ // Erase all manual breaks between nStartCol and nStartCol + nSize - 1 (inclusive).
std::set<SCCOL>::iterator itr1 = maColManualBreaks.lower_bound(nStartCol);
std::set<SCCOL>::iterator itr2 = maColManualBreaks.upper_bound(static_cast<SCCOL>(nStartCol + nSize - 1));
maColManualBreaks.erase(itr1, itr2);
// Copy all breaks from the 1st element up to nStartCol to the new container.
itr1 = maColManualBreaks.lower_bound(nStartCol);
::std::set<SCCOL> aNewBreaks(maColManualBreaks.begin(), itr1);
// Copy all breaks from nStartCol to the last element, but subtract each value by nSize.
itr2 = maColManualBreaks.end(); for (; itr1 != itr2; ++itr1)
aNewBreaks.insert(static_cast<SCCOL>(*itr1 - nSize));
maColManualBreaks.swap(aNewBreaks);
}
}
for (SCCOL col = nStartCol; col <= ClampToAllocatedColumns(nStartCol + nSize - 1); ++col)
aCol[col].DeleteArea(nStartRow, nEndRow, InsertDeleteFlags::ALL, false);
for (size_t i = 0; i < aRangeList.size(); ++i)
{ const ScRange & rRange = aRangeList[i];
if((nDelFlag & InsertDeleteFlags::ATTRIB) && rRange.aStart.Tab() == nTab)
mpCondFormatList->DeleteArea( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row() );
} // TODO: In the future we may want to check if the table has been // really modified before setting the stream invalid.
SetStreamValid(false);
}
// copy content //local range names need to be copied first for formula cells if (!pTable->mpRangeName && mpRangeName)
pTable->mpRangeName.reset( new ScRangeName(*mpRangeName) );
nCol2 = ClampToAllocatedColumns(nCol2);
pTable->CreateColumnIfNotExists(nCol2); // prevent repeated resizing for ( SCCOL i = nCol1; i <= nCol2; i++)
aCol[i].CopyToClip(rCxt, nRow1, nRow2, pTable->CreateColumnIfNotExists(i)); // notes are handled at column level
// copy widths/heights, and only "hidden", "filtered" and "manual" flags // also for all preceding columns/rows, to have valid positions for drawing objects
if (mpColWidth && pTable->mpColWidth)
pTable->mpColWidth->CopyFrom(*mpColWidth, 0, nCol2);
pTable->CopyColHidden(*this, 0, nCol2);
pTable->CopyColFiltered(*this, 0, nCol2); if (pDBDataNoName)
pTable->SetAnonymousDBData(std::unique_ptr<ScDBData>(new ScDBData(*pDBDataNoName)));
bool isFormatDependentOnRange(const ScConditionalFormat& rFormat)
{ for (size_t i = 0; i < rFormat.size(); ++i) if (auto* entry = rFormat.GetEntry(i)) if (auto type = entry->GetType(); type == ScFormatEntry::Type::Colorscale
|| type == ScFormatEntry::Type::Databar
|| type == ScFormatEntry::Type::Iconset) returntrue; returnfalse;
}
bool isRangeDependentFormatNeedDeduplication(const ScRangeList& rOld, const ScRangeList& rNew)
{ // Are they two adjacent vectors? if (rOld.size() == 1 && rNew.size() == 1)
{ // Test vertical vectors if (rOld[0].aStart.Col() == rOld[0].aEnd.Col() && rNew[0].aStart.Col() == rNew[0].aEnd.Col()
&& rNew[0].aStart.Col() == rOld[0].aStart.Col())
{ if (rOld[0].aEnd.Row() == rNew[0].aStart.Row() - 1
|| rNew[0].aEnd.Row() == rOld[0].aStart.Row() - 1)
{ returntrue; // Two joining vertical vectors -> merge
}
} // Test horizontal vectors if (rOld[0].aStart.Row() == rOld[0].aEnd.Row() && rNew[0].aStart.Row() == rNew[0].aEnd.Row()
&& rNew[0].aStart.Row() == rOld[0].aStart.Row())
{ if (rOld[0].aEnd.Col() == rNew[0].aStart.Col() - 1
|| rNew[0].aEnd.Col() == rOld[0].aStart.Col() - 1)
{ returntrue; // Two joining horizontal vectors -> merge
}
}
}
// Is the new one fully included into the old one? for (auto& range : rNew) if (!rOld.Contains(range)) returnfalse; // Different ranges, no deduplication
returntrue; // New is completely inside old -> merge (in fact, this means "nothing to do")
}
if (isFormatDependentOnRange(*pOldFormat)
&& !isRangeDependentFormatNeedDeduplication(rDstRangeList, rNewRangeList)) returnfalse; // No deduplication, create new format
for (size_t i = 0; i < rNewRangeList.size(); ++i)
{
rDstRangeList.Join(rNewRangeList[i]);
}
rDocument.AddCondFormatData(rNewRangeList, nTab, pOldFormat->GetKey()); returntrue;
}
returnfalse;
}
}
void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
SCCOL nDx, SCROW nDy, const ScTable* pTable)
{
ScRange aOldRange( nCol1 - nDx, nRow1 - nDy, pTable->nTab, nCol2 - nDx, nRow2 - nDy, pTable->nTab);
ScRange aNewRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ); // Don't deduplicate when undoing or creating an Undo document! It would disallow correct undo bool bUndoContext = rDocument.IsUndo() || pTable->rDocument.IsUndo(); // Note that Undo documents use same pool as the original document bool bSameDoc = rDocument.GetStyleSheetPool() == pTable->rDocument.GetStyleSheetPool();
if (!bUndoContext && bSameDoc && pTable->nTab == nTab && CheckAndDeduplicateCondFormat(rDocument, mpCondFormatList->GetFormat(rxCondFormat->GetKey()), pNewFormat.get(), nTab))
{ continue;
}
sal_uInt32 nMax = 0; bool bDuplicate = false; for(constauto& rxCond : *mpCondFormatList)
{ // Check if there is the same format in the destination // If there is, then simply expand its range if (!bUndoContext && CheckAndDeduplicateCondFormat(rDocument, rxCond.get(), pNewFormat.get(), nTab))
{
bDuplicate = true; break;
}
if (rxCond->GetKey() > nMax)
nMax = rxCond->GetKey();
} // Do not add duplicate entries if (bDuplicate)
{ continue;
}
pNewFormat->SetKey(nMax + 1); auto pNewFormatTmp = pNewFormat.get();
mpCondFormatList->InsertNew(std::move(pNewFormat));
if (!(ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))) return;
CreateColumnIfNotExists(nCol2); for ( SCCOL i = nCol1; i <= nCol2; i++)
{
pTable->CreateColumnIfNotExists(i - nDx);
aCol[i].CopyFromClip(rCxt, nRow1, nRow2, nDy, pTable->aCol[i - nDx]); // notes are handles at column level
}
if (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB)
{ // make sure that there are no old references to the cond formats
sal_uInt16 nWhichArray[2];
nWhichArray[0] = ATTR_CONDITIONAL;
nWhichArray[1] = 0; for ( SCCOL i = nCol1; i <= nCol2; ++i)
aCol[i].ClearItems(nRow1, nRow2, nWhichArray);
}
if ((rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB) == InsertDeleteFlags::NONE) return;
staticvoid lcl_SetTransposedPatternInRows(ScTable* pTransClip, SCROW nAttrRow1, SCROW nAttrRow2,
SCCOL nCol1, SCROW nRow1, SCROW nCombinedStartRow, SCCOL nCol, const CellAttributeHolder& rPatternHolder, bool bIncludeFiltered, const std::vector<SCROW>& rFilteredRows,
SCROW nRowDestOffset)
{ for (SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++)
{
size_t nFilteredRowAdjustment = 0; if (!bIncludeFiltered)
{ // aFilteredRows is sorted thus lower_bound() can be used. // lower_bound() has a logarithmic complexity O(log(n)) auto itRow1 = std::lower_bound(rFilteredRows.begin(), rFilteredRows.end(), nRow1); auto itRow = std::lower_bound(rFilteredRows.begin(), rFilteredRows.end(), nRow); bool bRefRowIsFiltered = itRow != rFilteredRows.end() && *itRow == nRow; if (bRefRowIsFiltered) continue;
// How many filtered rows are between the formula cell and the reference? // distance() has a constant complexity O(1) for vectors
nFilteredRowAdjustment = std::distance(itRow1, itRow);
}
if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB) && nCol2 >= aCol.size())
{ // tdf#154044: Copy also the default column data
aDefaultColData.AttrArray().CopyArea(nRow1, nRow2, 0,
pDestTab->aDefaultColData.AttrArray());
}
if ((bToUndoDoc || bFromUndoDoc) && (nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
{ // Copying formulas may create sheet-local named expressions on the // destination sheet. Add existing to Undo first. // During Undo restore the previous named expressions.
pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName()))); if (!pDestTab->rDocument.IsClipOrUndo())
{
ScDocShell* pDocSh = pDestTab->rDocument.GetDocumentShell(); if (pDocSh)
pDocSh->SetAreasChangedNeedBroadcast();
}
}
if (nFlags != InsertDeleteFlags::NONE)
{
InsertDeleteFlags nTempFlags( nFlags &
~InsertDeleteFlags( InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)); // tdf#102364 - in some pathological cases CopyToTable() replacing cells with new cells // can lead to repetitive splitting and rejoining of the same formula group, which can get // quadratically expensive with large groups. So do the grouping just once at the end.
sc::DelayFormulaGroupingSwitch delayGrouping( pDestTab->rDocument, true );
pDestTab->CreateColumnIfNotExists(ClampToAllocatedColumns(nCol2)); // avoid repeated resizing for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++)
aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : nTempFlags, bMarked,
pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal); // tdf#154044: Restore from the default column data if (bFromUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB) && nCol2 >= aCol.size())
{
aDefaultColData.AttrArray().CopyArea(nRow1, nRow2, 0,
pDestTab->aDefaultColData.AttrArray());
SCCOL nMaxSetDefault = pDestTab->ClampToAllocatedColumns(nCol2); for (SCCOL i = aCol.size(); i <= nMaxSetDefault; i++)
aDefaultColData.AttrArray().CopyArea(nRow1, nRow2, 0,
pDestTab->aCol[i].AttrArray());
}
}
if (!bColRowFlags) // Column widths/Row heights/Flags return;
if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB))
{
pDestTab->mpCondFormatList.reset(mpCondFormatList->Clone(pDestTab->rDocument));
}
if (pDBDataNoName)
{
std::unique_ptr<ScDBData> pNewDBData(new ScDBData(*pDBDataNoName));
SCCOL aCol1, aCol2;
SCROW aRow1, aRow2;
SCTAB aTab;
pNewDBData->GetArea(aTab, aCol1, aRow1, aCol2, aRow2);
pNewDBData->MoveTo(pDestTab->nTab, aCol1, aRow1, aCol2, aRow2);
pDestTab->SetAnonymousDBData(std::move(pNewDBData));
} // Charts have to be adjusted when hide/show
ScChartListenerCollection* pCharts = pDestTab->rDocument.GetChartListenerCollection();
bool bFlagChange = false;
if (nRow1 == 0 && nRow2 == rDocument.MaxRow() && mpColWidth && pDestTab->mpColWidth)
{ auto destTabColWidthIt = pDestTab->mpColWidth->begin() + nCol1; auto thisTabColWidthIt = mpColWidth->begin() + nCol1;
pDestTab->mpColWidth->CopyFrom(*mpColWidth, nCol1, nCol2);
pDestTab->mpColFlags->CopyFrom(*mpColFlags, nCol1, nCol2); for (SCCOL i = nCol1; i <= nCol2; ++i)
{ bool bThisHidden = ColHidden(i); bool bHiddenChange = (pDestTab->ColHidden(i) != bThisHidden); bool bChange = bHiddenChange || (*destTabColWidthIt != *thisTabColWidthIt);
pDestTab->SetColHidden(i, i, bThisHidden); //TODO: collect changes? if (bHiddenChange && pCharts)
pCharts->SetRangeDirty(ScRange(i, 0, nTab, i, rDocument.MaxRow(), nTab));
// Hidden flags. for (SCROW i = nRow1; i <= nRow2; ++i)
{
SCROW nLastRow; bool bHidden = RowHidden(i, nullptr, &nLastRow); if (nLastRow >= nRow2) // the last row shouldn't exceed the upper bound the caller specified.
nLastRow = nRow2;
bool bHiddenChanged = pDestTab->SetRowHidden(i, nLastRow, bHidden); if (bHiddenChanged && pCharts) // Hidden flags differ.
pCharts->SetRangeDirty(ScRange(0, i, nTab, rDocument.MaxCol(), nLastRow, nTab));
if (bHiddenChanged)
bFlagChange = true;
// Jump to the last row of the identical flag segment.
i = nLastRow;
}
// Filtered flags. for (SCROW i = nRow1; i <= nRow2; ++i)
{
SCROW nLastRow; bool bFiltered = RowFiltered(i, nullptr, &nLastRow); if (nLastRow >= nRow2) // the last row shouldn't exceed the upper bound the caller specified.
nLastRow = nRow2;
pDestTab->SetRowFiltered(i, nLastRow, bFiltered);
i = nLastRow;
}
pDestTab->SetRowManualBreaks(std::set(maRowManualBreaks));
}
if (bFlagChange)
pDestTab->InvalidatePageBreaks();
if ((nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName)
{ // Undo sheet-local named expressions created during copying // formulas. If mpRangeName is not set then the Undo wasn't even // set to an empty ScRangeName map so don't "undo" that.
pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName()))); if (!pDestTab->rDocument.IsClipOrUndo())
{
ScDocShell* pDocSh = pDestTab->rDocument.GetDocumentShell(); if (pDocSh)
pDocSh->SetAreasChangedNeedBroadcast();
}
}
for ( SCCOL i = 0; i < aCol.size(); i++)
{ auto& rDestCol = pDestTab->CreateColumnIfNotExists(i); if ( i >= nCol1 && i <= nCol2 )
aCol[i].UndoToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rDestCol); else
aCol[i].CopyToColumn(rCxt, 0, rDocument.MaxRow(), InsertDeleteFlags::FORMULA, false, rDestCol);
}
if (nFlags & InsertDeleteFlags::ATTRIB)
pDestTab->mpCondFormatList.reset(mpCondFormatList->Clone(pDestTab->rDocument));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.