summaryrefslogtreecommitdiffstats
path: root/sc/source/core/data/table7.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/table7.cxx')
-rw-r--r--sc/source/core/data/table7.cxx652
1 files changed, 652 insertions, 0 deletions
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
new file mode 100644
index 000000000..9af01cba7
--- /dev/null
+++ b/sc/source/core/data/table7.cxx
@@ -0,0 +1,652 @@
+/* -*- 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/.
+ */
+
+#include <table.hxx>
+#include <clipcontext.hxx>
+#include <document.hxx>
+#include <clipparam.hxx>
+#include <segmenttree.hxx>
+#include <sharedformula.hxx>
+#include <cellvalues.hxx>
+#include <olinetab.hxx>
+#include <tabprotection.hxx>
+#include <columniterator.hxx>
+#include <drwlayer.hxx>
+#include <compressedarray.hxx>
+
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <tools/stream.hxx>
+
+bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const
+{
+ if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount() )
+ return false;
+
+ return aCol[nCol].IsMerged(nRow);
+}
+
+sc::MultiDataCellState ScTable::HasMultipleDataCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
+{
+ if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
+ return sc::MultiDataCellState();
+
+ if (nCol1 > nCol2 || nRow1 > nRow2)
+ // invalid range.
+ return sc::MultiDataCellState();
+
+ if (aCol.empty())
+ return sc::MultiDataCellState(sc::MultiDataCellState::Empty);
+
+ auto setFirstCell = []( sc::MultiDataCellState& rRet, SCCOL nCurCol, SCROW nCurRow )
+ {
+ if (rRet.mnCol1 < 0)
+ {
+ // First cell not yet set. Set it.
+ rRet.mnCol1 = nCurCol;
+ rRet.mnRow1 = nCurRow;
+ }
+ };
+
+ SCCOL nMaxCol = aCol.size()-1;
+ bool bHasOne = false;
+ sc::MultiDataCellState aRet(sc::MultiDataCellState::Empty);
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2 && nCol <= nMaxCol; ++nCol)
+ {
+ SCROW nFirstDataRow = -1;
+ switch (aCol[nCol].HasDataCellsInRange(nRow1, nRow2, &nFirstDataRow))
+ {
+ case sc::MultiDataCellState::HasOneCell:
+ {
+ setFirstCell(aRet, nCol, nFirstDataRow);
+
+ if (bHasOne)
+ {
+ // We've already found one data cell in another column.
+ aRet.meState = sc::MultiDataCellState::HasMultipleCells;
+ return aRet;
+ }
+ bHasOne = true;
+ break;
+ }
+ case sc::MultiDataCellState::HasMultipleCells:
+ {
+ setFirstCell(aRet, nCol, nFirstDataRow);
+
+ aRet.meState = sc::MultiDataCellState::HasMultipleCells;
+ return aRet;
+ }
+ case sc::MultiDataCellState::Empty:
+ default:
+ ;
+ }
+ }
+
+ if (bHasOne)
+ aRet.meState = sc::MultiDataCellState::HasOneCell;
+
+ return aRet;
+}
+
+void ScTable::DeleteBeforeCopyFromClip(
+ sc::CopyFromClipContext& rCxt, const ScTable& rClipTab, sc::ColumnSpanSet& rBroadcastSpans )
+{
+ sc::CopyFromClipContext::Range aRange = rCxt.getDestRange();
+ if (!ValidCol(aRange.mnCol1) || !ValidCol(aRange.mnCol2))
+ return;
+
+ // Pass some stuff to the columns via context.
+ rCxt.setTableProtected(IsProtected());
+ rCxt.setCondFormatList(mpCondFormatList.get());
+
+ ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
+ SCCOL nClipCol = aClipRange.aStart.Col();
+ {
+ const SCCOL nMaxCol2 = std::min<SCCOL>( aRange.mnCol2, aCol.size() - 1 );
+ for (SCCOL nCol = aRange.mnCol1; nCol <= nMaxCol2; ++nCol, ++nClipCol)
+ {
+ if (nClipCol > aClipRange.aEnd.Col())
+ nClipCol = aClipRange.aStart.Col(); // loop through columns.
+
+ const ScColumn& rClipCol = const_cast<ScTable&>(rClipTab).CreateColumnIfNotExists(nClipCol);
+ aCol[nCol].DeleteBeforeCopyFromClip(rCxt, rClipCol, rBroadcastSpans);
+ }
+ }
+
+ SetStreamValid(false);
+}
+
+void ScTable::CopyOneCellFromClip(
+ sc::CopyFromClipContext& rCxt, const SCCOL nCol1, const SCROW nRow1, const SCCOL nCol2, const SCROW nRow2, const SCROW nSrcRow, const ScTable* pSrcTab )
+{
+ ScRange aSrcRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
+ SCCOL nSrcColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ SCCOL nColOffset = nCol - nCol1;
+ nColOffset = nColOffset % nSrcColSize;
+ assert(nColOffset >= 0);
+ CreateColumnIfNotExists(nCol).CopyOneCellFromClip(rCxt, nRow1, nRow2, nColOffset);
+
+ if (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB)
+ {
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ CopyConditionalFormat(nCol, nRow, nCol, nRow, nCol - aSrcRange.aStart.Col() - nColOffset,
+ nRow - nSrcRow, pSrcTab);
+ }
+ }
+
+ if (nCol1 == 0 && nCol2 == rDocument.MaxCol() && mpRowHeights)
+ {
+ mpRowHeights->setValue(nRow1, nRow2, pSrcTab->GetOriginalHeight(nSrcRow));
+
+ if (pRowFlags && pSrcTab->pRowFlags) {
+ if (pSrcTab->pRowFlags->GetValue(nSrcRow) & CRFlags::ManualSize)
+ pRowFlags->OrValue(nRow1, CRFlags::ManualSize);
+ else
+ pRowFlags->AndValue(nRow1, ~CRFlags::ManualSize);
+ }
+ }
+
+ // Copy graphics over too
+ bool bCopyGraphics
+ = (rCxt.getInsertFlag() & InsertDeleteFlags::OBJECTS) != InsertDeleteFlags::NONE;
+ if (!(bCopyGraphics && rCxt.getClipDoc()->mpDrawLayer))
+ return;
+
+ ScDrawLayer* pDrawLayer = GetDoc().GetDrawLayer();
+ OSL_ENSURE(pDrawLayer, "No drawing layer");
+ if (pDrawLayer)
+ {
+ const ScAddress aSrcStartPos
+ = rCxt.getClipDoc()->GetClipParam().getWholeRange().aStart;
+ const ScAddress aSrcEndPos = rCxt.getClipDoc()->GetClipParam().getWholeRange().aEnd;
+ tools::Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
+ aSrcStartPos.Col(), aSrcStartPos.Row(), aSrcEndPos.Col(), aSrcEndPos.Row(),
+ aSrcStartPos.Tab());
+ tools::Rectangle aDestRect = GetDoc().GetMMRect(nCol1, nRow1, nCol2, nRow2, nTab);
+ pDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), aSrcStartPos.Tab(),
+ aSourceRect, ScAddress(nCol1, nRow1, nTab), aDestRect);
+ }
+}
+
+void ScTable::SetValues( const SCCOL nCol, const SCROW nRow, const std::vector<double>& rVals )
+{
+ if (!ValidCol(nCol))
+ return;
+
+ CreateColumnIfNotExists(nCol).SetValues(nRow, rVals);
+}
+
+void ScTable::TransferCellValuesTo( const SCCOL nCol, SCROW nRow, size_t nLen, sc::CellValues& rDest )
+{
+ if (!ValidCol(nCol))
+ return;
+
+ CreateColumnIfNotExists(nCol).TransferCellValuesTo(nRow, nLen, rDest);
+}
+
+void ScTable::CopyCellValuesFrom( const SCCOL nCol, SCROW nRow, const sc::CellValues& rSrc )
+{
+ if (!ValidCol(nCol))
+ return;
+
+ CreateColumnIfNotExists(nCol).CopyCellValuesFrom(nRow, rSrc);
+}
+
+void ScTable::ConvertFormulaToValue(
+ sc::EndListeningContext& rCxt, const SCCOL nCol1, const SCROW nRow1, const SCCOL nCol2, const SCROW nRow2,
+ sc::TableValues* pUndo )
+{
+ if (!ValidCol(nCol1) || !ValidCol(nCol2) || nCol1 > nCol2)
+ return;
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ CreateColumnIfNotExists(nCol).ConvertFormulaToValue(rCxt, nRow1, nRow2, pUndo);
+}
+
+void ScTable::SwapNonEmpty(
+ sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt )
+{
+ const ScRange& rRange = rValues.getRange();
+ assert(rRange.IsValid());
+ for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+ CreateColumnIfNotExists(nCol).SwapNonEmpty(rValues, rStartCxt, rEndCxt);
+}
+
+void ScTable::PreprocessRangeNameUpdate(
+ sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
+{
+ for (SCCOL i = 0; i < aCol.size(); ++i)
+ aCol[i].PreprocessRangeNameUpdate(rEndListenCxt, rCompileCxt);
+}
+
+void ScTable::PreprocessDBDataUpdate(
+ sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
+{
+ for (SCCOL i = 0; i < aCol.size(); ++i)
+ aCol[i].PreprocessDBDataUpdate(rEndListenCxt, rCompileCxt);
+}
+
+void ScTable::CompileHybridFormula(
+ sc::StartListeningContext& rStartListenCxt, sc::CompileFormulaContext& rCompileCxt )
+{
+ for (SCCOL i = 0; i < aCol.size(); ++i)
+ aCol[i].CompileHybridFormula(rStartListenCxt, rCompileCxt);
+}
+
+void ScTable::UpdateScriptTypes( const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2 )
+{
+ if (!IsColValid(nCol1) || !ValidCol(nCol2) || nCol1 > nCol2)
+ return;
+
+ const SCCOL nMaxCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );
+
+ for (SCCOL nCol = nCol1; nCol <= nMaxCol2; ++nCol)
+ aCol[nCol].UpdateScriptTypes(nRow1, nRow2);
+}
+
+bool ScTable::HasUniformRowHeight( SCROW nRow1, SCROW nRow2 ) const
+{
+ if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
+ return false;
+
+ ScFlatUInt16RowSegments::RangeData aData;
+ if (!mpRowHeights->getRangeData(nRow1, aData))
+ // Search failed.
+ return false;
+
+ return nRow2 <= aData.mnRow2;
+}
+
+void ScTable::SplitFormulaGroups( SCCOL nCol, std::vector<SCROW>& rRows )
+{
+ if (!IsColValid(nCol))
+ return;
+
+ sc::SharedFormulaUtil::splitFormulaCellGroups(GetDoc(), aCol[nCol].maCells, rRows);
+}
+
+void ScTable::UnshareFormulaCells( SCCOL nCol, std::vector<SCROW>& rRows )
+{
+ if (!IsColValid(nCol))
+ return;
+
+ sc::SharedFormulaUtil::unshareFormulaCells(rDocument, aCol[nCol].maCells, rRows);
+}
+
+void ScTable::RegroupFormulaCells( SCCOL nCol )
+{
+ if (!IsColValid(nCol))
+ return;
+
+ aCol[nCol].RegroupFormulaCells();
+}
+
+bool ScTable::HasFormulaCell( const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2 ) const
+{
+ if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
+ return false;
+
+ const SCCOL nMaxCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );
+
+ for (SCCOL nCol = nCol1; nCol <= nMaxCol2; ++nCol)
+ if (aCol[nCol].HasFormulaCell(nRow1, nRow2))
+ return true;
+
+ return false;
+}
+
+void ScTable::EndListeningIntersectedGroup(
+ sc::EndListeningContext& rCxt, SCCOL nCol, SCROW nRow, std::vector<ScAddress>* pGroupPos )
+{
+ if (!IsColValid(nCol))
+ return;
+
+ aCol[nCol].EndListeningIntersectedGroup(rCxt, nRow, pGroupPos);
+}
+
+void ScTable::EndListeningIntersectedGroups(
+ sc::EndListeningContext& rCxt, const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2,
+ std::vector<ScAddress>* pGroupPos )
+{
+ if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
+ return;
+
+ for (SCCOL nCol : GetAllocatedColumnsRange(nCol1, nCol2))
+ aCol[nCol].EndListeningIntersectedGroups(rCxt, nRow1, nRow2, pGroupPos);
+}
+
+void ScTable::EndListeningGroup( sc::EndListeningContext& rCxt, const SCCOL nCol, SCROW nRow )
+{
+ if (!IsColValid(nCol))
+ return;
+
+ aCol[nCol].EndListeningGroup(rCxt, nRow);
+}
+
+void ScTable::SetNeedsListeningGroup( SCCOL nCol, SCROW nRow )
+{
+ if (!ValidCol(nCol))
+ return;
+
+ CreateColumnIfNotExists(nCol).SetNeedsListeningGroup(nRow);
+}
+
+bool ScTable::IsEditActionAllowed(
+ sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd ) const
+{
+ if (!IsProtected())
+ {
+ SCCOL nCol1 = 0, nCol2 = aCol.size() - 1;
+ SCROW nRow1 = 0, nRow2 = rDocument.MaxRow();
+
+ switch (eAction)
+ {
+ case sc::ColRowEditAction::InsertColumnsBefore:
+ case sc::ColRowEditAction::InsertColumnsAfter:
+ case sc::ColRowEditAction::DeleteColumns:
+ {
+ nCol1 = nStart;
+ nCol2 = nEnd;
+ break;
+ }
+ case sc::ColRowEditAction::InsertRowsBefore:
+ case sc::ColRowEditAction::InsertRowsAfter:
+ case sc::ColRowEditAction::DeleteRows:
+ {
+ nRow1 = nStart;
+ nRow2 = nEnd;
+ break;
+ }
+ default:
+ ;
+ }
+
+ return IsBlockEditable(nCol1, nRow1, nCol2, nRow2, nullptr);
+ }
+
+ if (IsScenario())
+ // TODO: I don't even know what this scenario thingie is. Perhaps we
+ // should check it against the scenario ranges?
+ return false;
+
+ assert(pTabProtection);
+
+ switch (eAction)
+ {
+ case sc::ColRowEditAction::InsertColumnsBefore:
+ case sc::ColRowEditAction::InsertColumnsAfter:
+ {
+ // TODO: improve the matrix range handling for the insert-before action.
+ if (HasBlockMatrixFragment(nStart, 0, nEnd, rDocument.MaxRow()))
+ return false;
+
+ return pTabProtection->isOptionEnabled(ScTableProtection::INSERT_COLUMNS);
+ }
+ case sc::ColRowEditAction::InsertRowsBefore:
+ case sc::ColRowEditAction::InsertRowsAfter:
+ {
+ // TODO: improve the matrix range handling for the insert-before action.
+ if (HasBlockMatrixFragment(0, nStart, rDocument.MaxCol(), nEnd))
+ return false;
+
+ return pTabProtection->isOptionEnabled(ScTableProtection::INSERT_ROWS);
+ }
+ case sc::ColRowEditAction::DeleteColumns:
+ {
+ if (!pTabProtection->isOptionEnabled(ScTableProtection::DELETE_COLUMNS))
+ return false;
+
+ return !HasAttrib(nStart, 0, nEnd, rDocument.MaxRow(), HasAttrFlags::Protected);
+ }
+ case sc::ColRowEditAction::DeleteRows:
+ {
+ if (!pTabProtection->isOptionEnabled(ScTableProtection::DELETE_ROWS))
+ return false;
+
+ return !HasAttrib(0, nStart, rDocument.MaxCol(), nEnd, HasAttrFlags::Protected);
+ }
+ default:
+ ;
+ }
+
+ return false;
+}
+
+std::optional<sc::ColumnIterator> ScTable::GetColumnIterator( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
+{
+ if (!ValidCol(nCol))
+ return {};
+
+ return const_cast<ScTable*>(this)->CreateColumnIfNotExists(nCol).GetColumnIterator(nRow1, nRow2);
+}
+
+bool ScTable::EnsureFormulaCellResults( const SCCOL nCol1, SCROW nRow1, const SCCOL nCol2, SCROW nRow2, bool bSkipRunning )
+{
+ if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
+ return false;
+
+ const SCCOL nMaxCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );
+
+ bool bAnyDirty = false;
+
+ for (SCCOL nCol = nCol1; nCol <= nMaxCol2; ++nCol)
+ {
+ bool bRet = aCol[nCol].EnsureFormulaCellResults(nRow1, nRow2, bSkipRunning);
+ bAnyDirty = bAnyDirty || bRet;
+ }
+
+ return bAnyDirty;
+}
+
+void ScTable::finalizeOutlineImport()
+{
+ if (pOutlineTable && pRowFlags)
+ {
+ pOutlineTable->GetRowArray().finalizeImport(*this);
+ }
+}
+
+void ScTable::StoreToCache(SvStream& rStrm) const
+{
+ SCCOL nStartCol = 0;
+ SCCOL nEndCol = rDocument.MaxCol();
+ SCROW nStartRow = 0;
+ SCROW nEndRow = rDocument.MaxRow();
+
+ GetDataArea(nStartCol, nStartRow, nEndCol, nEndRow, false, false);
+
+ rStrm.WriteUInt64(nEndCol + 1);
+ for (SCCOL nCol = 0; nCol <= nEndCol; ++nCol)
+ {
+ aCol[nCol].StoreToCache(rStrm);
+ }
+}
+
+void ScTable::RestoreFromCache(SvStream& rStrm)
+{
+ sal_uInt64 nCols = 0;
+ rStrm.ReadUInt64(nCols);
+ for (SCCOL nCol = 0; nCol < static_cast<SCCOL>(nCols); ++nCol)
+ {
+ aCol[nCol].RestoreFromCache(rStrm);
+ }
+}
+
+OString ScTable::dumpSheetGeomData(bool bColumns, SheetGeomType eGeomType)
+{
+ switch (eGeomType)
+ {
+ case SheetGeomType::SIZES:
+ // returns a non-empty space separated list of spans with trailing space.
+ // The format of the span is <size of any row/col in the span in print twips>:<last row/col of the span>
+ // Example (for columns with three spans if MAXCOL is 1023): "1280:3 1049:50 1280:1023"
+ return dumpColumnRowSizes(bColumns);
+ case SheetGeomType::HIDDEN:
+ // returns a non-empty space separated list of spans with trailing space.
+ // The format of the span is:
+ // 1) First span: <1 (span is hidden) / 0 (not hidden)>:<last row/col of the span>
+ // 2) Rest of the spans: <last row/col of the span>
+ // The hidden state of the spans after the first can be inferred from the first span's flag as no adjacent
+ // spans can have the same state by definition of span.
+ return dumpHiddenFiltered(bColumns, /*bHidden*/ true);
+ case SheetGeomType::FILTERED:
+ // has exactly the same format as 'hidden'.
+ return dumpHiddenFiltered(bColumns, /*bHidden*/ false);
+ case SheetGeomType::GROUPS:
+ // returns a space separated list of 'levels' with trailing space.
+ // A 'level' is a comma separated list of groups(outline entries) with trailing comma.
+ // format of a group is:
+ // <start row/col of group>:<number of rows/cols in the group>:<1/0(group is hidden?)>:<1/0(control is visible?)>
+ return dumpColumnRowGroups(bColumns);
+ default:
+ ;
+ }
+
+ return "";
+}
+
+OString ScTable::dumpColumnRowSizes(bool bColumns)
+{
+ // If the data-structures are not available, just report that all
+ // rows/cols have the default sizes.
+ static const OString aDefaultForCols
+ = OString::number(STD_COL_WIDTH) + ":" + OString::number(GetDoc().MaxCol()) + " ";
+ static const OString aDefaultForRows
+ = OString::number(ScGlobal::nStdRowHeight) + ":" + OString::number(GetDoc().MaxRow()) + " ";
+
+ // ScCompressedArray is a template class and we don't want to impose
+ // the restriction that its value type should be string serializable,
+ // instead just operate on the specialized object.
+ typedef ScCompressedArray<SCCOL, sal_uInt16> ColWidthsType;
+ auto dumpColWidths = [this](const ColWidthsType& rWidths) -> OString {
+ OString aOutput;
+ OString aSegment;
+ SCCOL nStartCol = 0;
+ const SCCOL nMaxCol = std::min(rWidths.GetLastPos(), GetDoc().MaxCol());
+ size_t nDummy = 0;
+ while (nStartCol <= nMaxCol)
+ {
+ SCCOL nEndCol;
+ sal_uInt16 nWidth = rWidths.GetValue(nStartCol, nDummy, nEndCol);
+ // The last span nEndCol is always MAXCOL+1 for some reason, and we don't want that.
+ if (nEndCol > nMaxCol)
+ nEndCol = nMaxCol;
+ aSegment = OString::number(nWidth) + ":" + OString::number(nEndCol) + " ";
+ aOutput += aSegment;
+ nStartCol = nEndCol + 1;
+ }
+
+ return aOutput;
+ };
+
+ if (bColumns)
+ return mpColWidth ? dumpColWidths(*mpColWidth) : aDefaultForCols;
+
+ return mpRowHeights ? mpRowHeights->dumpAsString() : aDefaultForRows;
+}
+
+OString ScTable::dumpHiddenFiltered(bool bColumns, bool bHidden)
+{
+ // defaults to no hidden/filtered row/cols.
+ static const OString aDefaultForCols = "0:" + OString::number(GetDoc().MaxCol()) + " ";
+ static const OString aDefaultForRows = "0:" + OString::number(GetDoc().MaxRow()) + " ";
+
+ if (bHidden)
+ {
+ if (bColumns)
+ return mpHiddenCols ? mpHiddenCols->dumpAsString() : aDefaultForCols;
+
+ return mpHiddenRows ? mpHiddenRows->dumpAsString() : aDefaultForRows;
+ }
+
+ if (bColumns)
+ return mpFilteredCols ? mpFilteredCols->dumpAsString() : aDefaultForCols;
+
+ return mpFilteredRows ? mpFilteredRows->dumpAsString() : aDefaultForRows;
+}
+
+OString ScTable::dumpColumnRowGroups(bool bColumns) const
+{
+ if (!pOutlineTable)
+ return "";
+
+ if (bColumns)
+ return pOutlineTable->GetColArray().dumpAsString();
+
+ return pOutlineTable->GetRowArray().dumpAsString();
+}
+
+SCCOL ScTable::GetLOKFreezeCol() const
+{
+ return maLOKFreezeCell.Col();
+}
+
+SCROW ScTable::GetLOKFreezeRow() const
+{
+ return maLOKFreezeCell.Row();
+}
+
+bool ScTable::SetLOKFreezeCol(SCCOL nFreezeCol)
+{
+ if (!ValidCol(nFreezeCol))
+ {
+ SAL_WARN("sc.core", "ScTable::SetLOKFreezeCol : invalid nFreezeCol = " << nFreezeCol);
+ return false;
+ }
+
+ if (maLOKFreezeCell.Col() != nFreezeCol)
+ {
+ maLOKFreezeCell.SetCol(nFreezeCol);
+ return true;
+ }
+
+ return false;
+}
+
+bool ScTable::SetLOKFreezeRow(SCROW nFreezeRow)
+{
+ if (!ValidRow(nFreezeRow))
+ {
+ SAL_WARN("sc.core", "ScTable::SetLOKFreezeRow : invalid nFreezeRow = " << nFreezeRow);
+ return false;
+ }
+
+ if (maLOKFreezeCell.Row() != nFreezeRow)
+ {
+ maLOKFreezeCell.SetRow(nFreezeRow);
+ return true;
+ }
+
+ return false;
+}
+
+std::set<SCCOL> ScTable::QueryColumnsWithFormulaCells() const
+{
+ std::set<SCCOL> aColIndices;
+
+ for (const auto& pCol : aCol)
+ {
+ if (pCol->HasFormulaCell())
+ aColIndices.insert(pCol->GetCol());
+ }
+
+ return aColIndices;
+}
+
+void ScTable::CheckIntegrity() const
+{
+ for (const auto& pCol : aCol)
+ pCol->CheckIntegrity();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */