summaryrefslogtreecommitdiff
path: root/sc/source
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-05-24 11:52:18 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-06-24 16:51:25 -0400
commitc008dc483f8c6840803983e7e351cec6fdd32070 (patch)
tree7c88eeabde57ea4a3c1a760d1c02ea2fd37bd721 /sc/source
parent75dec25730c88bdb8eb5e2a3f92689460fa89d29 (diff)
Switch to using multi_type_vector for cell storage.
The old style cell storage is no more. Currently the code is buildable, but crashes during unit test. Change-Id: Ie688e22e95c7fb02b9e97b23df0fc1883a97945f
Diffstat (limited to 'sc/source')
-rw-r--r--sc/source/core/data/cell2.cxx43
-rw-r--r--sc/source/core/data/cellclonehandler.cxx89
-rw-r--r--sc/source/core/data/cellvalue.cxx151
-rw-r--r--sc/source/core/data/column.cxx2865
-rw-r--r--sc/source/core/data/column2.cxx2446
-rw-r--r--sc/source/core/data/column3.cxx3079
-rw-r--r--sc/source/core/data/columnspanset.cxx117
-rw-r--r--sc/source/core/data/dociter.cxx1264
-rw-r--r--sc/source/core/data/documen2.cxx13
-rw-r--r--sc/source/core/data/documen4.cxx33
-rw-r--r--sc/source/core/data/documen8.cxx9
-rw-r--r--sc/source/core/data/document.cxx22
-rw-r--r--sc/source/core/data/documentimport.cxx47
-rw-r--r--sc/source/core/data/fillinfo.cxx92
-rw-r--r--sc/source/core/data/formulacell.cxx20
-rw-r--r--sc/source/core/data/markdata.cxx7
-rw-r--r--sc/source/core/data/mtvelements.cxx16
-rw-r--r--sc/source/core/data/table1.cxx100
-rw-r--r--sc/source/core/data/table2.cxx382
-rw-r--r--sc/source/core/data/table3.cxx297
-rw-r--r--sc/source/core/data/table4.cxx182
-rw-r--r--sc/source/core/data/table5.cxx18
-rw-r--r--sc/source/core/data/table6.cxx305
-rw-r--r--sc/source/core/inc/interpre.hxx1
-rw-r--r--sc/source/core/tool/chgtrack.cxx19
-rw-r--r--sc/source/core/tool/editutil.cxx26
-rw-r--r--sc/source/core/tool/scmatrix.cxx178
-rw-r--r--sc/source/core/tool/scopetools.cxx28
-rw-r--r--sc/source/filter/xml/XMLExportIterator.cxx2
-rw-r--r--sc/source/ui/docshell/dbdocimp.cxx3
-rw-r--r--sc/source/ui/docshell/docsh8.cxx3
-rw-r--r--sc/source/ui/docshell/impex.cxx2
-rw-r--r--sc/source/ui/undo/undodat.cxx1
33 files changed, 6565 insertions, 5295 deletions
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index 8345e488f980..0d46036bf07c 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -135,39 +135,22 @@ void ScEditCell::UpdateFields(SCTAB nTab)
aUpdater.updateTableFields(nTab);
}
-void ScEditCell::SetTextObject( const EditTextObject* pObject,
- const SfxItemPool* pFromPool )
+void ScEditCell::SetTextObject(
+ const EditTextObject* pObject, const SfxItemPool* pFromPool )
{
- if ( pObject )
+ if (!pObject)
{
- if ( pFromPool && mpDoc->GetEditPool() == pFromPool )
- mpData = pObject->Clone();
- else
- { //! another "spool"
- // Sadly there is no other way to change the Pool than to
- // "spool" the Object through a corresponding Engine
- EditEngine& rEngine = mpDoc->GetEditEngine();
- if ( pObject->HasOnlineSpellErrors() )
- {
- sal_uLong nControl = rEngine.GetControlWord();
- const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
- bool bNewControl = ( (nControl & nSpellControl) != nSpellControl );
- if ( bNewControl )
- rEngine.SetControlWord( nControl | nSpellControl );
- rEngine.SetText( *pObject );
- mpData = rEngine.CreateTextObject();
- if ( bNewControl )
- rEngine.SetControlWord( nControl );
- }
- else
- {
- rEngine.SetText( *pObject );
- mpData = rEngine.CreateTextObject();
- }
- }
- }
- else
mpData = NULL;
+ return;
+ }
+
+ if ( pFromPool && mpDoc->GetEditPool() == pFromPool )
+ {
+ mpData = pObject->Clone();
+ return;
+ }
+
+ mpData = ScEditUtil::Clone(*pObject, *mpDoc);
}
ScEditDataArray::ScEditDataArray()
diff --git a/sc/source/core/data/cellclonehandler.cxx b/sc/source/core/data/cellclonehandler.cxx
new file mode 100644
index 000000000000..1f1d75ccf802
--- /dev/null
+++ b/sc/source/core/data/cellclonehandler.cxx
@@ -0,0 +1,89 @@
+/* -*- 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 "cellclonehandler.hxx"
+#include "editutil.hxx"
+#include "document.hxx"
+
+namespace sc {
+
+CellBlockCloneHandler::CellBlockCloneHandler(
+ ScDocument& rSrcDoc, ScDocument& rDestDoc, CellStoreType& rDestCellStore) :
+ mrSrcDoc(rSrcDoc), mrDestDoc(rDestDoc), mrDestCellStore(rDestCellStore) {}
+
+CellBlockCloneHandler::~CellBlockCloneHandler() {}
+
+ScDocument& CellBlockCloneHandler::getSrcDoc()
+{
+ return mrSrcDoc;
+}
+
+ScDocument& CellBlockCloneHandler::getDestDoc()
+{
+ return mrDestDoc;
+}
+
+const ScDocument& CellBlockCloneHandler::getDestDoc() const
+{
+ return mrDestDoc;
+}
+
+CellStoreType& CellBlockCloneHandler::getDestCellStore()
+{
+ return mrDestCellStore;
+}
+
+void CellBlockCloneHandler::cloneDoubleBlock(
+ CellStoreType::iterator& itPos, const ScAddress& /*rSrcPos*/, const ScAddress& rDestPos,
+ const numeric_block::const_iterator& itBegin, const numeric_block::const_iterator& itEnd)
+{
+ itPos = mrDestCellStore.set(itPos, rDestPos.Row(), itBegin, itEnd);
+}
+
+void CellBlockCloneHandler::cloneStringBlock(
+ CellStoreType::iterator& itPos, const ScAddress& /*rSrcPos*/, const ScAddress& rDestPos,
+ const string_block::const_iterator& itBegin, const string_block::const_iterator& itEnd)
+{
+ itPos = mrDestCellStore.set(itPos, rDestPos.Row(), itBegin, itEnd);
+}
+
+void CellBlockCloneHandler::cloneEditTextBlock(
+ CellStoreType::iterator& itPos, const ScAddress& /*rSrcPos*/, const ScAddress& rDestPos,
+ const edittext_block::const_iterator& itBegin, const edittext_block::const_iterator& itEnd)
+{
+ std::vector<EditTextObject*> aCloned;
+ aCloned.reserve(std::distance(itBegin, itEnd));
+ for (edittext_block::const_iterator it = itBegin; it != itEnd; ++it)
+ aCloned.push_back(ScEditUtil::Clone(**it, getDestDoc()));
+
+ itPos = getDestCellStore().set(itPos, rDestPos.Row(), aCloned.begin(), aCloned.end());
+}
+
+void CellBlockCloneHandler::cloneFormulaBlock(
+ CellStoreType::iterator& itPos, const ScAddress& /*rSrcPos*/, const ScAddress& rDestPos,
+ const formula_block::const_iterator& itBegin, const formula_block::const_iterator& itEnd)
+{
+ std::vector<ScFormulaCell*> aCloned;
+ aCloned.reserve(std::distance(itBegin, itEnd));
+ ScAddress aDestPos = rDestPos;
+ for (formula_block::const_iterator it = itBegin; it != itEnd; ++it, aDestPos.IncRow())
+ {
+ const ScFormulaCell& rOld = **it;
+ if (rOld.GetDirty() && getSrcDoc().GetAutoCalc())
+ const_cast<ScFormulaCell&>(rOld).Interpret();
+
+ aCloned.push_back(new ScFormulaCell(rOld, getDestDoc(), aDestPos));
+ }
+
+ itPos = getDestCellStore().set(itPos, rDestPos.Row(), aCloned.begin(), aCloned.end());
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx
index 75362ba7bfc2..169d2f7ef6d7 100644
--- a/sc/source/core/data/cellvalue.cxx
+++ b/sc/source/core/data/cellvalue.cxx
@@ -9,6 +9,7 @@
#include "cellvalue.hxx"
#include "document.hxx"
+#include "column.hxx"
#include "cell.hxx"
#include "formulacell.hxx"
#include "editeng/editobj.hxx"
@@ -182,6 +183,41 @@ void ScCellValue::clear()
mfValue = 0.0;
}
+void ScCellValue::set( double fValue )
+{
+ clear();
+ meType = CELLTYPE_VALUE;
+ mfValue = fValue;
+}
+
+void ScCellValue::set( const OUString& rStr )
+{
+ clear();
+ meType = CELLTYPE_STRING;
+ mpString = new OUString(rStr);
+}
+
+void ScCellValue::set( const EditTextObject& rEditText )
+{
+ clear();
+ meType = CELLTYPE_EDIT;
+ mpEditText = rEditText.Clone();
+}
+
+void ScCellValue::set( const ScFormulaCell& rFormula )
+{
+ clear();
+ meType = CELLTYPE_FORMULA;
+ mpFormula = rFormula.Clone();
+}
+
+void ScCellValue::set( ScFormulaCell* pFormula )
+{
+ clear();
+ meType = CELLTYPE_FORMULA;
+ mpFormula = pFormula;
+}
+
void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
{
clear();
@@ -255,85 +291,87 @@ void ScCellValue::assign( const ScCellValue& rOther, ScDocument& rDestDoc, int n
}
}
-void ScCellValue::assign( const ScBaseCell& rCell )
+void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
{
- clear();
-
- meType = rCell.GetCellType();
switch (meType)
{
case CELLTYPE_STRING:
- mpString = new OUString(static_cast<const ScStringCell&>(rCell).GetString());
- break;
- case CELLTYPE_EDIT:
{
- const EditTextObject* p = static_cast<const ScEditCell&>(rCell).GetData();
- if (p)
- mpEditText = p->Clone();
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(rPos, *mpString, &aParam);
}
break;
+ case CELLTYPE_EDIT:
+ rDoc.SetEditText(rPos, mpEditText->Clone());
+ break;
case CELLTYPE_VALUE:
- mfValue = static_cast<const ScValueCell&>(rCell).GetValue();
+ rDoc.SetValue(rPos, mfValue);
break;
case CELLTYPE_FORMULA:
- mpFormula = static_cast<const ScFormulaCell&>(rCell).Clone();
+ rDoc.SetFormulaCell(rPos, mpFormula->Clone());
break;
default:
- meType = CELLTYPE_NONE; // reset to empty.
+ rDoc.SetEmptyCell(rPos);
}
}
-void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
+void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
{
switch (meType)
{
case CELLTYPE_STRING:
{
+ // Currently, string cannot be placed without copying.
ScSetStringParam aParam;
aParam.setTextInput();
rDoc.SetString(rPos, *mpString, &aParam);
+ delete mpString;
}
break;
case CELLTYPE_EDIT:
- rDoc.SetEditText(rPos, mpEditText->Clone());
+ // Cell takes the ownership of the text object.
+ rDoc.SetEditText(rPos, mpEditText);
break;
case CELLTYPE_VALUE:
rDoc.SetValue(rPos, mfValue);
break;
case CELLTYPE_FORMULA:
- rDoc.SetFormulaCell(rPos, mpFormula->Clone());
+ // This formula cell instance is directly placed in the document without copying.
+ rDoc.SetFormulaCell(rPos, mpFormula);
break;
default:
rDoc.SetEmptyCell(rPos);
}
+
+ meType = CELLTYPE_NONE;
+ mfValue = 0.0;
}
-void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
+void ScCellValue::release( ScColumn& rColumn, SCROW nRow )
{
switch (meType)
{
case CELLTYPE_STRING:
{
// Currently, string cannot be placed without copying.
- ScSetStringParam aParam;
- aParam.setTextInput();
- rDoc.SetString(rPos, *mpString, &aParam);
+ rColumn.SetRawString(nRow, *mpString);
delete mpString;
}
break;
case CELLTYPE_EDIT:
// Cell takes the ownership of the text object.
- rDoc.SetEditText(rPos, mpEditText);
+ rColumn.SetEditText(nRow, mpEditText);
break;
case CELLTYPE_VALUE:
- rDoc.SetValue(rPos, mfValue);
+ rColumn.SetValue(nRow, mfValue);
break;
case CELLTYPE_FORMULA:
// This formula cell instance is directly placed in the document without copying.
- rDoc.SetFormulaCell(rPos, mpFormula);
+ rColumn.SetFormulaCell(nRow, mpFormula);
break;
default:
- rDoc.SetEmptyCell(rPos);
+ rColumn.Delete(nRow);
}
meType = CELLTYPE_NONE;
@@ -403,52 +441,81 @@ void ScRefCellValue::assign( ScDocument& rDoc, const ScAddress& rPos )
*this = rDoc.GetRefCellValue(rPos);
}
-void ScRefCellValue::assign( ScBaseCell& rCell )
+void ScRefCellValue::assign( const sc::CellStoreType::const_iterator& itPos, size_t nOffset )
{
- clear();
+ switch (itPos->type)
+ {
+ case sc::element_type_numeric:
+ // Numeric cell
+ mfValue = sc::numeric_block::at(*itPos->data, nOffset);
+ meType = CELLTYPE_VALUE;
+ break;
+ case sc::element_type_string:
+ // String cell
+ mpString = &sc::string_block::at(*itPos->data, nOffset);
+ meType = CELLTYPE_STRING;
+ break;
+ case sc::element_type_edittext:
+ // Edit cell
+ mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
+ meType = CELLTYPE_EDIT;
+ break;
+ case sc::element_type_formula:
+ // Formula cell
+ mpFormula = sc::formula_block::at(*itPos->data, nOffset);
+ meType = CELLTYPE_FORMULA;
+ break;
+ default:
+ clear();
+ }
+}
- meType = rCell.GetCellType();
+void ScRefCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
+{
switch (meType)
{
case CELLTYPE_STRING:
- mpString = static_cast<const ScStringCell&>(rCell).GetStringPtr();
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(rPos, *mpString, &aParam);
+ }
break;
case CELLTYPE_EDIT:
- mpEditText = static_cast<const ScEditCell&>(rCell).GetData();
+ rDoc.SetEditText(rPos, ScEditUtil::Clone(*mpEditText, rDoc));
break;
case CELLTYPE_VALUE:
- mfValue = static_cast<const ScValueCell&>(rCell).GetValue();
+ rDoc.SetValue(rPos, mfValue);
break;
case CELLTYPE_FORMULA:
- mpFormula = static_cast<ScFormulaCell*>(&rCell);
+ rDoc.SetFormulaCell(rPos, new ScFormulaCell(*mpFormula, rDoc, rPos));
break;
default:
- meType = CELLTYPE_NONE; // reset to empty.
+ rDoc.SetEmptyCell(rPos);
}
}
-void ScRefCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
+void ScRefCellValue::commit( ScColumn& rColumn, SCROW nRow ) const
{
switch (meType)
{
case CELLTYPE_STRING:
- {
- ScSetStringParam aParam;
- aParam.setTextInput();
- rDoc.SetString(rPos, *mpString, &aParam);
- }
+ rColumn.SetRawString(nRow, *mpString);
break;
case CELLTYPE_EDIT:
- rDoc.SetEditText(rPos, mpEditText->Clone());
+ rColumn.SetEditText(nRow, ScEditUtil::Clone(*mpEditText, rColumn.GetDoc()));
break;
case CELLTYPE_VALUE:
- rDoc.SetValue(rPos, mfValue);
+ rColumn.SetValue(nRow, mfValue);
break;
case CELLTYPE_FORMULA:
- rDoc.SetFormulaCell(rPos, mpFormula->Clone());
+ {
+ ScAddress aDestPos(rColumn.GetCol(), nRow, rColumn.GetTab());
+ rColumn.SetFormulaCell(nRow, new ScFormulaCell(*mpFormula, rColumn.GetDoc(), aDestPos));
+ }
break;
default:
- rDoc.SetEmptyCell(rPos);
+ rColumn.Delete(nRow);
}
}
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 878255296911..1ac6471e9f74 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -35,28 +35,26 @@
#include "tokenarray.hxx"
#include "cellform.hxx"
#include "clipcontext.hxx"
+#include "types.hxx"
+#include "editutil.hxx"
+#include "cellclonehandler.hxx"
+#include "mtvcellfunc.hxx"
+#include "columnspanset.hxx"
+#include "scopetools.hxx"
#include <svl/poolcach.hxx>
#include <svl/zforlist.hxx>
#include <editeng/scripttypeitem.hxx>
+#include "editeng/fieldupdater.hxx"
#include <cstring>
#include <map>
#include <cstdio>
+#include <boost/scoped_ptr.hpp>
using ::editeng::SvxBorderLine;
using namespace formula;
-bool ColEntry::Less::operator() (const ColEntry& r1, const ColEntry& r2) const
-{
- return r1.nRow < r2.nRow;
-}
-
-bool ColDoubleEntry::LessByPtr::operator() (const ColDoubleEntry* p1, const ColDoubleEntry* p2) const
-{
- return p1->mnStart < p2->mnStart;
-}
-
namespace {
inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
@@ -75,25 +73,10 @@ ScNeededSizeOptions::ScNeededSizeOptions() :
{
}
-std::vector<ColEntry>::iterator ScColumn::Search( SCROW nRow )
-{
- // Find first cell whose position is equal or greater than nRow.
- ColEntry aBound;
- aBound.nRow = nRow;
- return std::lower_bound(maItems.begin(), maItems.end(), aBound, ColEntry::Less());
-}
-
-std::vector<ColEntry>::const_iterator ScColumn::Search( SCROW nRow ) const
-{
- // Find first cell whose position is equal or greater than nRow.
- ColEntry aBound;
- aBound.nRow = nRow;
- return std::lower_bound(maItems.begin(), maItems.end(), aBound, ColEntry::Less());
-}
-
ScColumn::ScColumn() :
maCellTextAttrs(MAXROWCOUNT),
maBroadcasters(MAXROWCOUNT),
+ maCells(MAXROWCOUNT),
nCol( 0 ),
pAttrArray( NULL ),
pDocument( NULL ),
@@ -126,135 +109,191 @@ SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
{
- // nothing:0, inside:1, bottom:2, left:4, top:8, right:16, open:32
- if ( maItems.empty() )
+ using namespace sc;
+
+ if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
return 0;
- if ( nRow1 == nRow2 )
+
+ ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
+
+ if (nRow1 == nRow2)
{
- SCSIZE nIndex;
- if ( Search( nRow1, nIndex ) )
- {
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA
- && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
- {
- ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
- return ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
- }
- }
- return 0;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
+ if (aPos.first->type != sc::element_type_formula)
+ return 0;
+
+ const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
+ if (!pCell->GetMatrixFlag())
+ return 0;
+
+ return pCell->GetMatrixEdge(aOrigin);
}
- else
+
+ bool bOpen = false;
+ sal_uInt16 nEdges = 0;
+
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ size_t nOffset = aPos.second;
+ SCROW nRow = nRow1;
+ for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
{
- ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
- bool bOpen = false;
- sal_uInt16 nEdges = 0;
- SCSIZE nIndex;
- Search( nRow1, nIndex );
- while ( nIndex < maItems.size() && maItems[nIndex].nRow <= nRow2 )
+ if (it->type != sc::element_type_formula)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA
- && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
- {
- nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
- if ( nEdges )
- {
- if ( nEdges & 8 )
- bOpen = true; // top edge opens, keep on looking
- else if ( !bOpen )
- return nEdges | 32; // there's something that wasn't opened
- else if ( nEdges & 1 )
- return nEdges; // inside
- // (nMask & 16 and (4 and not 16)) or
- // (nMask & 4 and (16 and not 4))
- if ( ((nMask & 16) && (nEdges & 4) && !(nEdges & 16))
- || ((nMask & 4) && (nEdges & 16) && !(nEdges & 4)) )
- return nEdges; // only left/right edge
- if ( nEdges & 2 )
- bOpen = false; // bottom edge closes
- }
- }
- nIndex++;
+ // Skip this block.
+ nRow += it->size - nOffset;
+ continue;
+ }
+
+ size_t nRowsToRead = nRow2 - nRow + 1;
+ size_t nEnd = std::min(it->size, nRowsToRead);
+ sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
+ std::advance(itCell, nOffset);
+ for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
+ {
+ // Loop inside the formula block.
+ const ScFormulaCell* pCell = *itCell;
+ if (!pCell->GetMatrixFlag())
+ continue;
+
+ nEdges = pCell->GetMatrixEdge(aOrigin);
+ if (!nEdges)
+ continue;
+
+ if (nEdges & MatrixEdgeTop)
+ bOpen = true; // top edge opens, keep on looking
+ else if (!bOpen)
+ return nEdges | MatrixEdgeOpen; // there's something that wasn't opened
+ else if (nEdges & MatrixEdgeInside)
+ return nEdges; // inside
+ // (nMask & 16 and (4 and not 16)) or
+ // (nMask & 4 and (16 and not 4))
+ if (((nMask & MatrixEdgeRight) && (nEdges & MatrixEdgeLeft) && !(nEdges & MatrixEdgeRight)) ||
+ ((nMask & MatrixEdgeLeft) && (nEdges & MatrixEdgeRight) && !(nEdges & MatrixEdgeLeft)))
+ return nEdges; // only left/right edge
+
+ if (nEdges & MatrixEdgeBottom)
+ bOpen = false; // bottom edge closes
}
- if ( bOpen )
- nEdges |= 32; // not closed, matrix continues
- return nEdges;
+
+ nRow += nEnd;
}
+ if (bOpen)
+ nEdges |= MatrixEdgeOpen; // not closed, matrix continues
+
+ return nEdges;
}
bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
{
- if ( rMark.IsMultiMarked() )
+ using namespace sc;
+
+ if (!rMark.IsMultiMarked())
+ return false;
+
+ ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
+ ScAddress aCurOrigin = aOrigin;
+
+ bool bOpen = false;
+ ScRangeList aRanges = rMark.GetMarkedRanges();
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
{
- bool bFound = false;
+ const ScRange& r = *aRanges[i];
+ if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
+ continue;
- ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
- ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID );
- SCROW nTop, nBottom;
- ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
- while ( !bFound && aMarkIter.Next( nTop, nBottom ) )
+ if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
+ continue;
+
+ SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
+ SCROW nRow = nTop;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ size_t nOffset = aPos.second;
+
+ for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
{
- bool bOpen = false;
- sal_uInt16 nEdges;
- SCSIZE nIndex;
- Search( nTop, nIndex );
- while ( !bFound && nIndex < maItems.size() && maItems[nIndex].nRow <= nBottom )
+ if (it->type != sc::element_type_formula)
+ {
+ // Skip this block.
+ nRow += it->size - nOffset;
+ continue;
+ }
+
+ // This is a formula cell block.
+ size_t nRowsToRead = nBottom - nRow + 1;
+ size_t nEnd = std::min(it->size, nRowsToRead);
+ sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
+ std::advance(itCell, nOffset);
+ for (size_t j = nOffset; j < nEnd; ++itCell, ++j)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA
- && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
+ // Loop inside the formula block.
+ const ScFormulaCell* pCell = *itCell;
+ if (!pCell->GetMatrixFlag())
+ // cell is not a part of a matrix.
+ continue;
+
+ sal_uInt16 nEdges = pCell->GetMatrixEdge(aOrigin);
+ if (!nEdges)
+ continue;
+
+ bool bFound = false;
+
+ if (nEdges & MatrixEdgeTop)
+ bOpen = true; // top edge opens, keep on looking
+ else if (!bOpen)
+ return true; // there's something that wasn't opened
+ else if (nEdges & MatrixEdgeInside)
+ bFound = true; // inside, all selected?
+
+ if ((((nEdges & MatrixEdgeLeft) | MatrixEdgeRight) ^ ((nEdges & MatrixEdgeRight) | MatrixEdgeLeft)))
+ // either left or right, but not both.
+ bFound = true; // only left/right edge, all selected?
+
+ if (nEdges & MatrixEdgeBottom)
+ bOpen = false; // bottom edge closes
+
+ if (bFound)
{
- nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
- if ( nEdges )
- {
- if ( nEdges & 8 )
- bOpen = true; // top edge opens, keep on looking
- else if ( !bOpen )
- return true; // there's something that wasn't opened
- else if ( nEdges & 1 )
- bFound = true; // inside, all selected?
- // (4 and not 16) or (16 and not 4)
- if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) )
- bFound = true; // only left/right edge, all selected?
- if ( nEdges & 2 )
- bOpen = false; // bottom edge closes
-
- if ( bFound )
- { // all selected?
- if ( aCurOrg != aOrg )
- { // new matrix to check?
- aCurOrg = aOrg;
- ScFormulaCell* pFCell;
- if ( ((ScFormulaCell*)pCell)->GetMatrixFlag()
- == MM_REFERENCE )
- pFCell = pDocument->GetFormulaCell(aOrg);
- else
- pFCell = (ScFormulaCell*)pCell;
- SCCOL nC;
- SCROW nR;
- pFCell->GetMatColsRows( nC, nR );
- ScRange aRange( aOrg, ScAddress(
- aOrg.Col() + nC - 1, aOrg.Row() + nR - 1,
- aOrg.Tab() ) );
- if ( rMark.IsAllMarked( aRange ) )
- bFound = false;
- }
- else
- bFound = false; // done already
- }
+ // Check if the matrix is inside the selection in its entirety.
+ //
+ // TODO: It's more efficient to skip the matrix range if
+ // it's within selection, to avoid checking it again and
+ // again.
+
+ if (aCurOrigin != aOrigin)
+ { // new matrix to check?
+ aCurOrigin = aOrigin;
+ const ScFormulaCell* pFCell;
+ if (pCell->GetMatrixFlag() == MM_REFERENCE)
+ pFCell = pDocument->GetFormulaCell(aOrigin);
+ else
+ pFCell = pCell;
+
+ SCCOL nC;
+ SCROW nR;
+ pFCell->GetMatColsRows(nC, nR);
+ ScRange aRange(aOrigin, ScAddress(aOrigin.Col()+nC-1, aOrigin.Row()+nR-1, aOrigin.Tab()));
+ if (rMark.IsAllMarked(aRange))
+ bFound = false;
}
+ else
+ bFound = false; // done already
}
- nIndex++;
+
+ if (bFound)
+ return true;
}
- if ( bOpen )
- return true;
+
+ nRow += nEnd;
}
- return bFound;
}
- else
- return false;
+
+ if (bOpen)
+ return true;
+
+ return false;
}
@@ -707,385 +746,484 @@ void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
delete pTemp;
}
-bool ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
+ScDocument& ScColumn::GetDoc()
{
- if ( maItems.empty() )
- {
- nIndex = 0;
- return false;
- }
- SCROW nMinRow = maItems[0].nRow;
- if ( nRow <= nMinRow )
- {
- nIndex = 0;
- return nRow == nMinRow;
- }
- SCROW nMaxRow = maItems.back().nRow;
- if ( nRow >= nMaxRow )
- {
- if ( nRow == nMaxRow )
- {
- nIndex = maItems.size() - 1;
- return true;
- }
- else
- {
- nIndex = maItems.size();
- return false;
- }
- }
+ return *pDocument;
+}
- long nOldLo, nOldHi;
- long nLo = nOldLo = 0;
- long nHi = nOldHi = std::min(static_cast<long>(maItems.size())-1, static_cast<long>(nRow) );
- long i = 0;
- bool bFound = false;
- // quite continuous distribution? => interpolating search
- bool bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < maItems.size() * 2);
- SCROW nR;
+const ScDocument& ScColumn::GetDoc() const
+{
+ return *pDocument;
+}
- while ( !bFound && nLo <= nHi )
- {
- if ( !bInterpol || nHi - nLo < 3 )
- i = (nLo+nHi) / 2; // no effort, no division by zero
- else
- { // interpolating search
- long nLoRow = maItems[nLo].nRow; // no unsigned underflow upon substraction
- i = nLo + (long)((long)(nRow - nLoRow) * (nHi - nLo)
- / (maItems[nHi].nRow - nLoRow));
- if ( i < 0 || static_cast<SCSIZE>(i) >= maItems.size() )
- { // oops ...
- i = (nLo+nHi) / 2;
- bInterpol = false;
- }
- }
- nR = maItems[i].nRow;
- if ( nR < nRow )
- {
- nLo = i+1;
- if ( bInterpol )
- {
- if ( nLo <= nOldLo )
- bInterpol = false;
- else
- nOldLo = nLo;
- }
- }
- else
- {
- if ( nR > nRow )
- {
- nHi = i-1;
- if ( bInterpol )
- {
- if ( nHi >= nOldHi )
- bInterpol = false;
- else
- nOldHi = nHi;
- }
- }
- else
- bFound = true;
- }
- }
- if (bFound)
- nIndex = static_cast<SCSIZE>(i);
- else
- nIndex = static_cast<SCSIZE>(nLo); // rear index
- return bFound;
+ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
+{
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ if (aPos.first == maCells.end())
+ return ScRefCellValue();
+
+ return GetCellValue(aPos.first, aPos.second);
}
-ScBaseCell* ScColumn::GetCell( SCROW nRow ) const
+ScRefCellValue ScColumn::GetCellValue( sc::CellStoreType::const_iterator& itPos, SCROW nRow ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- return maItems[nIndex].pCell;
- return NULL;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
+ itPos = aPos.first;
+ if (aPos.first == maCells.end())
+ return ScRefCellValue();
+
+ return GetCellValue(itPos, aPos.second);
}
-ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
+ScRefCellValue ScColumn::GetCellValue( sc::CellStoreType::const_iterator& itPos, size_t nOffset ) const
{
- ScRefCellValue aVal;
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- aVal.assign(*maItems[nIndex].pCell);
+ ScRefCellValue aVal; // Defaults to empty cell.
+ switch (itPos->type)
+ {
+ case sc::element_type_numeric:
+ // Numeric cell
+ aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
+ aVal.meType = CELLTYPE_VALUE;
+ break;
+ case sc::element_type_string:
+ // String cell
+ aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
+ aVal.meType = CELLTYPE_STRING;
+ break;
+ case sc::element_type_edittext:
+ // Edit cell
+ aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
+ aVal.meType = CELLTYPE_EDIT;
+ break;
+ case sc::element_type_formula:
+ // Formula cell
+ aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
+ aVal.meType = CELLTYPE_FORMULA;
+ break;
+ default:
+ ;
+ }
return aVal;
}
-void ScColumn::ReserveSize( SCSIZE nSize )
+void ScColumn::ReleaseCellValue( sc::CellStoreType::iterator& itPos, SCROW nRow, ScCellValue& rVal )
+{
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(itPos, nRow);
+ itPos = aPos.first; // Store it for the next iteration.
+ if (aPos.first == maCells.end())
+ return;
+
+ switch (itPos->type)
+ {
+ case sc::element_type_numeric:
+ // Numeric cell
+ itPos = maCells.release(itPos, nRow, rVal.mfValue);
+ rVal.meType = CELLTYPE_VALUE;
+ break;
+ case sc::element_type_string:
+ {
+ // Make a copy until we implement shared strings...
+ OUString aStr;
+ itPos = maCells.release(itPos, nRow, aStr);
+ rVal.mpString = new OUString(aStr);
+ rVal.meType = CELLTYPE_STRING;
+ }
+ break;
+ case sc::element_type_edittext:
+ itPos = maCells.release(itPos, nRow, rVal.mpEditText);
+ rVal.meType = CELLTYPE_EDIT;
+ break;
+ case sc::element_type_formula:
+ itPos = maCells.release(itPos, nRow, rVal.mpFormula);
+ rVal.meType = CELLTYPE_FORMULA;
+ break;
+ default:
+ ;
+ }
+}
+
+namespace {
+
+ScFormulaCell* cloneFormulaCell(ScDocument* pDoc, const ScAddress& rNewPos, ScFormulaCell& rOldCell)
{
- if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT))
- nSize = MAXROWCOUNT;
- if (nSize < maItems.size())
- nSize = maItems.size();
+ ScFormulaCell* pNew = new ScFormulaCell(rOldCell, *pDoc, rNewPos, SC_CLONECELL_ADJUST3DREL);
+ rOldCell.EndListeningTo(pDoc);
+ pNew->StartListeningTo(pDoc);
+ pNew->SetDirty();
+ return pNew;
+}
- maItems.reserve(nSize);
}
-// SwapRow for sorting
void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
{
+ typedef std::pair<sc::CellStoreType::iterator,size_t> CellPosType;
+
if (nRow1 == nRow2)
// Nothing to swap.
return;
- /* Simple swap of cell pointers does not work if broadcasters exist (crash
- if cell broadcasts directly or indirectly to itself). While swapping
- the cells, broadcasters have to remain at old positions! */
+ // Ensure that nRow1 < nRow2.
+ if (nRow2 < nRow1)
+ std::swap(nRow1, nRow2);
- ScBaseCell* pCell1 = 0;
- SCSIZE nIndex1;
- if ( Search( nRow1, nIndex1 ) )
- pCell1 = maItems[nIndex1].pCell;
+ // Broadcasters (if exist) should NOT be swapped.
- ScBaseCell* pCell2 = 0;
- SCSIZE nIndex2;
- if ( Search( nRow2, nIndex2 ) )
- pCell2 = maItems[nIndex2].pCell;
-
- // no cells found, nothing to do
- if ( !pCell1 && !pCell2 )
- return ;
-
- // swap variables if first cell is empty, to save some code below
- if ( !pCell1 )
- {
- ::std::swap( nRow1, nRow2 );
- ::std::swap( nIndex1, nIndex2 );
- ::std::swap( pCell1, pCell2 );
- }
-
- // from here: first cell (pCell1, nIndex1) exists always
+ CellPosType aPos1 = maCells.position(nRow1);
+ if (aPos1.first == maCells.end())
+ return;
- ScAddress aPos1( nCol, nRow1, nTab );
- ScAddress aPos2( nCol, nRow2, nTab );
+ CellPosType aPos2 = maCells.position(aPos1.first, nRow2);
+ if (aPos2.first == maCells.end())
+ return;
- CellType eType1 = pCell1->GetCellType();
- CellType eType2 = pCell2 ? pCell2->GetCellType() : CELLTYPE_NONE;
+ std::vector<SCROW> aRows;
+ aRows.reserve(2);
+ aRows.push_back(nRow1);
+ aRows.push_back(nRow2);
- ScFormulaCell* pFmlaCell1 = (eType1 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
- ScFormulaCell* pFmlaCell2 = (eType2 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
+ sc::CellStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
- // simple swap if no formula cells present
- if ( !pFmlaCell1 && !pFmlaCell2 )
+ if (it1->type == it2->type)
{
- if ( pCell2 )
+ // Both positions are of the same type. Do a simple value swap.
+ switch (it1->type)
{
- /* Both cells exist, no formula cells involved, a simple swap can
- be performed (but keep broadcasters and notes at old position). */
- maItems[nIndex1].pCell = pCell2;
- maItems[nIndex2].pCell = pCell1;
-
- // Swap text width values and script types.
- sc::CellTextAttr aVal1 = maCellTextAttrs.get<sc::CellTextAttr>(nRow1);
- sc::CellTextAttr aVal2 = maCellTextAttrs.get<sc::CellTextAttr>(nRow2);
- maCellTextAttrs.set(nRow1, aVal2);
- maCellTextAttrs.set(nRow2, aVal1);
-
- CellStorageModified();
+ case sc::element_type_empty:
+ // Both are empty. Nothing to swap.
+ return;
+ case sc::element_type_numeric:
+ std::swap(
+ sc::numeric_block::at(*it1->data, aPos1.second),
+ sc::numeric_block::at(*it2->data, aPos2.second));
+ break;
+ case sc::element_type_string:
+ std::swap(
+ sc::string_block::at(*it1->data, aPos1.second),
+ sc::string_block::at(*it2->data, aPos2.second));
+ break;
+ case sc::element_type_edittext:
+ std::swap(
+ sc::edittext_block::at(*it1->data, aPos1.second),
+ sc::edittext_block::at(*it2->data, aPos2.second));
+ break;
+ case sc::element_type_formula:
+ {
+ // Swapping of formula cells involve adjustment of references wrt their positions.
+ sc::formula_block::iterator itf1 = sc::formula_block::begin(*it1->data);
+ sc::formula_block::iterator itf2 = sc::formula_block::begin(*it2->data);
+ std::advance(itf1, aPos1.second);
+ std::advance(itf2, aPos2.second);
+
+ // TODO: Find out a way to adjust references without cloning new instances.
+ boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
+ boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
+ ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2);
+ ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1);
+ *itf1 = pNew1;
+ *itf2 = pNew2;
+ }
+ break;
+ default:
+ ;
}
- else
- {
- // Only cell 1 exists; cell 2 is empty. Move cell 1 from to row
- // 2.
- // remove ColEntry at old position
- maItems.erase( maItems.begin() + nIndex1 );
- maCellTextAttrs.set_empty(nRow1, nRow1);
+ SwapCellTextAttrs(nRow1, nRow2);
+ CellStorageModified();
+ BroadcastCells(aRows);
+ return;
+ }
+
+ // The two cells are of different types.
- // Empty text width at the cell 1 position. For now, we don't
- // transfer the old value to the cell 2 position since Insert() is
- // quite complicated.
- CellStorageModified();
+ sc::CellStoreType::const_iterator cit = it1;
+ ScRefCellValue aCell1 = GetCellValue(cit, nRow1);
+ cit = it2;
+ ScRefCellValue aCell2 = GetCellValue(cit, nRow2);
- // insert ColEntry at new position.
- Insert( nRow2, pCell1 );
+ if (aCell1.meType == CELLTYPE_NONE)
+ {
+ // cell 1 is empty and cell 2 is not.
+ switch (aCell2.meType)
+ {
+ case CELLTYPE_VALUE:
+ it1 = maCells.set(it1, nRow1, aCell2.mfValue); // it2 becomes invalid.
+ maCells.set_empty(it1, nRow2, nRow2);
+ break;
+ case CELLTYPE_STRING:
+ it1 = maCells.set(it1, nRow1, *aCell2.mpString);
+ maCells.set_empty(it1, nRow2, nRow2);
+ break;
+ case CELLTYPE_EDIT:
+ {
+ it1 = maCells.set(it1, nRow1, aCell2.mpEditText);
+ EditTextObject* p;
+ maCells.release(it1, nRow2, p);
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
+ it1 = maCells.set(it1, nRow1, pNew);
+ maCells.set_empty(it1, nRow2, nRow2); // original formula cell gets deleted.
+ }
+ break;
+ default:
+ ;
}
+ SwapCellTextAttrs(nRow1, nRow2);
+ CellStorageModified();
+ BroadcastCells(aRows);
return;
}
- // from here: at least one of the cells is a formula cell
+ if (aCell2.meType == CELLTYPE_NONE)
+ {
+ // cell 1 is not empty and cell 2 is empty.
+ switch (aCell1.meType)
+ {
+ case CELLTYPE_VALUE:
+ // Value is copied in Cell1.
+ it1 = maCells.set_empty(it1, nRow1, nRow1);
+ maCells.set(it1, nRow2, aCell1.mfValue);
+ break;
+ case CELLTYPE_STRING:
+ {
+ OUString aStr = *aCell1.mpString; // make a copy.
+ it1 = maCells.set_empty(it1, nRow1, nRow1); // original string is gone.
+ maCells.set(it1, nRow2, aStr);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ {
+ EditTextObject* p;
+ it1 = maCells.release(it1, nRow1, p);
+ maCells.set(it1, nRow2, p);
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
+ it1 = maCells.set_empty(it1, nRow1, nRow1); // original formula cell is gone.
+ maCells.set(it1, nRow2, pNew);
+ }
+ break;
+ default:
+ ;
+ }
- /* Never move any array formulas. Disabling sort if parts of array
- formulas are contained is done at UI. */
- if ( (pFmlaCell1 && (pFmlaCell1->GetMatrixFlag() != 0)) || (pFmlaCell2 && (pFmlaCell2->GetMatrixFlag() != 0)) )
+ SwapCellTextAttrs(nRow1, nRow2);
+ CellStorageModified();
+ BroadcastCells(aRows);
return;
+ }
- // do not swap, if formulas are equal
- if ( pFmlaCell1 && pFmlaCell2 )
+ // Neither cells are empty, and they are of different types.
+ switch (aCell1.meType)
{
- ScTokenArray* pCode1 = pFmlaCell1->GetCode();
- ScTokenArray* pCode2 = pFmlaCell2->GetCode();
-
- if (pCode1->GetLen() == pCode2->GetLen()) // not-UPN
+ case CELLTYPE_VALUE:
{
- bool bEqual = true;
- sal_uInt16 nLen = pCode1->GetLen();
- FormulaToken** ppToken1 = pCode1->GetArray();
- FormulaToken** ppToken2 = pCode2->GetArray();
- for (sal_uInt16 i=0; i<nLen; i++)
+ switch (aCell2.meType)
{
- if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ||
- ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() )
+ case CELLTYPE_STRING:
+ it1 = maCells.set(it1, nRow1, *aCell2.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ {
+ it1 = maCells.set(it1, nRow1, aCell2.mpEditText);
+ EditTextObject* p;
+ it1 = maCells.release(it1, nRow2, p);
+ }
+ break;
+ case CELLTYPE_FORMULA:
{
- bEqual = false;
- break;
+ ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
+ it1 = maCells.set(it1, nRow1, pNew);
+ // The old formula cell will get overwritten below.
}
+ break;
+ default:
+ ;
}
- // do not swap formula cells with equal formulas
- if (bEqual)
+ maCells.set(it1, nRow2, aCell1.mfValue);
+ }
+ break;
+ case CELLTYPE_STRING:
+ {
+ OUString aStr = *aCell1.mpString; // make a copy.
+ switch (aCell2.meType)
{
- return;
+ case CELLTYPE_VALUE:
+ it1 = maCells.set(it1, nRow1, aCell2.mfValue);
+ break;
+ case CELLTYPE_EDIT:
+ {
+ it1 = maCells.set(it1, nRow1, aCell2.mpEditText);
+ EditTextObject* p;
+ it1 = maCells.release(it1, nRow2, p); // prevent it being overwritten.
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ // cell 1 - string, cell 2 - formula
+ ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
+ it1 = maCells.set(it1, nRow1, pNew);
+ // Old formula cell will get overwritten below.
+ }
+ break;
+ default:
+ ;
}
+
+ maCells.set(it1, nRow2, aStr);
}
- }
+ break;
+ case CELLTYPE_EDIT:
+ {
+ EditTextObject* p;
+ it1 = maCells.release(it1, nRow1, p);
- /* Create clone of pCell1 at position of pCell2 (pCell1 exists always, see
- variable swapping above).*/
- ScBaseCell* pNew2 = pCell1->Clone( *pDocument, aPos2, SC_CLONECELL_ADJUST3DREL );
+ switch (aCell2.meType)
+ {
+ case CELLTYPE_VALUE:
+ it1 = maCells.set(it1, nRow1, aCell2.mfValue);
+ break;
+ case CELLTYPE_STRING:
+ it1 = maCells.set(it1, nRow1, *aCell2.mpString);
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
+ it1 = maCells.set(it1, nRow1, pNew);
+ // Old formula cell will get overwritten below.
+ }
+ break;
+ default:
+ ;
+ }
- /* Create clone of pCell2 at position of pCell1. Do not clone the note,
- but move pointer of old note to new cell. */
- ScBaseCell* pNew1 = 0;
- if ( pCell2 )
- {
- pNew1 = pCell2->Clone( *pDocument, aPos1, SC_CLONECELL_ADJUST3DREL );
- }
+ maCells.set(it1, nRow2, aCell1.mpEditText);
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
+ switch (aCell2.meType)
+ {
+ case CELLTYPE_VALUE:
+ it1 = maCells.set(it1, nRow1, aCell2.mfValue);
+ break;
+ case CELLTYPE_STRING:
+ it1 = maCells.set(it1, nRow1, *aCell2.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ {
+ it1 = maCells.set(it1, nRow1, aCell2.mpEditText);
+ EditTextObject* p;
+ it1 = maCells.release(it1, nRow2, p);
+ }
+ break;
+ default:
+ ;
+ }
- /* Insert the new cells. Old cell has to be deleted, if there is no new
- cell (call to Insert deletes old cell by itself). */
- if ( !pNew1 )
- Delete( nRow1 ); // deletes pCell1
- else
- Insert( nRow1, pNew1 ); // deletes pCell1, inserts pNew1
+ maCells.set(it1, nRow2, pNew);
+ }
+ break;
+ default:
+ ;
+ }
- if ( pCell2 && !pNew2 )
- Delete( nRow2 ); // deletes pCell2
- else if ( pNew2 )
- Insert( nRow2, pNew2 ); // deletes pCell2 (if existing), inserts pNew2
+ SwapCellTextAttrs(nRow1, nRow2);
+ CellStorageModified();
+ BroadcastCells(aRows);
}
+namespace {
-void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
+/**
+ * Adjust references in formula cell with respect to column-wise relocation.
+ */
+void updateRefInFormulaCell( ScFormulaCell& rCell, SCCOL nCol, SCTAB nTab, SCCOL nColDiff )
{
- ScBaseCell* pCell1 = 0;
- SCSIZE nIndex1;
- if ( Search( nRow, nIndex1 ) )
- pCell1 = maItems[nIndex1].pCell;
-
- ScBaseCell* pCell2 = 0;
- SCSIZE nIndex2;
- if ( rCol.Search( nRow, nIndex2 ) )
- pCell2 = rCol.maItems[nIndex2].pCell;
-
- // reverse call if own cell is missing (ensures own existing cell in following code)
- if( !pCell1 )
- {
- if( pCell2 )
- rCol.SwapCell( nRow, *this );
- return;
- }
-
- // from here: own cell (pCell1, nIndex1) exists always
+ ScRange aRange(ScAddress(nCol, 0, nTab), ScAddress(nCol, MAXROW, nTab));
+ rCell.aPos.SetCol(nCol);
+ rCell.UpdateReference(URM_MOVE, aRange, nColDiff, 0, 0);
+}
- ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
- ScFormulaCell* pFmlaCell2 = (pCell2 && (pCell2->GetCellType() == CELLTYPE_FORMULA)) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
+}
- if ( pCell2 )
- {
- // Both cell 1 and cell 2 exist. Swap them.
+void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
+{
+ ScFormulaCell* pCell1 = maCells.get<ScFormulaCell*>(nRow);
+ ScFormulaCell* pCell2 = rCol.maCells.get<ScFormulaCell*>(nRow);
+ if (pCell1)
+ updateRefInFormulaCell(*pCell1, rCol.nCol, nTab, rCol.nCol - nCol);
+ if (pCell2)
+ updateRefInFormulaCell(*pCell2, nCol, nTab, nCol - rCol.nCol);
- maItems[nIndex1].pCell = pCell2;
- rCol.maItems[nIndex2].pCell = pCell1;
+ maCells.swap(nRow, nRow, rCol.maCells, nRow);
+ maCellTextAttrs.swap(nRow, nRow, rCol.maCellTextAttrs, nRow);
- // update references
- SCsCOL dx = rCol.nCol - nCol;
- if ( pFmlaCell1 )
- {
- ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
- ScAddress( rCol.nCol, MAXROW, nTab ) );
- pFmlaCell1->aPos.SetCol( rCol.nCol );
- pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
- }
- if ( pFmlaCell2 )
- {
- ScRange aRange( ScAddress( nCol, 0, nTab ),
- ScAddress( nCol, MAXROW, nTab ) );
- pFmlaCell2->aPos.SetCol( nCol );
- pFmlaCell2->UpdateReference(URM_MOVE, aRange, -dx, 0, 0);
- }
+ CellStorageModified();
+ rCol.CellStorageModified();
+}
- // Swap text width values and script types.
- sc::CellTextAttr aVal1 = maCellTextAttrs.get<sc::CellTextAttr>(nRow);
- sc::CellTextAttr aVal2 = rCol.maCellTextAttrs.get<sc::CellTextAttr>(nRow);
- maCellTextAttrs.set(nRow, aVal2);
- rCol.maCellTextAttrs.set(nRow, aVal1);
- CellStorageModified();
- rCol.CellStorageModified();
- }
- else
- {
- // Cell 1 exists but cell 2 isn't.
- maItems.erase(maItems.begin() + nIndex1);
+bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
+{
+ if (IsEmpty())
+ return true;
- // update references
- SCsCOL dx = rCol.nCol - nCol;
- if ( pFmlaCell1 )
- {
- ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
- ScAddress( rCol.nCol, MAXROW, nTab ) );
- pFmlaCell1->aPos.SetCol( rCol.nCol );
- pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
- }
+ // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it->type != sc::element_type_empty)
+ return false;
- maCellTextAttrs.set_empty(nRow, nRow);
- CellStorageModified();
+ // Get the length of the remaining empty segment.
+ size_t nLen = it->size - aPos.second;
+ SCROW nNextNonEmptyRow = nStartRow + nLen;
+ if (nNextNonEmptyRow <= nEndRow)
+ return false;
- // We don't transfer the text width to the destination column because
- // of Insert()'s complexity.
+ // AttrArray only looks for merged cells
- // insert
- rCol.Insert(nRow, pCell1);
- }
+ return pAttrArray ? pAttrArray->TestInsertCol(nStartRow, nEndRow) : true;
}
-bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
+bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
{
- if (!IsEmpty())
+ // AttrArray only looks for merged cells
{
- bool bTest = true;
- if ( !maItems.empty() )
- for (SCSIZE i=0; (i<maItems.size()) && bTest; i++)
- bTest = (maItems[i].nRow < nStartRow) || (maItems[i].nRow > nEndRow);
-
- // AttrArray only looks for merged cells
-
- if ((bTest) && (pAttrArray))
- bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it->type == sc::element_type_empty && maCells.block_size() == 1)
+ // The entire cell array is empty.
+ return pAttrArray->TestInsertRow(nSize);
+ }
- //! consider the removed Attribute at Undo
+ // See if there would be any non-empty cell that gets pushed out.
- return bTest;
- }
- else
- return true;
-}
+ // Find the position of the last non-empty cell below nStartRow.
+ size_t nLastNonEmptyRow = MAXROW;
+ sc::CellStoreType::const_reverse_iterator it = maCells.rbegin(), itEnd = maCells.rend();
+ if (it->type == sc::element_type_empty)
+ nLastNonEmptyRow -= it->size;
+ if (nLastNonEmptyRow < static_cast<size_t>(nStartRow))
+ // No cells would get pushed out.
+ return pAttrArray->TestInsertRow(nSize);
-bool ScColumn::TestInsertRow( SCSIZE nSize ) const
-{
- // AttrArray only looks for merged cells
+ if (nLastNonEmptyRow + nSize > static_cast<size_t>(MAXROW))
+ // At least one cell would get pushed out. Not good.
+ return false;
- if ( !maItems.empty() )
- return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
- maItems[maItems.size()-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
- else
- return pAttrArray->TestInsertRow( nSize );
+ return pAttrArray->TestInsertRow(nSize);
}
@@ -1096,93 +1234,64 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
maBroadcasters.insert_empty(nStartRow, nSize);
maBroadcasters.resize(MAXROWCOUNT);
- if ( maItems.empty() )
- return;
+ maCellTextAttrs.insert_empty(nStartRow, nSize);
+ maCellTextAttrs.resize(MAXROWCOUNT);
- SCSIZE i;
- Search( nStartRow, i );
- if ( i >= maItems.size() )
- return ;
+ maCells.insert_empty(nStartRow, nSize);
+ maCells.resize(MAXROWCOUNT);
bool bOldAutoCalc = pDocument->GetAutoCalc();
pDocument->SetAutoCalc( false ); // avoid recalculations
- SCSIZE nNewCount = maItems.size();
- bool bCountChanged = false;
- ScAddress aAdr( nCol, 0, nTab );
- ScHint aHint(SC_HINT_DATACHANGED, aAdr); // only areas (ScBaseCell* == NULL)
- ScAddress& rAddress = aHint.GetAddress();
- // for sparse occupation use single broadcasts, not ranges
- bool bSingleBroadcasts = (((maItems.back().nRow - maItems[i].nRow) /
- (maItems.size() - i)) > 1);
- if ( bSingleBroadcasts )
- {
- SCROW nLastBroadcast = MAXROW+1;
- for ( ; i < maItems.size(); i++)
- {
- SCROW nOldRow = maItems[i].nRow;
- // Change source broadcaster
- if ( nLastBroadcast != nOldRow )
- { // Do not broadcast a direct sequence twice
- rAddress.SetRow( nOldRow );
- pDocument->AreaBroadcast( aHint );
- }
- SCROW nNewRow = (maItems[i].nRow += nSize);
- // Change target broadcaster
- rAddress.SetRow( nNewRow );
- pDocument->AreaBroadcast( aHint );
- nLastBroadcast = nNewRow;
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
- if ( nNewRow > MAXROW && !bCountChanged )
- {
- nNewCount = i;
- bCountChanged = true;
- }
- }
- }
- else
+ // Get the position of the first affected cell.
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nStartRow+nSize);
+ sc::CellStoreType::iterator it = aPos.first;
+
+ // Update the positions of all affected formula cells.
+ if (it->type == sc::element_type_formula)
{
- rAddress.SetRow( maItems[i].nRow );
- ScRange aRange( rAddress );
- for ( ; i < maItems.size(); i++)
+ sc::formula_block::iterator itf = sc::formula_block::begin(*it->data);
+ sc::formula_block::iterator itfEnd = sc::formula_block::end(*it->data);
+ std::advance(itf, aPos.second);
+ for (; itf != itfEnd; ++itf)
{
- SCROW nNewRow = (maItems[i].nRow += nSize);
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
- if ( nNewRow > MAXROW && !bCountChanged )
- {
- nNewCount = i;
- bCountChanged = true;
- aRange.aEnd.SetRow( MAXROW );
- }
+ ScFormulaCell* pCell = *itf;
+ pCell->aPos.IncRow(nSize);
}
- if ( !bCountChanged )
- aRange.aEnd.SetRow( maItems.back().nRow );
- pDocument->AreaBroadcastInRange( aRange, aHint );
}
- if (bCountChanged)
+ for (++it; it != maCells.end(); ++it)
{
- // Some cells in the lower part of the cell array have been pushed out
- // beyond MAXROW. Delete them.
- std::vector<ColEntry>::iterator itBeg = maItems.begin();
- std::advance(itBeg, nNewCount);
- for (std::vector<ColEntry>::iterator it = itBeg; it != maItems.end(); ++it)
- it->pCell->Delete();
+ if (it->type != sc::element_type_formula)
+ continue;
- maItems.erase(itBeg, maItems.end());
+ sc::formula_block::iterator itf = sc::formula_block::begin(*it->data);
+ sc::formula_block::iterator itfEnd = sc::formula_block::end(*it->data);
+ for (; itf != itfEnd; ++itf)
+ {
+ ScFormulaCell* pCell = *itf;
+ pCell->aPos.IncRow(nSize);
+ }
}
+ CellStorageModified();
+
pDocument->SetAutoCalc( bOldAutoCalc );
- maCellTextAttrs.insert_empty(nStartRow, nSize);
- maCellTextAttrs.resize(MAXROWCOUNT);
- CellStorageModified();
+ // We *probably* don't need to broadcast here since the parent call seems
+ // to take care of it.
}
+namespace {
+
+class CopyToClipHandler : public sc::CellBlockCloneHandler
+{
+public:
+ CopyToClipHandler(ScDocument& rSrcDoc, ScDocument& rDestDoc, sc::CellStoreType& rDestCellStore) :
+ sc::CellBlockCloneHandler(rSrcDoc, rDestDoc, rDestCellStore) {}
+};
+
+}
void ScColumn::CopyToClip(
sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
@@ -1190,181 +1299,410 @@ void ScColumn::CopyToClip(
pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
rCxt.isKeepScenarioFlags() ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
- SCSIZE i;
- SCSIZE nBlockCount = 0;
- SCSIZE nStartIndex = 0, nEndIndex = 0;
- for (i = 0; i < maItems.size(); i++)
- if ((maItems[i].nRow >= nRow1) && (maItems[i].nRow <= nRow2))
- {
- if (!nBlockCount)
- nStartIndex = i;
- nEndIndex = i;
- ++nBlockCount;
+ CopyToClipHandler aHdl(*pDocument, *rColumn.pDocument, rColumn.maCells);
+ CopyCellsInRangeToColumn(NULL, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), aHdl, nRow1, nRow2, rColumn);
+}
+
+void ScColumn::CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol)
+{
+ if (nRow1 > nRow2)
+ return;
+
+ sc::ColumnBlockPosition aDestPos;
+ CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
+
+ // First, clear the destination column for the specified row range.
+ rDestCol.maCells.set_empty(nRow1, nRow2);
- // put interpreted cells in the clipboard in order to create other formats (text, graphics, ...)
+ aDestPos.miCellPos = rDestCol.maCells.begin();
- if ( maItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ size_t nOffset = aPos.second;
+ size_t nDataSize = 0;
+ size_t nCurRow = nRow1;
+
+ for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
+ {
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
+ {
+ // Truncate the block to copy to clipboard.
+ nDataSize = nRow2 - nCurRow + 1;
+ bLastBlock = true;
+ }
+
+ switch (it->type)
+ {
+ case sc::element_type_numeric:
+ {
+ sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::numeric_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_string:
{
- ScFormulaCell* pFCell = (ScFormulaCell*) maItems[i].pCell;
- if (pFCell->GetDirty() && pDocument->GetAutoCalc())
- pFCell->Interpret();
+ sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::string_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
}
+ break;
+ case sc::element_type_edittext:
+ {
+ sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::edittext_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+
+ // Convert to simple strings.
+ std::vector<OUString> aConverted;
+ aConverted.reserve(nDataSize);
+ for (; itData != itDataEnd; ++itData)
+ {
+ const EditTextObject& rObj = **itData;
+ aConverted.push_back(ScEditUtil::GetString(rObj));
+ }
+ aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, aConverted.begin(), aConverted.end());
+ }
+ break;
+ case sc::element_type_formula:
+ {
+ sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::formula_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+
+ // Interpret and convert to raw values.
+ for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
+ {
+ SCROW nRow = nCurRow + i;
+
+ ScFormulaCell& rFC = const_cast<ScFormulaCell&>(**itData);
+ if (rFC.GetDirty() && pDocument->GetAutoCalc())
+ rFC.Interpret();
+
+ if (rFC.GetErrCode())
+ // Skip cells with error.
+ break;
+
+ if (rFC.IsValue())
+ aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetValue());
+ else
+ aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetString());
+ }
+ }
+ break;
+ default:
+ ;
}
- if (nBlockCount)
- {
- rColumn.ReserveSize(rColumn.GetCellCount() + nBlockCount);
- ScAddress aOwnPos( nCol, 0, nTab );
- ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
- for (i = nStartIndex; i <= nEndIndex; i++)
+ if (bLastBlock)
+ break;
+ }
+}
+
+void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
+{
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ bool bSet = true;
+ switch (it->type)
+ {
+ case sc::element_type_numeric:
+ rDestCol.maCells.set(nDestRow, sc::numeric_block::at(*it->data, aPos.second));
+ break;
+ case sc::element_type_string:
+ rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
+ break;
+ case sc::element_type_edittext:
{
- aOwnPos.SetRow( maItems[i].nRow );
- aDestPos.SetRow( maItems[i].nRow );
- ScBaseCell* pNewCell = maItems[i].pCell->Clone( *rColumn.pDocument, aDestPos, SC_CLONECELL_DEFAULT );
- sc::ColumnBlockPosition* p = rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol);
- if (p)
- rColumn.Append(*p, aDestPos.Row(), pNewCell);
+ EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
+ if (pDocument == rDestCol.pDocument)
+ rDestCol.maCells.set(nDestRow, p->Clone());
else
- rColumn.Append(aDestPos.Row(), pNewCell);
+ rDestCol.maCells.set(nDestRow, ScEditUtil::Clone(*p, *rDestCol.pDocument));
}
+ break;
+ case sc::element_type_formula:
+ {
+ ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
+ if (p->GetDirty() && pDocument->GetAutoCalc())
+ p->Interpret();
+
+ ScAddress aDestPos = p->aPos;
+ aDestPos.SetRow(nDestRow);
+ ScFormulaCell* pNew = new ScFormulaCell(*p, *rDestCol.pDocument, aDestPos);
+ rDestCol.maCells.set(nDestRow, pNew);
+ }
+ break;
+ case sc::element_type_empty:
+ default:
+ // empty
+ rDestCol.maCells.set_empty(nDestRow, nDestRow);
+ bSet = false;
}
+
+ if (bSet)
+ rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
+ else
+ rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
}
namespace {
-class FindInRows : std::unary_function<ColEntry, bool>
+bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, sal_uInt16 nFlags)
{
- SCROW mnRow1;
- SCROW mnRow2;
-public:
- FindInRows(SCROW nRow1, SCROW nRow2) : mnRow1(nRow1), mnRow2(nRow2) {}
- bool operator() (const ColEntry& rEntry)
- {
- return mnRow1 <= rEntry.nRow && rEntry.nRow <= mnRow2;
- }
-};
+ sal_uInt32 nNumIndex = static_cast<const SfxUInt32Item*>(rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT))->GetValue();
+ short nType = rDoc.GetFormatTable()->GetType(nNumIndex);
+ if ((nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME))
+ return ((nFlags & IDF_DATETIME) != 0);
-class FindAboveRow : std::unary_function<ColEntry, bool>
+ return ((nFlags & IDF_VALUE) != 0);
+}
+
+class CopyAsLinkHandler : public sc::CellBlockCloneHandler
{
- SCROW mnRow;
-public:
- FindAboveRow(SCROW nRow) : mnRow(nRow) {}
- bool operator() (const ColEntry& rEntry)
+ sal_uInt16 mnCopyFlags;
+ std::vector<ScFormulaCell*> maCellBuffer;
+
+ ScFormulaCell* createRefCell(const ScAddress& rSrcPos, const ScAddress& rDestPos)
{
- return mnRow < rEntry.nRow;
+ ScSingleRefData aRef;
+ aRef.InitAddress(rSrcPos); // Absolute reference.
+ aRef.SetFlag3D(true);
+
+ ScTokenArray aArr;
+ aArr.AddSingleReference(aRef);
+ return new ScFormulaCell(&getDestDoc(), rDestPos, &aArr);
}
-};
-struct DeleteCell : std::unary_function<ColEntry, void>
-{
- void operator() (ColEntry& rEntry)
+ template<typename _DataBlock>
+ void createRefBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const typename _DataBlock::const_iterator& itBegin, const typename _DataBlock::const_iterator& itEnd)
{
- rEntry.pCell->Delete();
+ maCellBuffer.clear();
+ maCellBuffer.reserve(std::distance(itBegin, itEnd));
+ ScAddress aSrcPos = rSrcPos;
+ ScAddress aDestPos = rDestPos;
+ for (typename _DataBlock::const_iterator it = itBegin; it != itEnd; ++it, aSrcPos.IncRow(), aDestPos.IncRow())
+ maCellBuffer.push_back(createRefCell(aSrcPos, aDestPos));
+
+ itPos = getDestCellStore().set(itPos, rDestPos.Row(), maCellBuffer.begin(), maCellBuffer.end());
}
-};
-}
+public:
+ CopyAsLinkHandler(
+ ScDocument& rSrcDoc, ScDocument& rDestDoc, sc::CellStoreType& rDestCellStore, sal_uInt16 nCopyFlags) :
+ sc::CellBlockCloneHandler(rSrcDoc, rDestDoc, rDestCellStore),
+ mnCopyFlags(nCopyFlags) {}
-void ScColumn::CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol)
-{
- if (nRow1 > nRow2)
- return;
+ virtual void cloneDoubleBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::numeric_block::const_iterator& itBegin, const sc::numeric_block::const_iterator& itEnd)
+ {
+ if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == 0)
+ return;
- CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
+ ScAddress aSrcPos = rSrcPos;
+ ScAddress aDestPos = rDestPos;
+ for (sc::numeric_block::const_iterator it = itBegin; it != itEnd; ++it, aSrcPos.IncRow(), aDestPos.IncRow())
+ {
+ if (!canCopyValue(getSrcDoc(), aSrcPos, mnCopyFlags))
+ continue;
- // First, clear the destination column for the row range specified.
- std::vector<ColEntry>::iterator it, itEnd;
+ itPos = getDestCellStore().set(itPos, aDestPos.Row(), createRefCell(aSrcPos, aDestPos));
+ }
+
+ }
- it = std::find_if(rDestCol.maItems.begin(), rDestCol.maItems.end(), FindInRows(nRow1, nRow2));
- if (it != rDestCol.maItems.end())
+ virtual void cloneStringBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::string_block::const_iterator& itBegin, const sc::string_block::const_iterator& itEnd)
{
- itEnd = std::find_if(it, rDestCol.maItems.end(), FindAboveRow(nRow2));
- std::for_each(it, itEnd, DeleteCell());
- rDestCol.maItems.erase(it, itEnd);
+ if (!(mnCopyFlags & IDF_STRING))
+ return;
+
+ createRefBlock<sc::string_block>(itPos, rSrcPos, rDestPos, itBegin, itEnd);
}
- // Determine the range of cells in the original column that need to be copied.
- it = std::find_if(maItems.begin(), maItems.end(), FindInRows(nRow1, nRow2));
- if (it == maItems.end())
- // Nothing to copy.
- return;
+ virtual void cloneEditTextBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::edittext_block::const_iterator& itBegin, const sc::edittext_block::const_iterator& itEnd)
+ {
+ if (!(mnCopyFlags & IDF_STRING))
+ return;
+
+ createRefBlock<sc::edittext_block>(itPos, rSrcPos, rDestPos, itBegin, itEnd);
+ }
- itEnd = std::find_if(it, maItems.end(), FindAboveRow(nRow2));
+ virtual void cloneFormulaBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::formula_block::const_iterator& itBegin, const sc::formula_block::const_iterator& itEnd)
+ {
+ if (!(mnCopyFlags & IDF_FORMULA))
+ return;
- // Clone and staticize all cells that need to be copied.
- std::vector<ColEntry> aCopied;
- aCopied.reserve(std::distance(it, itEnd));
- for (; it != itEnd; ++it)
+ createRefBlock<sc::formula_block>(itPos, rSrcPos, rDestPos, itBegin, itEnd);
+ }
+};
+
+class CopyByCloneHandler : public sc::CellBlockCloneHandler
+{
+ sal_uInt16 mnCopyFlags;
+
+ void cloneFormulaCell(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ ScFormulaCell& rSrcCell)
{
- ColEntry aEntry;
- aEntry.nRow = it->nRow;
- switch (it->pCell->GetCellType())
+ bool bCloneValue = (mnCopyFlags & IDF_VALUE) != 0;
+ bool bCloneDateTime = (mnCopyFlags & IDF_DATETIME) != 0;
+ bool bCloneString = (mnCopyFlags & IDF_STRING) != 0;
+ bool bCloneSpecialBoolean = (mnCopyFlags & IDF_SPECIAL_BOOLEAN) != 0;
+ bool bCloneFormula = (mnCopyFlags & IDF_FORMULA) != 0;
+
+ bool bForceFormula = false;
+
+ if (bCloneSpecialBoolean)
{
- case CELLTYPE_VALUE:
+ // See if the formula consists of =TRUE() or =FALSE().
+ ScTokenArray* pCode = rSrcCell.GetCode();
+ if (pCode && pCode->GetLen() == 1)
{
- const ScValueCell& rCell = static_cast<const ScValueCell&>(*it->pCell);
- aEntry.pCell = new ScValueCell(rCell.GetValue());
- aCopied.push_back(aEntry);
+ const formula::FormulaToken* p = pCode->First();
+ if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
+ // This is a boolean formula.
+ bForceFormula = true;
}
- break;
- case CELLTYPE_STRING:
+ }
+
+ if (bForceFormula || bCloneFormula)
+ {
+ // Clone as formula cell.
+ itPos = getDestCellStore().set(
+ itPos, rDestPos.Row(), new ScFormulaCell(rSrcCell, getDestDoc(), rDestPos));
+
+ return;
+ }
+
+ if (getDestDoc().IsUndo())
+ return;
+
+ if (bCloneValue)
+ {
+ sal_uInt16 nErr = rSrcCell.GetErrCode();
+ if (nErr)
{
- const ScStringCell& rCell = static_cast<const ScStringCell&>(*it->pCell);
- aEntry.pCell = new ScStringCell(rCell.GetString());
- aCopied.push_back(aEntry);
+ // error codes are cloned with values
+ ScFormulaCell* pErrCell = new ScFormulaCell(&getDestDoc(), rDestPos);
+ pErrCell->SetErrCode(nErr);
+ itPos = getDestCellStore().set(
+ itPos, rDestPos.Row(), new ScFormulaCell(rSrcCell, getDestDoc(), rDestPos));
+ return;
}
- break;
- case CELLTYPE_EDIT:
+ }
+
+ if (bCloneValue || bCloneDateTime)
+ {
+ if (rSrcCell.IsValue())
{
- // Convert to a simple string cell.
- const ScEditCell& rCell = static_cast<const ScEditCell&>(*it->pCell);
- aEntry.pCell = new ScStringCell(rCell.GetString());
- aCopied.push_back(aEntry);
+ if (canCopyValue(getSrcDoc(), rSrcPos, mnCopyFlags))
+ itPos = getDestCellStore().set(itPos, rDestPos.Row(), rSrcCell.GetValue());
+
+ return;
}
- break;
- case CELLTYPE_FORMULA:
+ }
+
+ if (bCloneString)
+ {
+ OUString aStr = rSrcCell.GetString();
+ if (aStr.isEmpty())
+ // Don't create empty string cells.
+ return;
+
+ if (rSrcCell.IsMultilineResult())
{
- ScFormulaCell& rCell = static_cast<ScFormulaCell&>(*it->pCell);
- if (rCell.GetDirty() && pDocument->GetAutoCalc())
- rCell.Interpret();
-
- if (rCell.GetErrCode())
- // Skip cells with error.
- break;
-
- if (rCell.IsValue())
- aEntry.pCell = new ScValueCell(rCell.GetValue());
- else
- aEntry.pCell = new ScStringCell(rCell.GetString());
- aCopied.push_back(aEntry);
+ // Clone as an edit text object.
+ EditEngine& rEngine = getDestDoc().GetEditEngine();
+ rEngine.SetText(aStr);
+ itPos = getDestCellStore().set(itPos, rDestPos.Row(), rEngine.CreateTextObject());
}
- break;
- default:
- ; // ignore the rest.
+ else
+ itPos = getDestCellStore().set(itPos, rDestPos.Row(), aStr);
}
}
- // Insert the cells into destination column. At this point the
- // destination column shouldn't have any cells within the specified range.
- it = std::find_if(rDestCol.maItems.begin(), rDestCol.maItems.end(), FindAboveRow(nRow2));
- rDestCol.maItems.insert(it, aCopied.begin(), aCopied.end());
-}
+public:
+ CopyByCloneHandler(ScDocument& rSrcDoc, ScDocument& rDestDoc, sc::CellStoreType& rDestCellStore, sal_uInt16 nCopyFlags) :
+ sc::CellBlockCloneHandler(rSrcDoc,rDestDoc,rDestCellStore),
+ mnCopyFlags(nCopyFlags)
+ {
+ }
-void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
-{
- SCSIZE nIndex;
- if (!Search(nSrcRow, nIndex))
+ virtual void cloneDoubleBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::numeric_block::const_iterator& itBegin, const sc::numeric_block::const_iterator& itEnd)
{
- // Source cell is empty. Remove the destination cell if one exists.
- rDestCol.Delete(nDestRow);
- return;
+ if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == 0)
+ return;
+
+ ScAddress aSrcPos = rSrcPos;
+ ScAddress aDestPos = rDestPos;
+ for (sc::numeric_block::const_iterator it = itBegin; it != itEnd; ++it, aSrcPos.IncRow(), aDestPos.IncRow())
+ {
+ if (!canCopyValue(getSrcDoc(), aSrcPos, mnCopyFlags))
+ continue;
+
+ itPos = getDestCellStore().set(itPos, aDestPos.Row(), *it);
+ }
}
- ScBaseCell* pDestCell =
- maItems[nSrcRow].pCell->Clone(
- *rDestCol.pDocument, ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab));
+ virtual void cloneStringBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& /*rSrcPos*/, const ScAddress& rDestPos,
+ const sc::string_block::const_iterator& itBegin, const sc::string_block::const_iterator& itEnd)
+ {
+ if (!(mnCopyFlags & IDF_STRING))
+ return;
+
+ ScAddress aDestPos = rDestPos;
+ for (sc::string_block::const_iterator it = itBegin; it != itEnd; ++it, aDestPos.IncRow())
+ {
+ const OUString& rStr = *it;
+ if (rStr.isEmpty())
+ // String cell with empty value is used to special-case cell value removal.
+ itPos = getDestCellStore().set_empty(itPos, aDestPos.Row(), aDestPos.Row());
+ else
+ itPos = getDestCellStore().set(itPos, aDestPos.Row(), rStr);
+ }
+ }
+
+ virtual void cloneEditTextBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::edittext_block::const_iterator& itBegin, const sc::edittext_block::const_iterator& itEnd)
+ {
+ if (!(mnCopyFlags & IDF_STRING))
+ return;
+
+ sc::CellBlockCloneHandler::cloneEditTextBlock(itPos, rSrcPos, rDestPos, itBegin, itEnd);
+ }
+
+ virtual void cloneFormulaBlock(
+ sc::CellStoreType::iterator& itPos, const ScAddress& rSrcPos, const ScAddress& rDestPos,
+ const sc::formula_block::const_iterator& itBegin, const sc::formula_block::const_iterator& itEnd)
+ {
+ ScAddress aSrcPos = rSrcPos;
+ ScAddress aDestPos = rDestPos;
+ for (sc::formula_block::const_iterator it = itBegin; it != itEnd; ++it, aSrcPos.IncRow(), aDestPos.IncRow())
+ cloneFormulaCell(itPos, aSrcPos, aDestPos, const_cast<ScFormulaCell&>(**it));
+ }
+};
- rDestCol.Insert(nDestRow, pDestCell);
}
void ScColumn::CopyToColumn(
@@ -1416,60 +1754,14 @@ void ScColumn::CopyToColumn(
if ((nFlags & IDF_CONTENTS) != 0)
{
- SCSIZE i;
- SCSIZE nBlockCount = 0;
- SCSIZE nStartIndex = 0, nEndIndex = 0;
- for (i = 0; i < maItems.size(); i++)
- if ((maItems[i].nRow >= nRow1) && (maItems[i].nRow <= nRow2))
- {
- if (!nBlockCount)
- nStartIndex = i;
- nEndIndex = i;
- ++nBlockCount;
- }
+ boost::scoped_ptr<sc::CellBlockCloneHandler> pHdl(NULL);
- if (nBlockCount)
- {
- rColumn.ReserveSize(rColumn.GetCellCount() + nBlockCount);
- ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
- for (i = nStartIndex; i <= nEndIndex; i++)
- {
- aDestPos.SetRow( maItems[i].nRow );
- ScBaseCell* pNew = bAsLink ?
- CreateRefCell( rColumn.pDocument, aDestPos, i, nFlags ) :
- CloneCell( i, nFlags, *rColumn.pDocument, aDestPos );
+ if (bAsLink)
+ pHdl.reset(new CopyAsLinkHandler(*pDocument, *rColumn.pDocument, rColumn.maCells, nFlags));
+ else
+ pHdl.reset(new CopyByCloneHandler(*pDocument, *rColumn.pDocument, rColumn.maCells, nFlags));
- if (pNew)
- {
- // Special case to allow removing of cell instances. A
- // string cell with empty content is used to indicate an
- // empty cell.
- sc::ColumnBlockPosition* p = rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol);
- if (pNew->GetCellType() == CELLTYPE_STRING)
- {
- OUString aStr = static_cast<ScStringCell*>(pNew)->GetString();
- if (aStr.isEmpty())
- // A string cell with empty string. Delete the cell itself.
- rColumn.Delete(maItems[i].nRow);
- else
- {
- // non-empty string cell
- if (p)
- rColumn.Insert(*p, maItems[i].nRow, pNew);
- else
- rColumn.Insert(maItems[i].nRow, pNew);
- }
- }
- else
- {
- if (p)
- rColumn.Insert(*p, maItems[i].nRow, pNew);
- else
- rColumn.Insert(maItems[i].nRow, pNew);
- }
- }
- }
- }
+ CopyCellsInRangeToColumn(NULL, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), *pHdl, nRow1, nRow2, rColumn);
}
}
@@ -1490,23 +1782,26 @@ void ScColumn::UndoToColumn(
void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
{
- ScDocument& rDestDoc = *rDestCol.pDocument;
- ScAddress aOwnPos( nCol, 0, nTab );
- ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab );
+ // Copy cells from this column to the destination column only for those
+ // rows that are present in the position column.
- SCSIZE nPosCount = rPosCol.maItems.size();
- for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++)
- {
- aOwnPos.SetRow( rPosCol.maItems[nPosIndex].nRow );
- aDestPos.SetRow( aOwnPos.Row() );
- SCSIZE nThisIndex;
- if ( Search( aDestPos.Row(), nThisIndex ) )
- {
- ScBaseCell* pNew = maItems[nThisIndex].pCell->Clone( rDestDoc, aDestPos );
- rDestCol.Insert( aDestPos.Row(), pNew );
- }
- }
+ sc::CellBlockCloneHandler aHdl(*pDocument, *rDestCol.pDocument, rDestCol.maCells);
+ sc::ColumnBlockConstPosition aSrcPos;
+ sc::ColumnBlockPosition aDestPos;
+ InitBlockPosition(aSrcPos);
+ rDestCol.InitBlockPosition(aDestPos);
+
+ // First, mark all the non-empty cell ranges from the position column.
+ sc::SingleColumnSpanSet aRangeSet;
+ aRangeSet.scan(rPosCol);
+ // Now, copy cells from this column to the destination column for those
+ // marked row ranges.
+ sc::SingleColumnSpanSet::SpansType aRanges;
+ aRangeSet.getSpans(aRanges);
+ sc::SingleColumnSpanSet::SpansType::const_iterator it = aRanges.begin(), itEnd = aRanges.end();
+ for (; it != itEnd; ++it)
+ CopyCellsInRangeToColumn(&aSrcPos, &aDestPos, aHdl, it->mnRow1, it->mnRow2, rDestCol);
}
@@ -1610,10 +1905,31 @@ void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
}
}
+namespace {
+
+void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
+{
+ sc::CellStoreType::iterator it = rCells.begin(), itEnd = rCells.end();
+ for (; it != itEnd; ++it)
+ {
+ if (it->type != sc::element_type_formula)
+ continue;
+
+ sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
+ sc::formula_block::iterator itCellEnd = sc::formula_block::end(*it->data);
+ for (; itCell != itCellEnd; ++itCell)
+ {
+ ScFormulaCell& rCell = **itCell;
+ rCell.aPos.SetCol(nCol);
+ }
+ }
+}
+
+}
void ScColumn::SwapCol(ScColumn& rCol)
{
- maItems.swap(rCol.maItems);
+ maCells.swap(rCol.maCells);
maCellTextAttrs.swap(rCol.maCellTextAttrs);
CellStorageModified();
@@ -1629,518 +1945,403 @@ void ScColumn::SwapCol(ScColumn& rCol)
std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
- SCSIZE i;
- for (i = 0; i < maItems.size(); i++)
- {
- ScFormulaCell* pCell = (ScFormulaCell*) maItems[i].pCell;
- if( pCell->GetCellType() == CELLTYPE_FORMULA)
- pCell->aPos.SetCol(nCol);
- }
- for (i = 0; i < rCol.maItems.size(); i++)
- {
- ScFormulaCell* pCell = (ScFormulaCell*) rCol.maItems[i].pCell;
- if( pCell->GetCellType() == CELLTYPE_FORMULA)
- pCell->aPos.SetCol(rCol.nCol);
- }
+ // Reset column positions in formula cells.
+ resetColumnPosition(maCells, nCol);
+ resetColumnPosition(rCol.maCells, rCol.nCol);
}
void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
{
pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
+ // Mark the non-empty cells within the specified range, for later broadcasting.
+ sc::SingleColumnSpanSet aNonEmpties;
+ aNonEmpties.scan(*this, nStartRow, nEndRow);
+ sc::SingleColumnSpanSet::SpansType aRanges;
+ aNonEmpties.getSpans(aRanges);
+
// Move the broadcasters to the destination column.
maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
+ maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
+ maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
- if (maItems.empty())
- // No cells to move.
- return;
+ CellStorageModified();
+ rCol.CellStorageModified();
- ::std::vector<SCROW> aRows;
- SCSIZE i;
- Search( nStartRow, i); // i points to start row or position thereafter
- SCSIZE nStartPos = i;
- // First, copy the cell instances to the new column.
- for ( ; i < maItems.size() && maItems[i].nRow <= nEndRow; ++i)
+ // Broadcast on moved ranges. Area-broadcast only.
+ ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
+ ScAddress& rPos = aHint.GetAddress();
+ sc::SingleColumnSpanSet::SpansType::const_iterator itRange = aRanges.begin(), itRangeEnd = aRanges.end();
+ for (; itRange != itRangeEnd; ++itRange)
{
- SCROW nRow = maItems[i].nRow;
- aRows.push_back( nRow);
- rCol.Insert( nRow, maItems[i].pCell);
+ for (SCROW nRow = itRange->mnRow1; nRow <= itRange->mnRow2; ++nRow)
+ {
+ rPos.SetRow(nRow);
+ pDocument->AreaBroadcast(aHint);
+ }
}
+}
+
+namespace {
- SCSIZE nStopPos = i;
- if (nStartPos < nStopPos)
+class UpdateRefHandler
+{
+protected:
+ ScRange maRange;
+ SCCOL mnDx;
+ SCROW mnDy;
+ SCTAB mnDz;
+ UpdateRefMode meMode;
+ ScDocument* mpUndoDoc;
+ bool mbUpdated;
+
+public:
+ UpdateRefHandler(const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz, UpdateRefMode eMode, ScDocument* pUndoDoc) :
+ maRange(rRange), mnDx(nDx), mnDy(nDy), mnDz(nDz), meMode(eMode), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
+
+ bool isUpdated() const { return mbUpdated; }
+
+ void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
{
- // At least one cell gets copied to the destination column.
- maCellTextAttrs.set_empty(nStartRow, nEndRow);
- CellStorageModified();
+ if (node.type != sc::element_type_formula)
+ return;
- // Create list of ranges of cell entry positions.
- typedef ::std::pair<SCSIZE,SCSIZE> PosPair;
- typedef ::std::vector<PosPair> EntryPosPairs;
- EntryPosPairs aEntries;
- {
- bool bFirst = true;
- nStopPos = 0;
- for (::std::vector<SCROW>::const_iterator it( aRows.begin());
- it != aRows.end() && nStopPos < maItems.size(); ++it,
- ++nStopPos)
- {
- if (!bFirst && *it != maItems[nStopPos].nRow)
- {
- aEntries.push_back( PosPair(nStartPos, nStopPos));
- bFirst = true;
- }
- if (bFirst && Search( *it, nStartPos))
- {
- bFirst = false;
- nStopPos = nStartPos;
- }
- }
- if (!bFirst && nStartPos < nStopPos)
- aEntries.push_back( PosPair(nStartPos, nStopPos));
- }
- // Broadcast changes
- ScAddress aAdr( nCol, 0, nTab );
- ScHint aHint(SC_HINT_DATACHANGED, aAdr); // areas only
- ScAddress& rAddress = aHint.GetAddress();
-
- // must iterate backwards, because indexes of following cells become invalid
- for (EntryPosPairs::reverse_iterator it( aEntries.rbegin());
- it != aEntries.rend(); ++it)
- {
- nStartPos = (*it).first;
- nStopPos = (*it).second;
- for (i=nStartPos; i<nStopPos; ++i)
- {
- rAddress.SetRow( maItems[i].nRow );
- pDocument->AreaBroadcast( aHint );
- }
- // Erase the slots containing pointers to the dummy cell instance.
- maItems.erase(maItems.begin() + nStartPos, maItems.begin() + nStopPos);
- }
+ sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
+ std::advance(it, nOffset);
+ sc::formula_block::iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
+
+ size_t nRow = node.position + nOffset;
+ for (; it != itEnd; ++it, ++nRow)
+ updateReference(**it, static_cast<SCROW>(nRow));
}
+
+ virtual void updateReference(ScFormulaCell& rCell, SCROW nRow) = 0;
+};
+
+class UpdateRefOnCopy : public UpdateRefHandler
+{
+public:
+ UpdateRefOnCopy(const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz, ScDocument* pUndoDoc) :
+ UpdateRefHandler(rRange, nDx, nDy, nDz, URM_COPY, pUndoDoc) {}
+
+ virtual void updateReference(ScFormulaCell& rCell, SCROW /*nRow*/)
+ {
+ mbUpdated |= rCell.UpdateReference(meMode, maRange, mnDx, mnDy, mnDz, mpUndoDoc);
+ }
+};
+
+class UpdateRefOnNonCopy : public UpdateRefHandler
+{
+ SCCOL mnCol;
+ SCROW mnTab;
+public:
+ UpdateRefOnNonCopy(SCCOL nCol, SCTAB nTab, const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz, UpdateRefMode eMode, ScDocument* pUndoDoc) :
+ UpdateRefHandler(rRange, nDx, nDy, nDz, eMode, pUndoDoc),
+ mnCol(nCol), mnTab(nTab) {}
+
+ virtual void updateReference(ScFormulaCell& rCell, SCROW nRow)
+ {
+ ScAddress aUndoPos(mnCol, nRow, mnTab);
+ mbUpdated |= rCell.UpdateReference(meMode, maRange, mnDx, mnDy, mnDz, mpUndoDoc, &aUndoPos);
+ }
+};
+
}
bool ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
ScDocument* pUndoDoc )
{
- bool bUpdated = false;
- if ( !maItems.empty() )
+ ScRange aRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+
+ if (eUpdateRefMode == URM_COPY)
{
- ScRange aRange( ScAddress( nCol1, nRow1, nTab1 ),
- ScAddress( nCol2, nRow2, nTab2 ) );
- if ( eUpdateRefMode == URM_COPY && nRow1 == nRow2 )
- { // e.g. put a single cell in the clipboard
- SCSIZE nIndex;
- if ( Search( nRow1, nIndex ) )
- {
- ScFormulaCell* pCell = (ScFormulaCell*) maItems[nIndex].pCell;
- if( pCell->GetCellType() == CELLTYPE_FORMULA)
- bUpdated |= pCell->UpdateReference(
- eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
- }
- }
- else
- {
- // For performance reasons two loop bodies instead of
- // testing for update mode in each iteration.
- // Anyways, this is still a bottleneck on large arrays with few
- // formulas cells.
- if ( eUpdateRefMode == URM_COPY )
- {
- SCSIZE i;
- Search( nRow1, i );
- for ( ; i < maItems.size(); i++ )
- {
- SCROW nRow = maItems[i].nRow;
- if ( nRow > nRow2 )
- break;
- ScBaseCell* pCell = maItems[i].pCell;
- if( pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- bUpdated |= ((ScFormulaCell*)pCell)->UpdateReference(
- eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener removed/inserted?
- }
- }
- }
- else
- {
- SCSIZE i = 0;
- for ( ; i < maItems.size(); i++ )
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if( pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- SCROW nRow = maItems[i].nRow;
- // When deleting rows on several sheets, the formula's position may be updated with the first call,
- // so the undo position must be passed from here.
- ScAddress aUndoPos( nCol, nRow, nTab );
- bUpdated |= ((ScFormulaCell*)pCell)->UpdateReference(
- eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc, &aUndoPos );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener removed/inserted?
- }
- }
- }
- }
+ UpdateRefOnCopy aHandler(aRange, nDx, nDy, nDz, pUndoDoc);
+ sc::ProcessBlock(maCells.begin(), maCells, aHandler, nRow1, nRow2);
+ return aHandler.isUpdated();
}
- return bUpdated;
+
+ UpdateRefOnNonCopy aHandler(nCol, nTab, aRange, nDx, nDy, nDz, eUpdateRefMode, pUndoDoc);
+ sc::ProcessBlock(maCells.begin(), maCells, aHandler, nRow1, nRow2);
+ return aHandler.isUpdated();
}
+namespace {
-void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
- ScDocument* pUndoDoc )
+class UpdateTransHandler
{
- if ( !maItems.empty() )
- for (SCSIZE i=0; i<maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- SCROW nRow = maItems[i].nRow;
- ((ScFormulaCell*)pCell)->UpdateTranspose( rSource, rDest, pUndoDoc );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener deleted/inserted?
- }
- }
-}
+ ScRange maSource;
+ ScAddress maDest;
+ ScDocument* mpUndoDoc;
+public:
+ UpdateTransHandler(const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) :
+ maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {}
+ void operator() (size_t, ScFormulaCell* pCell)
+ {
+ pCell->UpdateTranspose(maSource, maDest, mpUndoDoc);
+ }
+};
-void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+class UpdateGrowHandler
{
- if ( !maItems.empty() )
- for (SCSIZE i=0; i<maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- SCROW nRow = maItems[i].nRow;
- ((ScFormulaCell*)pCell)->UpdateGrow( rArea, nGrowX, nGrowY );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener deleted/inserted?
- }
- }
-}
+ ScRange maArea;
+ SCCOL mnGrowX;
+ SCROW mnGrowY;
+public:
+ UpdateGrowHandler(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) :
+ maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {}
+ void operator() (size_t, ScFormulaCell* pCell)
+ {
+ pCell->UpdateGrow(maArea, mnGrowX, mnGrowY);
+ }
+};
-void ScColumn::UpdateInsertTab(SCTAB nInsPos, SCTAB nNewSheets)
+class InsertTabUpdater
{
- if (nTab >= nInsPos)
+ sc::CellTextAttrStoreType& mrTextAttrs;
+ sc::CellTextAttrStoreType::iterator miAttrPos;
+ SCTAB mnTab;
+ SCTAB mnInsPos;
+ SCTAB mnNewSheets;
+public:
+ InsertTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nInsPos, SCTAB nNewSheets) :
+ mrTextAttrs(rTextAttrs),
+ miAttrPos(rTextAttrs.begin()),
+ mnTab(nTab),
+ mnInsPos(nInsPos),
+ mnNewSheets(nNewSheets) {}
+
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- nTab += nNewSheets;
- pAttrArray->SetTab(nTab);
+ pCell->UpdateInsertTab(mnInsPos, mnNewSheets);
}
- UpdateInsertTabOnlyCells(nInsPos, nNewSheets);
-}
+ void operator() (size_t nRow, EditTextObject* pCell)
+ {
+ editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
+ aUpdater.updateTableFields(mnTab);
+ miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
+ }
+};
-void ScColumn::UpdateInsertTabOnlyCells(SCTAB nInsPos, SCTAB nNewSheets)
+class DeleteTabUpdater
{
- if (maItems.empty())
- return;
+ sc::CellTextAttrStoreType& mrTextAttrs;
+ sc::CellTextAttrStoreType::iterator miAttrPos;
+ SCTAB mnDelPos;
+ SCTAB mnSheets;
+ SCTAB mnTab;
+ bool mbIsMove;
+public:
+ DeleteTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nDelPos, SCTAB nSheets, SCTAB nTab, bool bIsMove) :
+ mrTextAttrs(rTextAttrs),
+ miAttrPos(rTextAttrs.begin()),
+ mnDelPos(nDelPos),
+ mnSheets(nSheets),
+ mnTab(nTab),
+ mbIsMove(bIsMove) {}
- for (size_t i = 0; i < maItems.size(); ++i)
+ void operator() (size_t, ScFormulaCell* pCell)
{
- switch (maItems[i].pCell->GetCellType())
- {
- case CELLTYPE_FORMULA:
- {
- SCROW nRow = maItems[i].nRow;
- ScFormulaCell* p = static_cast<ScFormulaCell*>(maItems[i].pCell);
- p->UpdateInsertTab(nInsPos, nNewSheets);
- if (nRow != maItems[i].nRow)
- Search(nRow, i); // Listener deleted/inserted?
- }
- break;
- case CELLTYPE_EDIT:
- {
- ScEditCell* p = static_cast<ScEditCell*>(maItems[i].pCell);
- p->UpdateFields(nTab);
- SetTextWidth(maItems[i].nRow, TEXTWIDTH_DIRTY);
- }
- break;
- default:
- ;
- }
+ pCell->UpdateDeleteTab(mnDelPos, mbIsMove, mnSheets);
}
-}
-void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
+ void operator() (size_t nRow, EditTextObject* pCell)
+ {
+ editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
+ aUpdater.updateTableFields(mnTab);
+ miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
+ }
+};
+
+class InsertAbsTabUpdater
{
- if (maItems.empty())
- return;
+ sc::CellTextAttrStoreType& mrTextAttrs;
+ sc::CellTextAttrStoreType::iterator miAttrPos;
+ SCTAB mnTab;
+ SCTAB mnNewPos;
+public:
+ InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
+ mrTextAttrs(rTextAttrs),
+ miAttrPos(rTextAttrs.begin()),
+ mnTab(nTab),
+ mnNewPos(nNewPos) {}
- for (size_t i = 0; i < maItems.size(); ++i)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- switch (maItems[i].pCell->GetCellType())
- {
- case CELLTYPE_FORMULA:
- {
- SCROW nRow = maItems[i].nRow;
- ScFormulaCell* p = static_cast<ScFormulaCell*>(maItems[i].pCell);
- p->UpdateInsertTabAbs(nNewPos);
- if (nRow != maItems[i].nRow)
- Search(nRow, i); // Listener deleted/inserted?
- }
- break;
- case CELLTYPE_EDIT:
- {
- ScEditCell* p = static_cast<ScEditCell*>(maItems[i].pCell);
- p->UpdateFields(nTab);
- SetTextWidth(maItems[i].nRow, TEXTWIDTH_DIRTY);
- }
- break;
- default:
- ;
- }
+ pCell->UpdateInsertTabAbs(mnNewPos);
}
-}
-void ScColumn::UpdateDeleteTab(SCTAB nDelPos, bool bIsMove, ScColumn* pRefUndo, SCTAB nSheets)
-{
- if (nTab > nDelPos)
+ void operator() (size_t nRow, EditTextObject* pCell)
{
- nTab -= nSheets;
- pAttrArray->SetTab(nTab);
+ editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
+ aUpdater.updateTableFields(mnTab);
+ miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
}
+};
- if (maItems.empty())
- return;
+class MoveTabUpdater
+{
+ sc::CellTextAttrStoreType& mrTextAttrs;
+ sc::CellTextAttrStoreType::iterator miAttrPos;
+ SCTAB mnTab;
+ SCTAB mnOldPos;
+ SCTAB mnNewPos;
+public:
+ MoveTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nOldPos, SCTAB nNewPos) :
+ mrTextAttrs(rTextAttrs),
+ miAttrPos(rTextAttrs.begin()),
+ mnTab(nTab),
+ mnOldPos(nOldPos),
+ mnNewPos(nNewPos) {}
- for (size_t i = 0; i < maItems.size(); ++i)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- switch (maItems[i].pCell->GetCellType())
- {
- case CELLTYPE_FORMULA:
- {
- SCROW nRow = maItems[i].nRow;
- ScFormulaCell* pOld = static_cast<ScFormulaCell*>(maItems[i].pCell);
+ pCell->UpdateMoveTab(mnOldPos, mnNewPos, mnTab);
+ }
- /* Do not copy cell note to the undo document. Undo will copy
- back the formula cell while keeping the original note. */
- ScBaseCell* pSave = pRefUndo ? pOld->Clone( *pDocument ) : 0;
+ void operator() (size_t nRow, EditTextObject* pCell)
+ {
+ editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
+ aUpdater.updateTableFields(mnTab);
+ miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
+ }
+};
- bool bChanged = pOld->UpdateDeleteTab(nDelPos, bIsMove, nSheets);
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener deleted/inserted?
+class UpdateCompileHandler
+{
+ bool mbForceIfNameInUse;
+public:
+ UpdateCompileHandler(bool bForceIfNameInUse) : mbForceIfNameInUse(bForceIfNameInUse) {}
- if (pRefUndo)
- {
- if (bChanged)
- pRefUndo->Insert( nRow, pSave );
- else if(pSave)
- pSave->Delete();
- }
- }
- break;
- case CELLTYPE_EDIT:
- {
- ScEditCell* p = static_cast<ScEditCell*>(maItems[i].pCell);
- p->UpdateFields(nTab);
- SetTextWidth(maItems[i].nRow, TEXTWIDTH_DIRTY);
- }
- break;
- default:
- ;
- }
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
+ pCell->UpdateCompile(mbForceIfNameInUse);
}
-}
+};
-void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
+class TabNoSetter
{
- nTab = nTabNo;
- pAttrArray->SetTab( nTabNo );
- if (maItems.empty())
- return;
+ SCTAB mnTab;
+public:
+ TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
- for (size_t i = 0; i < maItems.size(); ++i)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- switch (maItems[i].pCell->GetCellType())
- {
- case CELLTYPE_FORMULA:
- {
- ScFormulaCell* p = static_cast<ScFormulaCell*>(maItems[i].pCell);
- SCROW nRow = maItems[i].nRow;
- p->UpdateMoveTab(nOldPos, nNewPos, nTabNo);
- if (nRow != maItems[i].nRow)
- Search(nRow, i); // Listener deleted/inserted?
- }
- break;
- case CELLTYPE_EDIT:
- {
- ScEditCell* p = static_cast<ScEditCell*>(maItems[i].pCell);
- p->UpdateFields(nTab);
- SetTextWidth(maItems[i].nRow, TEXTWIDTH_DIRTY);
- }
- break;
- default:
- ;
- }
+ pCell->aPos.SetTab(mnTab);
}
-}
-
+};
-void ScColumn::UpdateCompile( bool bForceIfNameInUse )
+class UsedRangeNameFinder
{
- if ( !maItems.empty() )
+ std::set<sal_uInt16>& mrIndexes;
+public:
+ UsedRangeNameFinder(std::set<sal_uInt16>& rIndexes) : mrIndexes(rIndexes) {}
+
+ void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
{
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
- if( p->GetCellType() == CELLTYPE_FORMULA )
- {
- SCROW nRow = maItems[i].nRow;
- p->UpdateCompile( bForceIfNameInUse );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener deleted/inserted?
- }
- }
+ pCell->FindRangeNamesInUse(mrIndexes);
}
-}
-
+};
-void ScColumn::SetTabNo(SCTAB nNewTab)
+struct SetDirtyVarHandler
{
- nTab = nNewTab;
- pAttrArray->SetTab( nNewTab );
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
- if( p->GetCellType() == CELLTYPE_FORMULA )
- p->aPos.SetTab( nNewTab );
- }
-}
+ void operator() (size_t /*nRow*/, ScFormulaCell* p)
+ {
+ p->SetDirtyVar();
+ }
+};
-void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
+class SetDirtyHandler
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- if ((maItems[i].nRow >= nRow1) &&
- (maItems[i].nRow <= nRow2) &&
- (maItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
- ((ScFormulaCell*)maItems[i].pCell)->FindRangeNamesInUse(rIndexes);
-}
+ ScDocument& mrDoc;
+public:
+ SetDirtyHandler(ScDocument& rDoc) : mrDoc(rDoc) {}
-void ScColumn::SetDirtyVar()
-{
- for (SCSIZE i=0; i<maItems.size(); i++)
+ void operator() (size_t /*nRow*/, ScFormulaCell* p)
{
- ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
- if( p->GetCellType() == CELLTYPE_FORMULA )
- p->SetDirtyVar();
+ p->SetDirtyVar();
+ if (!mrDoc.IsInFormulaTree(p))
+ mrDoc.PutInFormulaTree(p);
}
-}
+};
-bool ScColumn::IsFormulaDirty( SCROW nRow ) const
+class SetDirtyOnRangeHandler
{
- if (!ValidRow(nRow))
- return false;
+ sc::SingleColumnSpanSet maValueRanges;
+ ScColumn& mrColumn;
+public:
+ SetDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
- // No cell at this row position.
- return false;
+ void operator() (size_t /*nRow*/, ScFormulaCell* p)
+ {
+ p->SetDirty();
+ }
- const ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() != CELLTYPE_FORMULA)
- // Not even a formula cell.
- return false;
+ void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
+ {
+ if (type == sc::element_type_empty)
+ // Ignore empty blocks.
+ return;
- return static_cast<const ScFormulaCell*>(pCell)->GetDirty();
-}
+ // Non-formula cells.
+ SCROW nRow1 = nTopRow;
+ SCROW nRow2 = nTopRow + nDataSize - 1;
+ maValueRanges.set(nRow1, nRow2, true);
+ }
-void ScColumn::SetDirty()
-{
- // is only done documentwide, no FormulaTracking
- bool bOldAutoCalc = pDocument->GetAutoCalc();
- pDocument->SetAutoCalc( false ); // no multiple recalculation
- for (SCSIZE i=0; i<maItems.size(); i++)
+ void broadcast()
{
- ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
- if( p->GetCellType() == CELLTYPE_FORMULA )
- {
- p->SetDirtyVar();
- if ( !pDocument->IsInFormulaTree( p ) )
- pDocument->PutInFormulaTree( p );
- }
+ std::vector<SCROW> aRows;
+ maValueRanges.getRows(aRows);
+ mrColumn.BroadcastCells(aRows);
}
- pDocument->SetAutoCalc( bOldAutoCalc );
-}
+};
+class SetTableOpDirtyOnRangeHandler
+{
+ sc::SingleColumnSpanSet maValueRanges;
+ ScColumn& mrColumn;
+public:
+ SetTableOpDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
-void ScColumn::SetDirty( const ScRange& rRange )
-{ // broadcasts everything within the range, with FormulaTracking
- if ( maItems.empty() )
- return ;
- bool bOldAutoCalc = pDocument->GetAutoCalc();
- pDocument->SetAutoCalc( false ); // no multiple recalculation
- SCROW nRow2 = rRange.aEnd.Row();
- ScAddress aPos( nCol, 0, nTab );
- ScHint aHint(SC_HINT_DATACHANGED, aPos);
- SCROW nRow;
- SCSIZE nIndex;
- Search( rRange.aStart.Row(), nIndex );
- while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
+ void operator() (size_t /*nRow*/, ScFormulaCell* p)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->SetDirty();
- else
- {
- aHint.GetAddress().SetRow( nRow );
- pDocument->Broadcast( aHint );
- }
- nIndex++;
+ p->SetTableOpDirty();
}
- pDocument->SetAutoCalc( bOldAutoCalc );
-}
-
-void ScColumn::SetTableOpDirty( const ScRange& rRange )
-{
- if ( maItems.empty() )
- return ;
- bool bOldAutoCalc = pDocument->GetAutoCalc();
- pDocument->SetAutoCalc( false ); // no multiple recalculation
- SCROW nRow2 = rRange.aEnd.Row();
- ScAddress aPos( nCol, 0, nTab );
- ScHint aHint(SC_HINT_TABLEOPDIRTY, aPos);
- SCROW nRow;
- SCSIZE nIndex;
- Search( rRange.aStart.Row(), nIndex );
- while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
+ void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->SetTableOpDirty();
- else
- {
- aHint.GetAddress().SetRow( nRow );
- pDocument->Broadcast( aHint );
- }
- nIndex++;
+ if (type == sc::element_type_empty)
+ // Ignore empty blocks.
+ return;
+
+ // Non-formula cells.
+ SCROW nRow1 = nTopRow;
+ SCROW nRow2 = nTopRow + nDataSize - 1;
+ maValueRanges.set(nRow1, nRow2, true);
}
- pDocument->SetAutoCalc( bOldAutoCalc );
-}
+ void broadcast()
+ {
+ std::vector<SCROW> aRows;
+ maValueRanges.getRows(aRows);
+ mrColumn.BroadcastCells(aRows);
+ }
+};
-void ScColumn::SetDirtyAfterLoad()
+struct SetDirtyAfterLoadHandler
{
- bool bOldAutoCalc = pDocument->GetAutoCalc();
- pDocument->SetAutoCalc( false ); // no multiple recalculation
- for (SCSIZE i=0; i<maItems.size(); i++)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
#if 1
// Simply set dirty and append to FormulaTree, without broadcasting,
// which is a magnitude faster. This is used to calculate the entire
// document, e.g. when loading alien file formats.
- if ( p->GetCellType() == CELLTYPE_FORMULA )
- p->SetDirtyAfterLoad();
+ pCell->SetDirtyAfterLoad();
#else
/* This was used with the binary file format that stored results, where only
* newly compiled and volatile functions and their dependents had to be
@@ -2153,205 +2354,357 @@ void ScColumn::SetDirtyAfterLoad()
// If the cell was alsready dirty because of CalcAfterLoad,
// FormulaTracking has to take place.
- if ( p->GetCellType() == CELLTYPE_FORMULA && p->GetDirty() )
- p->SetDirty();
+ if (pCell->GetDirty())
+ pCell->SetDirty();
#endif
}
- pDocument->SetAutoCalc( bOldAutoCalc );
-}
-
+};
-void ScColumn::SetRelNameDirty()
+struct SetRelNameDirtyHandler
{
- bool bOldAutoCalc = pDocument->GetAutoCalc();
- pDocument->SetAutoCalc( false ); // no multiple recalculation
- for (SCSIZE i=0; i<maItems.size(); i++)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
- if( p->GetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() )
- p->SetDirty();
+ if (pCell->HasRelNameReference())
+ pCell->SetDirty();
}
- pDocument->SetAutoCalc( bOldAutoCalc );
-}
-
+};
-void ScColumn::CalcAll()
+struct CalcAllHandler
{
- if ( !maItems.empty() )
- for (SCSIZE i=0; i<maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
#if OSL_DEBUG_LEVEL > 1
- // after F9 ctrl-F9: check the calculation for each FormulaTree
- double nOldVal, nNewVal;
- nOldVal = pFCell->GetValue();
+ // after F9 ctrl-F9: check the calculation for each FormulaTree
+ double nOldVal, nNewVal;
+ nOldVal = pCell->GetValue();
#endif
- pFCell->Interpret();
+ pCell->Interpret();
#if OSL_DEBUG_LEVEL > 1
- if ( pFCell->GetCode()->IsRecalcModeNormal() )
- nNewVal = pFCell->GetValue();
- else
- nNewVal = nOldVal; // random(), jetzt() etc.
- OSL_ENSURE( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" );
-#endif
- }
- }
-}
+ if (pCell->GetCode()->IsRecalcModeNormal())
+ nNewVal = pCell->GetValue();
+ else
+ nNewVal = nOldVal; // random(), jetzt() etc.
+ OSL_ENSURE(nOldVal == nNewVal, "CalcAll: nOldVal != nNewVal");
+#endif
+ }
+};
-void ScColumn::CompileAll()
+struct CompileAllHandler
{
- if ( !maItems.empty() )
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- {
- SCROW nRow = maItems[i].nRow;
- // for unconditional compilation
- // bCompile=true and pCode->nError=0
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
- pFCell->GetCode()->SetCodeError( 0 );
- pFCell->SetCompile( true );
- pFCell->CompileTokenArray();
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener deleted/inserted?
- }
- }
+ // for unconditional compilation
+ // bCompile=true and pCode->nError=0
+ pCell->GetCode()->SetCodeError(0);
+ pCell->SetCompile(true);
+ pCell->CompileTokenArray();
}
-}
-
+};
-void ScColumn::CompileXML( ScProgress& rProgress )
+class CompileXMLHandler
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- {
- SCROW nRow = maItems[i].nRow;
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
- sal_uInt32 nCellFormat = GetNumberFormat( nRow );
- if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
- pFCell->SetNeedNumberFormat(false);
- else
- pFCell->SetDirty(true);
-
- pFCell->CompileXML( rProgress );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Listener deleted/inserted?
- }
- }
-}
+ ScProgress& mrProgress;
+public:
+ CompileXMLHandler(ScProgress& rProgress) : mrProgress(rProgress) {}
-bool ScColumn::CompileErrorCells(sal_uInt16 nErrCode)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
+ pCell->CompileXML(mrProgress);
+ }
+};
+
+class CompileErrorCellsHandler
{
- if (maItems.empty())
- return false;
+ sal_uInt16 mnErrCode;
+ FormulaGrammar::Grammar meGram;
+ bool mbCompiled;
+public:
+ CompileErrorCellsHandler(sal_uInt16 nErrCode, FormulaGrammar::Grammar eGram) :
+ mnErrCode(nErrCode), meGram(eGram), mbCompiled(false) {}
- bool bCompiled = false;
- std::vector<ColEntry>::iterator it = maItems.begin(), itEnd = maItems.end();
- for (; it != itEnd; ++it)
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
{
- ScBaseCell* pCell = it->pCell;
- if (pCell->GetCellType() != CELLTYPE_FORMULA)
- // Not a formula cell. Skip it.
- continue;
-
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
- sal_uInt16 nCurError = pFCell->GetRawError();
+ sal_uInt16 nCurError = pCell->GetRawError();
if (!nCurError)
// It's not an error cell. Skip it.
- continue;
+ return;
- if (nErrCode && nCurError != nErrCode)
+ if (mnErrCode && nCurError != mnErrCode)
// Error code is specified, and it doesn't match. Skip it.
- continue;
+ return;
- pFCell->GetCode()->SetCodeError(0);
+ pCell->GetCode()->SetCodeError(0);
OUStringBuffer aBuf;
- pFCell->GetFormula(aBuf, pDocument->GetGrammar());
- pFCell->Compile(aBuf.makeStringAndClear(), false, pDocument->GetGrammar());
+ pCell->GetFormula(aBuf, meGram);
+ pCell->Compile(aBuf.makeStringAndClear(), false, meGram);
- bCompiled = true;
+ mbCompiled = true;
}
- return bCompiled;
-}
+ bool isCompiled() const { return mbCompiled; }
+};
-void ScColumn::CalcAfterLoad()
+struct CalcAfterLoadHandler
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->CalcAfterLoad();
- }
-}
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
+ pCell->CalcAfterLoad();
+ }
+};
+struct ResetChangedHandler
+{
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
+ pCell->SetChanged(false);
+ }
+};
-void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
+/**
+ * Ambiguous script type counts as edit cell.
+ */
+class FindEditCellsHandler
{
- if ( !maItems.empty() )
+ ScColumn& mrColumn;
+ sc::CellTextAttrStoreType& mrAttrs;
+ sc::CellTextAttrStoreType::iterator miAttrPos;
+
+public:
+ FindEditCellsHandler(ScColumn& rColumn, sc::CellTextAttrStoreType& rAttrs) :
+ mrColumn(rColumn), mrAttrs(rAttrs), miAttrPos(rAttrs.begin()) {}
+
+ bool operator() (size_t, const EditTextObject*)
{
- SCSIZE nIndex;
- Search(nStartRow,nIndex);
- while (nIndex<maItems.size() && maItems[nIndex].nRow <= nEndRow)
+ return true;
+ }
+
+ bool operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow);
+ if (IsAmbiguousScriptNonZero(nScriptType))
+ return true;
+
+ return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
+ }
+
+ std::pair<size_t,bool> operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
+ {
+ typedef std::pair<size_t,bool> RetType;
+
+ if (type == sc::element_type_empty)
+ return RetType(0, false);
+
+ for (size_t i = 0; i < nDataSize; ++i)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- ((ScFormulaCell*)pCell)->SetChanged(false);
- ++nIndex;
+ SCROW nRow = nTopRow + i;
+ sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow);
+ if (IsAmbiguousScriptNonZero(nScriptType))
+ // Return the offset from the first row.
+ return RetType(i, true);
}
+
+ return RetType(0, false);
}
+};
+
}
+void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
+ ScDocument* pUndoDoc )
+{
+ UpdateTransHandler aFunc(rSource, rDest, pUndoDoc);
+ sc::ProcessFormula(maCells, aFunc);
+}
-bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
+
+void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
{
- // used in GetOptimalHeight - ambiguous script type counts as edit cell
+ UpdateGrowHandler aFunc(rArea, nGrowX, nGrowY);
+ sc::ProcessFormula(maCells, aFunc);
+}
- std::vector<ColEntry>::const_iterator itCell = Search(nStartRow);
- std::vector<ColEntry>::const_iterator itCellEnd = maItems.end();
- if (itCell == itCellEnd)
- return false;
- sc::CellTextAttrStoreType::iterator itAttrPos = maCellTextAttrs.begin();
- for (; itCell != itCellEnd && itCell->nRow <= nEndRow; ++itCell)
+void ScColumn::UpdateInsertTab(SCTAB nInsPos, SCTAB nNewSheets)
+{
+ if (nTab >= nInsPos)
{
- ScBaseCell* pCell = itCell->pCell;
- SCROW nRow = itCell->nRow;
- CellType eCellType = pCell->GetCellType();
+ nTab += nNewSheets;
+ pAttrArray->SetTab(nTab);
+ }
- // See if this is a real edit cell.
- if (eCellType == CELLTYPE_EDIT)
- {
- rFirst = nRow;
- return true;
- }
+ UpdateInsertTabOnlyCells(nInsPos, nNewSheets);
+}
- sal_uInt8 nScriptType = GetRangeScriptType(itAttrPos, nRow, nRow);
- if (IsAmbiguousScriptNonZero(nScriptType))
- {
- rFirst = nRow;
- return true;
- }
+void ScColumn::UpdateInsertTabOnlyCells(SCTAB nInsPos, SCTAB nNewSheets)
+{
+ InsertTabUpdater aFunc(maCellTextAttrs, nTab, nInsPos, nNewSheets);
+ sc::ProcessFormulaEditText(maCells, aFunc);
+}
- // Lastly, see if this is a formula cell with multi-line result.
- if (eCellType == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->IsMultilineResult())
- {
- rFirst = nRow;
- return true;
- }
+void ScColumn::UpdateDeleteTab(SCTAB nDelPos, bool bIsMove, ScColumn* /*pRefUndo*/, SCTAB nSheets)
+{
+ if (nTab > nDelPos)
+ {
+ nTab -= nSheets;
+ pAttrArray->SetTab(nTab);
}
- return false;
+ DeleteTabUpdater aFunc(maCellTextAttrs, nDelPos, nSheets, nTab, bIsMove);
+ sc::ProcessFormulaEditText(maCells, aFunc);
+}
+
+void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
+{
+ InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
+ sc::ProcessFormulaEditText(maCells, aFunc);
+}
+
+void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
+{
+ nTab = nTabNo;
+ pAttrArray->SetTab( nTabNo );
+
+ MoveTabUpdater aFunc(maCellTextAttrs, nTab, nOldPos, nNewPos);
+ sc::ProcessFormulaEditText(maCells, aFunc);
+}
+
+
+void ScColumn::UpdateCompile( bool bForceIfNameInUse )
+{
+ UpdateCompileHandler aFunc(bForceIfNameInUse);
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+
+void ScColumn::SetTabNo(SCTAB nNewTab)
+{
+ nTab = nNewTab;
+ pAttrArray->SetTab( nNewTab );
+
+ TabNoSetter aFunc(nTab);
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
+{
+ UsedRangeNameFinder aFunc(rIndexes);
+ sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+}
+
+void ScColumn::SetDirtyVar()
+{
+ SetDirtyVarHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+bool ScColumn::IsFormulaDirty( SCROW nRow ) const
+{
+ if (!ValidRow(nRow))
+ return false;
+
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it->type != sc::element_type_formula)
+ // This is not a formula cell block.
+ return false;
+
+ const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
+ return p->GetDirty();
+}
+
+void ScColumn::SetDirty()
+{
+ // is only done documentwide, no FormulaTracking
+ sc::AutoCalcSwitch aSwitch(*pDocument, false);
+ SetDirtyHandler aFunc(*pDocument);
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2 )
+{
+ // broadcasts everything within the range, with FormulaTracking
+ sc::AutoCalcSwitch aSwitch(*pDocument, false);
+
+ SetDirtyOnRangeHandler aHdl(*this);
+ sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
+ aHdl.broadcast();
+}
+
+void ScColumn::SetTableOpDirty( const ScRange& rRange )
+{
+ sc::AutoCalcSwitch aSwitch(*pDocument, false);
+
+ SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
+ SetTableOpDirtyOnRangeHandler aHdl(*this);
+ sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
+ aHdl.broadcast();
+}
+
+void ScColumn::SetDirtyAfterLoad()
+{
+ sc::AutoCalcSwitch aSwitch(*pDocument, false);
+ SetDirtyAfterLoadHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::SetRelNameDirty()
+{
+ sc::AutoCalcSwitch aSwitch(*pDocument, false);
+ SetRelNameDirtyHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::CalcAll()
+{
+ CalcAllHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::CompileAll()
+{
+ CompileAllHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::CompileXML( ScProgress& rProgress )
+{
+ CompileXMLHandler aFunc(rProgress);
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+bool ScColumn::CompileErrorCells(sal_uInt16 nErrCode)
+{
+ CompileErrorCellsHandler aHdl(nErrCode, pDocument->GetGrammar());
+ sc::ProcessFormula(maCells, aHdl);
+ return aHdl.isCompiled();
+}
+
+void ScColumn::CalcAfterLoad()
+{
+ CalcAfterLoadHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
+}
+
+void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
+{
+ ResetChangedHandler aFunc;
+ sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
+}
+
+bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
+{
+ // used in GetOptimalHeight - ambiguous script type counts as edit cell
+
+ FindEditCellsHandler aFunc(*this, maCellTextAttrs);
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
+ sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
+
+ if (aPos.first == maCells.end())
+ return false;
+
+ rFirst = aPos.first->position + aPos.second;
+ return true;
}
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 7915efd69071..3044ca3e039c 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -42,6 +42,7 @@
#include "globalnames.hxx"
#include "formulagroup.hxx"
#include "listenercontext.hxx"
+#include "mtvcellfunc.hxx"
#include <math.h>
@@ -100,455 +101,519 @@ long ScColumn::GetNeededSize(
const Fraction& rZoomX, const Fraction& rZoomY,
bool bWidth, const ScNeededSizeOptions& rOptions ) const
{
- long nValue=0;
- SCSIZE nIndex;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end() || it->type == sc::element_type_empty)
+ // Empty cell, or invalid row.
+ return 0;
+
+ long nValue = 0;
+ ScRefCellValue aCell = GetCellValue(it, aPos.second);
double nPPT = bWidth ? nPPTX : nPPTY;
- if (Search(nRow,nIndex))
- {
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
- const ScPatternAttr* pPattern = rOptions.pPattern;
- if (!pPattern)
- pPattern = pAttrArray->GetPattern( nRow );
+ const ScPatternAttr* pPattern = rOptions.pPattern;
+ if (!pPattern)
+ pPattern = pAttrArray->GetPattern( nRow );
- // merged?
- // Do not merge in conditional formatting
+ // merged?
+ // Do not merge in conditional formatting
- const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
- const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
+ const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
+ const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
- if ( bWidth )
- {
- if ( pFlag->IsHorOverlapped() )
- return 0;
- if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
- return 0;
- }
- else
- {
- if ( pFlag->IsVerOverlapped() )
- return 0;
- if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
- return 0;
- }
+ if ( bWidth )
+ {
+ if ( pFlag->IsHorOverlapped() )
+ return 0;
+ if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
+ return 0;
+ }
+ else
+ {
+ if ( pFlag->IsVerOverlapped() )
+ return 0;
+ if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
+ return 0;
+ }
- // conditional formatting
- const SfxItemSet* pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
+ // conditional formatting
+ const SfxItemSet* pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
- // line break?
+ // line break?
- const SfxPoolItem* pCondItem;
- SvxCellHorJustify eHorJust;
- if (pCondSet &&
- pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SFX_ITEM_SET)
- eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
- else
- eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
- pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
- bool bBreak;
- if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
- bBreak = true;
- else if ( pCondSet &&
- pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SFX_ITEM_SET)
- bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
- else
- bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
+ const SfxPoolItem* pCondItem;
+ SvxCellHorJustify eHorJust;
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SFX_ITEM_SET)
+ eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
+ else
+ eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
+ pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
+ bool bBreak;
+ if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
+ bBreak = true;
+ else if ( pCondSet &&
+ pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SFX_ITEM_SET)
+ bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
+ else
+ bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
- SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
- sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
- // #i111387# disable automatic line breaks only for "General" number format
- if (bBreak && aCell.hasNumeric() && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
- {
- bBreak = false;
- }
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
+ // #i111387# disable automatic line breaks only for "General" number format
+ if (bBreak && aCell.hasNumeric() && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
+ {
+ bBreak = false;
+ }
- // get other attributes from pattern and conditional formatting
+ // get other attributes from pattern and conditional formatting
- SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
- bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
- ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
- if ( bAsianVertical )
- bBreak = false;
+ SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
+ bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
+ ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
+ if ( bAsianVertical )
+ bBreak = false;
- if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
- return 0;
+ if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
+ return 0;
- long nRotate = 0;
- SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
- if ( eOrient == SVX_ORIENTATION_STANDARD )
+ long nRotate = 0;
+ SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
+ if ( eOrient == SVX_ORIENTATION_STANDARD )
+ {
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SFX_ITEM_SET)
+ nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
+ else
+ nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
+ if ( nRotate )
{
if (pCondSet &&
- pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SFX_ITEM_SET)
- nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
+ pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SFX_ITEM_SET)
+ eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
else
- nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
- if ( nRotate )
- {
- if (pCondSet &&
- pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SFX_ITEM_SET)
- eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
- else
- eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
- pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
+ eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
+ pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
- if ( nRotate == 18000 )
- eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
- }
+ if ( nRotate == 18000 )
+ eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
}
+ }
- if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
- {
- // ignore orientation/rotation if "repeat" is active
- eOrient = SVX_ORIENTATION_STANDARD;
- nRotate = 0;
- bAsianVertical = false;
- }
+ if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
+ {
+ // ignore orientation/rotation if "repeat" is active
+ eOrient = SVX_ORIENTATION_STANDARD;
+ nRotate = 0;
+ bAsianVertical = false;
+ }
- const SvxMarginItem* pMargin;
+ const SvxMarginItem* pMargin;
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SFX_ITEM_SET)
+ pMargin = (const SvxMarginItem*) pCondItem;
+ else
+ pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
+ sal_uInt16 nIndent = 0;
+ if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
+ {
if (pCondSet &&
- pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SFX_ITEM_SET)
- pMargin = (const SvxMarginItem*) pCondItem;
+ pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SFX_ITEM_SET)
+ nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
else
- pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
- sal_uInt16 nIndent = 0;
- if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
- {
- if (pCondSet &&
- pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SFX_ITEM_SET)
- nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
- else
- nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
- }
+ nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
+ }
- sal_uInt8 nScript = pDocument->GetScriptType(nCol, nRow, nTab);
- if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
+ sal_uInt8 nScript = pDocument->GetScriptType(nCol, nRow, nTab);
+ if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
- // also call SetFont for edit cells, because bGetFont may be set only once
- // bGetFont is set also if script type changes
- if (rOptions.bGetFont)
- {
- Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
- Font aFont;
- // font color doesn't matter here
- pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
- pDev->SetFont(aFont);
- }
+ // also call SetFont for edit cells, because bGetFont may be set only once
+ // bGetFont is set also if script type changes
+ if (rOptions.bGetFont)
+ {
+ Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
+ Font aFont;
+ // font color doesn't matter here
+ pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
+ pDev->SetFont(aFont);
+ }
+
+ bool bAddMargin = true;
+ CellType eCellType = aCell.meType;
- bool bAddMargin = true;
- CellType eCellType = aCell.meType;
+ bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
+ eOrient == SVX_ORIENTATION_STACKED ||
+ IsAmbiguousScript(nScript) ||
+ ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
- bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
- eOrient == SVX_ORIENTATION_STACKED ||
- IsAmbiguousScript(nScript) ||
- ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
+ if (!bEditEngine) // direct output
+ {
+ Color* pColor;
+ OUString aValStr;
+ ScCellFormat::GetString(
+ aCell, nFormat, aValStr, &pColor, *pFormatter, true, rOptions.bFormula, ftCheck);
- if (!bEditEngine) // direct output
+ if (!aValStr.isEmpty())
{
- Color* pColor;
- OUString aValStr;
- ScCellFormat::GetString(
- aCell, nFormat, aValStr, &pColor, *pFormatter, true, rOptions.bFormula, ftCheck);
+ // SetFont is moved up
- if (!aValStr.isEmpty())
+ Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
+ if ( eOrient != SVX_ORIENTATION_STANDARD )
{
- // SetFont is moved up
+ long nTemp = aSize.Width();
+ aSize.Width() = aSize.Height();
+ aSize.Height() = nTemp;
+ }
+ else if ( nRotate )
+ {
+ //! take different X/Y scaling into consideration
- Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
- if ( eOrient != SVX_ORIENTATION_STANDARD )
- {
- long nTemp = aSize.Width();
- aSize.Width() = aSize.Height();
- aSize.Height() = nTemp;
- }
- else if ( nRotate )
+ double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
+ double nCosAbs = fabs( cos( nRealOrient ) );
+ double nSinAbs = fabs( sin( nRealOrient ) );
+ long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
+ long nWidth;
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
+ else if ( rOptions.bTotalSize )
{
- //! take different X/Y scaling into consideration
-
- double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
- double nCosAbs = fabs( cos( nRealOrient ) );
- double nSinAbs = fabs( sin( nRealOrient ) );
- long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
- long nWidth;
- if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
- nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
- else if ( rOptions.bTotalSize )
- {
- nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
- bAddMargin = false;
- // only to the right:
- //! differ on direction up/down (only Text/whole height)
- if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
- nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
- nPPT * nCosAbs / nSinAbs );
- }
- else
- nWidth = (long)( aSize.Height() / nSinAbs ); //! limit?
-
- if ( bBreak && !rOptions.bTotalSize )
- {
- // limit size for line break
- long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
- if ( nHeight > nCmp )
- nHeight = nCmp;
- }
-
- aSize = Size( nWidth, nHeight );
+ nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
+ bAddMargin = false;
+ // only to the right:
+ //! differ on direction up/down (only Text/whole height)
+ if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
+ nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
+ nPPT * nCosAbs / nSinAbs );
}
- nValue = bWidth ? aSize.Width() : aSize.Height();
+ else
+ nWidth = (long)( aSize.Height() / nSinAbs ); //! limit?
- if ( bAddMargin )
+ if ( bBreak && !rOptions.bTotalSize )
{
- if (bWidth)
- {
- nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
- (long) ( pMargin->GetRightMargin() * nPPT );
- if ( nIndent )
- nValue += (long) ( nIndent * nPPT );
- }
- else
- nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
- (long) ( pMargin->GetBottomMargin() * nPPT );
+ // limit size for line break
+ long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
+ if ( nHeight > nCmp )
+ nHeight = nCmp;
}
- // linebreak done ?
+ aSize = Size( nWidth, nHeight );
+ }
+ nValue = bWidth ? aSize.Width() : aSize.Height();
- if ( bBreak && !bWidth )
+ if ( bAddMargin )
+ {
+ if (bWidth)
{
- // test with EditEngine the safety at 90%
- // (due to rounding errors and because EditEngine formats partially differently)
-
- long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
- pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
- nIndent )
- * nPPT );
- nDocPixel = (nDocPixel * 9) / 10; // for safety
- if ( aSize.Width() > nDocPixel )
- bEditEngine = true;
+ nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
+ (long) ( pMargin->GetRightMargin() * nPPT );
+ if ( nIndent )
+ nValue += (long) ( nIndent * nPPT );
}
+ else
+ nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
+ (long) ( pMargin->GetBottomMargin() * nPPT );
+ }
+
+ // linebreak done ?
+
+ if ( bBreak && !bWidth )
+ {
+ // test with EditEngine the safety at 90%
+ // (due to rounding errors and because EditEngine formats partially differently)
+
+ long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
+ pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
+ nIndent )
+ * nPPT );
+ nDocPixel = (nDocPixel * 9) / 10; // for safety
+ if ( aSize.Width() > nDocPixel )
+ bEditEngine = true;
}
}
+ }
- if (bEditEngine)
- {
- // the font is not reset each time with !bEditEngine
- Font aOldFont = pDev->GetFont();
+ if (bEditEngine)
+ {
+ // the font is not reset each time with !bEditEngine
+ Font aOldFont = pDev->GetFont();
- MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
+ MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
- // save in document ?
- ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
+ // save in document ?
+ ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
- pEngine->SetUpdateMode( false );
- bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
- sal_uLong nCtrl = pEngine->GetControlWord();
- if ( bTextWysiwyg )
- nCtrl |= EE_CNTRL_FORMAT100;
- else
- nCtrl &= ~EE_CNTRL_FORMAT100;
- pEngine->SetControlWord( nCtrl );
- MapMode aOld = pDev->GetMapMode();
- pDev->SetMapMode( aHMMMode );
- pEngine->SetRefDevice( pDev );
- pDocument->ApplyAsianEditSettings( *pEngine );
- SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
- pPattern->FillEditItemSet( pSet, pCondSet );
+ pEngine->SetUpdateMode( false );
+ bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
+ sal_uLong nCtrl = pEngine->GetControlWord();
+ if ( bTextWysiwyg )
+ nCtrl |= EE_CNTRL_FORMAT100;
+ else
+ nCtrl &= ~EE_CNTRL_FORMAT100;
+ pEngine->SetControlWord( nCtrl );
+ MapMode aOld = pDev->GetMapMode();
+ pDev->SetMapMode( aHMMMode );
+ pEngine->SetRefDevice( pDev );
+ pDocument->ApplyAsianEditSettings( *pEngine );
+ SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
+ pPattern->FillEditItemSet( pSet, pCondSet );
// no longer needed, are setted with the text (is faster)
// pEngine->SetDefaults( pSet );
- if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
+ if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
- com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
- pEngine->SetHyphenator( xXHyphenator );
- }
+ com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
+ pEngine->SetHyphenator( xXHyphenator );
+ }
- Size aPaper = Size( 1000000, 1000000 );
- if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
- aPaper.Width() = 1;
- else if (bBreak)
+ Size aPaper = Size( 1000000, 1000000 );
+ if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
+ aPaper.Width() = 1;
+ else if (bBreak)
+ {
+ double fWidthFactor = nPPTX;
+ if ( bTextWysiwyg )
{
- double fWidthFactor = nPPTX;
- if ( bTextWysiwyg )
- {
- // if text is formatted for printer, don't use PixelToLogic,
- // to ensure the exact same paper width (and same line breaks) as in
- // ScEditUtil::GetEditArea, used for output.
+ // if text is formatted for printer, don't use PixelToLogic,
+ // to ensure the exact same paper width (and same line breaks) as in
+ // ScEditUtil::GetEditArea, used for output.
- fWidthFactor = HMM_PER_TWIPS;
- }
-
- // use original width for hidden columns:
- long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
- SCCOL nColMerge = pMerge->GetColMerge();
- if (nColMerge > 1)
- for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
- nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
- nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
- + (long) ( pMargin->GetRightMargin() * fWidthFactor )
- + 1; // output size is width-1 pixel (due to gridline)
- if ( nIndent )
- nDocWidth -= (long) ( nIndent * fWidthFactor );
-
- // space for AutoFilter button: 20 * nZoom/100
- if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
- nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
-
- aPaper.Width() = nDocWidth;
-
- if ( !bTextWysiwyg )
- aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
+ fWidthFactor = HMM_PER_TWIPS;
}
- pEngine->SetPaperSize(aPaper);
- if (aCell.meType == CELLTYPE_EDIT)
- {
- pEngine->SetTextNewDefaults(*aCell.mpEditText, pSet);
- }
+ // use original width for hidden columns:
+ long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
+ SCCOL nColMerge = pMerge->GetColMerge();
+ if (nColMerge > 1)
+ for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
+ nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
+ nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
+ + (long) ( pMargin->GetRightMargin() * fWidthFactor )
+ + 1; // output size is width-1 pixel (due to gridline)
+ if ( nIndent )
+ nDocWidth -= (long) ( nIndent * fWidthFactor );
+
+ // space for AutoFilter button: 20 * nZoom/100
+ if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
+ nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
+
+ aPaper.Width() = nDocWidth;
+
+ if ( !bTextWysiwyg )
+ aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
+ }
+ pEngine->SetPaperSize(aPaper);
+
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ pEngine->SetTextNewDefaults(*aCell.mpEditText, pSet);
+ }
+ else
+ {
+ Color* pColor;
+ OUString aString;
+ ScCellFormat::GetString(
+ aCell, nFormat, aString, &pColor, *pFormatter, true,
+ rOptions.bFormula, ftCheck);
+
+ if (!aString.isEmpty())
+ pEngine->SetTextNewDefaults(aString, pSet);
else
+ pEngine->SetDefaults(pSet);
+ }
+
+ bool bEngineVertical = pEngine->IsVertical();
+ pEngine->SetVertical( bAsianVertical );
+ pEngine->SetUpdateMode( true );
+
+ bool bEdWidth = bWidth;
+ if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
+ bEdWidth = !bEdWidth;
+ if ( nRotate )
+ {
+ //! take different X/Y scaling into consideration
+
+ Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
+ double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
+ double nCosAbs = fabs( cos( nRealOrient ) );
+ double nSinAbs = fabs( sin( nRealOrient ) );
+ long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
+ long nWidth;
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
+ else if ( rOptions.bTotalSize )
{
- Color* pColor;
- OUString aString;
- ScCellFormat::GetString(
- aCell, nFormat, aString, &pColor, *pFormatter, true,
- rOptions.bFormula, ftCheck);
-
- if (!aString.isEmpty())
- pEngine->SetTextNewDefaults(aString, pSet);
- else
- pEngine->SetDefaults(pSet);
+ nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
+ bAddMargin = false;
+ if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
+ nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
+ nPPT * nCosAbs / nSinAbs );
}
+ else
+ nWidth = (long)( aSize.Height() / nSinAbs ); //! limit?
+ aSize = Size( nWidth, nHeight );
- bool bEngineVertical = pEngine->IsVertical();
- pEngine->SetVertical( bAsianVertical );
- pEngine->SetUpdateMode( true );
-
- bool bEdWidth = bWidth;
- if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
- bEdWidth = !bEdWidth;
- if ( nRotate )
+ Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
+ if ( bEdWidth )
+ nValue = aPixSize.Width();
+ else
{
- //! take different X/Y scaling into consideration
+ nValue = aPixSize.Height();
- Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
- double nRealOrient = nRotate * F_PI18000; // nRotate is in 1/100 Grad
- double nCosAbs = fabs( cos( nRealOrient ) );
- double nSinAbs = fabs( sin( nRealOrient ) );
- long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
- long nWidth;
- if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
- nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
- else if ( rOptions.bTotalSize )
+ if ( bBreak && !rOptions.bTotalSize )
{
- nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
- bAddMargin = false;
- if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
- nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
- nPPT * nCosAbs / nSinAbs );
+ // limit size for line break
+ long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
+ if ( nValue > nCmp )
+ nValue = nCmp;
}
- else
- nWidth = (long)( aSize.Height() / nSinAbs ); //! limit?
- aSize = Size( nWidth, nHeight );
-
- Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
- if ( bEdWidth )
- nValue = aPixSize.Width();
- else
- {
- nValue = aPixSize.Height();
+ }
+ }
+ else if ( bEdWidth )
+ {
+ if (bBreak)
+ nValue = 0;
+ else
+ nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
+ aHMMMode).Width();
+ }
+ else // height
+ {
+ nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
+ aHMMMode).Height();
- if ( bBreak && !rOptions.bTotalSize )
- {
- // limit size for line break
- long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
- if ( nValue > nCmp )
- nValue = nCmp;
- }
- }
+ // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
+ if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
+ ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
+ {
+ pEngine->SetControlWord( nCtrl | EE_CNTRL_FORMAT100 );
+ pEngine->QuickFormatDoc( sal_True );
+ long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
+ if ( nSecondValue > nValue )
+ nValue = nSecondValue;
}
- else if ( bEdWidth )
+ }
+
+ if ( nValue && bAddMargin )
+ {
+ if (bWidth)
{
- if (bBreak)
- nValue = 0;
- else
- nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
- aHMMMode).Width();
+ nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
+ (long) ( pMargin->GetRightMargin() * nPPT );
+ if (nIndent)
+ nValue += (long) ( nIndent * nPPT );
}
- else // height
+ else
{
- nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
- aHMMMode).Height();
+ nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
+ (long) ( pMargin->GetBottomMargin() * nPPT );
- // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
- if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
- ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
+ if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
{
- pEngine->SetControlWord( nCtrl | EE_CNTRL_FORMAT100 );
- pEngine->QuickFormatDoc( sal_True );
- long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
- if ( nSecondValue > nValue )
- nValue = nSecondValue;
+ // add 1pt extra (default margin value) for line breaks with SetVertical
+ nValue += (long) ( 20 * nPPT );
}
}
+ }
- if ( nValue && bAddMargin )
- {
- if (bWidth)
- {
- nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
- (long) ( pMargin->GetRightMargin() * nPPT );
- if (nIndent)
- nValue += (long) ( nIndent * nPPT );
- }
- else
- {
- nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
- (long) ( pMargin->GetBottomMargin() * nPPT );
+ // EditEngine is cached and re-used, so the old vertical flag must be restored
+ pEngine->SetVertical( bEngineVertical );
- if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
- {
- // add 1pt extra (default margin value) for line breaks with SetVertical
- nValue += (long) ( 20 * nPPT );
- }
- }
- }
+ pDocument->DisposeFieldEditEngine(pEngine);
- // EditEngine is cached and re-used, so the old vertical flag must be restored
- pEngine->SetVertical( bEngineVertical );
+ pDev->SetMapMode( aOld );
+ pDev->SetFont( aOldFont );
+ }
- pDocument->DisposeFieldEditEngine(pEngine);
+ if (bWidth)
+ {
+ // place for Autofilter Button
+ // 20 * nZoom/100
+ // Conditional formatting is not interesting here
- pDev->SetMapMode( aOld );
- pDev->SetFont( aOldFont );
- }
+ sal_Int16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
+ if (nFlags & SC_MF_AUTO)
+ nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
+ }
+ return nValue;
+}
- if (bWidth)
- {
- // place for Autofilter Button
- // 20 * nZoom/100
- // Conditional formatting is not interesting here
+namespace {
+
+class MaxStrLenFinder
+{
+ ScDocument& mrDoc;
+ sal_uInt32 mnFormat;
+ OUString maMaxLenStr;
+ sal_Int32 mnMaxLen;
- sal_Int16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
- if (nFlags & SC_MF_AUTO)
- nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
+ void checkLength(ScRefCellValue& rCell)
+ {
+ Color* pColor;
+ OUString aValStr;
+ ScCellFormat::GetString(
+ rCell, mnFormat, aValStr, &pColor, *mrDoc.GetFormatTable(), true, false, ftCheck);
+
+ if (aValStr.getLength() > mnMaxLen)
+ {
+ mnMaxLen = aValStr.getLength();
+ maMaxLenStr = aValStr;
}
}
- return nValue;
-}
+public:
+ MaxStrLenFinder(ScDocument& rDoc, sal_uInt32 nFormat) :
+ mrDoc(rDoc), mnFormat(nFormat), mnMaxLen(0) {}
+
+ void operator() (size_t /*nRow*/, double f)
+ {
+ ScRefCellValue aCell(f);
+ checkLength(aCell);
+ }
+
+ void operator() (size_t /*nRow*/, const OUString& rStr)
+ {
+ ScRefCellValue aCell(&rStr);
+ checkLength(aCell);
+ }
+
+ void operator() (size_t /*nRow*/, const EditTextObject* p)
+ {
+ ScRefCellValue aCell(p);
+ checkLength(aCell);
+ }
+
+ void operator() (size_t /*nRow*/, const ScFormulaCell* p)
+ {
+ ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
+ checkLength(aCell);
+ }
+};
+
+}
sal_uInt16 ScColumn::GetOptimalColWidth(
OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY,
bool bFormula, sal_uInt16 nOldWidth, const ScMarkData* pMarkData, const ScColWidthParam* pParam) const
{
- if ( maItems.empty() )
+ if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
+ // All cells are empty.
return nOldWidth;
- sal_uInt16 nWidth = (sal_uInt16) (nOldWidth * nPPTX);
- bool bFound = false;
+ sc::SingleColumnSpanSet aSpanSet;
+ sc::SingleColumnSpanSet::SpansType aMarkedSpans;
+ if (pMarkData)
+ {
+ aSpanSet.scan(*pMarkData, nTab, nCol);
+ aSpanSet.getSpans(aMarkedSpans);
+ }
+ else
+ // "Select" the entire column if no selection exists.
+ aMarkedSpans.push_back(sc::SingleColumnSpanSet::Span(0, MAXROW));
+
+ sal_uInt16 nWidth = static_cast<sal_uInt16>(nOldWidth*nPPTX);
+ bool bFound = false;
- SCSIZE nIndex;
- ScMarkedDataIter aDataIter(this, pMarkData, true);
if ( pParam && pParam->mbSimpleText )
{ // all the same except for number format
const ScPatternAttr* pPattern = GetPattern( 0 );
@@ -573,25 +638,12 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
}
else
{
- xub_StrLen nLongLen = 0;
- while (aDataIter.Next(nIndex))
- {
- if (nIndex >= maItems.size())
- // Out-of-bound reached. No need to keep going.
- break;
-
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
- OUString aValStr;
- ScCellFormat::GetString(
- aCell, nFormat, aValStr, &pColor, *pFormatter, true, false, ftCheck);
-
- if (aValStr.getLength() > nLongLen)
- {
- nLongLen = aValStr.getLength();
- aLongStr = aValStr;
- }
- }
+ // Go though all non-empty cells within selection.
+ MaxStrLenFinder aFunc(*pDocument, nFormat);
+ sc::CellStoreType::const_iterator itPos = maCells.begin();
+ sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
+ for (; it != itEnd; ++it)
+ itPos = sc::ParseAllNonEmpty(itPos, maCells, it->mnRow1, it->mnRow2, aFunc);
}
if (!aLongStr.isEmpty())
@@ -607,25 +659,44 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
const ScPatternAttr* pOldPattern = NULL;
sal_uInt8 nOldScript = 0;
- while (aDataIter.Next( nIndex ))
+ // Go though all non-empty cells within selection.
+ sc::CellStoreType::const_iterator itPos = maCells.begin();
+ sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
+ for (; it != itEnd; ++it)
{
- SCROW nRow = maItems[nIndex].nRow;
-
- sal_uInt8 nScript = pDocument->GetScriptType(nCol, nRow, nTab);
- if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
-
- const ScPatternAttr* pPattern = GetPattern( nRow );
- aOptions.pPattern = pPattern;
- aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
- sal_uInt16 nThis = (sal_uInt16) GetNeededSize( nRow, pDev, nPPTX, nPPTY,
- rZoomX, rZoomY, true, aOptions );
- pOldPattern = pPattern;
- if (nThis)
+ SCROW nRow1 = it->mnRow1, nRow2 = it->mnRow2;
+ SCROW nRow = nRow1;
+ while (nRow <= nRow2)
{
- if (nThis>nWidth || !bFound)
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
+ itPos = aPos.first;
+ if (itPos->type == sc::element_type_empty)
{
- nWidth = nThis;
- bFound = true;
+ // Skip empty cells.
+ nRow += itPos->size - aPos.second;
+ continue;
+ }
+
+ for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
+ {
+ sal_uInt8 nScript = pDocument->GetScriptType(nCol, nRow, nTab);
+ if (nScript == 0)
+ nScript = ScGlobal::GetDefaultScriptType();
+
+ const ScPatternAttr* pPattern = GetPattern(nRow);
+ aOptions.pPattern = pPattern;
+ aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
+ sal_uInt16 nThis = (sal_uInt16) GetNeededSize(
+ nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions);
+ pOldPattern = pPattern;
+ if (nThis)
+ {
+ if (nThis > nWidth || !bFound)
+ {
+ nWidth = nThis;
+ bFound = true;
+ }
+ }
}
}
}
@@ -704,7 +775,6 @@ void ScColumn::GetOptimalHeight(
}
else
{
- SCROW nRow = 0;
bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
bool bStdOnly = false;
if (bStdAllowed)
@@ -747,6 +817,11 @@ void ScColumn::GetOptimalHeight(
}
}
+ sc::SingleColumnSpanSet aSpanSet;
+ aSpanSet.scan(*this, nStart, nEnd);
+ sc::SingleColumnSpanSet::SpansType aSpans;
+ aSpanSet.getSpans(aSpans);
+
if (bStdAllowed)
{
sal_uInt16 nLatHeight = 0;
@@ -767,7 +842,7 @@ void ScColumn::GetOptimalHeight(
if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
- for (nRow=nStart; nRow<=nStdEnd; nRow++)
+ for (SCROW nRow = nStart; nRow <= nStdEnd; ++nRow)
if (nDefHeight > pHeight[nRow-nStartRow])
pHeight[nRow-nStartRow] = nDefHeight;
@@ -775,15 +850,16 @@ void ScColumn::GetOptimalHeight(
{
// if cells are not handled individually below,
// check for cells with different script type
-
- SCSIZE nIndex;
- Search(nStart,nIndex);
sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
- while ( nIndex < maItems.size() && (nRow=maItems[nIndex].nRow) <= nEnd )
+ sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+ for (; it != itEnd; ++it)
{
- sal_uInt8 nScript = GetRangeScriptType(itAttr, nRow, nRow);
- if ( nScript != nDefScript )
+ for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
{
+ sal_uInt8 nScript = GetRangeScriptType(itAttr, nRow, nRow);
+ if (nScript == nDefScript)
+ continue;
+
if ( nScript == SCRIPTTYPE_ASIAN )
{
if ( nCjkHeight == 0 )
@@ -806,7 +882,6 @@ void ScColumn::GetOptimalHeight(
pHeight[nRow-nStartRow] = nLatHeight;
}
}
- ++nIndex;
}
}
}
@@ -815,22 +890,23 @@ void ScColumn::GetOptimalHeight(
{
ScNeededSizeOptions aOptions;
- SCSIZE nIndex;
- Search(nStart,nIndex);
- while ( (nIndex < maItems.size()) ? ((nRow=maItems[nIndex].nRow) <= nEnd) : false )
+ sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+ for (; it != itEnd; ++it)
{
- // only calculate the cell height when it's used later (#37928#)
-
- if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
+ for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
{
- aOptions.pPattern = pPattern;
- sal_uInt16 nHeight = (sal_uInt16)
- ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
- rZoomX, rZoomY, false, aOptions ) / nPPTY );
- if (nHeight > pHeight[nRow-nStartRow])
- pHeight[nRow-nStartRow] = nHeight;
+ // only calculate the cell height when it's used later (#37928#)
+
+ if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
+ {
+ aOptions.pPattern = pPattern;
+ sal_uInt16 nHeight = (sal_uInt16)
+ ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, false, aOptions ) / nPPTY );
+ if (nHeight > pHeight[nRow-nStartRow])
+ pHeight[nRow-nStartRow] = nHeight;
+ }
}
- ++nIndex;
}
}
}
@@ -849,15 +925,14 @@ void ScColumn::GetOptimalHeight(
bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
{
bool bStop = false;
- CellType eCellType;
- SCSIZE nIndex;
- if (!bInSel && Search(nRow, nIndex))
+ sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
+ mdds::mtv::element_t eType = it->type;
+ if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
{
- eCellType = GetCellType(nRow);
- if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
!(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
pDocument->IsTabProtected(nTab)) )
- return true;
+ return true;
}
while (!bStop)
{
@@ -871,22 +946,24 @@ bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& r
}
else
{
- eCellType = GetCellType(nRow);
- if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ it = maCells.position(it, nRow).first;
+ eType = it->type;
+ if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
!(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
pDocument->IsTabProtected(nTab)) )
- return true;
+ return true;
else
nRow++;
}
}
else if (GetNextDataPos(nRow))
{
- eCellType = GetCellType(nRow);
- if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ it = maCells.position(it, nRow).first;
+ eType = it->type;
+ if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
!(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
pDocument->IsTabProtected(nTab)) )
- return true;
+ return true;
else
nRow++;
}
@@ -899,271 +976,218 @@ bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& r
return false;
}
-// =========================================================================================
+namespace {
-void ScColumn::RemoveAutoSpellObj()
+class StrEntries
{
- boost::scoped_ptr<ScTabEditEngine> pEngine;
-
- for (SCSIZE i=0; i<maItems.size(); i++)
- if ( maItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
- {
- ScEditCell* pOldCell = (ScEditCell*) maItems[i].pCell;
- const EditTextObject* pData = pOldCell->GetData();
- // no query on HasOnlineSpellErrors, this makes it also work after loading
-
- // For the test on hard formatting (ScEditAttrTester), are the defaults in the
- // EditEngine of no importance. When the tester would later recognise the same
- // attributes in default and hard formatting and has to remove them, the correct
- // defaults must be set in the EditEngine for each cell.
-
- // test for attributes
- if ( !pEngine )
- pEngine.reset(new ScTabEditEngine(pDocument));
- pEngine->SetText( *pData );
- ScEditAttrTester aTester(pEngine.get());
- if ( aTester.NeedsObject() ) // only remove spelling errors
- {
- pOldCell->SetData(pEngine->CreateTextObject());
- }
- else // create a string
- {
- OUString aText = ScEditUtil::GetSpaceDelimitedString(*pEngine);
- ScBaseCell* pNewCell = new ScStringCell( aText );
- maItems[i].pCell = pNewCell;
- delete pOldCell;
- }
- }
-}
+ sc::CellStoreType& mrCells;
-void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
-{
- boost::scoped_ptr<ScFieldEditEngine> pEngine;
+protected:
+ struct StrEntry
+ {
+ SCROW mnRow;
+ OUString maStr;
- SCSIZE i;
- Search( nStartRow, i );
- for (; i<maItems.size() && maItems[i].nRow <= nEndRow; i++)
- if ( maItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
- {
- ScEditCell* pOldCell = (ScEditCell*) maItems[i].pCell;
- const EditTextObject* pData = pOldCell->GetData();
+ StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
+ };
- // For the test on hard formatting (ScEditAttrTester), are the defaults in the
- // EditEngine of no importance. When the tester would later recognise the same
- // attributes in default and hard formatting and has to remove them, the correct
- // defaults must be set in the EditEngine for each cell.
+ std::vector<StrEntry> maStrEntries;
- // test for attributes
- if ( !pEngine )
- {
- pEngine.reset(new ScFieldEditEngine(pDocument, pDocument->GetEditPool()));
- // EE_CNTRL_ONLINESPELLING if there are errors already
- pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING );
- pDocument->ApplyAsianEditSettings( *pEngine );
- }
- pEngine->SetText( *pData );
- sal_Int32 nParCount = pEngine->GetParagraphCount();
- for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
- {
- pEngine->QuickRemoveCharAttribs( nPar );
- const SfxItemSet& rOld = pEngine->GetParaAttribs( nPar );
- if ( rOld.Count() )
- {
- SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // empty
- pEngine->SetParaAttribs( nPar, aNew );
- }
- }
- // change URL field to text (not possible otherwise, thus pType=0)
- pEngine->RemoveFields( true );
+ StrEntries(sc::CellStoreType& rCells) : mrCells(rCells) {}
- bool bSpellErrors = pEngine->HasOnlineSpellErrors();
- bool bNeedObject = bSpellErrors || nParCount>1; // keep errors/paragraphs
- // ScEditAttrTester is not needed anymore, arrays are gone
+public:
+ void commitStrings()
+ {
+ sc::CellStoreType::iterator it = mrCells.begin();
+ std::vector<StrEntry>::iterator itStr = maStrEntries.begin(), itStrEnd = maStrEntries.end();
+ for (; itStr != itStrEnd; ++itStr)
+ it = mrCells.set(it, itStr->mnRow, itStr->maStr);
+ }
+};
- if ( bNeedObject ) // remains edit cell
- {
- sal_uInt32 nCtrl = pEngine->GetControlWord();
- sal_uInt32 nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
- if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
- pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
- pOldCell->SetData(pEngine->CreateTextObject());
- }
- else // create String
- {
- String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
- ScBaseCell* pNewCell = new ScStringCell( aText );
- maItems[i].pCell = pNewCell;
- delete pOldCell;
- }
- }
-}
+class RemoveAutoSpellObjHandler : public StrEntries
+{
+ ScDocument* mpDoc;
+ boost::scoped_ptr<ScTabEditEngine> mpEngine;
-// =========================================================================================
+public:
+ RemoveAutoSpellObjHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells), mpDoc(pDoc) {}
-bool ScColumn::TestTabRefAbs(SCTAB nTable) const
-{
- bool bRet = false;
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- if ( maItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
- if (((ScFormulaCell*)maItems[i].pCell)->TestTabRefAbs(nTable))
- bRet = true;
- return bRet;
-}
+ void operator() (size_t nRow, EditTextObject*& pObj)
+ {
+ // no query on HasOnlineSpellErrors, this makes it also work after loading
-// =========================================================================================
+ // For the test on hard formatting (ScEditAttrTester), are the defaults in the
+ // EditEngine of no importance. When the tester would later recognise the same
+ // attributes in default and hard formatting and has to remove them, the correct
+ // defaults must be set in the EditEngine for each cell.
-ScColumnIterator::ScColumnIterator( const ScColumn* pCol, SCROW nStart, SCROW nEnd ) :
- pColumn( pCol ),
- nTop( nStart ),
- nBottom( nEnd )
-{
- pColumn->Search( nTop, nPos );
-}
+ // test for attributes
+ if (!mpEngine)
+ mpEngine.reset(new ScTabEditEngine(mpDoc));
-ScColumnIterator::~ScColumnIterator()
-{
-}
+ mpEngine->SetText(*pObj);
-bool ScColumnIterator::Next( SCROW& rRow, ScBaseCell*& rpCell )
-{
- if ( nPos < pColumn->maItems.size() )
- {
- rRow = pColumn->maItems[nPos].nRow;
- if ( rRow <= nBottom )
+ ScEditAttrTester aTester(mpEngine.get());
+ if (aTester.NeedsObject()) // only remove spelling errors
{
- rpCell = pColumn->maItems[nPos].pCell;
- ++nPos;
- return true;
+ // Overwrite the existing object.
+ delete pObj;
+ pObj = mpEngine->CreateTextObject();
+ }
+ else
+ {
+ // Store the string replacement for later commits.
+ OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
+ maStrEntries.push_back(StrEntry(nRow, aText));
}
}
+};
- rRow = 0;
- rpCell = NULL;
- return false;
-}
-
-SCSIZE ScColumnIterator::GetIndex() const // Index of the last cell asked
-{
- return nPos - 1; // next time the position is incremented
-}
-
-// -----------------------------------------------------------------------------------------
-
-ScMarkedDataIter::ScMarkedDataIter( const ScColumn* pCol, const ScMarkData* pMarkData,
- bool bAllIfNone ) :
- pColumn( pCol ),
- pMarkIter( NULL ),
- bNext( true ),
- bAll( bAllIfNone )
+class RemoveEditAttribsHandler : public StrEntries
{
- if (pMarkData && pMarkData->IsMultiMarked())
- pMarkIter = new ScMarkArrayIter( pMarkData->GetArray() + pCol->GetCol() );
-}
+ ScDocument* mpDoc;
+ boost::scoped_ptr<ScFieldEditEngine> mpEngine;
-ScMarkedDataIter::~ScMarkedDataIter()
-{
- delete pMarkIter;
-}
+public:
+ RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells), mpDoc(pDoc) {}
-bool ScMarkedDataIter::Next( SCSIZE& rIndex )
-{
- bool bFound = false;
- do
+ void operator() (size_t nRow, EditTextObject*& pObj)
{
- if (bNext)
- {
- if (!pMarkIter || !pMarkIter->Next( nTop, nBottom ))
+ // For the test on hard formatting (ScEditAttrTester), are the defaults in the
+ // EditEngine of no importance. When the tester would later recognise the same
+ // attributes in default and hard formatting and has to remove them, the correct
+ // defaults must be set in the EditEngine for each cell.
+
+ // test for attributes
+ if (!mpEngine)
+ {
+ mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
+ // EE_CNTRL_ONLINESPELLING if there are errors already
+ mpEngine->SetControlWord(mpEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING);
+ mpDoc->ApplyAsianEditSettings(*mpEngine);
+ }
+ mpEngine->SetText(*pObj);
+ sal_Int32 nParCount = mpEngine->GetParagraphCount();
+ for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
+ {
+ mpEngine->QuickRemoveCharAttribs(nPar);
+ const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
+ if ( rOld.Count() )
{
- if (bAll) // complete column
- {
- nTop = 0;
- nBottom = MAXROW;
- }
- else
- return false;
+ SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // empty
+ mpEngine->SetParaAttribs( nPar, aNew );
}
- pColumn->Search( nTop, nPos );
- bNext = false;
- bAll = false; // only the first time
}
+ // change URL field to text (not possible otherwise, thus pType=0)
+ mpEngine->RemoveFields(true);
- if ( nPos >= pColumn->maItems.size() )
- return false;
+ bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
+ bool bNeedObject = bSpellErrors || nParCount>1; // keep errors/paragraphs
+ // ScEditAttrTester is not needed anymore, arrays are gone
- if ( pColumn->maItems[nPos].nRow <= nBottom )
- bFound = true;
- else
- bNext = true;
+ if (bNeedObject) // remains edit cell
+ {
+ sal_uInt32 nCtrl = mpEngine->GetControlWord();
+ sal_uInt32 nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
+ if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
+ mpEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
+
+ // Overwrite the existing object.
+ delete pObj;
+ pObj = mpEngine->CreateTextObject();
+ }
+ else // create String
+ {
+ // Store the string replacement for later commits.
+ OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
+ maStrEntries.push_back(StrEntry(nRow, aText));
+ }
}
- while (!bFound);
+};
+
+class TestTabRefAbsHandler
+{
+ SCTAB mnTab;
+ bool mbTestResult;
+public:
+ TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
+
+ void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
+ {
+ if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
+ mbTestResult = true;
+ }
+
+ bool getTestResult() const { return mbTestResult; }
+};
- rIndex = nPos++;
- return true;
}
+void ScColumn::RemoveAutoSpellObj()
+{
+ RemoveAutoSpellObjHandler aFunc(maCells, pDocument);
+ sc::ProcessEditText(maCells, aFunc);
+ aFunc.commitStrings();
+}
-//------------
+void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
+{
+ RemoveEditAttribsHandler aFunc(maCells, pDocument);
+ sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
+ aFunc.commitStrings();
+}
-bool ScColumn::IsEmptyData() const
+bool ScColumn::TestTabRefAbs(SCTAB nTable) const
{
- return (maItems.empty());
+ TestTabRefAbsHandler aFunc(nTable);
+ sc::ParseFormula(maCells, aFunc);
+ return aFunc.getTestResult();
}
-bool ScColumn::IsEmptyVisData() const
+bool ScColumn::IsEmptyData() const
{
- return maItems.empty();
+ return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
}
-SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
+namespace {
+
+class CellCounter
{
- // Notes are not counted
+ size_t mnCount;
+public:
+ CellCounter() : mnCount(0) {}
- SCSIZE nVisCount = 0;
- SCSIZE nIndex;
- Search( nStartRow, nIndex );
- while ( nIndex < maItems.size() && maItems[nIndex].nRow <= nEndRow )
+ void operator() (
+ const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
{
- if ( maItems[nIndex].nRow >= nStartRow )
- {
- ++nVisCount;
- }
- ++nIndex;
+ if (node.type == sc::element_type_empty)
+ return;
+
+ mnCount += nDataSize;
}
- return nVisCount;
-}
-SCROW ScColumn::GetLastVisDataPos() const
-{
- if (maItems.empty())
- return 0;
+ size_t getCount() const { return mnCount; }
+};
- return maItems.back().nRow;
}
-SCROW ScColumn::GetFirstVisDataPos() const
+SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
{
- SCROW nRet = 0;
- if ( !maItems.empty() )
- {
- SCSIZE i;
- bool bFound = false;
- for (i=0; i<maItems.size() && !bFound; i++)
- {
- bFound = true;
- nRet = maItems[i].nRow;
- }
- }
- return nRet;
+ CellCounter aFunc;
+ sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
+ return aFunc.getCount();
}
bool ScColumn::HasVisibleDataAt(SCROW nRow) const
{
- std::vector<ColEntry>::const_iterator it = Search(nRow);
- if (it == maItems.end())
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
+ // Likely invalid row number.
return false;
- return it->nRow == nRow;
+ return it->type != sc::element_type_empty;
}
bool ScColumn::IsEmptyAttr() const
@@ -1181,100 +1205,174 @@ bool ScColumn::IsEmpty() const
bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
{
- if ( maItems.empty() )
- return true;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
+ // Invalid row number.
+ return false;
- std::vector<ColEntry>::const_iterator it = Search(nStartRow);
- if (it == maItems.end())
- // All non-empty cells are before nStartRow.
- return true;
+ if (it->type != sc::element_type_empty)
+ // Non-empty cell at the start position.
+ return false;
- return (it->nRow > nEndRow);
+ // start position of next block which is not empty.
+ SCROW nNextRow = nStartRow + it->size - aPos.second;
+ return nEndRow < nNextRow;
}
SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
{
- SCSIZE nLines = 0;
- SCSIZE i;
- if ( !maItems.empty() )
+ // Given a range of rows, find a top or bottom empty segment.
+ switch (eDir)
{
- bool bFound = false;
- if (eDir == DIR_BOTTOM)
- {
- i = maItems.size();
- while (!bFound && (i > 0))
- {
- i--;
- if ( maItems[i].nRow < nStartRow )
- break;
- bFound = maItems[i].nRow <= nEndRow;
- }
- if (bFound)
- nLines = static_cast<SCSIZE>(nEndRow - maItems[i].nRow);
- else
- nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
+ case DIR_TOP:
+ {
+ // Determine the length of empty head segment.
+ size_t nLength = nEndRow - nStartRow + 1;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it->type != sc::element_type_empty)
+ // First row is already not empty.
+ return 0;
+
+ // length of this empty block minus the offset.
+ size_t nThisLen = it->size - aPos.second;
+ return std::min(nThisLen, nLength);
}
- else if (eDir == DIR_TOP)
- {
- i = 0;
- while (!bFound && (i < maItems.size()))
- {
- if ( maItems[i].nRow > nEndRow )
- break;
- bFound = maItems[i].nRow >= nStartRow;
- i++;
- }
- if (bFound)
- nLines = static_cast<SCSIZE>(maItems[i-1].nRow - nStartRow);
- else
- nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
+ break;
+ case DIR_BOTTOM:
+ {
+ // Determine the length empty tail segment.
+ size_t nLength = nEndRow - nStartRow + 1;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it->type != sc::element_type_empty)
+ // end row is already not empty.
+ return 0;
+
+ // length of this empty block from the tip to the end row position.
+ size_t nThisLen = aPos.second;
+ return std::min(nThisLen, nLength);
}
+ break;
+ default:
+ ;
}
- else
- nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
- return nLines;
+
+ return 0;
}
SCROW ScColumn::GetFirstDataPos() const
{
- if ( !maItems.empty() )
- return maItems[0].nRow;
- else
+ if (IsEmptyData())
return 0;
+
+ sc::CellStoreType::const_iterator it = maCells.begin();
+ if (it->type != sc::element_type_empty)
+ return 0;
+
+ return it->size;
}
SCROW ScColumn::GetLastDataPos() const
{
- if ( !maItems.empty() )
- return maItems.back().nRow;
- else
+ if (IsEmptyData())
return 0;
+
+ sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
+ if (it->type != sc::element_type_empty)
+ return MAXROW;
+
+ return MAXROW - static_cast<SCROW>(it->size);
}
bool ScColumn::GetPrevDataPos(SCROW& rRow) const
{
- bool bFound = false;
- SCSIZE i = maItems.size();
- while (!bFound && (i > 0))
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
+ return false;
+
+ if (it->type == sc::element_type_empty)
+ {
+ if (it == maCells.begin())
+ // No more previous non-empty cell.
+ return false;
+
+ rRow -= aPos.second + 1; // Last row position of the previous block.
+ return true;
+ }
+
+ // This block is not empty.
+ if (aPos.second)
{
- --i;
- bFound = (maItems[i].nRow < rRow);
- if (bFound)
- rRow = maItems[i].nRow;
+ // There are preceding cells in this block. Simply move back one cell.
+ --rRow;
+ return true;
}
- return bFound;
+
+ // This is the first cell in an non-empty block. Move back to the previous block.
+ if (it == maCells.begin())
+ // No more preceding block.
+ return false;
+
+ --rRow; // Move to the last cell of the previous block.
+ --it;
+ if (it->type == sc::element_type_empty)
+ {
+ // This block is empty.
+ if (it == maCells.begin())
+ // No more preceding blocks.
+ return false;
+
+ // Skip the whole empty block segment.
+ rRow -= it->size;
+ }
+
+ return true;
}
bool ScColumn::GetNextDataPos(SCROW& rRow) const // greater than rRow
{
- SCSIZE nIndex;
- if (Search( rRow, nIndex ))
- ++nIndex; // next cell
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
+ return false;
+
+ if (it->type == sc::element_type_empty)
+ {
+ // This block is empty. Skip ahead to the next block (if exists).
+ rRow += it->size - aPos.second;
+ ++it;
+ if (it == maCells.end())
+ // No more next block.
+ return false;
+ }
+
+ if (aPos.second < it->size - 1)
+ {
+ // There are still cells following the current position.
+ ++rRow;
+ return true;
+ }
+
+ // This is the last cell in the block. Move ahead to the next block.
+ rRow += it->size - aPos.second; // First cell in the next block.
+ ++it;
+ if (it == maCells.end())
+ // No more next block.
+ return false;
+
+ if (it->type == sc::element_type_empty)
+ {
+ // Next block is empty. Move to the next block.
+ rRow += it->size;
+ ++it;
+ if (it == maCells.end())
+ return false;
+ }
- bool bMore = ( nIndex < maItems.size() );
- if ( bMore )
- rRow = maItems[nIndex].nRow;
- return bMore;
+ return true;
}
SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
@@ -1301,103 +1399,123 @@ SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
}
}
-SCROW ScColumn::FindNextVisibleRowWithContent(SCROW nRow, bool bForward) const
+SCROW ScColumn::FindNextVisibleRowWithContent(
+ sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
{
- if(bForward)
+ if (bForward)
{
do
{
nRow++;
SCROW nEndRow = 0;
bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
- if(bHidden)
+ if (bHidden)
{
nRow = nEndRow + 1;
if(nRow >= MAXROW)
return MAXROW;
}
- SCSIZE nIndex;
- bool bThere = Search( nRow, nIndex );
- if (bThere)
- return nRow;
- else if((bThere ? nIndex+1 : nIndex) >= maItems.size())
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
+ itPos = aPos.first;
+ if (itPos == maCells.end())
+ // Invalid row.
return MAXROW;
- else
- {
- if(bThere)
- nRow = maItems[nIndex+1].nRow - 1;
- else
- nRow = maItems[nIndex].nRow - 1;
- }
+
+ if (itPos->type != sc::element_type_empty)
+ return nRow;
+
+ // Move to the last cell of the current empty block.
+ nRow += itPos->size - aPos.second - 1;
}
- while(nRow < MAXROW);
+ while (nRow < MAXROW);
return MAXROW;
}
- else
+
+ do
{
- do
+ nRow--;
+ SCROW nStartRow = MAXROW;
+ bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
+ if (bHidden)
{
- nRow--;
- SCROW nStartRow = MAXROW;
- bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
- if(bHidden)
- {
- nRow = nStartRow - 1;
- if(nRow <= 0)
- return 0;
- }
-
- SCSIZE nIndex;
- bool bThere = Search( nRow, nIndex );
- if (bThere)
- return nRow;
- else if(nIndex == 0)
+ nRow = nStartRow - 1;
+ if(nRow <= 0)
return 0;
- else
- nRow = maItems[nIndex-1].nRow + 1;
}
- while(nRow > 0);
- return 0;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
+ itPos = aPos.first;
+ if (itPos == maCells.end())
+ // Invalid row.
+ return 0;
+
+ if (itPos->type != sc::element_type_empty)
+ return nRow;
+
+ // Move to the first cell of the current empty block.
+ nRow -= aPos.second;
}
+ while (nRow > 0);
+
+ return 0;
}
void ScColumn::CellStorageModified()
{
mbDirtyGroups = true;
+
#if DEBUG_COLUMN_STORAGE
- if (maItems.empty())
+ if (maCells.size() != MAXROWCOUNT)
{
- if (maCellTextAttrs.empty())
- {
- cout << "ScColumn::CellStorageModified: Text width array is empty, but shouldn't." << endl;
- cout.flush();
- abort();
- }
+ cout << "ScColumn::CellStorageModified: Size of the cell array is incorrect." << endl;
+ cout.flush();
+ abort();
+ }
- if (maCellTextAttrs.block_size() != 1 || maCellTextAttrs.begin()->type != mdds::mtv::element_type_empty)
- {
- cout << "ScColumn::CellStorageModified: When the cell array is empty, the cell text attribute array should consist of one empty block." << endl;
- cout.flush();
- abort();
- }
+ if (maCellTextAttrs.size() != MAXROWCOUNT)
+ {
+ cout << "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl;
+ cout.flush();
+ abort();
+ }
- return;
+ if (maBroadcasters.size() != MAXROWCOUNT)
+ {
+ cout << "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl;
+ cout.flush();
+ abort();
}
- ScColumnTextWidthIterator aIter(*this, 0, MAXROW);
- for (; aIter.hasCell(); aIter.next())
+ // Make sure that these two containers are synchronized wrt empty segments.
+ sc::CellStoreType::const_iterator itCell = maCells.begin();
+ sc::CellTextAttrStoreType::const_iterator itAttr = maCellTextAttrs.begin();
+
+ // Move to the first empty blocks.
+ while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
+ ++itCell;
+
+ while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
+ ++itAttr;
+
+ while (itCell != maCells.end())
{
- SCROW nRow = aIter.getPos();
- ScBaseCell* pCell = GetCell(nRow);
- if (!pCell)
+ if (itCell->position != itAttr->position || itCell->size != itAttr->size)
{
- cout << "ScColumn::CellStorageModified: Cell and text width storages are out of sync!" << endl;
+ cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
cout.flush();
abort();
}
+
+ // Move to the next empty blocks.
+ ++itCell;
+ while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
+ ++itCell;
+
+ ++itAttr;
+ while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
+ ++itAttr;
}
#endif
}
@@ -1465,142 +1583,87 @@ void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& r
}
}
-void ScColumn::SetCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell )
+namespace {
+
+class CellTextAttrInitializer
{
- if(pNewCell->GetCellType() == CELLTYPE_FORMULA)
+ sc::CellTextAttrStoreType maAttrs;
+ sc::CellTextAttrStoreType::iterator miPos;
+public:
+ CellTextAttrInitializer() : maAttrs(MAXROWCOUNT), miPos(maAttrs.begin()) {}
+
+ void operator() (const sc::CellStoreType::value_type& node)
{
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pNewCell);
- sal_uInt32 nCellFormat = GetNumberFormat( nRow );
- if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
- pFCell->SetNeedNumberFormat(true);
+ if (node.type == sc::element_type_empty)
+ return;
+ // Fill with default values for non-empty cell segments.
+ std::vector<sc::CellTextAttr> aDefaults(node.size);
+ miPos = maAttrs.set(miPos, node.position, aDefaults.begin(), aDefaults.end());
}
- bool bIsAppended = false;
- if ( !maItems.empty() )
+ void swap(sc::CellTextAttrStoreType& rAttrs)
{
- if (maItems.back().nRow < nRow)
- {
- Append(rBlockPos, nRow, pNewCell);
- bIsAppended = true;
- }
+ maAttrs.swap(rAttrs);
}
- if (!bIsAppended)
- {
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- {
- ScBaseCell* pOldCell = maItems[nIndex].pCell;
- if ( pOldCell->GetCellType() == CELLTYPE_FORMULA && !pDocument->IsClipOrUndo() )
- static_cast<ScFormulaCell*>(pOldCell)->EndListeningTo( pDocument );
- pOldCell->Delete();
- maItems[nIndex].pCell = pNewCell;
- }
- else
- {
- maItems.insert(maItems.begin() + nIndex, ColEntry());
- maItems[nIndex].pCell = pNewCell;
- maItems[nIndex].nRow = nRow;
- }
+};
- rBlockPos.miCellTextAttrPos =
- maCellTextAttrs.set(rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+}
- CellStorageModified();
- }
+void ScColumn::ResetCellTextAttrs()
+{
+ CellTextAttrInitializer aFunc;
+ std::for_each(maCells.begin(), maCells.end(), aFunc);
+ aFunc.swap(maCellTextAttrs);
}
-void ScColumn::SetCell( SCROW nRow, ScBaseCell* pNewCell )
+void ScColumn::SwapCellTextAttrs( SCROW nRow1, SCROW nRow2 )
{
- if(pNewCell->GetCellType() == CELLTYPE_FORMULA)
- {
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pNewCell);
- sal_uInt32 nCellFormat = GetNumberFormat( nRow );
- if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
- pFCell->SetNeedNumberFormat(true);
+ typedef std::pair<sc::CellTextAttrStoreType::iterator,size_t> PosType;
- }
+ if (nRow1 == nRow2)
+ return;
- bool bIsAppended = false;
- if ( !maItems.empty() )
- {
- if (maItems.back().nRow < nRow)
- {
- Append(nRow, pNewCell);
- bIsAppended = true;
- }
- }
- if (!bIsAppended)
- {
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- {
- ScBaseCell* pOldCell = maItems[nIndex].pCell;
- if ( pOldCell->GetCellType() == CELLTYPE_FORMULA && !pDocument->IsClipOrUndo() )
- static_cast<ScFormulaCell*>(pOldCell)->EndListeningTo( pDocument );
- pOldCell->Delete();
- maItems[nIndex].pCell = pNewCell;
- }
- else
- {
- maItems.insert(maItems.begin() + nIndex, ColEntry());
- maItems[nIndex].pCell = pNewCell;
- maItems[nIndex].nRow = nRow;
- }
+ if (nRow1 > nRow2)
+ std::swap(nRow1, nRow2);
- maCellTextAttrs.set(nRow, sc::CellTextAttr());
- CellStorageModified();
- }
-}
+ PosType aPos1 = maCellTextAttrs.position(nRow1);
+ if (aPos1.first == maCellTextAttrs.end())
+ return;
-void ScColumn::PostSetCell( SCROW nRow, ScBaseCell* pNewCell )
-{
- // When we insert from the Clipboard we still have wrong (old) References!
- // First they are rewired in CopyBlockFromClip via UpdateReference and the
- // we call StartListeningFromClip and BroadcastFromClip.
- // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
- // After Import we call CalcAfterLoad and in there Listening.
- if ( !(pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) )
- {
- CellType eCellType = pNewCell->GetCellType();
- if (eCellType == CELLTYPE_FORMULA)
- static_cast<ScFormulaCell*>(pNewCell)->StartListeningTo(pDocument);
+ PosType aPos2 = maCellTextAttrs.position(aPos1.first, nRow2);
+ if (aPos2.first == maCellTextAttrs.end())
+ return;
- if (!pDocument->IsCalcingAfterLoad())
- {
- if ( eCellType == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pNewCell)->SetDirty();
- else
- pDocument->Broadcast(
- ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
- }
- }
-}
+ sc::CellTextAttrStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
+ if (it1->type == it2->type)
+ {
+ if (it1->type == sc::element_type_empty)
+ // Both are empty. Nothing to swap.
+ return;
-namespace {
+ // Both are non-empty. Simply swap their values.
+ std::swap(
+ sc::celltextattr_block::at(*it1->data, aPos1.second),
+ sc::celltextattr_block::at(*it2->data, aPos2.second));
-class SetEmptyAttr : std::unary_function<ColEntry, void>
-{
- sc::CellTextAttrStoreType& mrAttrStore;
- sc::CellTextAttrStoreType::iterator miPos;
-public:
- SetEmptyAttr(sc::CellTextAttrStoreType& rAttrStore) :
- mrAttrStore(rAttrStore), miPos(rAttrStore.begin()) {}
+ return;
+ }
- void operator() (const ColEntry& rEntry)
+ // One is empty while the other isn't.
+ if (it1->type == sc::element_type_empty)
{
- miPos = mrAttrStore.set(miPos, rEntry.nRow, sc::CellTextAttr());
+ // row 1 is empty while row 2 is non-empty.
+ const sc::CellTextAttr& rVal2 = sc::celltextattr_block::at(*it2->data, aPos2.second);
+ it1 = maCellTextAttrs.set(it1, nRow1, rVal2);
+ maCellTextAttrs.set_empty(it1, nRow2, nRow2);
+ return;
}
-};
-
-}
-void ScColumn::ResetCellTextAttrs()
-{
- maCellTextAttrs.clear();
- maCellTextAttrs.resize(MAXROWCOUNT);
-
- std::for_each(maItems.begin(), maItems.end(), SetEmptyAttr(maCellTextAttrs));
+ // row 1 is non-empty while row 2 is empty.
+ sc::CellTextAttr aVal1 = sc::celltextattr_block::at(*it1->data, aPos1.second); // make a copy.
+ it1 = maCellTextAttrs.set_empty(it1, nRow1, nRow1);
+ maCellTextAttrs.set(it1, nRow2, aVal1);
}
SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
@@ -1751,73 +1814,78 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
{
- std::vector<ColEntry>::iterator it = Search(nRow);
- std::vector<ColEntry>::iterator itEnd = maItems.end();
-
- if (it == itEnd || it->nRow != nRow)
- {
- // Empty cell.
- return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
- }
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::iterator it = aPos.first;
+ if (it == maCells.end())
+ // Invalid row. Return a null token.
+ return formula::FormulaTokenRef();
- ScBaseCell* pCell = it->pCell;
- switch (pCell->GetCellType())
+ switch (it->type)
{
- case CELLTYPE_VALUE:
+ case sc::element_type_numeric:
{
- ScValueCell* pVC = static_cast<ScValueCell*>(pCell);
- return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pVC->GetValue()));
+ double fVal = sc::numeric_block::at(*it->data, aPos.second);
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(fVal));
}
- case CELLTYPE_FORMULA:
+ case sc::element_type_formula:
{
- ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
- if (pFC->GetDirty())
- // Dirty formula cell is not considered static. Return null token.
+ ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
+ if (p->GetDirty())
+ // Dirty formula cell is not considered static (for now).
+ // Return null token. Later we will switch to dynamically
+ // interpreting all dirty formula cells.
return formula::FormulaTokenRef();
- return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pFC->GetResultDouble()));
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(p->GetResultDouble()));
}
+ case sc::element_type_empty:
default:
- ;
+ // Return a value of 0.0 in all the other cases.
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
}
-
- return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
}
-bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
+namespace {
+
+class ToMatrixHandler
{
- if (nRow1 > nRow2)
- return false;
+ ScMatrix& mrMat;
+ SCCOL mnMatCol;
+ SCROW mnTopRow;
+ bool mbSuccess;
+public:
+ ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow) :
+ mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow), mbSuccess(true) {}
- std::vector<ColEntry>::iterator it = Search(nRow1);
- std::vector<ColEntry>::iterator itEnd = maItems.end();
+ void operator() (size_t nRow, double fVal)
+ {
+ mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
+ }
- for (; it != itEnd && it->nRow <= nRow2; ++it)
+ void operator() (size_t nRow, ScFormulaCell* p)
{
- switch (it->pCell->GetCellType())
+ if (p->GetDirty())
{
- case CELLTYPE_VALUE:
- {
- ScValueCell* pVC = static_cast<ScValueCell*>(it->pCell);
- rMat.PutDouble(pVC->GetValue(), nMatCol, it->nRow - nRow1);
- }
- break;
- case CELLTYPE_FORMULA:
- {
- ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
- if (pFC->GetDirty())
- // Dirty formula cell is not considered static. Return null token.
- return false;
-
- rMat.PutDouble(pFC->GetResultDouble(), nMatCol, it->nRow - nRow1);
- }
- break;
- default:
- ;
+ mbSuccess = false;
+ return;
}
+
+ mrMat.PutDouble(p->GetResultDouble(), mnMatCol, nRow - mnTopRow);
}
- return true;
+ bool isSuccess() const { return mbSuccess; }
+};
+
+}
+
+bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
+{
+ if (nRow1 > nRow2)
+ return false;
+
+ ToMatrixHandler aFunc(rMat, nMatCol, nRow1);
+ sc::ProcessFormulaNumeric(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+ return aFunc.isSuccess();
}
const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCROW nRow1, SCROW nRow2 ) const
@@ -1826,59 +1894,18 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCR
if (nRow1 > nRow2)
return NULL;
- std::vector<ColDoubleEntry*>::const_iterator it = maDoubles.begin(), itEnd = maDoubles.end();
- size_t nOffset = 0;
- for (; it != itEnd; ++it)
- {
- const ColDoubleEntry& rEntry = **it;
- SCROW nRowStart = rEntry.mnStart;
- SCROW nRowEnd = nRowStart + rEntry.maData.size() - 1;
- if (nRowStart <= nRow1 && nRow2 <= nRowEnd)
- {
- // Found it.
- nOffset = nRow1 - nRowStart;
- break;
- }
- }
-
- if (it == itEnd)
- {
- // Array not found.
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
+ if (aPos.first->type != sc::element_type_numeric)
+ // This is not a numeric cell block.
return NULL;
- }
- const ColDoubleEntry& rEntry = **it;
- return &rEntry.maData[0] + nOffset;
-}
-
-ScRefCellValue ScColumn::GetRefCellValue( SCROW nRow )
-{
- ScRefCellValue aCell; // start empty
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
- return aCell;
-
- ScBaseCell* pCell = maItems[nIndex].pCell;
- aCell.meType = pCell->GetCellType();
- switch (aCell.meType)
- {
- case CELLTYPE_STRING:
- aCell.mpString = static_cast<const ScStringCell*>(pCell)->GetStringPtr();
- break;
- case CELLTYPE_EDIT:
- aCell.mpEditText = static_cast<const ScEditCell*>(pCell)->GetData();
- break;
- case CELLTYPE_VALUE:
- aCell.mfValue = static_cast<const ScValueCell*>(pCell)->GetValue();
- break;
- case CELLTYPE_FORMULA:
- aCell.mpFormula = static_cast<ScFormulaCell*>(pCell);
- break;
- default:
- aCell.meType = CELLTYPE_NONE; // reset to empty.
+ size_t nLen = aPos.first->size - aPos.second;
+ if (static_cast<SCROW>(nLen) < nRow2 - nRow1 + 1)
+ // Array shorter than requested.
+ return NULL;
}
- return aCell;
+ return &sc::numeric_block::at(*aPos.first->data, aPos.second);
}
void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
@@ -1896,71 +1923,66 @@ const ScFormulaCell* ScColumn::FetchFormulaCell( SCROW nRow ) const
if (!ValidRow(nRow))
return NULL;
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
- // cell not found.
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
return NULL;
- const ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() != CELLTYPE_FORMULA)
+ if (it->type != sc::element_type_formula)
// Not a formula cell.
return NULL;
- return static_cast<const ScFormulaCell*>(pCell);
+ return sc::formula_block::at(*it->data, aPos.second);
}
void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
{
- // check if we are in a data area
- SCSIZE nIndex;
- bool bThere = Search(rRow, nIndex);
+ // If the cell is empty, find the next non-empty cell position. If the
+ // cell is not empty, find the last non-empty cell position in the current
+ // contiguous cell block.
- size_t nLastIndex = maItems.size() - 1;
- if (bThere)
- {
- SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
- SCSIZE nNewIndex;
- bool bNextThere = Search(nNextRow, nNewIndex);
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
+ // Invalid row.
+ return;
- if(bNextThere)
- {
- SCROW nLastRow;
- nLastRow = nNextRow;
- do
- {
- nNextRow = FindNextVisibleRow(nLastRow, bDown);
- bNextThere = Search(nNextRow, nNewIndex);
- if (!bNextThere)
- bNextThere = false;
- else
- nLastRow = nNextRow;
- }
- while(bNextThere && nNewIndex < nLastIndex && nNewIndex > 0);
+ if (it->type == sc::element_type_empty)
+ {
+ // Current cell is empty. Find the next non-empty cell.
+ rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
+ return;
+ }
- rRow = nLastRow;
- }
- else
- {
- rRow = FindNextVisibleRowWithContent(nNextRow, bDown);
- }
+ // Current cell is not empty.
+ SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
+ aPos = maCells.position(it, nNextRow);
+ it = aPos.first;
+ if (it->type == sc::element_type_empty)
+ {
+ // Next visible cell is empty. Find the next non-empty cell.
+ rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
+ return;
}
- else
+
+ // Next visible cell is non-empty. Find the edge that's still visible.
+ SCROW nLastRow = nNextRow;
+ do
{
- rRow = FindNextVisibleRowWithContent(rRow, bDown);
+ nNextRow = FindNextVisibleRow(nLastRow, bDown);
+ aPos = maCells.position(it, nNextRow);
+ it = aPos.first;
+ if (it->type != sc::element_type_empty)
+ nLastRow = nNextRow;
}
+ while (it->type != sc::element_type_empty);
+
+ rRow = nLastRow;
}
bool ScColumn::HasDataAt(SCROW nRow) const
{
- // are only visible cells interesting ?
- //! then HasVisibleDataAt out
-
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- return true;
-
- return false;
-
+ return maCells.get_type(nRow) != sc::element_type_empty;
}
bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
@@ -1992,7 +2014,7 @@ bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow, bool bFullFormattedArea ) co
if (pAttrArray)
{
// row of last cell is needed
- SCROW nLastData = GetLastVisDataPos(); // always including notes, 0 if none
+ SCROW nLastData = GetLastDataPos(); // always including notes, 0 if none
return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData, bFullFormattedArea );
}
@@ -2008,16 +2030,33 @@ bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
return false;
}
-void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, bool* pUsed ) const
+namespace {
+
+class FindUsedRowsHandler
{
- SCROW nRow = 0;
- SCSIZE nIndex;
- Search( nStartRow, nIndex );
- while ( (nIndex < maItems.size()) ? ((nRow=maItems[nIndex].nRow) <= nEndRow) : false )
+ typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
+ UsedRowsType& mrUsed;
+ UsedRowsType::const_iterator miUsed;
+public:
+ FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
+
+ void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
{
- pUsed[nRow-nStartRow] = true;
- ++nIndex;
+ if (node.type == sc::element_type_empty)
+ return;
+
+ SCROW nRow1 = node.position + nOffset;
+ SCROW nRow2 = nRow1 + nDataSize - 1;
+ miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
}
+};
+
+}
+
+void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
+{
+ FindUsedRowsHandler aFunc(rUsed);
+ sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
}
namespace {
@@ -2133,141 +2172,219 @@ void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListe
rCxt.addEmptyBroadcasterPosition(nTab, nCol, nRow);
}
+namespace {
+
+struct CompileDBFormulaHandler
+{
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ p->CompileDBFormula();
+ }
+};
+
+class CompileDBFormula2Handler
+{
+ bool mbCreateFormulaString;
+
+public:
+ CompileDBFormula2Handler(bool bCreateFormulaString) :
+ mbCreateFormulaString(bCreateFormulaString) {}
+
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ p->CompileDBFormula(mbCreateFormulaString);
+ }
+};
+
+class CompileNameFormulaHandler
+{
+ bool mbCreateFormulaString;
+
+public:
+ CompileNameFormulaHandler(bool bCreateFormulaString) :
+ mbCreateFormulaString(bCreateFormulaString) {}
+
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ p->CompileNameFormula(mbCreateFormulaString);
+ }
+};
+
+struct CompileColRowNameFormulaHandler
+{
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ p->CompileColRowNameFormula();
+ }
+};
+
+}
+
void ScColumn::CompileDBFormula()
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*) pCell)->CompileDBFormula();
- }
+ CompileDBFormulaHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
}
void ScColumn::CompileDBFormula( bool bCreateFormulaString )
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*) pCell)->CompileDBFormula( bCreateFormulaString );
- }
+ CompileDBFormula2Handler aFunc(bCreateFormulaString);
+ sc::ProcessFormula(maCells, aFunc);
}
void ScColumn::CompileNameFormula( bool bCreateFormulaString )
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*) pCell)->CompileNameFormula( bCreateFormulaString );
- }
+ CompileNameFormulaHandler aFunc(bCreateFormulaString);
+ sc::ProcessFormula(maCells, aFunc);
}
void ScColumn::CompileColRowNameFormula()
{
- if ( !maItems.empty() )
- for (SCSIZE i = 0; i < maItems.size(); i++)
- {
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*) pCell)->CompileColRowNameFormula();
- }
+ CompileColRowNameFormulaHandler aFunc;
+ sc::ProcessFormula(maCells, aFunc);
}
-static void lcl_UpdateSubTotal( ScFunctionData& rData, const ScBaseCell* pCell )
+namespace {
+
+class UpdateSubTotalHandler
{
- double nValue = 0.0;
- bool bVal = false;
- bool bCell = true;
- switch (pCell->GetCellType())
- {
- case CELLTYPE_VALUE:
- nValue = ((ScValueCell*)pCell)->GetValue();
- bVal = true;
- break;
- case CELLTYPE_FORMULA:
- {
- if ( rData.eFunc != SUBTOTAL_FUNC_CNT2 ) // it doesn't interest us
- {
- ScFormulaCell* pFC = (ScFormulaCell*)pCell;
- if ( pFC->GetErrCode() )
- {
- if ( rData.eFunc != SUBTOTAL_FUNC_CNT ) // simply remove from count
- rData.bError = true;
- }
- else if (pFC->IsValue())
- {
- nValue = pFC->GetValue();
- bVal = true;
- }
- // otherwise text
- }
- }
- break;
- default:
- {
- // added to avoid warnings
- }
- }
+ ScFunctionData& mrData;
+ ScFlatBoolRowSegments& mrHiddenRows;
- if (!rData.bError)
+ void update(double fVal, bool bVal)
{
- switch (rData.eFunc)
+ if (!mrData.bError)
+ return;
+
+ switch (mrData.eFunc)
{
case SUBTOTAL_FUNC_SUM:
case SUBTOTAL_FUNC_AVE:
- if (bVal)
- {
- ++rData.nCount;
- if (!SubTotal::SafePlus( rData.nVal, nValue ))
- rData.bError = true;
- }
- break;
+ {
+ if (!bVal)
+ return;
+
+ ++mrData.nCount;
+ if (!SubTotal::SafePlus(mrData.nVal, fVal))
+ mrData.bError = true;
+ }
+ break;
case SUBTOTAL_FUNC_CNT: // only the value
- if (bVal)
- ++rData.nCount;
- break;
+ {
+ if (!bVal)
+ return;
+
+ ++mrData.nCount;
+ }
+ break;
case SUBTOTAL_FUNC_CNT2: // everything
- if (bCell)
- ++rData.nCount;
- break;
+ ++mrData.nCount;
+ break;
case SUBTOTAL_FUNC_MAX:
- if (bVal)
- if (++rData.nCount == 1 || nValue > rData.nVal )
- rData.nVal = nValue;
- break;
+ {
+ if (!bVal)
+ return;
+
+ if (++mrData.nCount == 1 || fVal > mrData.nVal)
+ mrData.nVal = fVal;
+ }
+ break;
case SUBTOTAL_FUNC_MIN:
- if (bVal)
- if (++rData.nCount == 1 || nValue < rData.nVal )
- rData.nVal = nValue;
- break;
+ {
+ if (!bVal)
+ return;
+
+ if (++mrData.nCount == 1 || fVal < mrData.nVal)
+ mrData.nVal = fVal;
+ }
+ break;
default:
{
// added to avoid warnings
}
}
}
+
+public:
+ UpdateSubTotalHandler(ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows) :
+ mrData(rData), mrHiddenRows(rHiddenRows) {}
+
+ void operator() (size_t nRow, double fVal)
+ {
+ if (mrHiddenRows.getValue(nRow))
+ return;
+
+ update(fVal, true);
+ }
+
+ void operator() (size_t nRow, ScFormulaCell* pCell)
+ {
+ if (mrHiddenRows.getValue(nRow))
+ return;
+
+ double fVal = 0.0;
+ bool bVal = false;
+ if (mrData.eFunc != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
+ {
+
+ if (pCell->GetErrCode())
+ {
+ if (mrData.eFunc != SUBTOTAL_FUNC_CNT) // simply remove from count
+ mrData.bError = true;
+ }
+ else if (pCell->IsValue())
+ {
+ fVal = pCell->GetValue();
+ bVal = true;
+ }
+ // otherwise text
+ }
+
+ update(fVal, bVal);
+ }
+
+ void operator() (mdds::mtv::element_t eType, size_t nTopRow, size_t nDataSize)
+ {
+ if (eType == sc::element_type_empty)
+ return;
+
+ for (size_t i = 0; i < nDataSize; ++i)
+ {
+ size_t nRow = nTopRow + i;
+ if (mrHiddenRows.getValue(nRow))
+ continue;
+
+ update(0.0, false);
+ }
+ }
+};
+
}
// multiple selections:
void ScColumn::UpdateSelectionFunction(
const ScMarkData& rMark, ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows,
- bool bDoExclude, SCROW nExStartRow, SCROW nExEndRow) const
+ bool bDoExclude, SCROW nExStartRow, SCROW nExEndRow)
{
if ( rData.eFunc != SUBTOTAL_FUNC_SELECTION_COUNT )
{
- SCSIZE nIndex;
- ScMarkedDataIter aDataIter(this, &rMark, false);
- while (aDataIter.Next( nIndex ))
+ sc::SingleColumnSpanSet aSpanSet;
+ aSpanSet.scan(rMark, nTab, nCol);
+ if (bDoExclude)
+ {
+ aSpanSet.set(0, nExStartRow, false);
+ aSpanSet.set(nExEndRow+1, MAXROWCOUNT, false);
+ }
+
+ sc::SingleColumnSpanSet::SpansType aSpans;
+ aSpanSet.getSpans(aSpans);
+ UpdateSubTotalHandler aFunc(rData, rHiddenRows);
+ sc::CellStoreType::iterator itCellPos = maCells.begin();
+ sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+ for (; it != itEnd; ++it)
{
- SCROW nRow = maItems[nIndex].nRow;
- bool bRowHidden = rHiddenRows.getValue(nRow);
- if ( !bRowHidden )
- if ( !bDoExclude || nRow < nExStartRow || nRow > nExEndRow )
- lcl_UpdateSubTotal( rData, maItems[nIndex].pCell );
+ itCellPos = sc::ProcessFormulaNumeric(
+ itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
}
}
else
@@ -2314,21 +2431,13 @@ void ScColumn::UpdateSelectionFunction(
// with bNoMarked ignore the multiple selections
void ScColumn::UpdateAreaFunction(
- ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows, SCROW nStartRow, SCROW nEndRow) const
+ ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows, SCROW nStartRow, SCROW nEndRow)
{
if ( rData.eFunc != SUBTOTAL_FUNC_SELECTION_COUNT )
{
- SCSIZE nIndex;
- Search( nStartRow, nIndex );
- while ( nIndex<maItems.size() && maItems[nIndex].nRow<=nEndRow )
- {
- SCROW nRow = maItems[nIndex].nRow;
- bool bRowHidden = rHiddenRows.getValue(nRow);
- if ( !bRowHidden )
- if ( rData.eFunc != SUBTOTAL_FUNC_SELECTION_COUNT )
- lcl_UpdateSubTotal( rData, maItems[nIndex].pCell );
- ++nIndex;
- }
+ UpdateSubTotalHandler aFunc(rData, rHiddenRows);
+ sc::ProcessFormulaNumeric(
+ maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
}
else
{
@@ -2350,49 +2459,78 @@ void ScColumn::UpdateAreaFunction(
}
}
-sal_uInt32 ScColumn::GetWeightedCount() const
-{
- sal_uInt32 nTotal = 0;
+namespace {
- // Notes are not counted
+class WeightedCounter
+{
+ size_t mnCount;
+public:
+ WeightedCounter() : mnCount(0) {}
- for (SCSIZE i=0; i<maItems.size(); i++)
+ void operator() (const sc::CellStoreType::value_type& node)
{
- ScBaseCell* pCell = maItems[i].pCell;
- switch ( pCell->GetCellType() )
+ switch (node.type)
{
- case CELLTYPE_VALUE:
- case CELLTYPE_STRING:
- ++nTotal;
- break;
- case CELLTYPE_FORMULA:
- nTotal += 5 + ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
- break;
- case CELLTYPE_EDIT:
- nTotal += 50;
- break;
- default:
+ case sc::element_type_numeric:
+ case sc::element_type_string:
+ mnCount += node.size;
+ break;
+ case sc::element_type_formula:
{
- // added to avoid warnings
+ // Each formula cell is worth its code length plus 5.
+ sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
+ sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
+ for (; it != itEnd; ++it)
+ {
+ const ScFormulaCell* p = *it;
+ mnCount += 5 + p->GetCode()->GetCodeLen();
+ }
}
+ break;
+ case sc::element_type_edittext:
+ // each edit-text cell is worth 50.
+ mnCount += node.size * 50;
+ break;
+ default:
+ ;
}
}
- return nTotal;
+ size_t getCount() const { return mnCount; }
+};
+
}
-sal_uInt32 ScColumn::GetCodeCount() const
+sal_uInt32 ScColumn::GetWeightedCount() const
{
- sal_uInt32 nCodeCount = 0;
+ WeightedCounter aFunc;
+ std::for_each(maCells.begin(), maCells.end(), aFunc);
+ return aFunc.getCount();
+}
+
+namespace {
+
+class CodeCounter
+{
+ size_t mnCount;
+public:
+ CodeCounter() : mnCount(0) {}
- for (SCSIZE i=0; i<maItems.size(); i++)
+ void operator() (size_t, const ScFormulaCell* p)
{
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- nCodeCount += ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
+ mnCount += p->GetCode()->GetCodeLen();
}
- return nCodeCount;
+ size_t getCount() const { return mnCount; }
+};
+
+}
+
+sal_uInt32 ScColumn::GetCodeCount() const
+{
+ CodeCounter aFunc;
+ sc::ParseFormula(maCells, aFunc);
+ return aFunc.getCount();
}
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index f264aef5579d..021eba9bbf6d 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -42,6 +42,11 @@
#include "tokenarray.hxx"
#include "stlalgorithm.hxx"
#include "clipcontext.hxx"
+#include "columnspanset.hxx"
+#include "mtvcellfunc.hxx"
+#include "scopetools.hxx"
+#include "cellclonehandler.hxx"
+#include "editutil.hxx"
#include <com/sun/star/i18n/LocaleDataItem.hpp>
@@ -53,6 +58,8 @@
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <svl/broadcast.hxx>
+#include "editeng/editstat.hxx"
+
#include <cstdio>
using ::com::sun::star::i18n::LocaleDataItem;
@@ -66,6 +73,9 @@ namespace {
void broadcastCells(ScDocument& rDoc, SCCOL nCol, SCROW nTab, const std::vector<SCROW>& rRows)
{
+ if (rRows.empty())
+ return;
+
// Broadcast the changes.
ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
std::vector<SCROW>::const_iterator itRow = rRows.begin(), itRowEnd = rRows.end();
@@ -78,60 +88,48 @@ void broadcastCells(ScDocument& rDoc, SCCOL nCol, SCROW nTab, const std::vector<
}
-void ScColumn::Insert( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell )
-{
- SetCell(rBlockPos, nRow, pNewCell);
- PostSetCell(nRow, pNewCell);
-}
-
-void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
+void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows )
{
- SetCell(nRow, pNewCell);
- PostSetCell(nRow, pNewCell);
+ broadcastCells(*pDocument, nCol, nTab, rRows);
}
+namespace {
-void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell )
-{
- Insert(nRow, pCell);
- SetNumberFormat(nRow, nNumberFormat);
-}
-
-void ScColumn::Append( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pCell )
+class EndListeningHandler
{
- maItems.push_back(ColEntry());
- maItems.back().pCell = pCell;
- maItems.back().nRow = nRow;
+ ScDocument* mpDoc;
+public:
+ EndListeningHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
- rBlockPos.miCellTextAttrPos =
- maCellTextAttrs.set(rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+ void operator() (size_t, ScFormulaCell* p)
+ {
+ p->EndListeningTo(mpDoc);
+ }
+};
- CellStorageModified();
}
-void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
+void ScColumn::EndFormulaListening( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
{
- maItems.push_back(ColEntry());
- maItems.back().pCell = pCell;
- maItems.back().nRow = nRow;
-
- maCellTextAttrs.set<sc::CellTextAttr>(nRow, sc::CellTextAttr());
- CellStorageModified();
+ EndListeningHandler aFunc(pDocument);
+ rBlockPos.miCellPos =
+ sc::ProcessFormula(rBlockPos.miCellPos, maCells, nRow1, nRow2, aFunc);
}
void ScColumn::Delete( SCROW nRow )
{
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::iterator it = aPos.first;
+ if (it == maCells.end())
return;
- ScBaseCell* pCell = maItems[nIndex].pCell;
- maItems.erase(maItems.begin() + nIndex);
+ if (it->type == sc::element_type_formula)
+ {
+ ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
+ p->EndListeningTo(pDocument);
+ }
+ maCells.set_empty(nRow, nRow);
maCellTextAttrs.set_empty(nRow, nRow);
- // Should we free memory here (delta)? It'll be slower!
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- static_cast<ScFormulaCell*>(pCell)->EndListeningTo(pDocument);
- pCell->Delete();
pDocument->Broadcast(
ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
@@ -139,140 +137,332 @@ void ScColumn::Delete( SCROW nRow )
CellStorageModified();
}
-
-void ScColumn::DeleteAtIndex( SCSIZE nIndex )
+void ScColumn::FreeAll()
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- SCROW nRow = maItems[nIndex].nRow;
- maItems.erase(maItems.begin() + nIndex);
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- static_cast<ScFormulaCell*>(pCell)->EndListeningTo(pDocument);
- pCell->Delete();
-
- pDocument->Broadcast(
- ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
-
- maCellTextAttrs.set_empty(nRow, nRow);
+ // Keep a logical empty range of 0-MAXROW at all times.
+ maCells.clear();
+ maCells.resize(MAXROWCOUNT);
+ maCellTextAttrs.clear();
+ maCellTextAttrs.resize(MAXROWCOUNT);
CellStorageModified();
}
+namespace {
-void ScColumn::FreeAll()
+/**
+ * Collect all formula cells for later mass-unregistration. Also tag row
+ * positions of all non-empty cells in the range.
+ */
+class DeleteRowsHandler
{
- for (SCSIZE i = 0; i < maItems.size(); i++)
- maItems[i].pCell->Delete();
- maItems.clear();
+ ScDocument& mrDoc;
+ std::vector<SCROW> maRows;
+ std::vector<ScFormulaCell*> maFormulaCells;
+public:
+ DeleteRowsHandler(ScDocument& rDoc) : mrDoc(rDoc) {}
- // Text width should keep a logical empty range of 0-MAXROW when the cell array is empty.
- maCellTextAttrs.clear();
- maCellTextAttrs.resize(MAXROWCOUNT);
- CellStorageModified();
-}
+ void operator() (size_t nRow, ScFormulaCell* pCell)
+ {
+ maFormulaCells.push_back(pCell);
+ maRows.push_back(nRow);
+ }
+ void operator() (mdds::mtv::element_t nType, size_t nTopRow, size_t nDataSize)
+ {
+ if (nType == sc::element_type_empty)
+ // Ignore empty cells.
+ return;
-void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
+ for (size_t i = 0; i < nDataSize; ++i)
+ // Tag all non-empty cells.
+ maRows.push_back(i + nTopRow);
+ }
+
+ void endFormulas()
+ {
+ mrDoc.EndListeningFormulaCells(maFormulaCells);
+ }
+
+ const std::vector<SCROW>& getNonEmptyRows() const
+ {
+ return maRows;
+ }
+};
+
+class ShiftFormulaPosHandler
{
- SCROW nEndRow = nStartRow + nSize - 1;
+public:
- pAttrArray->DeleteRow( nStartRow, nSize );
+ void operator() (size_t nRow, ScFormulaCell* pCell)
+ {
+ pCell->aPos.SetRow(nRow);
+ }
+};
- maBroadcasters.erase(nStartRow, nEndRow);
- maBroadcasters.resize(MAXROWCOUNT);
+class RangeBroadcaster
+{
+ ScDocument& mrDoc;
+ ScHint maHint;
+public:
+ RangeBroadcaster(ScDocument& rDoc, SCTAB nTab, SCCOL nCol) :
+ mrDoc(rDoc),
+ maHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab)) {}
- if ( maItems.empty() )
- return ;
+ void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
+ {
+ SCROW nRow1 = rSpan.mnRow1, nRow2 = rSpan.mnRow2;
+ maHint.GetAddress().SetRow(nRow1);
+ ScRange aRange(maHint.GetAddress());
+ aRange.aEnd.SetRow(nRow2);
+ mrDoc.AreaBroadcastInRange(aRange, maHint);
+ }
+};
- SCSIZE nFirstIndex;
- Search( nStartRow, nFirstIndex );
- if ( nFirstIndex >= maItems.size() )
- return ;
+}
- sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
- pDocument->SetAutoCalc( false ); // Avoid calculating it multiple times
+void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
+{
+ pAttrArray->DeleteRow( nStartRow, nSize );
- bool bFound = false;
- SCSIZE nStartIndex = 0;
- SCSIZE nEndIndex = 0;
- SCSIZE i;
+ SCROW nEndRow = nStartRow + nSize - 1;
+ maBroadcasters.erase(nStartRow, nEndRow);
+ maBroadcasters.resize(MAXROWCOUNT);
- for ( i = nFirstIndex; i < maItems.size() && maItems[i].nRow <= nEndRow; i++ )
+ // See if we have any cells that would get deleted or shifted by deletion.
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nStartRow);
+ sc::CellStoreType::iterator itCell = aPos.first;
+ if (itCell->type == sc::element_type_empty)
{
- if (!bFound)
+ // This is an empty block. If this is the last block, then there is no cells to delete or shift.
+ sc::CellStoreType::iterator itTest = itCell;
+ ++itTest;
+ if (itTest == maCells.end())
{
- nStartIndex = i;
- bFound = true;
+ // No cells are affected by this deletion. Bail out.
+ CellStorageModified(); // broadcast array has been modified.
+ return;
}
- nEndIndex = i;
}
- if (bFound)
+ // Check if there are any cells below the end row that will get shifted.
+ bool bShiftCells = false;
+ aPos = maCells.position(itCell, nEndRow+1);
+ itCell = aPos.first;
+ if (itCell->type == sc::element_type_empty)
{
- std::vector<SCROW> aDeletedRows;
- DeleteRange(nStartIndex, nEndIndex, IDF_CONTENTS, aDeletedRows);
- broadcastCells(*pDocument, nCol, nTab, aDeletedRows);
-
- Search( nStartRow, i );
- if ( i >= maItems.size() )
- {
- pDocument->SetAutoCalc( bOldAutoCalc );
- return ;
- }
+ // This block is empty. See if there is any block that follows.
+ sc::CellStoreType::iterator itTest = itCell;
+ ++itTest;
+ if (itTest != maCells.end())
+ // Non-empty block follows -> cells that will get shifted.
+ bShiftCells = true;
}
else
- i = nFirstIndex;
+ bShiftCells = true;
+
+ sc::SingleColumnSpanSet aNonEmptySpans;
+ if (bShiftCells)
+ {
+ // Mark all non-empty cell positions below the end row.
+ sc::ColumnBlockConstPosition aBlockPos;
+ aBlockPos.miCellPos = itCell;
+ aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, MAXROW);
+ }
- // There are cells below the deletion point. Shift their row positions.
+ sc::AutoCalcSwitch aACSwitch(*pDocument, false);
- // Shift the text width array too (before the broadcast).
+ // Parse all non-empty cells in the range to pick up their row positions,
+ // and end all formula cells.
+ DeleteRowsHandler aDeleteRowsFunc(*pDocument);
+ sc::ProcessFormula(itCell, maCells, nStartRow, nEndRow, aDeleteRowsFunc, aDeleteRowsFunc);
+ aDeleteRowsFunc.endFormulas();
+
+ // Remove the cells.
+ maCells.erase(nStartRow, nEndRow);
+ maCells.resize(MAXROWCOUNT);
+
+ // Shift the formula cell positions below the start row.
+ ShiftFormulaPosHandler aShiftFormulaFunc;
+ sc::ProcessFormula(maCells.begin(), maCells, nStartRow, MAXROW, aShiftFormulaFunc);
+
+ // Single cell broadcasts on deleted cells.
+ BroadcastCells(aDeleteRowsFunc.getNonEmptyRows());
+
+ // Shift the text attribute array too (before the broadcast).
maCellTextAttrs.erase(nStartRow, nEndRow);
maCellTextAttrs.resize(MAXROWCOUNT);
- ScAddress aAdr( nCol, 0, nTab );
- ScHint aHint(SC_HINT_DATACHANGED, aAdr); // only areas (ScBaseCell* == NULL)
- ScAddress& rAddress = aHint.GetAddress();
- // for sparse occupation use single broadcasts, not ranges
- bool bSingleBroadcasts = (((maItems.back().nRow - maItems[i].nRow) /
- (maItems.size() - i)) > 1);
- if ( bSingleBroadcasts )
+ CellStorageModified();
+
+ if (!bShiftCells)
+ return;
+
+ // Do area broadcast on the old non-empty cell ranges prior to the shift.
+ sc::SingleColumnSpanSet::SpansType aSpans;
+ aNonEmptySpans.getSpans(aSpans);
+ std::for_each(aSpans.begin(), aSpans.end(), RangeBroadcaster(*pDocument, nTab, nCol));
+}
+
+void ScColumn::CopyCellsInRangeToColumn(
+ sc::ColumnBlockConstPosition* pSrcColPos,
+ sc::ColumnBlockPosition* pDestColPos, sc::CellBlockCloneHandler& rHdl, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
+{
+ sc::ColumnBlockConstPosition aSrcColPos;
+ sc::ColumnBlockPosition aDestColPos;
+
+ if (pSrcColPos)
+ aSrcColPos = *pSrcColPos;
+ else
+ InitBlockPosition(aSrcColPos);
+
+ if (pDestColPos)
+ aDestColPos = *pDestColPos;
+ else
+ rColumn.InitBlockPosition(aDestColPos);
+
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(aSrcColPos.miCellPos, nRow1);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ aSrcColPos.miCellPos = aPos.first;
+ size_t nOffset = aPos.second;
+ size_t nDataSize = 0;
+ size_t nCurRow = nRow1;
+
+ for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
{
- SCROW nLastBroadcast = MAXROW+1;
- for ( ; i < maItems.size(); i++ )
+ bool bLastBlock = false;
+ nDataSize = it->size - nOffset;
+ if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
+ {
+ // Truncate the block to copy to clipboard.
+ nDataSize = nRow2 - nCurRow + 1;
+ bLastBlock = true;
+ }
+
+ bool bHasCells = true;
+ switch (it->type)
{
- SCROW nOldRow = maItems[i].nRow;
- // Broadcast change in source
- rAddress.SetRow( nOldRow );
- pDocument->AreaBroadcast( aHint );
- SCROW nNewRow = (maItems[i].nRow -= nSize);
- // Broadcast change in target
- if ( nLastBroadcast != nNewRow )
- { // Do not broadcast successive ones
- rAddress.SetRow( nNewRow );
- pDocument->AreaBroadcast( aHint );
+ case sc::element_type_numeric:
+ {
+ sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::numeric_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ ScAddress aSrcPos(nCol, nCurRow, nTab);
+ ScAddress aDestPos(rColumn.nCol, nCurRow, rColumn.nTab);
+ rHdl.cloneDoubleBlock(aDestColPos.miCellPos, aSrcPos, aDestPos, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_string:
+ {
+ sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::string_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ ScAddress aSrcPos(nCol, nCurRow, nTab);
+ ScAddress aDestPos(rColumn.nCol, nCurRow, rColumn.nTab);
+ rHdl.cloneStringBlock(aDestColPos.miCellPos, aSrcPos, aDestPos, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_edittext:
+ {
+ sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::edittext_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ ScAddress aSrcPos(nCol, nCurRow, nTab);
+ ScAddress aDestPos(rColumn.nCol, nCurRow, rColumn.nTab);
+ rHdl.cloneEditTextBlock(aDestColPos.miCellPos, aSrcPos, aDestPos, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_formula:
+ {
+ sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
+ std::advance(itData, nOffset);
+ sc::formula_block::const_iterator itDataEnd = itData;
+ std::advance(itDataEnd, nDataSize);
+ ScAddress aSrcPos(nCol, nCurRow, nTab);
+ ScAddress aDestPos(rColumn.nCol, nCurRow, rColumn.nTab);
+ rHdl.cloneFormulaBlock(aDestColPos.miCellPos, aSrcPos, aDestPos, itData, itDataEnd);
}
- nLastBroadcast = nOldRow;
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
+ break;
+ default:
+ bHasCells = false;
}
- }
- else
- {
- rAddress.SetRow( maItems[i].nRow );
- ScRange aRange( rAddress );
- aRange.aEnd.SetRow( maItems.back().nRow );
- for ( ; i < maItems.size(); i++ )
+
+ if (bHasCells)
{
- SCROW nNewRow = (maItems[i].nRow -= nSize);
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
+ // Set default text attribute values for the new cells in the clip doc.
+ std::vector<sc::CellTextAttr> aTextAttrs(nDataSize, sc::CellTextAttr());
+ aDestColPos.miCellTextAttrPos = rColumn.maCellTextAttrs.set(
+ aDestColPos.miCellTextAttrPos, nCurRow, aTextAttrs.begin(), aTextAttrs.end());
}
- pDocument->AreaBroadcastInRange( aRange, aHint );
+
+ if (bLastBlock)
+ break;
}
- CellStorageModified();
- pDocument->SetAutoCalc( bOldAutoCalc );
+ if (pSrcColPos)
+ {
+ // Save the positions for the next iteration.
+ *pSrcColPos = aSrcColPos;
+ }
+
+ if (pDestColPos)
+ {
+ // Save the positions for the next iteration.
+ *pDestColPos = aDestColPos;
+ }
+
+ rColumn.CellStorageModified();
+}
+
+sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow )
+{
+ return GetPositionToInsert(maCells.begin(), nRow);
+}
+
+sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow )
+{
+ // See if we are overwriting an existing formula cell.
+ std::pair<sc::CellStoreType::iterator,size_t> aRet = maCells.position(it, nRow);
+ sc::CellStoreType::iterator itRet = aRet.first;
+ if (itRet->type == sc::element_type_formula && !pDocument->IsClipOrUndo())
+ {
+ ScFormulaCell* pCell = sc::formula_block::at(*itRet->data, aRet.second);
+ pCell->EndListeningTo(pDocument);
+ }
+
+ return itRet;
+}
+
+void ScColumn::ActivateNewFormulaCell( ScFormulaCell* pCell )
+{
+ // When we insert from the Clipboard we still have wrong (old) References!
+ // First they are rewired in CopyBlockFromClip via UpdateReference and the
+ // we call StartListeningFromClip and BroadcastFromClip.
+ // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
+ // After Import we call CalcAfterLoad and in there Listening.
+ if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
+ {
+ pCell->StartListeningTo(pDocument);
+ if (!pDocument->IsCalcingAfterLoad())
+ pCell->SetDirty();
+ }
+}
+
+void ScColumn::BroadcastNewCell( SCROW nRow )
+{
+ // When we insert from the Clipboard we still have wrong (old) References!
+ // First they are rewired in CopyBlockFromClip via UpdateReference and the
+ // we call StartListeningFromClip and BroadcastFromClip.
+ // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
+ // After Import we call CalcAfterLoad and in there Listening.
+ if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc() || pDocument->IsCalcingAfterLoad())
+ return;
+
+ ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab));
+ pDocument->Broadcast(aHint);
}
void ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow )
@@ -314,171 +504,92 @@ void ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow )
namespace {
-bool isDate(const ScDocument& rDoc, const ScColumn& rCol, SCROW nRow)
+class DeleteAreaHandler
{
- sal_uLong nIndex = (sal_uLong)((SfxUInt32Item*)rCol.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
- short nType = rDoc.GetFormatTable()->GetType(nIndex);
- return (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
-}
+ ScDocument& mrDoc;
+ std::vector<ScFormulaCell*> maFormulaCells;
+ sc::SingleColumnSpanSet maDeleteRanges;
-bool checkDeleteCellByFlag(
- CellType eCellType, sal_uInt16 nDelFlag, const ScDocument& rDoc, const ScColumn& rCol, const ColEntry& rEntry)
-{
- bool bDelete = false;
+ bool mbNumeric:1;
+ bool mbDateTime:1;
+ bool mbString:1;
+ bool mbFormula:1;
- switch (eCellType)
- {
- case CELLTYPE_VALUE:
- {
- sal_uInt16 nValFlags = nDelFlag & (IDF_DATETIME|IDF_VALUE);
- // delete values and dates?
- bDelete = nValFlags == (IDF_DATETIME|IDF_VALUE);
- // if not, decide according to cell number format
- if (!bDelete && (nValFlags != 0))
- {
- bool bIsDate = isDate(rDoc, rCol, rEntry.nRow);
- bDelete = nValFlags == (bIsDate ? IDF_DATETIME : IDF_VALUE);
- }
- }
- break;
- case CELLTYPE_STRING:
- case CELLTYPE_EDIT:
- bDelete = (nDelFlag & IDF_STRING) != 0;
- break;
- case CELLTYPE_FORMULA:
- bDelete = (nDelFlag & IDF_FORMULA) != 0;
- break;
- default:; // added to avoid warnings
- }
-
- return bDelete;
-}
-
-}
-
-void ScColumn::DeleteRange(
- SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDelFlag, std::vector<SCROW>& rDeletedRows )
-{
- /* If caller specifies to not remove the note caption objects, all cells
- have to forget the pointers to them. This is used e.g. while undoing a
- "paste cells" operation, which removes the caption objects later in
- drawing undo. */
-
- // cache all formula cells, they will be deleted at end of this function
- std::vector<ScFormulaCell*> aDelCells;
- aDelCells.reserve( nEndIndex - nStartIndex + 1 );
-
- typedef mdds::flat_segment_tree<SCSIZE, bool> RemovedSegments_t;
- RemovedSegments_t aRemovedSegments(nStartIndex, maItems.size(), false);
- SCSIZE nFirst = nStartIndex;
-
- for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
+public:
+ DeleteAreaHandler(ScDocument& rDoc, sal_uInt16 nDelFlag) :
+ mrDoc(rDoc),
+ mbNumeric(nDelFlag & IDF_VALUE),
+ mbDateTime(nDelFlag & IDF_DATETIME),
+ mbString(nDelFlag & IDF_STRING),
+ mbFormula(nDelFlag & IDF_FORMULA) {}
+
+ void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
{
- if (((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS))
+ switch (node.type)
{
- // all content is to be deleted.
-
- ScBaseCell* pOldCell = maItems[ nIdx ].pCell;
- rDeletedRows.push_back(maItems[nIdx].nRow);
-
- if (pOldCell->GetCellType() == CELLTYPE_FORMULA)
+ case sc::element_type_numeric:
+ if (!mbNumeric)
+ return;
+ break;
+ case sc::element_type_string:
+ case sc::element_type_edittext:
+ if (!mbString)
+ return;
+ break;
+ case sc::element_type_formula:
{
- // cache formula cell, will be deleted below
- aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) );
- }
- else
- pOldCell->Delete();
+ if (!mbFormula)
+ return;
- continue;
- }
-
- // delete some contents of the cells, or cells with broadcaster
- bool bDelete = false;
- ScBaseCell* pOldCell = maItems[nIdx].pCell;
- CellType eCellType = pOldCell->GetCellType();
- if ((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS)
- // All cell types to be deleted.
- bDelete = true;
- else
- {
- // Decide whether to delete the cell object according to passed
- // flags.
- bDelete = checkDeleteCellByFlag(eCellType, nDelFlag, *pDocument, *this, maItems[nIdx]);
- }
+ sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
+ std::advance(it, nOffset);
+ sc::formula_block::iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
- if (bDelete)
- {
- // remove cell entry in cell item list
- if (eCellType == CELLTYPE_FORMULA)
- {
- // Cache formula cells (will be deleted later), delete cell of other type.
- aDelCells.push_back(static_cast<ScFormulaCell*>(pOldCell));
+ for (; it != itEnd; ++it)
+ maFormulaCells.push_back(*it);
}
- else
- pOldCell->Delete();
-
- rDeletedRows.push_back(maItems[nIdx].nRow);
+ break;
+ case sc::element_type_empty:
+ default:
+ return;
}
- if (!bDelete)
- {
- // We just came to a non-deleted cell after a segment of
- // deleted ones. So we need to remember the segment
- // before moving on.
- if (nFirst < nIdx)
- aRemovedSegments.insert_back(nFirst, nIdx, true);
- nFirst = nIdx + 1;
- }
+ // Tag these cells for deletion.
+ SCROW nRow1 = node.position + nOffset;
+ SCROW nRow2 = nRow1 + nDataSize - 1;
+ maDeleteRanges.set(nRow1, nRow2, true);
}
- // there is a segment of deleted cells at the end
- if (nFirst <= nEndIndex)
- aRemovedSegments.insert_back(nFirst, nEndIndex + 1, true);
+ void endFormulas()
{
- // Remove segments from the column array, containing pDummyCell and
- // formula cell pointers to be deleted.
-
- RemovedSegments_t::const_reverse_iterator it = aRemovedSegments.rbegin();
- RemovedSegments_t::const_reverse_iterator itEnd = aRemovedSegments.rend();
-
- std::vector<ColEntry>::iterator itErase, itEraseEnd;
- SCSIZE nEndSegment = it->first; // should equal maItems.size(). Non-inclusive.
- // Skip the first node.
- for (++it; it != itEnd; ++it)
- {
- if (!it->second)
- {
- // Don't remove this segment.
- nEndSegment = it->first;
- continue;
- }
-
- // Remove this segment.
- SCSIZE nStartSegment = it->first;
- SCROW nStartRow = maItems[nStartSegment].nRow;
- SCROW nEndRow = maItems[nEndSegment-1].nRow;
+ mrDoc.EndListeningFormulaCells(maFormulaCells);
+ }
- itErase = maItems.begin();
- std::advance(itErase, nStartSegment);
- itEraseEnd = maItems.begin();
- std::advance(itEraseEnd, nEndSegment);
- maItems.erase(itErase, itEraseEnd);
+ const sc::SingleColumnSpanSet& getSpans() const
+ {
+ return maDeleteRanges;
+ }
+};
- maCellTextAttrs.set_empty(nStartRow, nEndRow);
+class EmptyCells
+{
+ sc::CellStoreType::iterator miPos;
+ sc::CellStoreType& mrCells;
+public:
+ EmptyCells(sc::CellStoreType::iterator itPos, sc::CellStoreType& rCells) :
+ miPos(itPos), mrCells(rCells) {}
- nEndSegment = nStartSegment;
- }
+ void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
+ {
+ miPos = mrCells.set_empty(miPos, rSpan.mnRow1, rSpan.mnRow2);
}
+};
- pDocument->EndListeningFormulaCells(aDelCells);
- std::for_each(aDelCells.begin(), aDelCells.end(), ScDeleteObjectByPtr<ScFormulaCell>());
}
void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
{
- // FreeAll must not be called here due to Broadcasters
- // Delete attribute at the end so that we can distinguish between numbers and dates
-
sal_uInt16 nContMask = IDF_CONTENTS;
// IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
if( nDelFlag & IDF_NOTE )
@@ -487,30 +598,17 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
std::vector<SCROW> aDeletedRows;
- if ( !maItems.empty() && nContFlag)
+ if (!IsEmptyData() && nContFlag)
{
- if (nStartRow==0 && nEndRow==MAXROW)
- {
- DeleteRange(0, maItems.size()-1, nContFlag, aDeletedRows);
- }
- else
- {
- sal_Bool bFound=false;
- SCSIZE nStartIndex = 0;
- SCSIZE nEndIndex = 0;
- for (SCSIZE i = 0; i < maItems.size(); i++)
- if ((maItems[i].nRow >= nStartRow) && (maItems[i].nRow <= nEndRow))
- {
- if (!bFound)
- {
- nStartIndex = i;
- bFound = sal_True;
- }
- nEndIndex = i;
- }
- if (bFound)
- DeleteRange(nStartIndex, nEndIndex, nContFlag, aDeletedRows);
- }
+ DeleteAreaHandler aFunc(*pDocument, nDelFlag);
+ sc::CellStoreType::iterator itPos = maCells.position(nStartRow).first;
+ sc::ProcessBlock(itPos, maCells, aFunc, nStartRow, nEndRow);
+ aFunc.endFormulas(); // Have the formula cells stop listening.
+ aFunc.getSpans().getRows(aDeletedRows);
+
+ sc::SingleColumnSpanSet::SpansType aSpans;
+ aFunc.getSpans().getSpans(aSpans);
+ std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(itPos, maCells));
}
if ( nDelFlag & IDF_EDITATTR )
@@ -527,78 +625,264 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
// Broadcast on only cells that were deleted; no point broadcasting on
// cells that were already empty before the deletion.
- broadcastCells(*pDocument, nCol, nTab, aDeletedRows);
+ BroadcastCells(aDeletedRows);
}
+bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
+{
+ rBlockPos.miBroadcasterPos = maBroadcasters.begin();
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
+ rBlockPos.miCellPos = maCells.begin();
+ return true;
+}
-ScFormulaCell* ScColumn::CreateRefCell( ScDocument* pDestDoc, const ScAddress& rDestPos,
- SCSIZE nIndex, sal_uInt16 nFlags ) const
+bool ScColumn::InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const
{
- sal_uInt16 nContFlags = nFlags & IDF_CONTENTS;
- if (!nContFlags)
- return NULL;
+ rBlockPos.miBroadcasterPos = maBroadcasters.begin();
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
+ rBlockPos.miCellPos = maCells.begin();
+ return true;
+}
+
+namespace {
+
+class CopyAttrArrayByRange : std::unary_function<sc::SingleColumnSpanSet::Span, void>
+{
+ ScAttrArray& mrDestAttrArray;
+ ScAttrArray& mrSrcAttrArray;
+ long mnRowOffset;
+public:
+ CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, long nRowOffset) :
+ mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {}
+
+ void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
+ {
+ mrDestAttrArray.CopyAreaSafe(
+ rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray);
+ }
+};
+
+class CopyCellsFromClipHandler
+{
+ sc::CopyFromClipContext& mrCxt;
+ ScColumn& mrSrcCol;
+ ScColumn& mrDestCol;
+ SCTAB mnTab;
+ SCCOL mnCol;
+ long mnRowOffset;
+ sc::ColumnBlockPosition maDestBlockPos;
+
+ bool isDateCell(SCROW nSrcRow) const
+ {
+ ScDocument* pSrcDoc = mrCxt.getClipDoc(); // clip document is the source.
+ sal_uLong nNumIndex = static_cast<const SfxUInt32Item*>(mrSrcCol.GetAttr(nSrcRow, ATTR_VALUE_FORMAT))->GetValue();
+ short nType = pSrcDoc->GetFormatTable()->GetType(nNumIndex);
+ return (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
+ }
+
+ void insertRefCell(SCROW nSrcRow, SCROW nDestRow)
+ {
+ ScAddress aSrcPos(mnCol, nSrcRow, mnTab);
+ ScAddress aDestPos(mnCol, nDestRow, mnTab);
+ ScSingleRefData aRef;
+ aRef.InitAddress(aSrcPos);
+ aRef.SetFlag3D(true);
+
+ ScTokenArray aArr;
+ aArr.AddSingleReference(aRef);
- // Test whether the Cell should be copied
- // Also do this for IDF_CONTENTS, due to Notes/Broadcasters
- sal_Bool bMatch = false;
- ScBaseCell* pCell = maItems[nIndex].pCell;
- CellType eCellType = pCell->GetCellType();
- switch ( eCellType )
+ mrDestCol.SetFormulaCell(
+ maDestBlockPos, nDestRow, new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos, &aArr));
+ }
+
+public:
+ CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, long nRowOffset) :
+ mrCxt(rCxt),
+ mrSrcCol(rSrcCol),
+ mrDestCol(rDestCol),
+ mnTab(nDestTab),
+ mnCol(nDestCol),
+ mnRowOffset(nRowOffset)
{
- case CELLTYPE_VALUE:
+ sc::ColumnBlockPosition* p = mrCxt.getBlockPosition(nDestTab, nDestCol);
+ if (p)
+ maDestBlockPos = *p;
+ else
+ mrDestCol.InitBlockPosition(maDestBlockPos);
+ }
+
+ void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
+ {
+ if (node.type == sc::element_type_empty)
+ return;
+
+ SCROW nSrcRow1 = node.position + nOffset;
+
+ sal_uInt16 nFlags = mrCxt.getInsertFlag();
+ bool bNumeric = (nFlags & IDF_VALUE) != 0;
+ bool bDateTime = (nFlags & IDF_DATETIME) != 0;
+ bool bString = (nFlags & IDF_STRING) != 0;
+ bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != 0;
+ bool bFormula = (nFlags & IDF_FORMULA) != 0;
+
+ bool bAsLink = mrCxt.isAsLink();
+
+ switch (node.type)
+ {
+ case sc::element_type_numeric:
{
- sal_uInt16 nValFlags = nFlags & (IDF_DATETIME|IDF_VALUE);
+ // We need to copy numeric cells individually because of date type check.
+ sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
+ std::advance(it, nOffset);
+ sc::numeric_block::const_iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
+ for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
+ {
+ bool bCopy = isDateCell(nSrcRow) ? bDateTime : bNumeric;
+ if (!bCopy)
+ continue;
- if ( nValFlags == (IDF_DATETIME|IDF_VALUE) )
- bMatch = sal_True;
- else if ( nValFlags )
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
+ else
+ mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it);
+ }
+ }
+ break;
+ case sc::element_type_string:
+ {
+ if (!bString)
+ return;
+
+ sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
+ std::advance(it, nOffset);
+ sc::string_block::const_iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
+ for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
{
- sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)GetAttr(
- maItems[nIndex].nRow, ATTR_VALUE_FORMAT ))->GetValue();
- short nTyp = pDocument->GetFormatTable()->GetType(nNumIndex);
- if ((nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME))
- bMatch = ((nFlags & IDF_DATETIME) != 0);
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
else
- bMatch = ((nFlags & IDF_VALUE) != 0);
+ mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it);
}
}
break;
- case CELLTYPE_STRING:
- case CELLTYPE_EDIT: bMatch = ((nFlags & IDF_STRING) != 0); break;
- case CELLTYPE_FORMULA: bMatch = ((nFlags & IDF_FORMULA) != 0); break;
- default:
- {
- // added to avoid warnings
- }
- }
- if (!bMatch)
- return NULL;
-
-
- // Insert Reference
- ScSingleRefData aRef;
- aRef.nCol = nCol;
- aRef.nRow = maItems[nIndex].nRow;
- aRef.nTab = nTab;
- aRef.InitFlags(); // -> Everything absolute
- aRef.SetFlag3D(true);
-
- // 3D (false) and TabRel (true), if the final Position is at the same Table?
- // The target position is not yet known for TransposeClip!
+ case sc::element_type_edittext:
+ {
+ if (!bString)
+ return;
+
+ sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
+ std::advance(it, nOffset);
+ sc::edittext_block::const_iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
+ for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
+ {
- aRef.CalcRelFromAbs( rDestPos );
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
+ else
+ mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it);
+ }
+ }
+ break;
+ case sc::element_type_formula:
+ {
+ sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
+ std::advance(it, nOffset);
+ sc::formula_block::const_iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
+ for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
+ {
+ ScFormulaCell& rSrcCell = const_cast<ScFormulaCell&>(**it);
+ bool bForceFormula = false;
+ if (bBoolean)
+ {
+ // See if the formula consists of =TRUE() or =FALSE().
+ ScTokenArray* pCode = rSrcCell.GetCode();
+ if (pCode && pCode->GetLen() == 1)
+ {
+ const formula::FormulaToken* p = pCode->First();
+ if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
+ // This is a boolean formula.
+ bForceFormula = true;
+ }
+ }
- ScTokenArray aArr;
- aArr.AddSingleReference( aRef );
+ ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab);
+ if (bFormula || bForceFormula)
+ {
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
+ else
+ {
+ mrDestCol.SetFormulaCell(
+ maDestBlockPos, nSrcRow + mnRowOffset,
+ new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos));
+ }
+ }
+ else if (bNumeric || bDateTime || bString)
+ {
+ // Always just copy the original row to the Undo Documen;
+ // do not create Value/string cells from formulas
- return new ScFormulaCell( pDestDoc, rDestPos, &aArr );
-}
+ sal_uInt16 nErr = rSrcCell.GetErrCode();
+ if (nErr)
+ {
+ // error codes are cloned with values
+ if (bNumeric)
+ {
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
+ else
+ {
+ ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
+ pErrCell->SetErrCode(nErr);
+ mrDestCol.SetFormulaCell(
+ maDestBlockPos, nSrcRow + mnRowOffset, pErrCell);
+ }
+ }
+ }
+ else if (rSrcCell.IsValue())
+ {
+ bool bCopy = isDateCell(nSrcRow) ? bDateTime : bNumeric;
+ if (!bCopy)
+ continue;
+
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
+ else
+ mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue());
+ }
+ else if (bString)
+ {
+ OUString aStr = rSrcCell.GetString();
+ if (aStr.isEmpty())
+ // do not clone empty string
+ continue;
+
+ if (bAsLink)
+ insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
+ else if (rSrcCell.IsMultilineResult())
+ {
+ // Clone as an edit text object.
+ ScFieldEditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
+ rEngine.SetText(aStr);
+ mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject());
+ }
+ else
+ mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+};
-bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
-{
- rBlockPos.miBroadcasterPos = maBroadcasters.begin();
- rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
- return true;
}
// rColumn = source
@@ -611,29 +895,13 @@ void ScColumn::CopyFromClip(
{
if (rCxt.isSkipAttrForEmptyCells())
{
- // copy only attributes for non-empty cells
- // (notes are not counted as non-empty here, to match the content behavior)
-
- SCSIZE nStartIndex;
- rColumn.Search( nRow1-nDy, nStartIndex );
- while ( nStartIndex < rColumn.maItems.size() && rColumn.maItems[nStartIndex].nRow <= nRow2-nDy )
- {
- SCSIZE nEndIndex = nStartIndex;
- SCROW nStartRow = rColumn.maItems[nStartIndex].nRow;
- SCROW nEndRow = nStartRow;
-
- // find consecutive non-empty cells
- while ( nEndRow < nRow2-nDy &&
- nEndIndex+1 < rColumn.maItems.size() &&
- rColumn.maItems[nEndIndex+1].nRow == nEndRow+1 )
- {
- ++nEndIndex;
- ++nEndRow;
- }
-
- rColumn.pAttrArray->CopyAreaSafe( nStartRow+nDy, nEndRow+nDy, nDy, *pAttrArray );
- nStartIndex = nEndIndex + 1;
- }
+ // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
+ sc::SingleColumnSpanSet aSpanSet;
+ aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy);
+ sc::SingleColumnSpanSet::SpansType aSpans;
+ aSpanSet.getSpans(aSpans);
+ std::for_each(
+ aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy));
}
else
rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
@@ -647,8 +915,6 @@ void ScColumn::CopyFromClip(
// IDF_ALL must always contain more flags when compared to "Insert contents" as
// contents can be selected one by one!
- ReserveSize(maItems.size() + static_cast<SCSIZE>(nRow2-nRow1+1));
-
ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
// Create reference (Source Position)
@@ -667,167 +933,19 @@ void ScColumn::CopyFromClip(
aRef.CalcRelFromAbs( aDestPos );
ScTokenArray aArr;
aArr.AddSingleReference( aRef );
- Insert( nDestRow, new ScFormulaCell( pDocument, aDestPos, &aArr ) );
+ SetFormulaCell(nDestRow, new ScFormulaCell(pDocument, aDestPos, &aArr));
}
return;
}
- SCSIZE nColCount = rColumn.maItems.size();
-
- // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells
- if ((rCxt.getInsertFlag() & ( IDF_CONTENTS & ~IDF_FORMULA )) == ( IDF_CONTENTS & ~IDF_FORMULA ) && nRow2-nRow1 >= 64)
- {
- //! Always do the Resize from the outside, where the number of repetitions is known
- //! (then it can be removed here)
-
- ReserveSize(maItems.size() + nColCount);
- }
-
- sal_Bool bAtEnd = false;
- for (SCSIZE i = 0; i < nColCount && !bAtEnd; i++)
- {
- SCsROW nDestRow = rColumn.maItems[i].nRow + nDy;
- if ( nDestRow > (SCsROW) nRow2 )
- bAtEnd = sal_True;
- else if ( nDestRow >= (SCsROW) nRow1 )
- {
- // rows at the beginning may be skipped if filtered rows are left out,
- // nDestRow may be negative then
-
- ScAddress aDestPos( nCol, (SCROW)nDestRow, nTab );
-
- ScBaseCell* pNewCell = rCxt.isAsLink() ?
- rColumn.CreateRefCell(pDocument, aDestPos, i, rCxt.getInsertFlag()) :
- rColumn.CloneCell(i, rCxt.getInsertFlag(), *pDocument, aDestPos);
- if (pNewCell)
- {
- sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
- if (p)
- Insert(*p, aDestPos.Row(), pNewCell);
- else
- Insert(aDestPos.Row(), pNewCell);
- }
- }
- }
-}
-
-
-namespace {
-
-/**
- * Helper for ScColumn::CloneCell
- * Decide whether to clone a value cell depending on clone flags and number format.
- */
-bool lclCanCloneValue( ScDocument& rDoc, const ScColumn& rCol, SCROW nRow, bool bCloneValue, bool bCloneDateTime )
-{
- // values and dates, or nothing to be cloned -> not needed to check number format
- if( bCloneValue == bCloneDateTime )
- return bCloneValue;
-
- // check number format of value cell
- sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)rCol.GetAttr( nRow, ATTR_VALUE_FORMAT ))->GetValue();
- short nTyp = rDoc.GetFormatTable()->GetType( nNumIndex );
- bool bIsDateTime = (nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME);
- return bIsDateTime ? bCloneDateTime : bCloneValue;
-}
-
-} // namespace
-
-
-ScBaseCell* ScColumn::CloneCell(
- SCSIZE nIndex, sal_uInt16 nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos) const
-{
- bool bCloneValue = (nFlags & IDF_VALUE) != 0;
- bool bCloneDateTime = (nFlags & IDF_DATETIME) != 0;
- bool bCloneString = (nFlags & IDF_STRING) != 0;
- bool bCloneSpecialBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != 0;
- bool bCloneFormula = (nFlags & IDF_FORMULA) != 0;
- bool bForceFormula = false;
-
- ScBaseCell* pNew = 0;
- ScBaseCell& rSource = *maItems[nIndex].pCell;
- switch (rSource.GetCellType())
- {
- case CELLTYPE_STRING:
- case CELLTYPE_EDIT:
- // note will be cloned below
- if (bCloneString)
- pNew = rSource.Clone( rDestDoc, rDestPos );
- break;
-
- case CELLTYPE_VALUE:
- // note will be cloned below
- if (lclCanCloneValue( *pDocument, *this, maItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
- pNew = rSource.Clone( rDestDoc, rDestPos );
- break;
-
- case CELLTYPE_FORMULA:
- if ( bCloneSpecialBoolean )
- {
- ScFormulaCell& rForm = (ScFormulaCell&)rSource;
- OUStringBuffer aBuf;
- // FIXME: do we have a localisation issue here?
- rForm.GetFormula( aBuf );
- OUString aVal( aBuf.makeStringAndClear() );
- if ( aVal == "=TRUE()" || aVal == "=FALSE()" )
- bForceFormula = true;
- }
- if (bForceFormula || bCloneFormula)
- {
- // note will be cloned below
- pNew = rSource.Clone( rDestDoc, rDestPos );
- }
- else if ( (bCloneValue || bCloneDateTime || bCloneString) && !rDestDoc.IsUndo() )
- {
- // Always just copy the original row to the Undo Documen;
- // do not create Value/string cells from formulas
- ScFormulaCell& rForm = (ScFormulaCell&)rSource;
- sal_uInt16 nErr = rForm.GetErrCode();
- if ( nErr )
- {
- // error codes are cloned with values
- if (bCloneValue)
- {
- ScFormulaCell* pErrCell = new ScFormulaCell( &rDestDoc, rDestPos );
- pErrCell->SetErrCode( nErr );
- pNew = pErrCell;
- }
- }
- else if (rForm.IsValue())
- {
- if (lclCanCloneValue( *pDocument, *this, maItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
- {
- double nVal = rForm.GetValue();
- pNew = new ScValueCell(nVal);
- }
- }
- else if (bCloneString)
- {
- String aString = rForm.GetString();
- // do not clone empty string
- if (aString.Len() > 0)
- {
- if ( rForm.IsMultilineResult() )
- {
- pNew = new ScEditCell( aString, &rDestDoc );
- }
- else
- {
- pNew = new ScStringCell( aString );
- }
- }
- }
- }
- break;
-
- default: OSL_FAIL( "ScColumn::CloneCell - unknown cell type" );
- }
+ // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range.
- return pNew;
+ // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column.
+ CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy);
+ sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy);
}
-
void ScColumn::MixMarked(
sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
bool bSkipEmpty, const ScColumn& rSrcCol )
@@ -867,7 +985,7 @@ bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
return bOk;
}
-void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
+void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
{
rArr.AddOpCode(ocOpen);
@@ -885,138 +1003,167 @@ void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
rArr.AddOpCode(ocClose);
}
-struct FindRemovedCell : std::unary_function<ColEntry, bool>
+class MixDataHandler
{
- bool operator() (const ColEntry& rEntry) const
- {
- return rEntry.pCell == NULL;
- }
-};
-
-}
+ ScColumn& mrDestColumn;
-void ScColumn::MixData(
- sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
- bool bSkipEmpty, const ScColumn& rSrcCol )
-{
- SCSIZE nSrcCount = rSrcCol.maItems.size();
+ sc::CellStoreType& mrDestCells;
+ sc::CellStoreType::iterator miDestPos;
- sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
+ sc::CellTextAttrStoreType& mrDestAttrs;
- SCSIZE nIndex;
- Search( nRow1, nIndex );
+ sc::CellStoreType maNewCells;
+ sc::CellStoreType::iterator miNewCellsPos;
- SCSIZE nSrcIndex = 0, nDestIndex = 0;
- rSrcCol.Search( nRow1, nSrcIndex ); // See if data is at the beginning
+ size_t mnRowOffset;
+ sal_uInt16 mnFunction;
- SCROW nNextThis = MAXROW+1;
- if ( nIndex < maItems.size() )
- nNextThis = maItems[nIndex].nRow;
- SCROW nNextSrc = MAXROW+1;
- if ( nSrcIndex < nSrcCount )
- nNextSrc = rSrcCol.maItems[nSrcIndex].nRow;
+ bool mbSkipEmpty;
- bool bDeferredDelete = false;
- while ( nNextThis <= nRow2 || nNextSrc <= nRow2 )
+public:
+ MixDataHandler(
+ sc::ColumnBlockPosition* pBlockPos,
+ ScColumn& rDestColumn,
+ sc::CellStoreType& rDestCells,
+ sc::CellTextAttrStoreType& rDestAttrs,
+ SCROW nRow1, SCROW nRow2,
+ sal_uInt16 nFunction, bool bSkipEmpty) :
+ mrDestColumn(rDestColumn),
+ mrDestCells(rDestCells),
+ mrDestAttrs(rDestAttrs),
+ maNewCells(0, nRow2 - nRow1 + 1),
+ miNewCellsPos(maNewCells.begin()),
+ mnRowOffset(nRow1),
+ mnFunction(nFunction),
+ mbSkipEmpty(bSkipEmpty)
{
- SCROW nRow = std::min( nNextThis, nNextSrc );
+ if (pBlockPos)
+ miDestPos = pBlockPos->miCellPos;
+ else
+ miDestPos = mrDestCells.begin();
+ }
- ScBaseCell* pSrc = NULL;
- ScBaseCell* pDest = NULL;
- ScBaseCell* pNew = NULL;
- bool bDelete = false;
+ void operator() (size_t nRow, double f)
+ {
+ std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nRow);
+ miDestPos = aPos.first;
+ switch (miDestPos->type)
+ {
+ case sc::element_type_numeric:
+ {
+ // Both src and dest are of numeric type.
+ bool bOk = lcl_DoFunction(f, sc::numeric_block::at(*miDestPos->data, aPos.second), mnFunction);
- if ( nSrcIndex < nSrcCount && nNextSrc == nRow )
- pSrc = rSrcCol.maItems[nSrcIndex].pCell;
+ if (bOk)
+ miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
+ else
+ {
+ ScFormulaCell* pFC =
+ new ScFormulaCell(
+ &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()));
- if ( nIndex < maItems.size() && nNextThis == nRow )
- {
- pDest = maItems[nIndex].pCell;
- nDestIndex = nIndex;
- }
+ pFC->SetErrCode(errNoValue);
+ miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, pFC);
+ }
+ }
+ break;
+ case sc::element_type_formula:
+ {
+ // Combination of value and at least one formula -> Create formula
+ ScTokenArray aArr;
- OSL_ENSURE( pSrc || pDest, "What happened?" );
+ // First row
+ aArr.AddDouble(f);
- CellType eSrcType = pSrc ? pSrc->GetCellType() : CELLTYPE_NONE;
- CellType eDestType = pDest ? pDest->GetCellType() : CELLTYPE_NONE;
+ // Operator
+ OpCode eOp = ocAdd;
+ switch (mnFunction)
+ {
+ case PASTE_ADD: eOp = ocAdd; break;
+ case PASTE_SUB: eOp = ocSub; break;
+ case PASTE_MUL: eOp = ocMul; break;
+ case PASTE_DIV: eOp = ocDiv; break;
+ }
+ aArr.AddOpCode(eOp); // Function
- bool bSrcEmpty = (eSrcType == CELLTYPE_NONE);
- bool bDestEmpty = (eDestType == CELLTYPE_NONE);
+ // Second row
+ ScFormulaCell* pDest = sc::formula_block::at(*miDestPos->data, aPos.second);
+ lcl_AddCode(aArr, pDest);
- if ( bSkipEmpty && bDestEmpty ) // Restore original row
- {
- if ( pSrc ) // Did we have a row here?
+ miNewCellsPos = maNewCells.set(
+ miNewCellsPos, nRow-mnRowOffset,
+ new ScFormulaCell(
+ &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), &aArr));
+ }
+ break;
+ case sc::element_type_string:
+ case sc::element_type_edittext:
+ case sc::element_type_empty:
{
- pNew = pSrc->Clone( *pDocument );
+ // Destination cell is not a number. Just take the source cell.
+ miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
}
+ break;
+ default:
+ ;
}
- else if ( nFunction ) // Really provide calculation function
- {
- double nVal1;
- double nVal2;
- if ( eSrcType == CELLTYPE_VALUE )
- nVal1 = ((ScValueCell*)pSrc)->GetValue();
- else
- nVal1 = 0.0;
- if ( eDestType == CELLTYPE_VALUE )
- nVal2 = ((ScValueCell*)pDest)->GetValue();
- else
- nVal2 = 0.0;
+ }
- // Empty row is treated as a value
- sal_Bool bSrcVal = ( bSrcEmpty || eSrcType == CELLTYPE_VALUE );
- sal_Bool bDestVal = ( bDestEmpty || eDestType == CELLTYPE_VALUE );
+ void operator() (size_t nRow, const OUString& rStr)
+ {
+ miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr);
+ }
- sal_Bool bSrcText = ( eSrcType == CELLTYPE_STRING ||
- eSrcType == CELLTYPE_EDIT );
- sal_Bool bDestText = ( eDestType == CELLTYPE_STRING ||
- eDestType == CELLTYPE_EDIT );
+ void operator() (size_t nRow, const EditTextObject* p)
+ {
+ miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone());
+ }
- // Else we only have formulas ...
- if ( bSrcEmpty && bDestEmpty )
- {
- // Both empty -> do nothing
- }
- else if ( bSrcVal && bDestVal )
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nRow);
+ miDestPos = aPos.first;
+ switch (miDestPos->type)
+ {
+ case sc::element_type_numeric:
{
- // Insterted new value or both have overflown
- sal_Bool bOk = lcl_DoFunction( nVal1, nVal2, nFunction );
+ // Source is formula, and dest is value.
+ ScTokenArray aArr;
- if (bOk)
- pNew = new ScValueCell( nVal1 );
- else
+ // First row
+ lcl_AddCode(aArr, p);
+
+ // Operator
+ OpCode eOp = ocAdd;
+ switch (mnFunction)
{
- ScFormulaCell* pFC = new ScFormulaCell( pDocument,
- ScAddress( nCol, nRow, nTab ) );
- pFC->SetErrCode( errNoValue );
- //! oder NOVALUE, dann auch in consoli,
- //! sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus
- //! (dann geht Stringzelle+Wertzelle nicht mehr)
- pNew = pFC;
+ case PASTE_ADD: eOp = ocAdd; break;
+ case PASTE_SUB: eOp = ocSub; break;
+ case PASTE_MUL: eOp = ocMul; break;
+ case PASTE_DIV: eOp = ocDiv; break;
}
+ aArr.AddOpCode(eOp); // Function
+
+ // Second row
+ aArr.AddDouble(sc::numeric_block::at(*miDestPos->data, aPos.second));
+
+ miNewCellsPos = maNewCells.set(
+ miNewCellsPos, nRow-mnRowOffset,
+ new ScFormulaCell(
+ &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), &aArr));
}
- else if ( bSrcText || bDestText )
- {
- // We do no not calculate with texts - alwyas "old" cell, thus pSrc
- if (pSrc)
- pNew = pSrc->Clone( *pDocument );
- else if (pDest)
- bDelete = sal_True;
- }
- else
+ break;
+ case sc::element_type_formula:
{
- // Combination of value and at least one formula -> Create formula
+ // Both are formulas.
ScTokenArray aArr;
// First row
- if ( eSrcType == CELLTYPE_FORMULA )
- lcl_AddCode( aArr, (ScFormulaCell*)pSrc );
- else
- aArr.AddDouble( nVal1 );
+ lcl_AddCode(aArr, p);
// Operator
OpCode eOp = ocAdd;
- switch ( nFunction )
+ switch (mnFunction)
{
case PASTE_ADD: eOp = ocAdd; break;
case PASTE_SUB: eOp = ocSub; break;
@@ -1026,72 +1173,177 @@ void ScColumn::MixData(
aArr.AddOpCode(eOp); // Function
// Second row
- if ( eDestType == CELLTYPE_FORMULA )
- lcl_AddCode( aArr, (ScFormulaCell*)pDest );
- else
- aArr.AddDouble( nVal2 );
+ ScFormulaCell* pDest = sc::formula_block::at(*miDestPos->data, aPos.second);
+ lcl_AddCode(aArr, pDest);
- pNew = new ScFormulaCell( pDocument, ScAddress( nCol, nRow, nTab ), &aArr );
+ miNewCellsPos = maNewCells.set(
+ miNewCellsPos, nRow-mnRowOffset,
+ new ScFormulaCell(
+ &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), &aArr));
+ }
+ break;
+ case sc::element_type_string:
+ case sc::element_type_edittext:
+ case sc::element_type_empty:
+ {
+ // Destination cell is not a number. Just take the source cell.
+ ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab());
+ miNewCellsPos = maNewCells.set(
+ miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, mrDestColumn.GetDoc(), aDestPos));
}
+ break;
+ default:
+ ;
}
+ }
+ /**
+ * Empty cell series in the source (clip) document.
+ */
+ void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize)
+ {
+ if (mbSkipEmpty)
+ return;
- if ( pNew || bDelete ) // New result?
+ // Source cells are empty. Treat them as if they have a value of 0.0.
+ for (size_t i = 0; i < nDataSize; ++i)
{
- if (pDest && !pNew) // Old cell present?
+ size_t nDestRow = nTopRow + i;
+ std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nDestRow);
+ miDestPos = aPos.first;
+ switch (miDestPos->type)
{
- // Delete the destination cell because the cell was originally
- // empty. Don't erase its slot in the cell array yet.
- OSL_ASSERT(pDest == maItems[nDestIndex].pCell);
- maItems[nDestIndex].pCell = NULL;
+ case sc::element_type_numeric:
+ case sc::element_type_string:
+ case sc::element_type_edittext:
+ // Dont' do anything.
+ break;
+ case sc::element_type_formula:
+ {
+ ScTokenArray aArr;
- if (pDest->GetCellType() == CELLTYPE_FORMULA)
- static_cast<ScFormulaCell*>(pDest)->EndListeningTo(pDocument);
- pDest->Delete();
+ // First row
+ ScFormulaCell* pSrc = sc::formula_block::at(*miDestPos->data, aPos.second);
+ lcl_AddCode( aArr, pSrc);
- bDeferredDelete = true;
+ // Operator
+ OpCode eOp = ocAdd;
+ switch (mnFunction)
+ {
+ case PASTE_ADD: eOp = ocAdd; break;
+ case PASTE_SUB: eOp = ocSub; break;
+ case PASTE_MUL: eOp = ocMul; break;
+ case PASTE_DIV: eOp = ocDiv; break;
+ }
+
+ aArr.AddOpCode(eOp); // Function
+ aArr.AddDouble(0.0);
+
+ miNewCellsPos = maNewCells.set(
+ miNewCellsPos, nDestRow-mnRowOffset,
+ new ScFormulaCell(
+ &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), &aArr));
+ }
+ break;
+ default:
+ ;
}
- if (pNew)
+ }
+ }
+
+ /**
+ * Set the new cells to the destination (this) column.
+ */
+ void commit(sc::ColumnBlockPosition* pDestBlockPos)
+ {
+ sc::ColumnBlockPosition aDestBlockPos;
+ if (pDestBlockPos)
+ aDestBlockPos = *pDestBlockPos;
+ else
+ mrDestColumn.InitBlockPosition(aDestBlockPos);
+
+ // Stop all formula cells in the destination range first.
+ sc::ColumnBlockPosition aCopy = aDestBlockPos;
+ mrDestColumn.EndFormulaListening(aCopy, mnRowOffset, mnRowOffset + maNewCells.size() - 1);
+
+ // Move the new cells to the destination range.
+ sc::CellStoreType::iterator& itDestPos = aDestBlockPos.miCellPos;
+ sc::CellTextAttrStoreType::iterator& itDestAttrPos = aDestBlockPos.miCellTextAttrPos;
+
+ sc::CellStoreType::iterator it = maNewCells.begin(), itEnd = maNewCells.end();
+ for (; it != itEnd; ++it)
+ {
+ bool bHasContent = true;
+ size_t nDestRow = mnRowOffset + it->position;
+
+ switch (it->type)
{
- if (p)
- Insert(*p, nRow, pNew);
- else
- Insert(nRow, pNew); // Insert new one
+ case sc::element_type_numeric:
+ {
+ sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data);
+ sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*it->data);
+ itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_string:
+ {
+ sc::string_block::iterator itData = sc::string_block::begin(*it->data);
+ sc::string_block::iterator itDataEnd = sc::string_block::end(*it->data);
+ itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_edittext:
+ {
+ sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
+ sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*it->data);
+ itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+ }
+ case sc::element_type_formula:
+ {
+ sc::formula_block::iterator itData = sc::formula_block::begin(*it->data);
+ sc::formula_block::iterator itDataEnd = sc::formula_block::end(*it->data);
+ itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+ }
+ break;
+ case sc::element_type_empty:
+ {
+ itDestPos = mrDestCells.set_empty(itDestPos, nDestRow, nDestRow+it->size-1);
+ bHasContent = false;
+ }
+ break;
+ default:
+ ;
}
- Search( nRow, nIndex ); // Everything could have moved
- if (pNew)
- nNextThis = nRow; // nIndex points right at nRow now
+ if (bHasContent)
+ {
+ std::vector<sc::CellTextAttr> aAttrs(it->size, sc::CellTextAttr());
+ itDestAttrPos = mrDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
+ }
else
- nNextThis = ( nIndex < maItems.size() ) ? maItems[nIndex].nRow : MAXROW+1;
+ itDestAttrPos = mrDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+it->size-1);
}
- if ( nNextThis == nRow )
- {
- ++nIndex;
- nNextThis = ( nIndex < maItems.size() ) ? maItems[nIndex].nRow : MAXROW+1;
- }
- if ( nNextSrc == nRow )
- {
- ++nSrcIndex;
- nNextSrc = ( nSrcIndex < nSrcCount ) ?
- rSrcCol.maItems[nSrcIndex].nRow :
- MAXROW+1;
- }
+ maNewCells.release();
+
+ if (pDestBlockPos)
+ *pDestBlockPos = aDestBlockPos;
}
+};
- if (bDeferredDelete)
- {
- // Erase all the slots in the cell array where the deleted cells
- // previously occupied.
- std::vector<ColEntry>::iterator it =
- std::remove_if(maItems.begin(), maItems.end(), FindRemovedCell());
+}
- maItems.erase(it, maItems.end());
+void ScColumn::MixData(
+ sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
+ bool bSkipEmpty, const ScColumn& rSrcCol )
+{
+ // destination (this column) block position.
- // Reset the cell text attriute array to keep it in sync again.
- ResetCellTextAttrs();
- }
+ sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
+ MixDataHandler aFunc(p, *this, maCells, maCellTextAttrs, nRow1, nRow2, nFunction, bSkipEmpty);
+ sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
+
+ aFunc.commit(p);
}
@@ -1100,90 +1352,68 @@ ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) c
return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
}
+namespace {
-void ScColumn::StartAllListeners()
+class StartAllListenersHandler
{
- if (maItems.empty())
- return;
+ ScDocument* mpDoc;
+public:
+ StartAllListenersHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
- for (SCSIZE i = 0; i < maItems.size(); i++)
+ void operator() (size_t, ScFormulaCell* p)
{
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- {
- SCROW nRow = maItems[i].nRow;
- ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Insert Listener?
- }
+ p->StartListeningTo(mpDoc);
}
-}
-
+};
-void ScColumn::StartNeededListeners()
+class StartNeededListenerHandler
{
- if (maItems.empty())
- return;
+ ScDocument* mpDoc;
+public:
+ StartNeededListenerHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
- for (SCSIZE i = 0; i < maItems.size(); i++)
+ void operator() (size_t, ScFormulaCell* p)
{
- ScBaseCell* pCell = maItems[i].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- {
- ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
- if (pFCell->NeedsListening())
- {
- SCROW nRow = maItems[i].nRow;
- pFCell->StartListeningTo( pDocument );
- if ( nRow != maItems[i].nRow )
- Search( nRow, i ); // Insert Listener?
- }
- }
+ if (p->NeedsListening())
+ p->StartListeningTo(mpDoc);
}
-}
+};
+}
-void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 )
+void ScColumn::StartAllListeners()
{
- if (maItems.empty())
- return;
+ StartAllListenersHandler aFunc(pDocument);
+ sc::ProcessFormula(maCells, aFunc);
+}
- SCROW nRow;
- SCSIZE nIndex;
- if (!Search(nRow1, nIndex))
- return;
- while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
- {
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->SetDirty();
- else
- pDocument->Broadcast( ScHint(SC_HINT_DATACHANGED,
- ScAddress(nCol, nRow, nTab)));
- nIndex++;
- }
+void ScColumn::StartNeededListeners()
+{
+ StartNeededListenerHandler aFunc(pDocument);
+ sc::ProcessFormula(maCells, aFunc);
}
+namespace {
-void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
+class StartListeningInAreaHandler
{
- if (maItems.empty())
- return;
+ sc::StartListeningContext& mrCxt;
+public:
+ StartListeningInAreaHandler(sc::StartListeningContext& rCxt) : mrCxt(rCxt) {}
- SCROW nRow;
- SCSIZE nIndex;
- Search( nRow1, nIndex );
- while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRow2 )
+ void operator() (size_t /*nRow*/, ScFormulaCell* p)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- ((ScFormulaCell*)pCell)->StartListeningTo(rCxt);
- if ( nRow != maItems[nIndex].nRow )
- Search( nRow, nIndex ); // Inserted via Listening
-
- ++nIndex;
+ p->StartListeningTo(mrCxt);
}
+};
+
+}
+
+void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
+{
+ StartListeningInAreaHandler aFunc(rCxt);
+ sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
}
@@ -1198,8 +1428,7 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
if (!ValidRow(nRow))
return false;
- ScBaseCell* pNewCell = NULL;
- sal_Bool bIsLoading = false;
+ ScCellValue aNewCell;
if (rString.Len() > 0)
{
ScSetStringParam aParam;
@@ -1211,33 +1440,24 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
sal_Unicode cFirstChar;
if (!aParam.mpNumFormatter)
aParam.mpNumFormatter = pDocument->GetFormatTable();
- SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
- if ( pDocSh )
- bIsLoading = pDocSh->IsLoading();
- // IsLoading for ConvertFrom import
- if ( !bIsLoading )
- {
- nIndex = nOldIndex = GetNumberFormat( nRow );
- if ( rString.Len() > 1
- && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
- cFirstChar = rString.GetChar(0);
- else
- cFirstChar = 0; // Text
- }
- else
- { // There are not applied formats when importing during ConvertFrom
+
+ nIndex = nOldIndex = GetNumberFormat( nRow );
+ if ( rString.Len() > 1
+ && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
cFirstChar = rString.GetChar(0);
- }
+ else
+ cFirstChar = 0; // Text
if ( cFirstChar == '=' )
{
if ( rString.Len() == 1 ) // = Text
- pNewCell = new ScStringCell( rString );
+ aNewCell.set(rString);
else // = Formula
- pNewCell = new ScFormulaCell( pDocument,
- ScAddress( nCol, nRow, nTabP ), rString,
- formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT,
- eConv), MM_NONE );
+ aNewCell.set(
+ new ScFormulaCell(
+ pDocument, ScAddress(nCol, nRow, nTabP), rString,
+ formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv),
+ MM_NONE));
}
else if ( cFirstChar == '\'') // 'Text
{
@@ -1251,53 +1471,18 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
if (bNumeric)
// This is a number. Strip out the first char.
- pNewCell = new ScStringCell(aTest);
+ aNewCell.set(aTest);
}
if (!bNumeric)
// This is normal text. Take it as-is.
- pNewCell = new ScStringCell(rString);
+ aNewCell.set(rString);
}
else
{
double nVal;
- sal_Bool bIsText = false;
- if ( bIsLoading )
- {
- if ( !maItems.empty() )
- {
- String aStr;
- SCSIZE i = maItems.size();
- SCSIZE nStop = (i >= 3 ? i - 3 : 0);
- // Compare the last lines and see whether same String
- // and IsNumberFormat can be made obsolete
- do
- {
- i--;
- ScBaseCell* pCell = maItems[i].pCell;
- switch ( pCell->GetCellType() )
- {
- case CELLTYPE_STRING :
- aStr = ((ScStringCell*)pCell)->GetString();
- if ( rString == aStr )
- bIsText = true;
- break;
- default:
- if ( i == maItems.size() - 1 )
- i = 0;
- // Probably whole column and no String
- }
- } while ( i && i > nStop && !bIsText );
- }
- // Prefill nIndex for IsNumberFormat
- if ( !bIsText )
- nIndex = nOldIndex = aParam.mpNumFormatter->GetStandardIndex();
- }
do
{
- if (bIsText)
- break;
-
if (aParam.mbDetectNumberFormat)
{
if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
@@ -1311,7 +1496,7 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
}
- pNewCell = new ScValueCell( nVal );
+ aNewCell.set(nVal);
if ( nIndex != nOldIndex)
{
// #i22345# New behavior: Apply the detected number format only if
@@ -1365,12 +1550,12 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
break;
- pNewCell = new ScValueCell(nVal);
+ aNewCell.set(nVal);
}
}
while (false);
- if (!pNewCell)
+ if (aNewCell.meType == CELLTYPE_NONE)
{
if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
{
@@ -1382,52 +1567,12 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
ApplyPattern(nRow, aNewAttrs);
}
- pNewCell = new ScStringCell(rString);
+ aNewCell.set(rString);
}
}
}
- if ( bIsLoading && (maItems.empty() || nRow > maItems.back().nRow) )
- { // Save search and build up Listener without a detour via Insert
- // Broadcast comes after Loading
- if ( pNewCell )
- Append( nRow, pNewCell );
- }
- else
- {
- SCSIZE i;
- if (Search(nRow, i))
- {
- ScBaseCell* pOldCell = maItems[i].pCell;
- if (pNewCell)
- {
- if ( pOldCell->GetCellType() == CELLTYPE_FORMULA )
- static_cast<ScFormulaCell*>(pOldCell)->EndListeningTo(pDocument);
-
- pOldCell->Delete();
- maItems[i].pCell = pNewCell; // Replace
- maCellTextAttrs.set<sc::CellTextAttr>(nRow, sc::CellTextAttr());
- CellStorageModified();
-
- if ( pNewCell->GetCellType() == CELLTYPE_FORMULA )
- {
- static_cast<ScFormulaCell*>(pNewCell)->StartListeningTo(pDocument);
- ((ScFormulaCell*)pNewCell)->SetDirty();
- }
- else
- pDocument->Broadcast(
- ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTabP)));
- }
- else
- {
- DeleteAtIndex(i); // Delete and Broadcast
- }
- }
- else if (pNewCell)
- {
- Insert(nRow, pNewCell); // Re-insert and Broadcast
- }
- }
+ aNewCell.release(*this, nRow);
// Do not set Formats and Formulas here anymore!
// These are queried during output
@@ -1437,114 +1582,361 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
{
- Insert(nRow, new ScEditCell(pEditText, pDocument));
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+ maCells.set(it, nRow, pEditText);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ BroadcastNewCell(nRow);
+}
+
+void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
+{
+ rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+ rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
+ rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ BroadcastNewCell(nRow);
+}
+
+void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
+{
+ if (pDocument->GetEditPool() == rEditText.GetPool())
+ {
+ SetEditText(rBlockPos, nRow, rEditText.Clone());
+ return;
+ }
+
+ //! another "spool"
+ // Sadly there is no other way to change the Pool than to
+ // "spool" the Object through a corresponding Engine
+ EditEngine& rEngine = pDocument->GetEditEngine();
+ if (!rEditText.HasOnlineSpellErrors())
+ {
+ rEngine.SetText(rEditText);
+ SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
+ return;
+ }
+
+ sal_uLong nControl = rEngine.GetControlWord();
+ const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
+ bool bNewControl = (nControl & nSpellControl) != nSpellControl;
+ if (bNewControl)
+ rEngine.SetControlWord(nControl | nSpellControl);
+ rEngine.SetText(rEditText);
+ EditTextObject* pData = rEngine.CreateTextObject();
+ if (bNewControl)
+ rEngine.SetControlWord(nControl);
+
+ SetEditText(rBlockPos, nRow, pData);
}
void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
{
- Insert(nRow, new ScEditCell(rEditText, pDocument, pEditPool));
+ if (pEditPool && pDocument->GetEditPool() == pEditPool)
+ {
+ SetEditText(nRow, rEditText.Clone());
+ return;
+ }
+
+ //! another "spool"
+ // Sadly there is no other way to change the Pool than to
+ // "spool" the Object through a corresponding Engine
+ EditEngine& rEngine = pDocument->GetEditEngine();
+ if (!rEditText.HasOnlineSpellErrors())
+ {
+ rEngine.SetText(rEditText);
+ SetEditText(nRow, rEngine.CreateTextObject());
+ return;
+ }
+
+ sal_uLong nControl = rEngine.GetControlWord();
+ const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
+ bool bNewControl = (nControl & nSpellControl) != nSpellControl;
+ if (bNewControl)
+ rEngine.SetControlWord(nControl | nSpellControl);
+ rEngine.SetText(rEditText);
+ EditTextObject* pData = rEngine.CreateTextObject();
+ if (bNewControl)
+ rEngine.SetControlWord(nControl);
+
+ SetEditText(nRow, pData);
}
void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
{
ScAddress aPos(nCol, nRow, nTab);
+
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, &rArray, eGram);
- sal_uInt32 nCellFormat = GetNumberFormat( nRow );
+ sal_uInt32 nCellFormat = GetNumberFormat(nRow);
if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
pCell->SetNeedNumberFormat(true);
- Insert(nRow, pCell);
+ maCells.set(it, nRow, pCell);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ ActivateNewFormulaCell(pCell);
}
void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
{
ScAddress aPos(nCol, nRow, nTab);
- ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
- sal_uInt32 nCellFormat = GetNumberFormat( nRow );
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+ ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
+ sal_uInt32 nCellFormat = GetNumberFormat(nRow);
if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
pCell->SetNeedNumberFormat(true);
- Insert(nRow, pCell);
+ maCells.set(it, nRow, pCell);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ ActivateNewFormulaCell(pCell);
}
void ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell )
{
- Insert(nRow, pCell);
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+ maCells.set(it, nRow, pCell);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ ActivateNewFormulaCell(pCell);
}
-void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
+void ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell )
{
- bool bHasDates = false;
- SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
- OUString aString;
- SCSIZE nIndex;
+ rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+ rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
+ rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+ CellStorageModified();
- Search( nStartRow, nIndex );
+ ActivateNewFormulaCell(pCell);
+}
- for (; nIndex < maItems.size(); ++nIndex)
- {
- SCROW nRow = maItems[nIndex].nRow;
- if (nRow > nEndRow)
- break;
+namespace {
- ScBaseCell* pCell = maItems[nIndex].pCell;
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
- sal_uLong nFormat = GetNumberFormat( nRow );
+class FilterEntriesHandler
+{
+ ScColumn& mrColumn;
+ std::vector<ScTypedStrData>& mrStrings;
+ bool mbHasDates;
- ScCellFormat::GetInputString(aCell, nFormat, aString, *pFormatter);
+ void processCell(SCROW nRow, ScRefCellValue& rCell)
+ {
+ SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
+ OUString aStr;
+ sal_uLong nFormat = mrColumn.GetNumberFormat(nRow);
+ ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter);
- if ( pDocument->HasStringData( nCol, nRow, nTab ) )
+ if (rCell.hasString())
{
- rStrings.push_back(ScTypedStrData(aString));
- continue;
+ mrStrings.push_back(ScTypedStrData(aStr));
+ return;
}
- double nValue = 0.0;
+ double fVal = 0.0;
- switch ( pCell->GetCellType() )
+ switch (rCell.meType)
{
case CELLTYPE_VALUE:
- nValue = ((ScValueCell*)pCell)->GetValue();
+ fVal = rCell.mfValue;
break;
case CELLTYPE_FORMULA:
{
- ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
+ ScFormulaCell* pFC = rCell.mpFormula;
sal_uInt16 nErr = pFC->GetErrCode();
if (nErr)
{
// Error cell is evaluated as string (for now).
- String aErr = ScGlobal::GetErrorString(nErr);
- if (aErr.Len())
+ OUString aErr = ScGlobal::GetErrorString(nErr);
+ if (!aErr.isEmpty())
{
- rStrings.push_back(ScTypedStrData(aErr));
- continue;
+ mrStrings.push_back(ScTypedStrData(aErr));
+ return;
}
}
else
- nValue = pFC->GetValue();
+ fVal = pFC->GetValue();
}
break;
default:
;
}
- if (pFormatter)
+ short nType = pFormatter->GetType(nFormat);
+ if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
+ {
+ // special case for date values. Disregard the time
+ // element if the number format is of date type.
+ fVal = rtl::math::approxFloor(fVal);
+ mbHasDates = true;
+ }
+
+ mrStrings.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value));
+ }
+
+public:
+ FilterEntriesHandler(ScColumn& rColumn, std::vector<ScTypedStrData>& rStrings) :
+ mrColumn(rColumn), mrStrings(rStrings), mbHasDates(false) {}
+
+ void operator() (size_t nRow, double fVal)
+ {
+ ScRefCellValue aCell(fVal);
+ processCell(nRow, aCell);
+ }
+
+ void operator() (size_t nRow, const OUString& rStr)
+ {
+ ScRefCellValue aCell(&rStr);
+ processCell(nRow, aCell);
+ }
+
+ void operator() (size_t nRow, const EditTextObject* p)
+ {
+ ScRefCellValue aCell(p);
+ processCell(nRow, aCell);
+ }
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
+ processCell(nRow, aCell);
+ }
+
+ bool hasDates() const { return mbHasDates; }
+};
+
+}
+
+void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
+{
+ FilterEntriesHandler aFunc(*this, rStrings);
+ sc::ParseAllNonEmpty(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
+ rHasDates = aFunc.hasDates();
+}
+
+namespace {
+
+/**
+ * Iterate over only string and edit-text cells.
+ */
+class StrCellIterator
+{
+ typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
+ const sc::CellStoreType& mrCells;
+ PosType maPos;
+ sc::CellStoreType::const_iterator miBeg;
+ sc::CellStoreType::const_iterator miEnd;
+public:
+ StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart) :
+ mrCells(rCells), maPos(rCells.position(nStart)), miBeg(rCells.begin()), miEnd(rCells.end()) {}
+
+ bool valid() const { return (maPos.first != miEnd); }
+
+ bool has() const
+ {
+ return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
+ }
+
+ bool prev()
+ {
+ if (!has())
+ {
+ // Not in a string block. Move back until we hit a string block.
+ while (!has())
+ {
+ if (maPos.first == miBeg)
+ return false;
+
+ --maPos.first; // move to the preceding block.
+ maPos.second = maPos.first->size - 1; // last cell in the block.
+ }
+ return true;
+ }
+
+ // We are in a string block.
+ if (maPos.second > 0)
+ {
+ // Move back one cell in the same block.
+ --maPos.second;
+ }
+ else
+ {
+ // Move back to the preceding string block.
+ while (true)
+ {
+ if (maPos.first == miBeg)
+ return false;
+
+ // Move to the last cell of the previous block.
+ --maPos.first;
+ maPos.second = maPos.first->size - 1;
+ if (has())
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool next()
+ {
+ if (!has())
{
- short nType = pFormatter->GetType(nFormat);
- if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
+ // Not in a string block. Move forward until we hit a string block.
+ while (!has())
{
- // special case for date values. Disregard the time
- // element if the number format is of date type.
- nValue = ::rtl::math::approxFloor(nValue);
- bHasDates = true;
+ ++maPos.first;
+ if (maPos.first == miEnd)
+ return false;
+
+ maPos.second = 0; // First cell in this block.
}
+ return true;
}
- rStrings.push_back(ScTypedStrData(aString, nValue, ScTypedStrData::Value));
+ // We are in a string block.
+ ++maPos.second;
+ if (maPos.second >= maPos.first->size)
+ {
+ // Move to the next string block.
+ while (true)
+ {
+ ++maPos.first;
+ if (maPos.first == miEnd)
+ return false;
+
+ maPos.second = 0;
+ if (has())
+ break;
+ }
+ }
+ return true;
}
- rHasDates = bHasDates;
+ OUString get() const
+ {
+ switch (maPos.first->type)
+ {
+ case sc::element_type_string:
+ return sc::string_block::at(*maPos.first->data, maPos.second);
+ case sc::element_type_edittext:
+ {
+ const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
+ return ScEditUtil::GetString(*p);
+ }
+ default:
+ ;
+ }
+ return OUString();
+ }
+};
+
}
//
@@ -1556,87 +1948,132 @@ void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTy
#define DATENT_MAX 200
#define DATENT_SEARCH 2000
-
-bool ScColumn::GetDataEntries(SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit)
+bool ScColumn::GetDataEntries(
+ SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit ) const
{
- sal_Bool bFound = false;
- SCSIZE nThisIndex;
- sal_Bool bThisUsed = Search( nStartRow, nThisIndex );
- String aString;
- sal_uInt16 nCells = 0;
+ // Start at the specified row position, and collect all string values
+ // going upward and downward directions in parallel. The start position
+ // cell must be skipped.
- // The limitation to neighbouring cells (without gaps) is not wanted anymore
- // (Featurecommission for 5.1), search upwards/downwards instead so that
- // nearby cell are cought at least first.
- // TODO: Compare distances of cell numbers? Performance??
+ StrCellIterator aItrUp(maCells, nStartRow);
+ StrCellIterator aItrDown(maCells, nStartRow+1);
- SCSIZE nUpIndex = nThisIndex; // Points after the row
- SCSIZE nDownIndex = nThisIndex; // Points to the row
- if (bThisUsed)
- ++nDownIndex; // Skip starting row
+ bool bMoveUp = aItrUp.valid();
+ if (!bMoveUp)
+ // Current cell is invalid.
+ return false;
+
+ // Skip the start position cell.
+ bMoveUp = aItrUp.prev(); // Find the previous string cell position.
- while ( nUpIndex || nDownIndex < maItems.size() )
+ bool bMoveDown = aItrDown.valid();
+ if (bMoveDown && !aItrDown.has())
+ bMoveDown = aItrDown.next(); // Find the next string cell position.
+
+ bool bFound = false;
+ size_t nCellsSearched = 0;
+ while (bMoveUp || bMoveDown)
{
- if ( nUpIndex ) // Up
+ if (bMoveUp)
{
- ScBaseCell* pCell = maItems[nUpIndex-1].pCell;
- CellType eType = pCell->GetCellType();
- if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // Only Strings are of interest
+ // Get the current string and move up.
+ OUString aStr = aItrUp.get();
+ if (!aStr.isEmpty())
{
- if (eType == CELLTYPE_STRING)
- aString = ((ScStringCell*)pCell)->GetString();
- else
- aString = ((ScEditCell*)pCell)->GetString();
-
- bool bInserted = rStrings.insert(ScTypedStrData(aString)).second;
+ bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
- break; // Maximum reached
+ return true; // Maximum reached
bFound = true;
-
- if ( bLimit )
- if (++nCells >= DATENT_SEARCH)
- break; // Searched enough
}
- --nUpIndex;
+
+ if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
+ return bFound; // max search cell count reached.
+
+ bMoveUp = aItrUp.prev();
}
- if ( nDownIndex < maItems.size() ) // Down
+ if (bMoveDown)
{
- ScBaseCell* pCell = maItems[nDownIndex].pCell;
- CellType eType = pCell->GetCellType();
- if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // Only Strings are of interest
+ // Get the current string and move down.
+ OUString aStr = aItrDown.get();
+ if (!aStr.isEmpty())
{
- if (eType == CELLTYPE_STRING)
- aString = ((ScStringCell*)pCell)->GetString();
- else
- aString = ((ScEditCell*)pCell)->GetString();
-
- bool bInserted = rStrings.insert(ScTypedStrData(aString)).second;
+ bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
- break; // Maximum reached
+ return true; // Maximum reached
bFound = true;
-
- if ( bLimit )
- if (++nCells >= DATENT_SEARCH)
- break; // Searched enough
}
- ++nDownIndex;
+
+ if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
+ return bFound; // max search cell count reached.
+
+ bMoveDown = aItrDown.next();
}
}
return bFound;
}
-#undef DATENT_MAX
-#undef DATENT_SEARCH
+namespace {
+
+class FormulaToValueHandler
+{
+ struct Entry
+ {
+ SCROW mnRow;
+ ScCellValue maValue;
+
+ Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
+ Entry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maValue(rStr) {}
+ };
+ typedef std::vector<Entry> EntriesType;
+ EntriesType maEntries;
+
+public:
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
+ if (p2->IsValue())
+ maEntries.push_back(Entry(nRow, p2->GetValue()));
+ else
+ maEntries.push_back(Entry(nRow, p2->GetString()));
+ }
+
+ void commitCells(ScColumn& rColumn)
+ {
+ sc::ColumnBlockPosition aBlockPos;
+ rColumn.InitBlockPosition(aBlockPos);
+
+ EntriesType::iterator it = maEntries.begin(), itEnd = maEntries.end();
+ for (; it != itEnd; ++it)
+ {
+ Entry& r = *it;
+ switch (r.maValue.meType)
+ {
+ case CELLTYPE_VALUE:
+ rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
+ break;
+ case CELLTYPE_STRING:
+ rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
+ default:
+ ;
+ }
+ }
+ }
+};
+
+}
void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
{
+ FormulaToValueHandler aFunc;
+ sc::CellStoreType::const_iterator itPos = maCells.begin();
+
ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
SCROW nTop = -1;
SCROW nBottom = -1;
- SCSIZE nIndex;
const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
while (pPattern)
{
@@ -1645,186 +2082,193 @@ void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
DeleteArea( nTop, nBottom, IDF_CONTENTS );
else if ( pAttr->GetHideFormula() )
{
- Search( nTop, nIndex );
- while ( nIndex<maItems.size() && maItems[nIndex].nRow<=nBottom )
- {
- if ( maItems[nIndex].pCell->GetCellType() == CELLTYPE_FORMULA )
- {
- ScFormulaCell* pFormula = (ScFormulaCell*)maItems[nIndex].pCell;
- if (pFormula->IsValue())
- {
- double nVal = pFormula->GetValue();
- maItems[nIndex].pCell = new ScValueCell( nVal );
- }
- else
- {
- String aString = pFormula->GetString();
- maItems[nIndex].pCell = new ScStringCell( aString );
- }
- delete pFormula;
-
- SetTextWidth(maItems[nIndex].nRow, TEXTWIDTH_DIRTY);
- CellStorageModified();
- }
- ++nIndex;
- }
+ // Replace all formula cells between nTop and nBottom with raw value cells.
+ itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
}
pPattern = aAttrIter.Next( nTop, nBottom );
}
+
+ aFunc.commitCells(*this);
}
void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError)
{
- if (ValidRow(nRow))
- {
- ScFormulaCell* pCell = new ScFormulaCell
- ( pDocument, ScAddress( nCol, nRow, nTab ) );
- pCell->SetErrCode( nError );
- Insert( nRow, pCell );
- }
+ if (!ValidRow(nRow))
+ return;
+
+ ScFormulaCell* pCell = new ScFormulaCell(pDocument, ScAddress(nCol, nRow, nTab));
+ pCell->SetErrCode(nError);
+
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+ maCells.set(it, nRow, pCell);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ ActivateNewFormulaCell(pCell);
}
+void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast )
+{
+ if (!ValidRow(nRow))
+ return;
-void ScColumn::SetValue( SCROW nRow, const double& rVal)
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+ maCells.set(it, nRow, rStr);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ if (bBroadcast)
+ BroadcastNewCell(nRow);
+}
+
+void ScColumn::SetRawString(
+ sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const OUString& rStr, bool bBroadcast )
{
- if (ValidRow(nRow))
- {
- ScBaseCell* pCell = new ScValueCell(rVal);
- Insert( nRow, pCell );
- }
+ if (!ValidRow(nRow))
+ return;
+
+ rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+ rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
+ rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ if (bBroadcast)
+ BroadcastNewCell(nRow);
+}
+
+void ScColumn::SetValue( SCROW nRow, double fVal )
+{
+ if (!ValidRow(nRow))
+ return;
+
+ sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+ maCells.set(it, nRow, fVal);
+ maCellTextAttrs.set(nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ BroadcastNewCell(nRow);
}
+void ScColumn::SetValue(
+ sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
+{
+ if (!ValidRow(nRow))
+ return;
+
+ rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+ rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
+ rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
+ rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+ CellStorageModified();
+
+ if (bBroadcast)
+ BroadcastNewCell(nRow);
+}
void ScColumn::GetString( SCROW nRow, OUString& rString ) const
{
- SCSIZE nIndex;
- Color* pColor;
- if (Search(nRow, nIndex))
- {
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
+ ScRefCellValue aCell = GetCellValue(nRow);
- // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
- if(aCell.meType == CELLTYPE_FORMULA)
- aCell.mpFormula->MaybeInterpret();
+ // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
+ if (aCell.meType == CELLTYPE_FORMULA)
+ aCell.mpFormula->MaybeInterpret();
- sal_uLong nFormat = GetNumberFormat( nRow );
- ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()));
- }
- else
- rString = EMPTY_OUSTRING;
+ sal_uLong nFormat = GetNumberFormat(nRow);
+ Color* pColor = NULL;
+ ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()));
}
const OUString* ScColumn::GetStringCell( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
return NULL;
- const ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() != CELLTYPE_STRING)
+ if (it->type != sc::element_type_string)
return NULL;
- return static_cast<const ScStringCell*>(pCell)->GetStringPtr();
+ return &sc::string_block::at(*it->data, aPos.second);
}
double* ScColumn::GetValueCell( SCROW nRow )
{
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::iterator it = aPos.first;
+ if (it == maCells.end())
return NULL;
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() != CELLTYPE_VALUE)
+ if (it->type != sc::element_type_numeric)
return NULL;
- return static_cast<ScValueCell*>(pCell)->GetValuePtr();
+ return &sc::numeric_block::at(*it->data, aPos.second);
}
void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- {
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
- sal_uLong nFormat = GetNumberFormat( nRow );
- ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()));
- }
- else
- rString = OUString();
+ ScRefCellValue aCell = GetCellValue(nRow);
+ sal_uLong nFormat = GetNumberFormat(nRow);
+ ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()));
}
-
double ScColumn::GetValue( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ switch (it->type)
{
- ScBaseCell* pCell = maItems[nIndex].pCell;
- switch (pCell->GetCellType())
+ case sc::element_type_numeric:
+ return sc::numeric_block::at(*it->data, aPos.second);
+ case sc::element_type_formula:
{
- case CELLTYPE_VALUE:
- return ((ScValueCell*)pCell)->GetValue();
-
- case CELLTYPE_FORMULA:
- {
- if (((ScFormulaCell*)pCell)->IsValue())
- return ((ScFormulaCell*)pCell)->GetValue();
- else
- return 0.0;
- }
-
- default:
- return 0.0;
+ const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
+ ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
+ return p2->IsValue() ? p2->GetValue() : 0.0;
}
+ default:
+ ;
}
+
return 0.0;
}
const EditTextObject* ScColumn::GetEditText( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
return NULL;
- const ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() != CELLTYPE_EDIT)
+ if (it->type != sc::element_type_edittext)
return NULL;
- const ScEditCell* pEditCell = static_cast<const ScEditCell*>(pCell);
- return pEditCell->GetData();
+ return sc::edittext_block::at(*it->data, aPos.second);
}
void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr )
{
- SCSIZE nIndex;
- if (!Search(nRow, nIndex))
+ std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::iterator it = aPos.first;
+ if (it == maCells.end())
return;
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() != CELLTYPE_EDIT)
+ if (it->type != sc::element_type_edittext)
return;
- ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell);
- pEditCell->RemoveCharAttribs(rAttr);
+ EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
+ ScEditUtil::RemoveCharAttribs(*p, rAttr);
}
void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- {
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- ((ScFormulaCell*)pCell)->GetFormula( rFormula );
- else
- rFormula = OUString();
- }
+ const ScFormulaCell* p = FetchFormulaCell(nRow);
+ if (p)
+ p->GetFormula(rFormula);
else
- rFormula = OUString();
+ rFormula = EMPTY_OUSTRING;
}
const ScTokenArray* ScColumn::GetFormulaTokens( SCROW nRow ) const
@@ -1848,44 +2292,105 @@ ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow )
CellType ScColumn::GetCellType( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- return maItems[nIndex].pCell->GetCellType();
+ switch (maCells.get_type(nRow))
+ {
+ case sc::element_type_numeric:
+ return CELLTYPE_VALUE;
+ case sc::element_type_string:
+ return CELLTYPE_STRING;
+ case sc::element_type_edittext:
+ return CELLTYPE_EDIT;
+ case sc::element_type_formula:
+ return CELLTYPE_FORMULA;
+ default:
+ ;
+ }
return CELLTYPE_NONE;
}
+namespace {
+
+/**
+ * Count the number of all non-empty cells.
+ */
+class CellCounter
+{
+ size_t mnCount;
+public:
+ CellCounter() : mnCount(0) {}
+
+ void operator() (const sc::CellStoreType::value_type& node)
+ {
+ if (node.type == sc::element_type_empty)
+ return;
+
+ mnCount += node.size;
+ }
+
+ size_t getCount() const { return mnCount; }
+};
+
+}
+
SCSIZE ScColumn::GetCellCount() const
{
- return maItems.size();
+ CellCounter aFunc;
+ std::for_each(maCells.begin(), maCells.end(), aFunc);
+ return aFunc.getCount();
}
sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- {
- ScBaseCell* pCell = maItems[nIndex].pCell;
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- return ((ScFormulaCell*)pCell)->GetErrCode();
- }
- return 0;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ if (it == maCells.end())
+ return 0;
+
+ if (it->type != sc::element_type_formula)
+ return 0;
+
+ const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
+ return const_cast<ScFormulaCell*>(p)->GetErrCode();
}
bool ScColumn::HasStringData( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- return (maItems[nIndex].pCell)->HasStringData();
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ switch (aPos.first->type)
+ {
+ case sc::element_type_string:
+ case sc::element_type_edittext:
+ return true;
+ case sc::element_type_formula:
+ {
+ const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
+ return !const_cast<ScFormulaCell*>(p)->IsValue();
+ }
+ default:
+ ;
+ }
+
return false;
}
bool ScColumn::HasValueData( SCROW nRow ) const
{
- SCSIZE nIndex;
- if (Search(nRow, nIndex))
- return (maItems[nIndex].pCell)->HasValueData();
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
+ switch (aPos.first->type)
+ {
+ case sc::element_type_numeric:
+ return true;
+ case sc::element_type_formula:
+ {
+ const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
+ return const_cast<ScFormulaCell*>(p)->IsValue();
+ }
+ default:
+ ;
+ }
+
return false;
}
@@ -1894,267 +2399,297 @@ bool ScColumn::HasValueData( SCROW nRow ) const
*/
bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
{
- if ( !maItems.empty() )
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ size_t nOffset = aPos.second;
+ SCROW nRow = nStartRow;
+ for (; it != maCells.end() && nRow <= nEndRow; ++it)
{
- SCSIZE nIndex;
- Search( nStartRow, nIndex );
- while ( nIndex < maItems.size() && maItems[nIndex].nRow <= nEndRow )
- {
- CellType eType = maItems[nIndex].pCell->GetCellType();
- if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
- return sal_True;
- ++nIndex;
- }
+ if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
+ return true;
+
+ nRow += it->size - nOffset;
+ nOffset = 0;
}
+
return false;
}
+namespace {
-sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
+class MaxStringLenHandler
{
- sal_Int32 nStringLen = 0;
- if ( !maItems.empty() )
+ sal_Int32 mnMaxLen;
+ const ScColumn& mrColumn;
+ SvNumberFormatter* mpFormatter;
+ CharSet meCharSet;
+ bool mbOctetEncoding;
+
+ void processCell(size_t nRow, ScRefCellValue& rCell)
{
+ Color* pColor;
OUString aString;
- OString aOString;
- bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
- SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
- SCSIZE nIndex;
- SCROW nRow;
- Search( nRowStart, nIndex );
- while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRowEnd )
+ sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
+ ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter);
+ sal_Int32 nLen = 0;
+ if (mbOctetEncoding)
{
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
- Color* pColor;
- sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr(
- nRow, ATTR_VALUE_FORMAT ))->GetValue();
- ScCellFormat::GetString(aCell, nFormat, aString, &pColor, *pNumFmt);
- sal_Int32 nLen;
- if (bIsOctetTextEncoding)
+ OString aOString;
+ if (!aString.convertToString(&aOString, meCharSet,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
{
- if (!aString.convertToString( &aOString, eCharSet,
- RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
- RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
- {
- // TODO: anything? this is used by the dBase export filter
- // that throws an error anyway, but in case of another
- // context we might want to indicate a conversion error
- // early.
- }
- nLen = aOString.getLength();
+ // TODO: anything? this is used by the dBase export filter
+ // that throws an error anyway, but in case of another
+ // context we might want to indicate a conversion error
+ // early.
}
- else
- nLen = aString.getLength() * sizeof(sal_Unicode);
- if ( nStringLen < nLen)
- nStringLen = nLen;
- nIndex++;
+ nLen = aOString.getLength();
}
+ else
+ nLen = aString.getLength() * sizeof(sal_Unicode);
+
+ if (mnMaxLen < nLen)
+ mnMaxLen = nLen;
+ }
+
+public:
+ MaxStringLenHandler(const ScColumn& rColumn, CharSet eCharSet) :
+ mnMaxLen(0),
+ mrColumn(rColumn),
+ mpFormatter(rColumn.GetDoc().GetFormatTable()),
+ meCharSet(eCharSet),
+ mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
+ {
+ }
+
+ void operator() (size_t nRow, double fVal)
+ {
+ ScRefCellValue aCell(fVal);
+ processCell(nRow, aCell);
}
- return nStringLen;
+
+ void operator() (size_t nRow, const OUString& rStr)
+ {
+ ScRefCellValue aCell(&rStr);
+ processCell(nRow, aCell);
+ }
+
+ void operator() (size_t nRow, const EditTextObject* p)
+ {
+ ScRefCellValue aCell(p);
+ processCell(nRow, aCell);
+ }
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
+ processCell(nRow, aCell);
+ }
+
+ sal_Int32 getMaxLen() const { return mnMaxLen; }
+};
+
}
+sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
+{
+ MaxStringLenHandler aFunc(*this, eCharSet);
+ sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
+ return aFunc.getMaxLen();
+}
-xub_StrLen ScColumn::GetMaxNumberStringLen(
- sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
+namespace {
+
+class MaxNumStringLenHandler
{
- xub_StrLen nStringLen = 0;
- nPrecision = pDocument->GetDocOptions().GetStdPrecision();
- if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION )
- // In case of unlimited precision, use 2 instead.
- nPrecision = 2;
+ const ScColumn& mrColumn;
+ SvNumberFormatter* mpFormatter;
+ sal_Int32 mnMaxLen;
+ sal_uInt16 mnPrecision;
- if ( !maItems.empty() )
+ void processCell(size_t nRow, ScRefCellValue& rCell)
{
+ if (rCell.meType == CELLTYPE_FORMULA && !rCell.mpFormula->IsValue())
+ return;
+
OUString aString;
- SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
- SCSIZE nIndex;
- SCROW nRow;
- Search( nRowStart, nIndex );
- while ( nIndex < maItems.size() && (nRow = maItems[nIndex].nRow) <= nRowEnd )
+ sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(
+ mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
+ ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter);
+ sal_Int32 nLen = aString.getLength();
+ if (nLen <= 0)
+ // Ignore empty string.
+ return;
+
+ if (nFormat)
{
- ScRefCellValue aCell;
- aCell.assign(*maItems[nIndex].pCell);
- CellType eType = aCell.meType;
- if ( eType == CELLTYPE_VALUE || (eType == CELLTYPE_FORMULA
- && aCell.mpFormula->IsValue()) )
+ const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
+ sal_uInt16 nPrec;
+ if (pEntry)
{
- sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr(
- nRow, ATTR_VALUE_FORMAT ))->GetValue();
- ScCellFormat::GetInputString(aCell, nFormat, aString, *pNumFmt);
- xub_StrLen nLen = aString.getLength();
- if ( nLen )
- {
- if ( nFormat )
- {
- const SvNumberformat* pEntry = pNumFmt->GetEntry( nFormat );
- sal_uInt16 nPrec;
- if (pEntry)
- {
- bool bThousand, bNegRed;
- sal_uInt16 nLeading;
- pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
- }
- else
- nPrec = pNumFmt->GetFormatPrecision( nFormat );
+ bool bThousand, bNegRed;
+ sal_uInt16 nLeading;
+ pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
+ }
+ else
+ nPrec = mpFormatter->GetFormatPrecision(nFormat);
- if ( nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > nPrecision )
- nPrecision = nPrec;
- }
- if ( nPrecision )
- { // less than nPrecision in string => widen it
- // more => shorten it
- String aSep = pNumFmt->GetFormatDecimalSep( nFormat );
- sal_Int32 nTmp = aString.indexOf( aSep );
- if ( nTmp == -1 )
- nLen += nPrecision + aSep.Len();
- else
- {
- nTmp = aString.getLength() - (nTmp + aSep.Len());
- if ( nTmp != nPrecision )
- nLen += nPrecision - nTmp;
- // nPrecision > nTmp : nLen + Diff
- // nPrecision < nTmp : nLen - Diff
- }
- }
- if ( nStringLen < nLen )
- nStringLen = nLen;
- }
+ if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
+ mnPrecision = nPrec;
+ }
+
+ if (mnPrecision)
+ { // less than mnPrecision in string => widen it
+ // more => shorten it
+ OUString aSep = mpFormatter->GetFormatDecimalSep(nFormat);
+ sal_Int32 nTmp = aString.indexOf(aSep);
+ if ( nTmp == -1 )
+ nLen += mnPrecision + aSep.getLength();
+ else
+ {
+ nTmp = aString.getLength() - (nTmp + aSep.getLength());
+ if (nTmp != mnPrecision)
+ nLen += mnPrecision - nTmp;
+ // nPrecision > nTmp : nLen + Diff
+ // nPrecision < nTmp : nLen - Diff
}
- nIndex++;
}
+
+ if (mnMaxLen < nLen)
+ mnMaxLen = nLen;
+ }
+
+public:
+ MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nPrecision) :
+ mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
+ mnMaxLen(0), mnPrecision(nPrecision)
+ {
}
- return nStringLen;
+
+ void operator() (size_t nRow, double fVal)
+ {
+ ScRefCellValue aCell(fVal);
+ processCell(nRow, aCell);
+ }
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
+ processCell(nRow, aCell);
+ }
+
+ sal_Int32 getMaxLen() const { return mnMaxLen; }
+
+ sal_uInt16 getPrecision() const { return mnPrecision; }
+};
+
+}
+
+xub_StrLen ScColumn::GetMaxNumberStringLen(
+ sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
+{
+ nPrecision = pDocument->GetDocOptions().GetStdPrecision();
+ if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION )
+ // In case of unlimited precision, use 2 instead.
+ nPrecision = 2;
+
+ MaxNumStringLenHandler aFunc(*this, nPrecision);
+ sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
+ nPrecision = aFunc.getPrecision();
+ return aFunc.getMaxLen();
}
namespace {
-struct CellGroupSetter : std::unary_function<ColEntry, void>
+class CellGroupSetter
{
ScFormulaCellGroupRef mxGroup;
public:
CellGroupSetter(const ScFormulaCellGroupRef& xGroup) : mxGroup(xGroup) {}
- void operator() (ColEntry& rEntry)
+ void operator() (size_t, ScFormulaCell* pCell)
{
- if (rEntry.pCell && rEntry.pCell->GetCellType() == CELLTYPE_FORMULA)
- static_cast<ScFormulaCell*>(rEntry.pCell)->SetCellGroup(mxGroup);
+ pCell->SetCellGroup(mxGroup);
}
};
-}
-
-// Very[!] slow way to look for and merge contiguous runs
-// of similar formulae into a formulagroup
-void ScColumn::RebuildFormulaGroups()
+class GroupFormulaCells
{
- if ( maItems.empty() || !mbDirtyGroups )
- return;
+ std::vector<ScFormulaCellGroupRef>& mrFnGroups;
+ ScFormulaCellGroupRef mxNone;
- // clear double groups
- std::for_each(maDoubles.begin(), maDoubles.end(), ScDeleteObjectByPtr<ColDoubleEntry>());
- maDoubles.clear();
-
- // clear previous groups
- ScFormulaCellGroupRef xNone;
- std::for_each(maItems.begin(), maItems.end(), CellGroupSetter(xNone));
- maFnGroups.clear();
+public:
+ GroupFormulaCells(std::vector<ScFormulaCellGroupRef>& rFnGroups) : mrFnGroups(rFnGroups) {}
- // re-build groups
- ColDoubleEntry *pLastDouble = NULL;
- for (size_t i = 1; i < maItems.size(); i++)
+ void operator() (sc::CellStoreType::value_type& node)
{
- ColEntry &rCur = maItems[ i ];
- ColEntry &rPrev = maItems[ i - 1 ];
- if ( ( rPrev.nRow != rCur.nRow - 1 ) || // not contiguous
- !rCur.pCell || !rPrev.pCell || // paranoia
- rCur.pCell->GetCellType() != rPrev.pCell->GetCellType() ) // same type
- {
- // Non-contiguous cell detected. Break the series.
- pLastDouble = NULL;
- continue;
- }
+ if (node.type != sc::element_type_formula)
+ // We are only interested in formula cells.
+ return;
- // collate doubles
- if ( rCur.pCell->GetCellType() == CELLTYPE_VALUE )
+ ScFormulaCell* pPrev = NULL;
+ ScFormulaCell* pCur = NULL;
+ size_t nRow = node.position; // start row position.
+
+ sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
+ sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
+ for (; it != itEnd; ++it, ++nRow, pPrev = pCur)
{
- if ( !pLastDouble )
+ pCur = *it;
+ if (!pPrev)
+ continue;
+
+ ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(pCur);
+ if (eCompState == ScFormulaCell::NotEqual)
{
- pLastDouble = new ColDoubleEntry();
- pLastDouble->mnStart = rPrev.nRow;
- pLastDouble->maData.push_back(
- static_cast< ScValueCell * >( rPrev.pCell )->GetValue() );
- maDoubles.push_back( pLastDouble );
+ // different formula tokens.
+ pCur->SetCellGroup(mxNone);
+ continue;
}
- pLastDouble->maData.push_back(
- static_cast< ScValueCell * >( rCur.pCell )->GetValue() );
- continue;
- }
- if ( rCur.pCell->GetCellType() != CELLTYPE_FORMULA )
- continue;
+ // Formula tokens equal those of the previous formula cell.
+ ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
+ if (!xGroup)
+ {
+ // create a new group ...
+ xGroup.reset(new ScFormulaCellGroup);
+ xGroup->mnStart = nRow - 1;
+ xGroup->mbInvariant = (eCompState == ScFormulaCell::EqualInvariant);
+ xGroup->mnLength = 2;
- // see if these formula tokens are identical.
- ScFormulaCell *pCur = static_cast< ScFormulaCell *>( rCur.pCell );
- ScFormulaCell *pPrev = static_cast< ScFormulaCell *>( rPrev.pCell );
+ mrFnGroups.push_back(xGroup);
- ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(pCur);
- if (eCompState == ScFormulaCell::NotEqual)
- {
- // different formula tokens.
- pCur->SetCellGroup( xNone );
- continue;
+ pCur->SetCellGroup(xGroup);
+ pPrev->SetCellGroup(xGroup);
+ }
+ else
+ {
+ // existing group. extend its length.
+ pCur->SetCellGroup(xGroup);
+ ++xGroup->mnLength;
+ }
}
+ }
+};
- ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
- if (!xGroup)
- {
- // create a new group ...
- xGroup.reset(new ScFormulaCellGroup);
- xGroup->mnStart = rPrev.nRow;
- xGroup->mbInvariant = eCompState == ScFormulaCell::EqualInvariant;
- xGroup->mnLength = 2;
-
- maFnGroups.push_back( xGroup );
+}
- pCur->SetCellGroup( xGroup );
- pPrev->SetCellGroup( xGroup );
- }
- else
- {
- // existing group. extend its length.
- pCur->SetCellGroup( xGroup );
- xGroup->mnLength++;
- }
- }
+// Very[!] slow way to look for and merge contiguous runs
+// of similar formulae into a formulagroup
+void ScColumn::RebuildFormulaGroups()
+{
+ if (!mbDirtyGroups)
+ return;
-#if OSL_DEBUG_LEVEL > 0
- if ( maDoubles.size() + maFnGroups.size() > 0 )
- {
- OUString aStr;
- fprintf( stderr, "column %2d has %2d double span(s): ", (int)nCol, (int)maDoubles.size() );
- for (std::vector< ColDoubleEntry *>::iterator it = maDoubles.begin();
- it != maDoubles.end(); ++it )
- {
- ScRange aDoubleRange( nCol, (*it)->mnStart, nTab,
- nCol, (*it)->mnStart + (*it)->maData.size() - 1, nTab );
- aDoubleRange.Format( aStr, SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW, pDocument );
- fprintf( stderr, "%s, ", OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- fprintf( stderr, "\n" );
+ // clear previous formula groups.
+ ScFormulaCellGroupRef xNone;
+ CellGroupSetter aFunc(xNone);
+ sc::ProcessFormula(maCells, aFunc);
+ maFnGroups.clear();
- fprintf( stderr, "column %2d has %2d formula span(s): ", (int)nCol, (int)maFnGroups.size() );
- for (std::vector< ScFormulaCellGroupRef>::iterator it = maFnGroups.begin();
- it != maFnGroups.end(); ++it )
- {
- ScRange aDoubleRange( nCol, (*it)->mnStart, nTab,
- nCol, (*it)->mnStart + (*it)->mnLength - 1, nTab );
- aDoubleRange.Format( aStr, SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW, pDocument );
- fprintf( stderr, "%s, ", OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- fprintf( stderr, "\n" );
- }
-#endif
+ // re-build formula groups.
+ std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells(maFnGroups));
mbDirtyGroups = false;
}
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index 9b63dc75f728..8bfb7fc6fa79 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -9,6 +9,10 @@
#include "columnspanset.hxx"
#include "stlalgorithm.hxx"
+#include "column.hxx"
+#include "mtvfunctions.hxx"
+#include "markdata.hxx"
+#include "rangelst.hxx"
#include <algorithm>
@@ -98,6 +102,119 @@ void ColumnSpanSet::executeFromTop(Action& ac) const
}
}
+namespace {
+
+class Scanner
+{
+ SingleColumnSpanSet::ColumnSpansType& mrRanges;
+public:
+ Scanner(SingleColumnSpanSet::ColumnSpansType& rRanges) : mrRanges(rRanges) {}
+
+ void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
+ {
+ if (node.type == sc::element_type_empty)
+ return;
+
+ size_t nRow = node.position + nOffset;
+ size_t nEndRow = nRow + nDataSize; // Last row of current block plus 1
+ mrRanges.insert_back(nRow, nEndRow, true);
+ }
+};
+
+}
+
+SingleColumnSpanSet::SingleColumnSpanSet() : maSpans(0, MAXROWCOUNT, false) {}
+
+void SingleColumnSpanSet::scan(const ScColumn& rColumn)
+{
+ const CellStoreType& rCells = rColumn.maCells;
+ sc::CellStoreType::const_iterator it = rCells.begin(), itEnd = rCells.end();
+ SCROW nCurRow = 0;
+ for (;it != itEnd; ++it)
+ {
+ SCROW nEndRow = nCurRow + it->size; // Last row of current block plus 1.
+ if (it->type != sc::element_type_empty)
+ maSpans.insert_back(nCurRow, nEndRow, true);
+
+ nCurRow = nEndRow;
+ }
+}
+
+void SingleColumnSpanSet::scan(const ScColumn& rColumn, SCROW nStart, SCROW nEnd)
+{
+ const CellStoreType& rCells = rColumn.maCells;
+ Scanner aScanner(maSpans);
+ sc::ParseBlock(rCells.begin(), rCells, aScanner, nStart, nEnd);
+}
+
+void SingleColumnSpanSet::scan(
+ ColumnBlockConstPosition& rBlockPos, const ScColumn& rColumn, SCROW nStart, SCROW nEnd)
+{
+ const CellStoreType& rCells = rColumn.maCells;
+ Scanner aScanner(maSpans);
+ rBlockPos.miCellPos = sc::ParseBlock(rBlockPos.miCellPos, rCells, aScanner, nStart, nEnd);
+}
+
+void SingleColumnSpanSet::scan(const ScMarkData& rMark, SCTAB nTab, SCCOL nCol)
+{
+ if (!rMark.GetTableSelect(nTab))
+ // This table is not selected. Nothing to scan.
+ return;
+
+ ScRangeList aRanges = rMark.GetMarkedRanges();
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ const ScRange* p = aRanges[i];
+ if (nCol < p->aStart.Col() || p->aEnd.Col() < nCol)
+ // This column is not in this range. Skip it.
+ continue;
+
+ maSpans.insert_back(p->aStart.Row(), p->aEnd.Row()+1, true);
+ }
+}
+
+void SingleColumnSpanSet::set(SCROW nRow1, SCROW nRow2, bool bVal)
+{
+ maSpans.insert_back(nRow1, nRow2+1, bVal);
+}
+
+void SingleColumnSpanSet::getRows(std::vector<SCROW> &rRows) const
+{
+ std::vector<SCROW> aRows;
+
+ SpansType aRanges;
+ getSpans(aRanges);
+ SpansType::const_iterator it = aRanges.begin(), itEnd = aRanges.end();
+ for (; it != itEnd; ++it)
+ {
+ for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
+ aRows.push_back(nRow);
+ }
+
+ rRows.swap(aRows);
+}
+
+void SingleColumnSpanSet::getSpans(SpansType& rSpans) const
+{
+ SpansType aSpans;
+ ColumnSpansType::const_iterator it = maSpans.begin(), itEnd = maSpans.end();
+ SCROW nLastRow = it->first;
+ bool bLastVal = it->second;
+ for (++it; it != itEnd; ++it)
+ {
+ SCROW nThisRow = it->first;
+ bool bThisVal = it->second;
+
+ if (bLastVal)
+ aSpans.push_back(Span(nLastRow, nThisRow-1));
+
+ nLastRow = nThisRow;
+ bLastVal = bThisVal;
+ }
+
+ rSpans.swap(aSpans);
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 8f6d1c2eaa2f..b3dab8d331e4 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -50,177 +50,39 @@ using ::std::set;
// STATIC DATA -----------------------------------------------------------
-namespace
-{
- void lcl_uppercase(OUString& rStr)
- {
- rStr = ScGlobal::pCharClass->uppercase(rStr.trim());
- }
-}
-
-ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument,
- SCTAB nStartTable, SCTAB nEndTable ) :
- pDoc( pDocument ),
- nStartTab( nStartTable ),
- nEndTab( nEndTable )
-{
- SCTAB nDocMaxTab = pDoc->GetTableCount() - 1;
- PutInOrder( nStartTab, nEndTab );
- if (!ValidTab(nStartTab) || nStartTab > nDocMaxTab ) nStartTab = nDocMaxTab;
- if (!ValidTab(nEndTab) || nEndTab > nDocMaxTab ) nEndTab = nDocMaxTab;
-
- pDefPattern = pDoc->GetDefPattern();
-
- nCol = 0;
- nRow = 0;
- nTab = nStartTab;
-
- nColPos = 0;
- nAttrPos = 0;
-}
-
-ScDocumentIterator::~ScDocumentIterator()
-{
-}
-
-bool ScDocumentIterator::GetThisCol()
-{
- ScTable* pTab = NULL;
- while ( nTab < pDoc->GetTableCount() && (pTab = pDoc->maTabs[nTab]) == NULL )
- {
- if ( nTab == nEndTab )
- {
- nCol = MAXCOL;
- nRow = MAXROW;
- return false;
- }
- ++nTab;
- }
- if (pTab == NULL)
- {
- OSL_FAIL("no table in document?");
- return false;
- }
- ScColumn* pCol = &pTab->aCol[nCol];
- const ScAttrArray* pAtt = pCol->pAttrArray;
-
- bool bFound = false;
- do
- {
- SCROW nColRow;
- SCROW nAttrEnd;
-
- do
- {
- nAttrEnd = pAtt->pData[nAttrPos].nRow;
- if (nAttrEnd < nRow)
- ++nAttrPos;
- }
- while (nAttrEnd < nRow);
-
- do
- {
- nColRow = (nColPos < pCol->maItems.size()) ? pCol->maItems[nColPos].nRow : MAXROW+1;
- if (nColRow < nRow)
- ++nColPos;
- }
- while (nColRow < nRow);
-
- if (nColRow == nRow)
- {
- bFound = true;
- pCell = pCol->maItems[nColPos].pCell;
- pPattern = pAtt->pData[nAttrPos].pPattern;
- }
- else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
- {
- bFound = true;
- pCell = NULL;
- pPattern = pAtt->pData[nAttrPos].pPattern;
- }
- else
- {
- nRow = std::min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
- }
- }
- while (!bFound && nRow <= MAXROW);
-
- return bFound;
-}
-
-bool ScDocumentIterator::GetThis()
-{
- bool bEnd = false;
- bool bSuccess = false;
-
- while ( !bSuccess && !bEnd )
- {
- if ( nRow > MAXROW )
- bSuccess = false;
- else
- bSuccess = GetThisCol();
-
- if ( !bSuccess )
- {
- ++nCol;
- if (nCol > MAXCOL)
- {
- nCol = 0;
- ++nTab;
- if (nTab > nEndTab)
- bEnd = true;
- }
- nRow = 0;
- nColPos = 0;
- nAttrPos = 0;
- }
- }
-
- return !bEnd;
-}
+namespace {
-bool ScDocumentIterator::GetFirst()
+void upperCase(OUString& rStr)
{
- nCol = 0;
- nTab = nStartTab;
-
- nRow = 0;
- nColPos = 0;
- nAttrPos = 0;
-
- return GetThis();
+ rStr = ScGlobal::pCharClass->uppercase(rStr.trim());
}
-bool ScDocumentIterator::GetNext()
+template<typename _Iter>
+void incBlock(std::pair<_Iter, size_t>& rPos)
{
- ++nRow;
-
- return GetThis();
+ // Move to the next block.
+ ++rPos.first;
+ rPos.second = 0;
}
-ScCellValue ScDocumentIterator::GetCellValue() const
+template<typename _Iter>
+void incPos(std::pair<_Iter, size_t>& rPos)
{
- ScCellValue aRet;
- if (pCell)
- aRet.assign(*pCell);
- return aRet;
+ if (rPos.second + 1 < rPos.first->size)
+ // Increment within the block.
+ ++rPos.second;
+ else
+ incBlock(rPos);
}
-const ScPatternAttr* ScDocumentIterator::GetPattern()
+template<typename _Iter>
+size_t toLogicalPos(const std::pair<_Iter, size_t>& rPos)
{
- return pPattern;
+ return rPos.first->position + rPos.second;
}
-void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
-{
- rCol = nCol;
- rRow = nRow;
- rTab = nTab;
}
-
-//------------------------------------------------------------------------
-//------------------------------------------------------------------------
void ScAttrArray_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr,
SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
ScDocument* pDoc )
@@ -246,197 +108,202 @@ ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
bool bSTotal, bool bTextZero ) :
pDoc( pDocument ),
nNumFmtIndex(0),
- nStartCol( rRange.aStart.Col() ),
- nStartRow( rRange.aStart.Row() ),
- nStartTab( rRange.aStart.Tab() ),
- nEndCol( rRange.aEnd.Col() ),
- nEndRow( rRange.aEnd.Row() ),
- nEndTab( rRange.aEnd.Tab() ),
+ maStartPos(rRange.aStart),
+ maEndPos(rRange.aEnd),
nNumFmtType( NUMBERFORMAT_UNDEFINED ),
bNumValid( false ),
bSubTotal(bSTotal),
- bNextValid( false ),
bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
bTextAsZero( bTextZero )
{
SCTAB nDocMaxTab = pDocument->GetTableCount() - 1;
- PutInOrder( nStartCol, nEndCol);
- PutInOrder( nStartRow, nEndRow);
- PutInOrder( nStartTab, nEndTab );
-
- if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
- if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
- if (!ValidRow(nStartRow)) nStartRow = MAXROW;
- if (!ValidRow(nEndRow)) nEndRow = MAXROW;
- if (!ValidTab(nStartTab) || nStartTab > nDocMaxTab) nStartTab = nDocMaxTab;
- if (!ValidTab(nEndTab) || nEndTab > nDocMaxTab) nEndTab = nDocMaxTab;
-
- nCol = nStartCol;
- nRow = nStartRow;
- nTab = nStartTab;
+ if (!ValidCol(maStartPos.Col())) maStartPos.SetCol(MAXCOL);
+ if (!ValidCol(maEndPos.Col())) maEndPos.SetCol(MAXCOL);
+ if (!ValidRow(maStartPos.Row())) maStartPos.SetRow(MAXROW);
+ if (!ValidRow(maEndPos.Row())) maEndPos.SetRow(MAXROW);
+ if (!ValidTab(maStartPos.Tab()) || maStartPos.Tab() > nDocMaxTab) maStartPos.SetTab(nDocMaxTab);
+ if (!ValidTab(maEndPos.Tab()) || maEndPos.Tab() > nDocMaxTab) maEndPos.SetTab(nDocMaxTab);
- nColRow = 0; // Initialized in GetFirst
nNumFormat = 0; // Initialized in GetNumberFormat
pAttrArray = 0;
nAttrEndRow = 0;
}
+SCROW ScValueIterator::GetRow() const
+{
+ // Position of the head of the current block + offset within the block
+ // equals the logical element position.
+ return maCurPos.first->position + maCurPos.second;
+}
+
+void ScValueIterator::IncBlock()
+{
+ ++maCurPos.first;
+ maCurPos.second = 0;
+}
+
+void ScValueIterator::IncPos()
+{
+ if (maCurPos.second + 1 < maCurPos.first->size)
+ // Move within the same block.
+ ++maCurPos.second;
+ else
+ // Move to the next block.
+ IncBlock();
+}
+
+void ScValueIterator::SetPos(size_t nPos)
+{
+ maCurPos = mpCells->position(maCurPos.first, nPos);
+}
+
bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr)
{
- if (nTab >= pDoc->GetTableCount())
- {
- OSL_FAIL("try to access out of index, FIX IT");
- }
- ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- for (;;)
+ while (true)
{
- if ( nRow > nEndRow )
+ bool bNextColumn = maCurPos.first == mpCells->end();
+ if (!bNextColumn)
+ {
+ if (GetRow() > maEndPos.Row())
+ bNextColumn = true;
+ }
+
+ ScColumn* pCol = NULL;
+ if (bNextColumn)
{
- nRow = nStartRow;
+ // Find the next available column.
do
{
- nCol++;
- if ( nCol > nEndCol )
+ ++mnCol;
+ if (mnCol > maEndPos.Col())
{
- nCol = nStartCol;
- nTab++;
- if ( nTab > nEndTab )
+ mnCol = maStartPos.Col();
+ ++mnTab;
+ if (mnTab > maEndPos.Tab())
{
rErr = 0;
return false; // Over and out
}
}
- pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- } while ( pCol->maItems.empty() );
- pCol->Search( nRow, nColRow );
+ pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
+ }
+ while (pCol->IsEmptyData());
+
+ mpCells = &pCol->maCells;
+ maCurPos = mpCells->position(maStartPos.Row());
}
- while (( nColRow < pCol->maItems.size() ) && ( pCol->maItems[nColRow].nRow < nRow ))
- nColRow++;
+ SCROW nCurRow = GetRow();
+ SCROW nLastRow;
+ if (bSubTotal && pDoc->maTabs[mnTab]->RowFiltered(nCurRow, NULL, &nLastRow))
+ {
+ // Skip all filtered rows for subtotal mode.
+ SetPos(nLastRow+1);
+ continue;
+ }
- if ( nColRow < pCol->maItems.size() && pCol->maItems[nColRow].nRow <= nEndRow )
+ switch (maCurPos.first->type)
{
- nRow = pCol->maItems[nColRow].nRow + 1;
- if ( !bSubTotal || !pDoc->maTabs[nTab]->RowFiltered( nRow-1 ) )
+ case sc::element_type_numeric:
{
- ScBaseCell* pCell = pCol->maItems[nColRow].pCell;
- ++nColRow;
- switch (pCell->GetCellType())
+ bNumValid = false;
+ rValue = sc::numeric_block::at(*maCurPos.first->data, maCurPos.second);
+ rErr = 0;
+ if (bCalcAsShown)
{
- case CELLTYPE_VALUE:
- {
- bNumValid = false;
- rValue = ((ScValueCell*)pCell)->GetValue();
- rErr = 0;
- --nRow;
- if ( bCalcAsShown )
- {
- ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
- nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
- rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
- }
- /*
- * If there's another Value Cell in the same column,
- * which is also within the Area, we retrieve it's value
- */
- if ( nColRow < pCol->maItems.size() &&
- pCol->maItems[nColRow].nRow <= nEndRow &&
- pCol->maItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE &&
- !bSubTotal )
- {
- fNextValue = ((ScValueCell*)pCol->maItems[nColRow].pCell)->GetValue();
- nNextRow = pCol->maItems[nColRow].nRow;
- bNextValid = true;
- if ( bCalcAsShown )
- {
- ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
- nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
- fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
- }
- }
-
- return true; // Found it!
- }
-
- case CELLTYPE_FORMULA:
- {
- if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
- {
- rErr = ((ScFormulaCell*)pCell)->GetErrCode();
- if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
- {
- rValue = ((ScFormulaCell*)pCell)->GetValue();
- nRow--;
- bNumValid = false;
- return true; // Found it!
- }
- else if ( bTextAsZero )
- {
- rValue = 0.0;
- nRow--;
- bNumValid = false;
- return true;
- }
- }
- }
+ ScAttrArray_IterGetNumberFormat(nNumFormat, pAttrArray,
+ nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc);
+ rValue = pDoc->RoundValueAsShown(rValue, nNumFormat);
+ }
+ return true; // Found it!
+ }
+ break;
+ case sc::element_type_formula:
+ {
+ ScFormulaCell* pCell = sc::formula_block::at(*maCurPos.first->data, maCurPos.second);
+ if (bSubTotal && pCell->IsSubTotal())
+ {
+ // Skip subtotal formula cells.
+ IncPos();
break;
+ }
- case CELLTYPE_STRING :
- case CELLTYPE_EDIT :
- {
- if ( bTextAsZero )
- {
- rErr = 0;
- rValue = 0.0;
- nNumFmtType = NUMBERFORMAT_NUMBER;
- nNumFmtIndex = 0;
- bNumValid = true;
- --nRow;
- return true;
- }
- }
- break;
- default:
- {
- // added to avoid warnings
- }
+ rErr = pCell->GetErrCode();
+ if (rErr || pCell->IsValue())
+ {
+ rValue = pCell->GetValue();
+ bNumValid = false;
+ return true; // Found it!
+ }
+ else if (bTextAsZero)
+ {
+ rValue = 0.0;
+ bNumValid = false;
+ return true;
+ }
+ IncPos();
+ }
+ break;
+ case sc::element_type_string :
+ case sc::element_type_edittext :
+ {
+ if (bTextAsZero)
+ {
+ rErr = 0;
+ rValue = 0.0;
+ nNumFmtType = NUMBERFORMAT_NUMBER;
+ nNumFmtIndex = 0;
+ bNumValid = true;
+ return true;
}
+ IncBlock();
}
+ break;
+ case sc::element_type_empty:
+ default:
+ // Skip the whole block.
+ IncBlock();
}
- else
- nRow = nEndRow + 1; // Next column
}
}
void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
{
- if (!bNumValid && nTab < pDoc->GetTableCount())
+ if (!bNumValid && mnTab < pDoc->GetTableCount())
{
- const ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- nNumFmtIndex = pCol->GetNumberFormat( nRow );
+ SCROW nCurRow = GetRow();
+ const ScColumn* pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
+ nNumFmtIndex = pCol->GetNumberFormat(nCurRow);
nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
bNumValid = true;
}
+
nType = nNumFmtType;
nIndex = nNumFmtIndex;
}
bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr)
{
- nCol = nStartCol;
- nRow = nStartRow;
- nTab = nStartTab;
+ mnCol = maStartPos.Col();
+ mnTab = maStartPos.Tab();
- if (nTab >= pDoc->GetTableCount())
- OSL_FAIL("try to access index out of bounds, FIX IT");
- ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- pCol->Search( nRow, nColRow );
+ ScTable* pTab = pDoc->FetchTable(mnTab);
+ if (pTab)
+ return false;
nNumFormat = 0; // Initialized in GetNumberFormat
pAttrArray = 0;
nAttrEndRow = 0;
+ mpCells = &pTab->aCol[maStartPos.Col()].maCells;
+ maCurPos = mpCells->position(maStartPos.Row());
+ return GetThis(rValue, rErr);
+}
+
+bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
+{
+ IncPos();
return GetThis(rValue, rErr);
}
@@ -451,20 +318,13 @@ ScDBQueryDataIterator::DataAccess::~DataAccess()
{
}
-SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
+const sc::CellStoreType* ScDBQueryDataIterator::GetColumnCellStore(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
{
- if (nTab >= rDoc.GetTableCount())
- OSL_FAIL("try to access index out of bounds, FIX IT");
- ScColumn* pCol = &rDoc.maTabs[nTab]->aCol[nCol];
- return pCol->maItems[nColRow].nRow;
-}
+ ScTable* pTab = rDoc.FetchTable(nTab);
+ if (!pTab)
+ return NULL;
-ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
-{
- if (nTab >= rDoc.GetTableCount())
- OSL_FAIL("try to access index out of bounds, FIX IT");
- ScColumn* pCol = &rDoc.maTabs[nTab]->aCol[nCol];
- return pCol->maItems[nColRow].pCell;
+ return &pTab->aCol[nCol].maCells;
}
const ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
@@ -475,27 +335,19 @@ const ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SC
return pCol->pAttrArray;
}
-bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell)
-{
- if (nTab >= rDoc.GetTableCount())
- OSL_FAIL("try to access index out of bounds, FIX IT");
- return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, pCell);
-}
-
-SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol)
+bool ScDBQueryDataIterator::IsQueryValid(
+ ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScRefCellValue& rCell)
{
if (nTab >= rDoc.GetTableCount())
OSL_FAIL("try to access index out of bounds, FIX IT");
- ScColumn* pCol = &rDoc.maTabs[nTab]->aCol[nCol];
- SCSIZE nColRow;
- pCol->Search(nRow, nColRow);
- return nColRow;
+ return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, &rCell);
}
// ----------------------------------------------------------------------------
ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) :
DataAccess(pParent),
+ mpCells(NULL),
mpParam(pParam),
mpDoc(pDoc),
bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() )
@@ -503,8 +355,6 @@ ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDat
nCol = mpParam->mnField;
nRow = mpParam->nRow1;
nTab = mpParam->nTab;
-
- nColRow = 0; // Initialized in GetFirst
SCSIZE i;
SCSIZE nCount = mpParam->GetEntryCount();
for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
@@ -529,108 +379,96 @@ ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
{
- SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
- for ( ;; )
+ // Start with the current row position, and find the first row position
+ // that satisfies the query.
+
+ // TODO: The following line nFirstQueryField is supposed to be used some
+ // way. Find out how it's supposed to be used and fix this bug.
+
+ // SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
+ while (true)
{
- if (nRow > mpParam->nRow2)
+ if (maCurPos.first == mpCells->end() || nRow > mpParam->nRow2)
{
// Bottom of the range reached. Bail out.
rValue.mnError = 0;
return false;
}
- SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol);
- if (!nCellCount)
- // No cells found in this column. Bail out.
- return false;
-
- SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
- while ( (nColRow < nCellCount) && (nThisRow < nRow) )
+ if (maCurPos.first->type == sc::element_type_empty)
{
- ++nColRow;
- if(nColRow < nCellCount)
- nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
+ // Skip the whole empty block.
+ incBlock();
+ continue;
}
- if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 )
- {
- nRow = nThisRow;
- ScBaseCell* pCell = NULL;
- if (nCol == static_cast<SCCOL>(nFirstQueryField))
- pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
+ ScRefCellValue aCell;
+ aCell.assign(maCurPos.first, maCurPos.second);
- if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell))
+ if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, aCell))
+ {
+ switch (aCell.meType)
{
- // #i109812# get cell here if it wasn't done above
- if (nCol != static_cast<SCCOL>(nFirstQueryField))
- pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
-
- switch (pCell ? pCell->GetCellType() : CELLTYPE_NONE)
+ case CELLTYPE_VALUE:
{
- case CELLTYPE_VALUE:
- {
- rValue.mfValue = ((ScValueCell*)pCell)->GetValue();
- rValue.mbIsNumber = true;
- if ( bCalcAsShown )
- {
- const ScAttrArray* pNewAttrArray =
- ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
- ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
- nAttrEndRow, pNewAttrArray, nRow, mpDoc );
- rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
- }
- nNumFmtType = NUMBERFORMAT_NUMBER;
- nNumFmtIndex = 0;
- rValue.mnError = 0;
- return true; // Found it!
- }
+ rValue.mfValue = aCell.mfValue;
+ rValue.mbIsNumber = true;
+ if ( bCalcAsShown )
+ {
+ const ScAttrArray* pNewAttrArray =
+ ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
+ ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pNewAttrArray, nRow, mpDoc );
+ rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
+ }
+ nNumFmtType = NUMBERFORMAT_NUMBER;
+ nNumFmtIndex = 0;
+ rValue.mnError = 0;
+ return true; // Found it!
+ }
- case CELLTYPE_FORMULA:
- {
- if (((ScFormulaCell*)pCell)->IsValue())
- {
- rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue();
- rValue.mbIsNumber = true;
- mpDoc->GetNumberFormatInfo( nNumFmtType,
- nNumFmtIndex, ScAddress(nCol, nRow, nTab));
- rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode();
- return true; // Found it!
- }
- else if(mpParam->mbSkipString)
- nRow++;
- else
- {
- rValue.maString = static_cast<ScFormulaCell*>(pCell)->GetString();
- rValue.mfValue = 0.0;
- rValue.mnError = static_cast<ScFormulaCell*>(pCell)->GetErrCode();
- rValue.mbIsNumber = false;
- return true;
- }
- }
- break;
- case CELLTYPE_STRING:
- case CELLTYPE_EDIT:
- if (mpParam->mbSkipString)
- ++nRow;
- else
- {
- rValue.maString = pCell->GetStringData();
- rValue.mfValue = 0.0;
- rValue.mnError = 0;
- rValue.mbIsNumber = false;
- return true;
- }
- break;
- default:
- nRow++;
- break;
+ case CELLTYPE_FORMULA:
+ {
+ if (aCell.mpFormula->IsValue())
+ {
+ rValue.mfValue = aCell.mpFormula->GetValue();
+ rValue.mbIsNumber = true;
+ mpDoc->GetNumberFormatInfo(
+ nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
+ rValue.mnError = aCell.mpFormula->GetErrCode();
+ return true; // Found it!
+ }
+ else if(mpParam->mbSkipString)
+ incPos();
+ else
+ {
+ rValue.maString = aCell.mpFormula->GetString();
+ rValue.mfValue = 0.0;
+ rValue.mnError = aCell.mpFormula->GetErrCode();
+ rValue.mbIsNumber = false;
+ return true;
+ }
}
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ if (mpParam->mbSkipString)
+ incPos();
+ else
+ {
+ rValue.maString = aCell.getString();
+ rValue.mfValue = 0.0;
+ rValue.mnError = 0;
+ rValue.mbIsNumber = false;
+ return true;
+ }
+ break;
+ default:
+ incPos();
}
- else
- nRow++;
}
else
- nRow = mpParam->nRow2 + 1; // Next column
+ incPos();
}
// statement unreachable
}
@@ -638,18 +476,52 @@ bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
{
if (mpParam->bHasHeader)
- nRow++;
+ ++nRow;
- nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol);
+ mpCells = ScDBQueryDataIterator::GetColumnCellStore(*mpDoc, nTab, nCol);
+ if (!mpCells)
+ return false;
+
+ maCurPos = mpCells->position(nRow);
return getCurrent(rValue);
}
bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
{
- ++nRow;
+ if (!mpCells || maCurPos.first == mpCells->end())
+ return false;
+
+ incPos();
return getCurrent(rValue);
}
+void ScDBQueryDataIterator::DataAccessInternal::incBlock()
+{
+ ++maCurPos.first;
+ maCurPos.second = 0;
+
+ nRow = maCurPos.first->position;
+}
+
+void ScDBQueryDataIterator::DataAccessInternal::incPos()
+{
+ if (maCurPos.second + 1 < maCurPos.first->size)
+ {
+ // Move within the same block.
+ ++maCurPos.second;
+ ++nRow;
+ }
+ else
+ // Move to the next block.
+ incBlock();
+}
+
+void ScDBQueryDataIterator::DataAccessInternal::setPos(size_t nPos)
+{
+ maCurPos = mpCells->position(maCurPos.first, nPos);
+ nRow = nPos;
+}
+
// ----------------------------------------------------------------------------
ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
@@ -812,9 +684,9 @@ bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScM
{
// Equality check first.
OUString aMatStr = rMat.GetString(nField, nRow);
- lcl_uppercase(aMatStr);
+ upperCase(aMatStr);
OUString aQueryStr = rEntry.GetQueryItem().maString;
- lcl_uppercase(aQueryStr);
+ upperCase(aQueryStr);
bool bDone = false;
switch (rEntry.eOp)
{
@@ -922,12 +794,43 @@ ScCellIterator::ScCellIterator( ScDocument* pDoc, const ScRange& rRange, bool bS
mpDoc(pDoc),
maStartPos(rRange.aStart),
maEndPos(rRange.aEnd),
- mnIndex(0),
mbSubTotal(bSTotal)
{
init();
}
+void ScCellIterator::incBlock()
+{
+ ++maCurColPos.first;
+ maCurColPos.second = 0;
+
+ maCurPos.SetRow(maCurColPos.first->position);
+}
+
+void ScCellIterator::incPos()
+{
+ if (maCurColPos.second + 1 < maCurColPos.first->size)
+ {
+ // Move within the same block.
+ ++maCurColPos.second;
+ maCurPos.IncRow();
+ }
+ else
+ // Move to the next block.
+ incBlock();
+}
+
+void ScCellIterator::setPos(size_t nPos)
+{
+ maCurColPos = getColumn()->maCells.position(maCurColPos.first, nPos);
+ maCurPos.SetRow(nPos);
+}
+
+const ScColumn* ScCellIterator::getColumn() const
+{
+ return &mpDoc->maTabs[maCurPos.Tab()]->aCol[maCurPos.Col()];
+}
+
void ScCellIterator::init()
{
SCTAB nDocMaxTab = mpDoc->GetTableCount() - 1;
@@ -959,11 +862,20 @@ void ScCellIterator::init()
bool ScCellIterator::getCurrent()
{
- ScColumn* pCol = &(mpDoc->maTabs[maCurPos.Tab()])->aCol[maCurPos.Col()];
+ const ScColumn* pCol = getColumn();
+
while (true)
{
- if (maCurPos.Row() > maEndPos.Row())
+ bool bNextColumn = maCurColPos.first == pCol->maCells.end();
+ if (!bNextColumn)
{
+ if (maCurPos.Row() > maEndPos.Row())
+ bNextColumn = true;
+ }
+
+ if (bNextColumn)
+ {
+ // Move to the next column.
maCurPos.SetRow(maStartPos.Row());
do
{
@@ -978,57 +890,39 @@ bool ScCellIterator::getCurrent()
return false; // Over and out
}
}
- pCol = &(mpDoc->maTabs[maCurPos.Tab()])->aCol[maCurPos.Col()];
- } while ( pCol->maItems.empty() );
- pCol->Search(maCurPos.Row(), mnIndex);
- }
+ pCol = getColumn();
+ }
+ while (pCol->IsEmptyData());
- while ( (mnIndex < pCol->maItems.size()) && (pCol->maItems[mnIndex].nRow < maCurPos.Row()) )
- ++mnIndex;
+ maCurColPos = pCol->maCells.position(maCurPos.Row());
+ }
- if (mnIndex < pCol->maItems.size() && pCol->maItems[mnIndex].nRow <= maEndPos.Row())
+ if (maCurColPos.first->type == sc::element_type_empty)
{
- maCurPos.SetRow(pCol->maItems[mnIndex].nRow);
- if (!mbSubTotal || !mpDoc->maTabs[maCurPos.Tab()]->RowFiltered(maCurPos.Row()))
- {
- ScBaseCell* pCell = pCol->maItems[mnIndex].pCell;
-
- if ( mbSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
- && ((ScFormulaCell*)pCell)->IsSubTotal() )
- maCurPos.IncRow(); // Don't subtotal rows
- else
- {
- // Found it!
- maCurCell.meType = pCell->GetCellType();
- switch (maCurCell.meType)
- {
- case CELLTYPE_VALUE:
- maCurCell.mfValue = static_cast<const ScValueCell*>(pCell)->GetValue();
- break;
- case CELLTYPE_STRING:
- maCurCell.mpString = static_cast<const ScStringCell*>(pCell)->GetStringPtr();
- break;
- case CELLTYPE_EDIT:
- maCurCell.mpEditText = static_cast<const ScEditCell*>(pCell)->GetData();
- break;
- case CELLTYPE_FORMULA:
- maCurCell.mpFormula = static_cast<ScFormulaCell*>(pCell);
- break;
- default:
- maCurCell.meType = CELLTYPE_NONE;
- }
+ incBlock();
+ continue;
+ }
- if (maCurCell.meType != CELLTYPE_NONE)
- return true;
+ SCROW nLastRow;
+ if (mbSubTotal && pCol->GetDoc().maTabs[maCurPos.Tab()]->RowFiltered(maCurPos.Row(), NULL, &nLastRow))
+ {
+ // Skip all filtered rows for subtotal mode.
+ setPos(nLastRow+1);
+ continue;
+ }
- maCurPos.IncRow();
- }
+ if (maCurColPos.first->type == sc::element_type_formula)
+ {
+ const ScFormulaCell* pCell = sc::formula_block::at(*maCurColPos.first->data, maCurColPos.second);
+ if (pCell->IsSubTotal())
+ {
+ // Skip subtotal formula cells.
+ incPos();
+ continue;
}
- else
- maCurPos.IncRow();
}
- else
- maCurPos.SetRow(maEndPos.Row() + 1); // Next column
+
+ maCurCell.assign(maCurColPos.first, maCurColPos.second);
}
return false;
}
@@ -1133,8 +1027,9 @@ bool ScCellIterator::first()
return false;
maCurPos = maStartPos;
- ScColumn* pCol = &(mpDoc->maTabs[maCurPos.Tab()])->aCol[maCurPos.Col()];
- pCol->Search(maCurPos.Row(), mnIndex);
+ const ScColumn* pCol = getColumn();
+
+ maCurColPos = pCol->maCells.position(maCurPos.Row());
return getCurrent();
}
@@ -1158,7 +1053,6 @@ ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
{
nCol = mpParam->nCol1;
nRow = mpParam->nRow1;
- nColRow = 0; // Initialized in GetFirst
SCSIZE i;
if (bMod) // Or else it's already inserted
{
@@ -1178,11 +1072,40 @@ ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
nAttrEndRow = 0;
}
-ScBaseCell* ScQueryCellIterator::GetThis()
+void ScQueryCellIterator::InitPos()
+{
+ nRow = mpParam->nRow1;
+ if (mpParam->bHasHeader && mpParam->bByRow)
+ ++nRow;
+ ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
+ maCurPos = pCol->maCells.position(nRow);
+}
+
+void ScQueryCellIterator::IncPos()
+{
+ if (maCurPos.second + 1 < maCurPos.first->size)
+ {
+ // Move within the same block.
+ ++maCurPos.second;
+ ++nRow;
+ }
+ else
+ // Move to the next block.
+ IncBlock();
+}
+
+void ScQueryCellIterator::IncBlock()
+{
+ ++maCurPos.first;
+ maCurPos.second = 0;
+
+ nRow = maCurPos.first->position;
+}
+
+bool ScQueryCellIterator::GetThis()
{
if (nTab >= pDoc->GetTableCount())
OSL_FAIL("try to access index out of bounds, FIX IT");
- ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
const ScQueryEntry& rEntry = mpParam->GetEntry(0);
const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
@@ -1193,13 +1116,19 @@ ScBaseCell* ScQueryCellIterator::GetThis()
!mpParam->bHasHeader && rItem.meType == ScQueryEntry::ByString &&
((mpParam->bByRow && nRow == mpParam->nRow1) ||
(!mpParam->bByRow && nCol == mpParam->nCol1));
- for ( ;; )
+
+ ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
+ while (true)
{
- if ( nRow > mpParam->nRow2 )
+ bool bNextColumn = maCurPos.first == pCol->maCells.end();
+ if (!bNextColumn)
+ {
+ if (nRow > mpParam->nRow2)
+ bNextColumn = true;
+ }
+
+ if (bNextColumn)
{
- nRow = mpParam->nRow1;
- if (mpParam->bHasHeader && mpParam->bByRow)
- nRow++;
do
{
if ( ++nCol > mpParam->nCol2 )
@@ -1210,89 +1139,87 @@ ScBaseCell* ScQueryCellIterator::GetThis()
nFirstQueryField = rEntry.nField;
}
pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- } while ( pCol->maItems.empty() );
- pCol->Search( nRow, nColRow );
+ }
+ while (pCol->IsEmptyData());
+
+ InitPos();
+
bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
!mpParam->bHasHeader && rItem.meType == ScQueryEntry::ByString &&
mpParam->bByRow;
}
- while ( nColRow < pCol->maItems.size() && pCol->maItems[nColRow].nRow < nRow )
- nColRow++;
+ if (maCurPos.first->type == sc::element_type_empty)
+ {
+ IncBlock();
+ continue;
+ }
+
+ ScRefCellValue aCell;
+ aCell.assign(maCurPos.first, maCurPos.second);
- if ( nColRow < pCol->maItems.size() &&
- (nRow = pCol->maItems[nColRow].nRow) <= mpParam->nRow2 )
+ if (bAllStringIgnore && aCell.hasString())
+ IncPos();
+ else
{
- ScBaseCell* pCell = pCol->maItems[nColRow].pCell;
- if (bAllStringIgnore && pCell->HasStringData())
- ++nRow;
- else
+ bool bTestEqualCondition = false;
+ if ( pDoc->maTabs[nTab]->ValidQuery( nRow, *mpParam,
+ (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : NULL),
+ (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
+ {
+ if ( nTestEqualCondition && bTestEqualCondition )
+ nTestEqualCondition |= nTestEqualConditionMatched;
+ return !aCell.isEmpty(); // Found it!
+ }
+ else if ( nStopOnMismatch )
{
- bool bTestEqualCondition = false;
- if ( (pDoc->maTabs[nTab])->ValidQuery( nRow, *mpParam,
- (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
- (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
+ // Yes, even a mismatch may have a fulfilled equal
+ // condition if regular expressions were involved and
+ // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
+ if ( nTestEqualCondition && bTestEqualCondition )
{
- if ( nTestEqualCondition && bTestEqualCondition )
- nTestEqualCondition |= nTestEqualConditionMatched;
- return pCell; // Found it!
+ nTestEqualCondition |= nTestEqualConditionMatched;
+ nStopOnMismatch |= nStopOnMismatchOccurred;
+ return false;
}
- else if ( nStopOnMismatch )
+ bool bStop;
+ if (bFirstStringIgnore)
{
- // Yes, even a mismatch may have a fulfilled equal
- // condition if regular expressions were involved and
- // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
- if ( nTestEqualCondition && bTestEqualCondition )
+ if (aCell.hasString())
{
- nTestEqualCondition |= nTestEqualConditionMatched;
- nStopOnMismatch |= nStopOnMismatchOccurred;
- return NULL;
- }
- bool bStop;
- if (bFirstStringIgnore)
- {
- if (pCell->HasStringData())
- {
- ++nRow;
- bStop = false;
- }
- else
- bStop = true;
+ IncPos();
+ bStop = false;
}
else
bStop = true;
- if (bStop)
- {
- nStopOnMismatch |= nStopOnMismatchOccurred;
- return NULL;
- }
}
else
- nRow++;
+ bStop = true;
+ if (bStop)
+ {
+ nStopOnMismatch |= nStopOnMismatchOccurred;
+ return false;
+ }
}
+ else
+ IncPos();
}
- else
- nRow = mpParam->nRow2 + 1; // Next column
bFirstStringIgnore = false;
}
}
-ScBaseCell* ScQueryCellIterator::GetFirst()
+bool ScQueryCellIterator::GetFirst()
{
if (nTab >= pDoc->GetTableCount())
OSL_FAIL("try to access index out of bounds, FIX IT");
nCol = mpParam->nCol1;
- nRow = mpParam->nRow1;
- if (mpParam->bHasHeader)
- nRow++;
- ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- pCol->Search( nRow, nColRow );
+ InitPos();
return GetThis();
}
-ScBaseCell* ScQueryCellIterator::GetNext()
+bool ScQueryCellIterator::GetNext()
{
- ++nRow;
+ IncPos();
if ( nStopOnMismatch )
nStopOnMismatch = nStopOnMismatchEnabled;
if ( nTestEqualCondition )
@@ -1336,24 +1263,25 @@ bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
{
// First equal entry or last smaller than (greater than) entry.
- SCSIZE nColRowSave;
- ScBaseCell* pNext = 0;
+ PositionType aPosSave;
+ bool bNext = false;
do
{
nFoundCol = GetCol();
nFoundRow = GetRow();
- nColRowSave = nColRow;
- } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
+ aPosSave = maCurPos;
+ }
+ while ( !IsEqualConditionFulfilled() && (bNext = GetNext()));
// There may be no pNext but equal condition fulfilled if regular
// expressions are involved. Keep the found entry and proceed.
- if (!pNext && !IsEqualConditionFulfilled())
+ if (!bNext && !IsEqualConditionFulfilled())
{
// Step back to last in range and adjust position markers for
// GetNumberFormat() or similar.
nCol = nFoundCol;
nRow = nFoundRow;
- nColRow = nColRowSave;
+ maCurPos = aPosSave;
}
}
if ( IsEqualConditionFulfilled() )
@@ -1380,20 +1308,20 @@ bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
else
break; // for
}
- SCSIZE nColRowSave;
+ PositionType aPosSave;
bIgnoreMismatchOnLeadingStrings = false;
SetTestEqualCondition( false );
do
{
nFoundCol = GetCol();
nFoundRow = GetRow();
- nColRowSave = nColRow;
+ aPosSave = maCurPos;
} while (GetNext());
// Step back conditions are the same as above
nCol = nFoundCol;
nRow = nFoundRow;
- nColRow = nColRowSave;
+ maCurPos = aPosSave;
return true;
}
if ( (bSearchForEqualAfterMismatch || mpParam->bRegExp) &&
@@ -1429,35 +1357,37 @@ bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
// Last of a consecutive area, avoid searching the entire parameter
// range as it is a real performance bottleneck in case of regular
// expressions.
- SCSIZE nColRowSave;
+ PositionType aPosSave;
do
{
nFoundCol = GetCol();
nFoundRow = GetRow();
- nColRowSave = nColRow;
+ aPosSave = maCurPos;
SetStopOnMismatch( true );
} while (GetNext());
nCol = nFoundCol;
nRow = nFoundRow;
- nColRow = nColRowSave;
+ maCurPos = aPosSave;
}
}
return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
}
-ScBaseCell* ScQueryCellIterator::BinarySearch()
+bool ScQueryCellIterator::BinarySearch()
{
+ // TODO: This will be extremely slow with mdds::multi_type_vector.
+
if (nTab >= pDoc->GetTableCount())
OSL_FAIL("try to access index out of bounds, FIX IT");
nCol = mpParam->nCol1;
ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
- if (!pCol->maItems.size())
- return 0;
+ if (pCol->IsEmptyData())
+ return false;
+ PositionType aHiPos, aLoPos;
ScRefCellValue aCell;
- ScBaseCell* pCell;
- SCSIZE nHi, nLo;
+
CollatorWrapper* pCollator = (mpParam->bCaseSens ? ScGlobal::GetCaseCollator() :
ScGlobal::GetCollator());
SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
@@ -1472,41 +1402,59 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
nRow = mpParam->nRow1;
if (mpParam->bHasHeader)
nRow++;
- if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
- pCol->maItems[nLo].pCell->HasStringData())
+
+ aLoPos = pCol->maCells.position(nRow);
+ if (bFirstStringIgnore && aLoPos.first->type == sc::element_type_string)
{
OUString aCellStr;
- sal_uLong nFormat = pCol->GetNumberFormat( pCol->maItems[nLo].nRow);
- aCell.assign(*pCol->maItems[nLo].pCell);
+ sal_uLong nFormat = pCol->GetNumberFormat(toLogicalPos(aLoPos));
+ aCell.assign(aLoPos.first, aLoPos.second);
ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter);
sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString);
if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
(rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
(rEntry.eOp == SC_EQUAL && nTmp != 0))
- ++nLo;
+ {
+ // Skip the first string value at low point.
+ incPos(aLoPos);
+ }
+ }
+
+ aHiPos = pCol->maCells.position(mpParam->nRow2);
+ if (bAllStringIgnore)
+ {
+ // Skip all string cells, but never go past the high point.
+ if (aLoPos.first->type == sc::element_type_string)
+ {
+ if (aLoPos.first == pCol->maCells.end())
+ // This is the last block. Move to the last element in this block.
+ aLoPos.second = aLoPos.first->size - 1;
+ else
+ // Move to the next block.
+ incBlock(aLoPos);
+ }
+
+ if (toLogicalPos(aLoPos) > toLogicalPos(aHiPos))
+ // Never go past the high point.
+ aLoPos = aHiPos;
}
- if (!pCol->Search( mpParam->nRow2, nHi ) && nHi>0)
- --nHi;
- while (bAllStringIgnore && nLo <= nHi && nLo < pCol->maItems.size() &&
- pCol->maItems[nLo].pCell->HasStringData())
- ++nLo;
// Bookkeeping values for breaking up the binary search in case the data
// range isn't strictly sorted.
- SCSIZE nLastInRange = nLo;
- SCSIZE nFirstLastInRange = nLastInRange;
+ PositionType aLastInRange = aLoPos;
+ PositionType aFirstLastInRange = aLastInRange;
double fLastInRangeValue = bLessEqual ?
-(::std::numeric_limits<double>::max()) :
::std::numeric_limits<double>::max();
- String aLastInRangeString;
+ OUString aLastInRangeString;
if (!bLessEqual)
- aLastInRangeString.Assign( sal_Unicode(0xFFFF));
- if (nLastInRange < pCol->maItems.size())
+ aLastInRangeString = OUString(sal_Unicode(0xFFFF));
+ if (aLastInRange.first != pCol->maCells.end())
{
- aCell.assign(*pCol->maItems[nLastInRange].pCell);
+ aCell.assign(aLastInRange.first, aLastInRange.second);
if (aCell.hasString())
{
- sal_uLong nFormat = pCol->GetNumberFormat( pCol->maItems[nLastInRange].nRow);
+ sal_uLong nFormat = pCol->GetNumberFormat(toLogicalPos(aLastInRange));
OUString aStr;
ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter);
aLastInRangeString = aStr;
@@ -1532,20 +1480,22 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
sal_Int32 nRes = 0;
bool bFound = false;
bool bDone = false;
- while (nLo <= nHi && !bDone)
+ size_t nLogicalLow = toLogicalPos(aLoPos), nLogicalHigh = toLogicalPos(aHiPos);
+ while (nLogicalLow <= nLogicalHigh && !bDone)
{
- SCSIZE nMid = (nLo+nHi)/2;
- SCSIZE i = nMid;
- if (i > nHi)
+ size_t nMid = (nLogicalLow+nLogicalHigh)/2;
+ size_t i = nMid;
+ if (i > nLogicalHigh)
{
if (nMid > 0)
- nHi = nMid - 1;
+ nLogicalHigh = nMid - 1;
else
bDone = true;
continue; // while
}
- bool bStr = pCol->maItems[i].pCell->HasStringData();
+ PositionType aPos = pCol->maCells.position(i);
+ bool bStr = aPos.first->type == sc::element_type_string;
nRes = 0;
// compares are content<query:-1, content>query:1
@@ -1553,14 +1503,14 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
if (!bStr && !bByString)
{
double nCellVal;
- pCell = pCol->maItems[i].pCell;
- switch ( pCell->GetCellType() )
+ aCell.assign(aPos.first, aPos.second);
+ switch (aCell.meType)
{
case CELLTYPE_VALUE :
- nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
+ nCellVal = aCell.mfValue;
break;
case CELLTYPE_FORMULA :
- nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
+ nCellVal = aCell.mpFormula->GetValue();
break;
default:
nCellVal = 0.0;
@@ -1574,12 +1524,12 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
if (fLastInRangeValue < nCellVal)
{
fLastInRangeValue = nCellVal;
- nLastInRange = i;
+ aLastInRange = aPos;
}
else if (fLastInRangeValue > nCellVal)
{
// not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
+ aLastInRange = aFirstLastInRange;
bDone = true;
}
}
@@ -1593,12 +1543,12 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
if (fLastInRangeValue > nCellVal)
{
fLastInRangeValue = nCellVal;
- nLastInRange = i;
+ aLastInRange = aPos;
}
else if (fLastInRangeValue < nCellVal)
{
// not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
+ aLastInRange = aFirstLastInRange;
bDone = true;
}
}
@@ -1607,8 +1557,8 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
else if (bStr && bByString)
{
OUString aCellStr;
- sal_uLong nFormat = pCol->GetNumberFormat( pCol->maItems[i].nRow);
- aCell.assign(*pCol->maItems[i].pCell);
+ sal_uLong nFormat = pCol->GetNumberFormat(i);
+ aCell.assign(aPos.first, aPos.second);
ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter);
nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString);
@@ -1619,12 +1569,12 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
if (nTmp < 0)
{
aLastInRangeString = aCellStr;
- nLastInRange = i;
+ aLastInRange = aPos;
}
else if (nTmp > 0)
{
// not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
+ aLastInRange = aFirstLastInRange;
bDone = true;
}
}
@@ -1635,12 +1585,12 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
if (nTmp > 0)
{
aLastInRangeString = aCellStr;
- nLastInRange = i;
+ aLastInRange = aPos;
}
else if (nTmp < 0)
{
// not strictly sorted, continue with GetThis()
- nLastInRange = nFirstLastInRange;
+ aLastInRange = aFirstLastInRange;
bDone = true;
}
}
@@ -1649,22 +1599,22 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
{
nRes = -1; // numeric < string
if (bLessEqual)
- nLastInRange = i;
+ aLastInRange = aPos;
}
else // if (bStr && !bByString)
{
nRes = 1; // string > numeric
if (!bLessEqual)
- nLastInRange = i;
+ aLastInRange = aPos;
}
if (nRes < 0)
{
if (bLessEqual)
- nLo = nMid + 1;
+ nLogicalLow = nMid + 1;
else // assumed to be SC_GREATER_EQUAL
{
if (nMid > 0)
- nHi = nMid - 1;
+ nLogicalHigh = nMid - 1;
else
bDone = true;
}
@@ -1674,16 +1624,16 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
if (bLessEqual)
{
if (nMid > 0)
- nHi = nMid - 1;
+ nLogicalHigh = nMid - 1;
else
bDone = true;
}
else // assumed to be SC_GREATER_EQUAL
- nLo = nMid + 1;
+ nLogicalLow = nMid + 1;
}
else
{
- nLo = i;
+ aLoPos = aPos;
bDone = bFound = true;
}
}
@@ -1697,21 +1647,24 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
// Else, in case no exact match was found, we step back for a
// subsequent GetThis() to find the last in range. Effectively this is
// --nLo with nLastInRange == nLo-1. Both conditions combined yield:
- nLo = nLastInRange;
+ aLoPos = aLastInRange;
}
- if (nLo < pCol->maItems.size() && pCol->maItems[nLo].nRow <= mpParam->nRow2)
+
+ if (aLoPos.first != pCol->maCells.end() && toLogicalPos(aLoPos) <= static_cast<size_t>(mpParam->nRow2))
{
- nRow = pCol->maItems[nLo].nRow;
- pCell = pCol->maItems[nLo].pCell;
- nColRow = nLo;
+ nRow = toLogicalPos(aLoPos);
+ maCurPos = aLoPos;
+ return true;
}
else
{
nRow = mpParam->nRow2 + 1;
- pCell = 0;
- nColRow = pCol->maItems.size() - 1;
+ // Set current position to the last possible row.
+ maCurPos.first = pCol->maCells.end();
+ --maCurPos.first;
+ maCurPos.second = maCurPos.first->size - 1;
+ return false;
}
- return pCell;
}
@@ -1719,23 +1672,24 @@ ScBaseCell* ScQueryCellIterator::BinarySearch()
ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
+ maColPositions(nCol2-nCol2+1),
pDoc( pDocument ),
- nTab( nTable ),
+ mnTab( nTable ),
nStartCol( nCol1 ),
nEndCol( nCol2 ),
nStartRow( nRow1 ),
nEndRow( nRow2 ),
- nCol( nCol1 ),
- nRow( nRow1 ),
+ mnCol( nCol1 ),
+ mnRow( nRow1 ),
bMore( true )
{
- if (nTab >= pDoc->GetTableCount())
+ if (mnTab >= pDoc->GetTableCount())
OSL_FAIL("try to access index out of bounds, FIX IT");
pNextRows = new SCROW[ nCol2-nCol1+1 ];
pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
- SetTab( nTab );
+ SetTab( mnTab );
}
ScHorizontalCellIterator::~ScHorizontalCellIterator()
@@ -1746,101 +1700,103 @@ ScHorizontalCellIterator::~ScHorizontalCellIterator()
void ScHorizontalCellIterator::SetTab( SCTAB nTabP )
{
- nTab = nTabP;
- nRow = nStartRow;
- nCol = nStartCol;
+ mnTab = nTabP;
+ mnRow = nStartRow;
+ mnCol = nStartCol;
bMore = true;
- for (SCCOL i=nStartCol; i<=nEndCol; i++)
+ // Set the start position in each column.
+ for (SCCOL i = nStartCol; i <= nEndCol; ++i)
{
- ScColumn* pCol = &pDoc->maTabs[nTab]->aCol[i];
-
- SCSIZE nIndex;
- pCol->Search( nStartRow, nIndex );
- if ( nIndex < pCol->maItems.size() )
- {
- pNextRows[i-nStartCol] = pCol->maItems[nIndex].nRow;
- pNextIndices[i-nStartCol] = nIndex;
- }
- else
- {
- pNextRows[i-nStartCol] = MAXROWCOUNT; // Nothing found
- pNextIndices[i-nStartCol] = MAXROWCOUNT;
- }
+ ScColumn* pCol = &pDoc->maTabs[mnTab]->aCol[i];
+ maColPositions[i-nStartCol].maPos = pCol->maCells.position(nStartRow).first;
+ maColPositions[i-nStartCol].maEnd = pCol->maCells.end();
}
- if (pNextRows[0] != nStartRow)
+ if (maColPositions[0].maPos->type == sc::element_type_empty)
+ // Skip to the first non-empty cell.
Advance();
}
ScRefCellValue* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
{
- if ( bMore )
- {
- rCol = nCol;
- rRow = nRow;
-
- ScColumn* pCol = &pDoc->maTabs[nTab]->aCol[nCol];
- SCSIZE nIndex = pNextIndices[nCol-nStartCol];
- OSL_ENSURE( nIndex < pCol->maItems.size(), "ScHorizontalCellIterator::GetNext: nIndex out of range" );
- ScBaseCell* pCell = pCol->maItems[nIndex].pCell;
- if ( ++nIndex < pCol->maItems.size() )
- {
- pNextRows[nCol-nStartCol] = pCol->maItems[nIndex].nRow;
- pNextIndices[nCol-nStartCol] = nIndex;
- }
- else
- {
- pNextRows[nCol-nStartCol] = MAXROWCOUNT; // Nothing found
- pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
- }
-
- Advance();
- maCurCell.assign(*pCell);
- return &maCurCell;
- }
- else
+ if (!bMore)
return NULL;
+
+ // Return the current non-empty cell, and move the cursor to the next one.
+ rCol = mnCol;
+ rRow = mnRow;
+
+ ColParam& r = maColPositions[mnCol-nStartCol];
+ size_t nOffset = static_cast<size_t>(mnRow) - r.maPos->position;
+ maCurCell.assign(r.maPos, nOffset);
+ Advance();
+
+ return &maCurCell;
}
-bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
+bool ScHorizontalCellIterator::GetPos( SCCOL& rCol, SCROW& rRow )
{
- rCol = nCol;
- rRow = nRow;
+ rCol = mnCol;
+ rRow = mnRow;
return bMore;
}
void ScHorizontalCellIterator::Advance()
{
- bool bFound = false;
- SCCOL i;
+ // Find the next non-empty cell in the current row.
+ for (SCCOL i = mnCol+1; i <= nEndCol; ++i)
+ {
+ ColParam& r = maColPositions[i-nStartCol];
+ if (r.maPos == r.maEnd)
+ continue;
- for (i=nCol+1; i<=nEndCol && !bFound; i++)
- if (pNextRows[i-nStartCol] == nRow)
- {
- nCol = i;
- bFound = true;
- }
+ if (r.maPos->type == sc::element_type_empty)
+ continue;
- if (!bFound)
+ size_t nRow = static_cast<size_t>(mnRow);
+ if (nRow < r.maPos->position)
+ continue;
+
+ if (r.maPos->position + r.maPos->size <= nRow)
+ continue;
+
+ // Found in the current row.
+ mnCol = i;
+ bMore = true;
+ return;
+ }
+
+ // Move to the next row that has at least one non-empty cell.
+ size_t nMinRow = MAXROW+1;
+ size_t nMinRowCol = maColPositions.size();
+ for (size_t i = 0, n = maColPositions.size(); i < n; ++i)
{
- SCROW nMinRow = MAXROW+1;
- for (i=nStartCol; i<=nEndCol; i++)
- if (pNextRows[i-nStartCol] < nMinRow)
- {
- nCol = i;
- nMinRow = pNextRows[i-nStartCol];
- }
+ ColParam& r = maColPositions[i];
+ if (r.maPos == r.maEnd)
+ // This column has ended.
+ continue;
- if (nMinRow <= nEndRow)
+ // Move to the next block.
+ ++r.maPos;
+
+ if (r.maPos != r.maEnd && r.maPos->position < nMinRow)
{
- nRow = nMinRow;
- bFound = true;
+ nMinRow = r.maPos->position;
+ nMinRowCol = i;
}
}
- if ( !bFound )
+ if (nMinRowCol == maColPositions.size() || static_cast<SCROW>(nMinRow) > nEndRow)
+ {
+ // No more cells found.
bMore = false;
+ return;
+ }
+
+ mnCol = nMinRowCol + nStartCol;
+ mnRow = nMinRow;
+ bMore = true;
}
//------------------------------------------------------------------------
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index bc9a5af324d8..df4b328e62e0 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -587,19 +587,6 @@ void ScDocument::EnsureTable( SCTAB nTab )
maTabs[nTab] = new ScTable(this, nTab, "temp", bExtras, bExtras);
}
-void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
- ScBaseCell* pCell, sal_uLong nFormatIndex, bool bForceTab )
-{
- if (ValidTab(nTab))
- {
- if (bForceTab)
- EnsureTable(nTab);
-
- if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
- maTabs[nTab]->PutCell( nCol, nRow, nFormatIndex, pCell );
- }
-}
-
ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
{
if (!TableExists(rPos.Tab()))
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index 90a5d9abff78..0595e109121f 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -143,13 +143,16 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
for (; itr != itrEnd && *itr < nMax; ++itr)
{
- if (maTabs[*itr])
- {
- if (*itr == nTab1)
- maTabs[*itr]->PutCell(nCol1, nRow1, pCell);
- else
- maTabs[*itr]->PutCell(nCol1, nRow1, pCell->Clone(*this, ScAddress( nCol1, nRow1, *itr), SC_CLONECELL_STARTLISTENING));
- }
+ if (!maTabs[*itr])
+ continue;
+
+ if (*itr == nTab1)
+ maTabs[*itr]->SetFormulaCell(nCol1, nRow1, pCell);
+ else
+ maTabs[*itr]->SetFormulaCell(
+ nCol1, nRow1,
+ new ScFormulaCell(
+ *pCell, *this, ScAddress(nCol1, nRow1, *itr), SC_CLONECELL_STARTLISTENING));
}
ScSingleRefData aRefData;
@@ -170,7 +173,6 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
{
if (maTabs[*itr])
{
- maTabs[*itr]->DoColResize( nCol1, nCol2, static_cast<SCSIZE>(nRow2 - nRow1 + 1) );
if (*itr != nTab1)
{
aRefData.nTab = *itr;
@@ -189,7 +191,7 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
t->CalcRelFromAbs( aPos );
boost::scoped_ptr<ScTokenArray> pTokArr(aArr.Clone());
pCell = new ScFormulaCell( this, aPos, pTokArr.get(), eGram, MM_REFERENCE );
- maTabs[*itr]->PutCell(j, k, (ScBaseCell*) pCell);
+ maTabs[*itr]->SetFormulaCell(j, k, pCell);
}
}
}
@@ -284,7 +286,8 @@ void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // Mehrfachopera
itr = rMark.begin();
for (; itr != itrEnd && *itr < nMax; ++itr)
if( maTabs[*itr] )
- maTabs[*itr]->PutCell( j, k, aRefCell.Clone( *this, ScAddress( j, k, *itr ), SC_CLONECELL_STARTLISTENING ) );
+ maTabs[*itr]->SetFormulaCell(
+ j, k, new ScFormulaCell(aRefCell, *this, ScAddress(j, k, *itr), SC_CLONECELL_STARTLISTENING));
}
}
@@ -428,16 +431,6 @@ void ScDocument::CompileColRowNameFormula()
}
}
-void ScDocument::DoColResize( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
-{
- if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
- maTabs[nTab]->DoColResize( nCol1, nCol2, nAdd );
- else
- {
- OSL_FAIL("DoColResize: wrong table");
- }
-}
-
void ScDocument::InvalidateTableArea()
{
TableContainer::iterator it = maTabs.begin();
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
index 236b9e5983b1..3a2030e682e3 100644
--- a/sc/source/core/data/documen8.cxx
+++ b/sc/source/core/data/documen8.cxx
@@ -423,6 +423,15 @@ ScMacroManager* ScDocument::GetMacroManager()
return mpMacroMgr.get();
}
+bool ScDocument::IsEmptyData( SCTAB nTab, SCCOL nCol ) const
+{
+ const ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ return true;
+
+ return pTab->IsEmptyData(nCol);
+}
+
//------------------------------------------------------------------------
void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index e1997fe22be5..d33711df9343 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1111,7 +1111,7 @@ bool ScDocument::CanInsertRow( const ScRange& rRange ) const
bool bTest = true;
for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
- bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+ bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nStartRow, nSize );
return bTest;
}
@@ -1138,7 +1138,7 @@ bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
SetAutoCalc( false ); // avoid mulitple calculations
for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
- bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+ bTest &= maTabs[i]->TestInsertRow(nStartCol, nEndCol, nStartRow, nSize);
if (bTest)
{
// UpdateBroadcastAreas have to be called before UpdateReference, so that entries
@@ -3016,24 +3016,6 @@ void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
}
}
-void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, bool bForceTab )
-{
- SCTAB nTab = rPos.Tab();
- if ( bForceTab && ( nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab]) )
- {
- bool bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
-
- if (nTab >= static_cast<SCTAB>(maTabs.size()))
- maTabs.resize(nTab + 1,NULL);
- maTabs[nTab] = new ScTable(this, nTab,
- OUString("temp"),
- bExtras, bExtras);
- }
-
- if (maTabs[nTab])
- maTabs[nTab]->PutCell( rPos, pCell );
-}
-
bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
ScSetStringParam* pParam )
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index ec5b1c498d24..c3be0338ccda 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -75,32 +75,51 @@ void ScDocumentImport::setOriginDate(sal_uInt16 nYear, sal_uInt16 nMonth, sal_uI
void ScDocumentImport::setAutoInput(const ScAddress& rPos, const OUString& rStr)
{
- if (!mpImpl->mrDoc.TableExists(rPos.Tab()))
+ ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
+ if (!pTab)
return;
- mpImpl->mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()].SetString(
+ pTab->aCol[rPos.Col()].SetString(
rPos.Row(), rPos.Tab(), rStr, mpImpl->mrDoc.GetAddressConvention());
}
void ScDocumentImport::setNumericCell(const ScAddress& rPos, double fVal)
{
- insertCell(rPos, new ScValueCell(fVal));
+ ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
+ if (!pTab)
+ return;
+
+ pTab->aCol[rPos.Col()].SetValue(rPos.Row(), fVal);
}
void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr)
{
- insertCell(rPos, new ScStringCell(rStr));
+ ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
+ if (!pTab)
+ return;
+
+ pTab->aCol[rPos.Col()].SetRawString(rPos.Row(), rStr);
}
void ScDocumentImport::setFormulaCell(
const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar)
{
- insertCell(rPos, new ScFormulaCell(&mpImpl->mrDoc, rPos, rFormula, eGrammar));
+ ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
+ if (!pTab)
+ return;
+
+ pTab->aCol[rPos.Col()].SetFormulaCell(
+ rPos.Row(), new ScFormulaCell(&mpImpl->mrDoc, rPos, rFormula, eGrammar));
}
void ScDocumentImport::setFormulaCell(const ScAddress& rPos, const ScTokenArray& rArray)
{
- insertCell(rPos, new ScFormulaCell(&mpImpl->mrDoc, rPos, &rArray));
+ ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
+ if (!pTab)
+ return;
+
+ pTab->aCol[rPos.Col()].SetFormulaCell(
+ rPos.Row(), new ScFormulaCell(&mpImpl->mrDoc, rPos, &rArray));
}
void ScDocumentImport::finalize()
@@ -123,20 +142,4 @@ void ScDocumentImport::finalize()
}
}
-void ScDocumentImport::insertCell(const ScAddress& rPos, ScBaseCell* pCell)
-{
- if (!mpImpl->mrDoc.TableExists(rPos.Tab()))
- {
- pCell->Delete();
- return;
- }
-
- ScColumn& rCol = mpImpl->mrDoc.maTabs[rPos.Tab()]->aCol[rPos.Col()];
- sc::ColumnBlockPosition* p = mpImpl->maBlockPosSet.getBlockPosition(rPos.Tab(), rPos.Col());
- if (p)
- rCol.SetCell(*p, rPos.Row(), pCell);
- else
- rCol.SetCell(rPos.Row(), pCell);
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 8eb78e649127..c64a54d94c9e 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -40,6 +40,7 @@
#include "colorscale.hxx"
#include "stlpool.hxx"
#include "cellvalue.hxx"
+#include "mtvcellfunc.hxx"
#include <iostream>
@@ -130,6 +131,68 @@ static void lcl_GetMergeRange( SCsCOL nX, SCsROW nY, SCSIZE nArrY,
#define CELLINFO(x,y) pRowInfo[nArrY+y].pCellInfo[nArrX+x]
+namespace {
+
+class RowInfoFiller
+{
+ ScDocument& mrDoc;
+ SCTAB mnTab;
+ RowInfo* mpRowInfo;
+ SCCOL mnArrX;
+ SCSIZE& mrArrY;
+ SCROW mnHiddenEndRow;
+ bool mbHiddenRow;
+
+ bool isHidden(size_t nRow)
+ {
+ SCROW nThisRow = static_cast<SCROW>(nRow);
+ if (nThisRow > mnHiddenEndRow)
+ mbHiddenRow = mrDoc.RowHidden(nThisRow, mnTab, NULL, &mnHiddenEndRow);
+ return mbHiddenRow;
+ }
+
+ void setInfo(const ScRefCellValue& rCell)
+ {
+ RowInfo* pThisRowInfo = &mpRowInfo[mrArrY];
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[mnArrX];
+ pInfo->maCell = rCell;
+ pThisRowInfo->bEmptyText = false;
+ pInfo->bEmptyCellText = false;
+ ++mrArrY;
+ }
+
+public:
+ RowInfoFiller(ScDocument& rDoc, SCTAB nTab, RowInfo* pRowInfo, SCCOL nArrX, SCSIZE& rArrY) :
+ mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnArrX(nArrX), mrArrY(rArrY),
+ mnHiddenEndRow(-1), mbHiddenRow(false) {}
+
+ void operator() (size_t nRow, double fVal)
+ {
+ if (!isHidden(nRow))
+ setInfo(ScRefCellValue(fVal));
+ }
+
+ void operator() (size_t nRow, const OUString& rStr)
+ {
+ if (!isHidden(nRow))
+ setInfo(ScRefCellValue(&rStr));
+ }
+
+ void operator() (size_t nRow, const EditTextObject* p)
+ {
+ if (!isHidden(nRow))
+ setInfo(ScRefCellValue(p));
+ }
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ if (!isHidden(nRow))
+ setInfo(ScRefCellValue(const_cast<ScFormulaCell*>(p)));
+ }
+};
+
+}
+
void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
SCTAB nTab, double nScaleX, double nScaleY,
bool bPageMode, bool bFormulaMode, const ScMarkData* pMarkData )
@@ -363,30 +426,11 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX
ScColumn* pThisCol = &maTabs[nTab]->aCol[nX]; // Spalten-Daten
nArrY = 1;
- SCSIZE nUIndex;
- bool bHiddenRow = true;
- SCROW nHiddenEndRow = -1;
- (void) pThisCol->Search( nY1, nUIndex );
- while ( nUIndex < pThisCol->maItems.size() &&
- (nThisRow=pThisCol->maItems[nUIndex].nRow) <= nY2 )
- {
- if (nThisRow > nHiddenEndRow)
- bHiddenRow = RowHidden( nThisRow, nTab, NULL, &nHiddenEndRow);
- if ( !bHiddenRow )
- {
- while ( pRowInfo[nArrY].nRowNo < nThisRow )
- ++nArrY;
- OSL_ENSURE( pRowInfo[nArrY].nRowNo == nThisRow, "FillInfo: Row not found" );
-
- RowInfo* pThisRowInfo = &pRowInfo[nArrY];
- CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
- pInfo->maCell.assign(*pThisCol->maItems[nUIndex].pCell);
- pThisRowInfo->bEmptyText = false; // Zeile nicht leer
- pInfo->bEmptyCellText = false; // Zelle nicht leer
- ++nArrY;
- }
- ++nUIndex;
- }
+ // Iterate between rows nY1 and nY2 and pick up non-empty
+ // cells that are not hidden.
+ RowInfoFiller aFunc(*this, nTab, pRowInfo, nArrX, nArrY);
+ sc::ParseAllNonEmpty(
+ pThisCol->maCells.begin(), pThisCol->maCells, nY1, nY2, aFunc);
if (nX+1 >= nX1) // Attribute/Blockmarken ab nX1-1
{
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index da36a3435a0c..2cd5317102eb 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -45,6 +45,7 @@
#include "rtl/strbuf.hxx"
#include "formulagroup.hxx"
#include "listenercontext.hxx"
+#include "types.hxx"
#include <boost/bind.hpp>
@@ -1804,7 +1805,7 @@ bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
(reserved: open: 32)
*/
-sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
+sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos ) const
{
switch ( cMatrixFlag )
{
@@ -1819,7 +1820,7 @@ sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
if ( aOrg != rOrgPos )
{ // First time or a different matrix than last time.
rOrgPos = aOrg;
- ScFormulaCell* pFCell;
+ const ScFormulaCell* pFCell;
if ( cMatrixFlag == MM_REFERENCE )
pFCell = pDocument->GetFormulaCell(aOrg);
else
@@ -1866,7 +1867,8 @@ sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
else
bCont = false;
} while ( bCont );
- pFCell->SetMatColsRows( nC, nR );
+
+ const_cast<ScFormulaCell*>(pFCell)->SetMatColsRows(nC, nR);
}
}
else
@@ -1892,15 +1894,15 @@ sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
{
if ( dC == 0 )
- nEdges |= 4; // left edge
+ nEdges |= sc::MatrixEdgeLeft; // left edge
if ( dC+1 == nC )
- nEdges |= 16; // right edge
+ nEdges |= sc::MatrixEdgeRight; // right edge
if ( dR == 0 )
- nEdges |= 8; // top edge
+ nEdges |= sc::MatrixEdgeTop; // top edge
if ( dR+1 == nR )
- nEdges |= 2; // bottom edge
+ nEdges |= sc::MatrixEdgeBottom; // bottom edge
if ( !nEdges )
- nEdges = 1; // inside
+ nEdges = sc::MatrixEdgeInside; // inside
}
#if OSL_DEBUG_LEVEL > 0
else
@@ -2251,7 +2253,7 @@ bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
pOld, eTempGrammar, cMatrixFlag );
pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
- pUndoDoc->PutCell( aUndoPos, pFCell );
+ pUndoDoc->SetFormulaCell(aUndoPos, pFCell);
}
}
bValChanged = false;
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx
index 0bd54badf8a4..a4232f89168a 100644
--- a/sc/source/core/data/markdata.cxx
+++ b/sc/source/core/data/markdata.cxx
@@ -426,6 +426,13 @@ void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const
}
}
+ScRangeList ScMarkData::GetMarkedRanges() const
+{
+ ScRangeList aRet;
+ FillRangeListWithMarks(&aRet, false);
+ return aRet;
+}
+
SCCOLROW ScMarkData::GetMarkColumnRanges( SCCOLROW* pRanges )
{
if (bMarked)
diff --git a/sc/source/core/data/mtvelements.cxx b/sc/source/core/data/mtvelements.cxx
index efe07cff5ad7..57573a5a1480 100644
--- a/sc/source/core/data/mtvelements.cxx
+++ b/sc/source/core/data/mtvelements.cxx
@@ -25,6 +25,22 @@ CellTextAttr::CellTextAttr(sal_uInt16 nTextWidth, sal_uInt8 nScriptType) :
mnTextWidth(nTextWidth),
mnScriptType(nScriptType) {}
+ColumnBlockPosition& ColumnBlockPosition::operator= (const ColumnBlockPosition& r)
+{
+ miBroadcasterPos = r.miBroadcasterPos;
+ miCellTextAttrPos = r.miCellTextAttrPos;
+ miCellPos = r.miCellPos;
+ return *this;
+}
+
+ColumnBlockConstPosition& ColumnBlockConstPosition::operator= (const ColumnBlockConstPosition& r)
+{
+ miBroadcasterPos = r.miBroadcasterPos;
+ miCellTextAttrPos = r.miCellTextAttrPos;
+ miCellPos = r.miCellPos;
+ return *this;
+}
+
ColumnBlockPositionSet::ColumnBlockPositionSet(ScDocument& rDoc) : mrDoc(rDoc) {}
ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL nCol)
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index c0e2c3f94e82..d26a42c2ba64 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -516,11 +516,11 @@ bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
SCCOL nMaxX = 0;
SCROW nMaxY = 0;
for (SCCOL i=0; i<=MAXCOL; i++)
- if (!aCol[i].IsEmptyVisData())
+ if (!aCol[i].IsEmptyData())
{
bFound = true;
nMaxX = i;
- SCROW nColY = aCol[i].GetLastVisDataPos();
+ SCROW nColY = aCol[i].GetLastDataPos();
if (nColY > nMaxY)
nMaxY = nColY;
}
@@ -564,12 +564,12 @@ bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bF
SCCOL i;
for (i=0; i<=MAXCOL; i++) // Daten testen
- if (!aCol[i].IsEmptyVisData())
+ if (!aCol[i].IsEmptyData())
{
bFound = true;
if (i>nMaxX)
nMaxX = i;
- SCROW nColY = aCol[i].GetLastVisDataPos();
+ SCROW nColY = aCol[i].GetLastDataPos();
if (nColY > nMaxY)
nMaxY = nColY;
}
@@ -697,10 +697,10 @@ bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
}
for (i=nStartCol; i<=nEndCol; i++) // Daten testen
- if (!aCol[i].IsEmptyVisData())
+ if (!aCol[i].IsEmptyData())
{
bFound = true;
- SCROW nColY = aCol[i].GetLastVisDataPos();
+ SCROW nColY = aCol[i].GetLastDataPos();
if (nColY > nMaxY)
nMaxY = nColY;
}
@@ -756,12 +756,12 @@ bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
bool bDatFound = false;
for (i=0; i<=MAXCOL; i++) // Daten testen
- if (!aCol[i].IsEmptyVisData())
+ if (!aCol[i].IsEmptyData())
{
if (!bDatFound && i<nMinX)
nMinX = i;
bFound = bDatFound = true;
- SCROW nColY = aCol[i].GetFirstVisDataPos();
+ SCROW nColY = aCol[i].GetFirstDataPos();
if (nColY < nMinY)
nMinY = nColY;
}
@@ -991,7 +991,7 @@ SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
SCCOL nCol;
if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP))
{
- nCount = static_cast<SCSIZE>(nEndRow - nStartRow);
+ nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
for (nCol = nStartCol; nCol <= nEndCol; nCol++)
nCount = std::min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir));
}
@@ -1385,17 +1385,31 @@ bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMa
if ( nStart <= MAXROW )
{
SCROW nEnd = rArray.GetMarkEnd( nStart, false );
- ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd );
- SCROW nCellRow;
- ScBaseCell* pCell = NULL;
- while ( aColIter.Next( nCellRow, pCell ) )
+
+ const sc::CellStoreType& rCells = aCol[rCol].maCells;
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos = rCells.position(nStart);
+ sc::CellStoreType::const_iterator it = aPos.first;
+ SCROW nTestRow = nStart;
+ if (it->type == sc::element_type_empty)
{
- if (pCell)
+ // Skip the empty block.
+ nTestRow += it->size - aPos.second;
+ ++it;
+ if (it == rCells.end())
{
- rRow = nCellRow;
- return true; // Zelle gefunden
+ // No more block.
+ rRow = MAXROW + 1;
+ return false;
}
}
+
+ if (nTestRow < nEnd)
+ {
+ // Cell found.
+ rRow = nTestRow;
+ return true;
+ }
+
rRow = nEnd + 1; // naechsten markierten Bereich suchen
}
else
@@ -1719,12 +1733,12 @@ void ScTable::ExtendPrintArea( OutputDevice* pDev,
{
SCCOL nPrintCol = nDataCol;
VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]);
- ScBaseCell* pCell = aIter.reset(nStartRow);
- if (!pCell)
+ ScRefCellValue aCell = aIter.reset(nStartRow);
+ if (aCell.isEmpty())
// No visible cells found in this column. Skip it.
continue;
- while (pCell)
+ while (!aCell.isEmpty())
{
SCCOL nNewCol = nDataCol;
SCROW nRow = aIter.getRow();
@@ -1735,7 +1749,7 @@ void ScTable::ExtendPrintArea( OutputDevice* pDev,
MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY);
if (nNewCol > nPrintCol)
nPrintCol = nNewCol;
- pCell = aIter.next();
+ aCell = aIter.next();
}
if (nPrintCol > rEndCol)
@@ -1748,8 +1762,8 @@ void ScTable::ExtendPrintArea( OutputDevice* pDev,
void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY)
{
- ScBaseCell* pCell = aCol[rCol].GetCell(nRow);
- if (!pCell || !pCell->HasStringData())
+ ScRefCellValue aCell = aCol[rCol].GetCellValue(nRow);
+ if (!aCell.hasString())
return;
bool bFormula = false; //! ueberge
@@ -1799,8 +1813,8 @@ void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, d
SCCOL nNewCol = rCol;
while (nMissing > 0 && nNewCol < MAXCOL)
{
- ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow);
- if (pNextCell)
+ ScRefCellValue aNextCell = aCol[nNewCol+1].GetCellValue(nRow);
+ if (!aNextCell.isEmpty())
// Cell content in a next column ends display of this string.
nMissing = 0;
else
@@ -1868,12 +1882,6 @@ void ScTable::CopyPrintRange(const ScTable& rTable)
}
}
-void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
-{
- for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
- aCol[nCol].ReserveSize(aCol[nCol].GetCellCount() + nAdd);
-}
-
void ScTable::SetRepeatColRange( const ScRange* pNew )
{
setPrintRange( pRepeatColRange, pNew );
@@ -1954,7 +1962,6 @@ SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1;
ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) :
mrRowSegs(rRowSegs),
mrColumn(rColumn),
- mpCell(NULL),
mnCurRow(ROW_NOT_FOUND),
mnUBound(ROW_NOT_FOUND)
{
@@ -1964,19 +1971,19 @@ ScTable::VisibleDataCellIterator::~VisibleDataCellIterator()
{
}
-ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow)
+ScRefCellValue ScTable::VisibleDataCellIterator::reset(SCROW nRow)
{
if (nRow > MAXROW)
{
mnCurRow = ROW_NOT_FOUND;
- return NULL;
+ return ScRefCellValue();
}
ScFlatBoolRowSegments::RangeData aData;
if (!mrRowSegs.getRangeData(nRow, aData))
{
mnCurRow = ROW_NOT_FOUND;
- return NULL;
+ return ScRefCellValue();
}
if (!aData.mbValue)
@@ -1995,23 +2002,23 @@ ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow)
{
// Make sure the row doesn't exceed our current limit.
mnCurRow = ROW_NOT_FOUND;
- return NULL;
+ return ScRefCellValue();
}
}
- mpCell = mrColumn.GetCell(mnCurRow);
- if (mpCell)
+ maCell = mrColumn.GetCellValue(mnCurRow);
+ if (!maCell.isEmpty())
// First visible cell found.
- return mpCell;
+ return maCell;
// Find a first visible cell below this row (if any).
return next();
}
-ScBaseCell* ScTable::VisibleDataCellIterator::next()
+ScRefCellValue ScTable::VisibleDataCellIterator::next()
{
if (mnCurRow == ROW_NOT_FOUND)
- return NULL;
+ return ScRefCellValue();
while (mrColumn.GetNextDataPos(mnCurRow))
{
@@ -2022,7 +2029,7 @@ ScBaseCell* ScTable::VisibleDataCellIterator::next()
if (!mrRowSegs.getRangeData(mnCurRow, aData))
{
mnCurRow = ROW_NOT_FOUND;
- return NULL;
+ return ScRefCellValue();
}
if (aData.mbValue)
@@ -2037,12 +2044,13 @@ ScBaseCell* ScTable::VisibleDataCellIterator::next()
mnUBound = aData.mnRow2;
}
- mpCell = mrColumn.GetCell(mnCurRow);
- if (mpCell)
- return mpCell;
+ maCell = mrColumn.GetCellValue(mnCurRow);
+ if (!maCell.isEmpty())
+ return maCell;
}
+
mnCurRow = ROW_NOT_FOUND;
- return NULL;
+ return ScRefCellValue();
}
SCROW ScTable::VisibleDataCellIterator::getRow() const
@@ -2166,7 +2174,7 @@ ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
if (!ValidColRow(nCol, nRow))
return ScRefCellValue();
- return aCol[nCol].GetRefCellValue(nRow);
+ return aCol[nCol].GetCellValue(nRow);
}
SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow )
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 5df2ac12f636..3c5b486efa07 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -44,6 +44,9 @@
#include "colorscale.hxx"
#include "tokenarray.hxx"
#include "clipcontext.hxx"
+#include "types.hxx"
+#include "editutil.hxx"
+#include "mtvcellfunc.hxx"
#include "scitems.hxx"
#include <editeng/boxitem.hxx>
@@ -121,7 +124,7 @@ void ScTable::SetCalcNotification( bool bSet )
}
-bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize ) const
+bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize ) const
{
bool bTest = true;
@@ -129,7 +132,7 @@ bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize ) cons
bTest = pOutlineTable->TestInsertRow(nSize);
for (SCCOL i=nStartCol; (i<=nEndCol) && bTest; i++)
- bTest = aCol[i].TestInsertRow( nSize );
+ bTest = aCol[i].TestInsertRow(nStartRow, nSize);
return bTest;
}
@@ -850,6 +853,106 @@ void ScTable::MixMarked(
aCol[i].MixMarked(rCxt, rMark, nFunction, bSkipEmpty, pSrcTab->aCol[i]);
}
+namespace {
+
+class TransClipHandler
+{
+ ScTable& mrClipTab;
+ SCTAB mnSrcTab;
+ SCCOL mnSrcCol;
+ size_t mnTopRow;
+ SCROW mnTransRow;
+ bool mbAsLink;
+ bool mbWasCut;
+
+ ScAddress getDestPos(size_t nRow) const
+ {
+ return ScAddress(static_cast<SCCOL>(nRow-mnTopRow), mnTransRow, mrClipTab.GetTab());
+ }
+
+ ScFormulaCell* createRefCell(size_t nSrcRow, const ScAddress& rDestPos) const
+ {
+ ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
+ ScSingleRefData aRef;
+ aRef.InitAddress(aSrcPos); // Absolute reference.
+ aRef.SetFlag3D(true);
+
+ ScTokenArray aArr;
+ aArr.AddSingleReference(aRef);
+ return new ScFormulaCell(&mrClipTab.GetDoc(), rDestPos, &aArr);
+ }
+
+ void setLink(size_t nRow)
+ {
+ SCCOL nTransCol = nRow - mnTopRow;
+ mrClipTab.SetFormulaCell(
+ nTransCol, mnTransRow, createRefCell(nRow, getDestPos(nRow)));
+ }
+
+public:
+ TransClipHandler(ScTable& rClipTab, SCTAB nSrcTab, SCCOL nSrcCol, size_t nTopRow, SCROW nTransRow, bool bAsLink, bool bWasCut) :
+ mrClipTab(rClipTab), mnSrcTab(nSrcTab), mnSrcCol(nSrcCol),
+ mnTopRow(nTopRow), mnTransRow(nTransRow), mbAsLink(bAsLink), mbWasCut(bWasCut) {}
+
+ void operator() (size_t nRow, double fVal)
+ {
+ if (mbAsLink)
+ {
+ setLink(nRow);
+ return;
+ }
+
+ SCCOL nTransCol = nRow - mnTopRow;
+ mrClipTab.SetValue(nTransCol, mnTransRow, fVal);
+ }
+
+ void operator() (size_t nRow, const OUString& rStr)
+ {
+ if (mbAsLink)
+ {
+ setLink(nRow);
+ return;
+ }
+
+ SCCOL nTransCol = nRow - mnTopRow;
+ mrClipTab.SetRawString(nTransCol, mnTransRow, rStr);
+ }
+
+ void operator() (size_t nRow, const EditTextObject* p)
+ {
+ if (mbAsLink)
+ {
+ setLink(nRow);
+ return;
+ }
+
+ SCCOL nTransCol = nRow - mnTopRow;
+ mrClipTab.SetEditText(nTransCol, mnTransRow, ScEditUtil::Clone(*p, mrClipTab.GetDoc()));
+ }
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ if (mbAsLink)
+ {
+ setLink(nRow);
+ return;
+ }
+
+ ScFormulaCell* pNew = new ScFormulaCell(
+ *p, mrClipTab.GetDoc(), getDestPos(nRow), SC_CLONECELL_STARTLISTENING);
+
+ // Referenzen drehen
+ // bei Cut werden Referenzen spaeter per UpdateTranspose angepasst
+
+ if (!mbWasCut)
+ pNew->TransposeReference();
+
+ SCCOL nTransCol = nRow - mnTopRow;
+ mrClipTab.SetFormulaCell(nTransCol, mnTransRow, pNew);
+ }
+};
+
+}
void ScTable::TransposeClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
ScTable* pTransClip, sal_uInt16 nFlags, bool bAsLink )
@@ -861,8 +964,6 @@ void ScTable::TransposeClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
{
SCROW nRow;
- ScBaseCell* pCell;
-
if ( bAsLink && nFlags == IDF_ALL )
{
// with IDF_ALL, also create links (formulas) for empty cells
@@ -882,41 +983,16 @@ void ScTable::TransposeClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
ScTokenArray aArr;
aArr.AddSingleReference( aRef );
- ScBaseCell* pNew = new ScFormulaCell( pDestDoc, aDestPos, &aArr );
- pTransClip->PutCell( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pNew );
+ pTransClip->SetFormulaCell(
+ static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1),
+ new ScFormulaCell(pDestDoc, aDestPos, &aArr));
}
}
else
{
- ScColumnIterator aIter( &aCol[nCol], nRow1, nRow2 );
- while (aIter.Next( nRow, pCell ))
- {
- ScAddress aDestPos( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pTransClip->nTab );
- ScBaseCell* pNew;
- if ( bAsLink ) // Referenz erzeugen ?
- {
- pNew = aCol[nCol].CreateRefCell( pDestDoc, aDestPos, aIter.GetIndex(), nFlags );
- }
- else // kopieren
- {
- ScAddress aOwnPos( nCol, nRow, nTab );
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- pNew = pCell->Clone( *pDestDoc, aDestPos, SC_CLONECELL_STARTLISTENING );
-
- // Referenzen drehen
- // bei Cut werden Referenzen spaeter per UpdateTranspose angepasst
-
- if (!bWasCut)
- ((ScFormulaCell*)pNew)->TransposeReference();
- }
- else
- {
- pNew = pCell->Clone( *pDestDoc, aDestPos );
- }
- }
- pTransClip->PutCell( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pNew );
- }
+ TransClipHandler aFunc(*pTransClip, nTab, nCol, nRow1, static_cast<SCROW>(nCol-nCol1), bAsLink, bWasCut);
+ const sc::CellStoreType& rCells = aCol[nCol].maCells;
+ sc::ParseAllNonEmpty(rCells.begin(), rCells, nRow1, nRow2, aFunc);
}
// Attribute
@@ -1008,7 +1084,7 @@ void ScTable::BroadcastInArea( SCCOL nCol1, SCROW nRow1,
if (nRow2 > MAXROW) nRow2 = MAXROW;
if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
for (SCCOL i = nCol1; i <= nCol2; i++)
- aCol[i].BroadcastInArea( nRow1, nRow2 );
+ aCol[i].SetDirty(nRow1, nRow2);
}
@@ -1312,39 +1388,6 @@ bool ScTable::TestCopyScenarioTo( const ScTable* pDestTab ) const
return bOk;
}
-void ScTable::PutCell( SCCOL nCol, SCROW nRow, ScBaseCell* pCell )
-{
- if (ValidColRow(nCol,nRow))
- {
- if (pCell)
- aCol[nCol].Insert( nRow, pCell );
- else
- aCol[nCol].Delete( nRow );
- }
-}
-
-
-void ScTable::PutCell( SCCOL nCol, SCROW nRow, sal_uLong nFormatIndex, ScBaseCell* pCell )
-{
- if (ValidColRow(nCol,nRow))
- {
- if (pCell)
- aCol[nCol].Insert( nRow, nFormatIndex, pCell );
- else
- aCol[nCol].Delete( nRow );
- }
-}
-
-
-void ScTable::PutCell( const ScAddress& rPos, ScBaseCell* pCell )
-{
- if (pCell)
- aCol[rPos.Col()].Insert( rPos.Row(), pCell );
- else
- aCol[rPos.Col()].Delete( rPos.Row() );
-}
-
-
bool ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const String& rString,
ScSetStringParam* pParam )
{
@@ -1417,6 +1460,11 @@ void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
aCol[nCol].SetValue( nRow, rVal );
}
+void ScTable::SetRawString( SCCOL nCol, SCROW nRow, const OUString& rStr )
+{
+ if (ValidColRow(nCol, nRow))
+ aCol[nCol].SetRawString(nRow, rStr);
+}
void ScTable::GetString( SCCOL nCol, SCROW nRow, OUString& rString ) const
{
@@ -1530,14 +1578,12 @@ CellType ScTable::GetCellType( SCCOL nCol, SCROW nRow ) const
return CELLTYPE_NONE;
}
-
-ScBaseCell* ScTable::GetCell( SCCOL nCol, SCROW nRow ) const
+ScRefCellValue ScTable::GetCellValue( SCCOL nCol, SCROW nRow ) const
{
- if (ValidColRow( nCol, nRow ))
- return aCol[nCol].GetCell( nRow );
+ if (!ValidColRow(nCol, nRow))
+ return ScRefCellValue();
- OSL_FAIL("GetCell: out of range");
- return NULL;
+ return aCol[nCol].GetCellValue(nRow);
}
void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
@@ -1629,7 +1675,7 @@ void ScTable::SetDirty( const ScRange& rRange )
pDocument->SetAutoCalc( false ); // Mehrfachberechnungen vermeiden
SCCOL nCol2 = rRange.aEnd.Col();
for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
- aCol[i].SetDirty( rRange );
+ aCol[i].SetDirty(rRange.aStart.Row(), rRange.aEnd.Row());
pDocument->SetAutoCalc( bOldAutoCalc );
}
@@ -1717,6 +1763,13 @@ void ScTable::CalcAfterLoad()
for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].CalcAfterLoad();
}
+bool ScTable::IsEmptyData( SCCOL nCol ) const
+{
+ if (!ValidCol(nCol))
+ return true;
+
+ return aCol[nCol].IsEmptyData();
+}
void ScTable::ResetChanged( const ScRange& rRange )
{
@@ -2001,34 +2054,35 @@ void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCC
bool ScTable::HasBlockMatrixFragment( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
{
- // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
- sal_uInt16 nEdges;
+ using namespace sc;
+
+ sal_uInt16 nEdges = 0;
if ( nCol1 == nCol2 )
{ // linke und rechte Spalte
- const sal_uInt16 n = 4 | 16;
+ const sal_uInt16 n = MatrixEdgeLeft | MatrixEdgeRight;
nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, n );
// nicht (4 und 16) oder 1 oder 32
- if ( nEdges && (((nEdges & n) != n) || (nEdges & 33)) )
+ if (nEdges && (((nEdges & n) != n) || (nEdges & (MatrixEdgeInside|MatrixEdgeOpen))))
return true; // linke oder rechte Kante fehlt oder offen
}
else
{ // linke Spalte
- nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, 4 );
+ nEdges = aCol[nCol1].GetBlockMatrixEdges(nRow1, nRow2, MatrixEdgeLeft);
// nicht 4 oder 1 oder 32
- if ( nEdges && (((nEdges & 4) != 4) || (nEdges & 33)) )
+ if (nEdges && (((nEdges & MatrixEdgeLeft) != MatrixEdgeLeft) || (nEdges & (MatrixEdgeInside|MatrixEdgeOpen))))
return true; // linke Kante fehlt oder offen
// rechte Spalte
- nEdges = aCol[nCol2].GetBlockMatrixEdges( nRow1, nRow2, 16 );
+ nEdges = aCol[nCol2].GetBlockMatrixEdges(nRow1, nRow2, MatrixEdgeRight);
// nicht 16 oder 1 oder 32
- if ( nEdges && (((nEdges & 16) != 16) || (nEdges & 33)) )
+ if (nEdges && (((nEdges & MatrixEdgeRight) != MatrixEdgeRight) || (nEdges & (MatrixEdgeInside|MatrixEdgeOpen))))
return true; // rechte Kante fehlt oder offen
}
if ( nRow1 == nRow2 )
{ // obere und untere Zeile
bool bOpen = false;
- const sal_uInt16 n = 2 | 8;
+ const sal_uInt16 n = MatrixEdgeBottom | MatrixEdgeTop;
for ( SCCOL i=nCol1; i<=nCol2; i++)
{
nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow1, n );
@@ -2036,11 +2090,11 @@ bool ScTable::HasBlockMatrixFragment( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCR
{
if ( (nEdges & n) != n )
return true; // obere oder untere Kante fehlt
- if ( nEdges & 4 )
+ if (nEdges & MatrixEdgeLeft)
bOpen = true; // linke Kante oeffnet, weitersehen
else if ( !bOpen )
return true; // es gibt was, was nicht geoeffnet wurde
- if ( nEdges & 16 )
+ if (nEdges & MatrixEdgeRight)
bOpen = false; // rechte Kante schliesst
}
}
@@ -2064,11 +2118,11 @@ bool ScTable::HasBlockMatrixFragment( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCR
// in unterer Zeile keine untere Kante
if ( (nEdges & n) != n )
return true;
- if ( nEdges & 4 )
+ if (nEdges & MatrixEdgeLeft)
bOpen = true; // linke Kante oeffnet, weitersehen
else if ( !bOpen )
return true; // es gibt was, was nicht geoeffnet wurde
- if ( nEdges & 16 )
+ if (nEdges & MatrixEdgeRight)
bOpen = false; // rechte Kante schliesst
}
}
@@ -3332,84 +3386,109 @@ short DiffSign( T a, T b )
(a>b) ? 1 : 0;
}
+namespace {
+
+class OutlineArrayFinder
+{
+ ScRange maRef;
+ SCCOL mnCol;
+ SCTAB mnTab;
+ ScOutlineArray* mpArray;
+ bool mbSizeChanged;
+
+public:
+ OutlineArrayFinder(const ScRange& rRef, SCCOL nCol, SCTAB nTab, ScOutlineArray* pArray, bool bSizeChanged) :
+ maRef(rRef), mnCol(nCol), mnTab(nTab), mpArray(pArray),
+ mbSizeChanged(bSizeChanged) {}
+
+ bool operator() (size_t nRow, const ScFormulaCell* pCell)
+ {
+ SCROW nRow2 = static_cast<SCROW>(nRow);
+
+ if (!pCell->HasRefListExpressibleAsOneReference(maRef))
+ return false;
+
+ if (maRef.aStart.Row() != nRow2 || maRef.aEnd.Row() != nRow2 ||
+ maRef.aStart.Tab() != mnTab || maRef.aEnd.Tab() != mnTab)
+ return false;
+
+ if (DiffSign(maRef.aStart.Col(), mnCol) != DiffSign(maRef.aEnd.Col(), mnCol))
+ return false;
+
+ return mpArray->Insert(maRef.aStart.Col(), maRef.aEnd.Col(), mbSizeChanged);
+ }
+};
+
+}
void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
{
+ typedef mdds::flat_segment_tree<SCROW, bool> UsedRowsType;
+
bool bSizeChanged = false;
SCCOL nCol;
SCROW nRow;
- SCROW i;
bool bFound;
ScOutlineArray* pArray;
- ScBaseCell* pCell;
ScRange aRef;
StartOutlineTable();
// Zeilen
- SCROW nCount = nEndRow-nStartRow+1;
- bool* pUsed = new bool[nCount];
- for (i=0; i<nCount; i++)
- pUsed[i] = false;
+ UsedRowsType aUsed(0, MAXROW+1, false);
for (nCol=nStartCol; nCol<=nEndCol; nCol++)
- if (!aCol[nCol].IsEmptyData())
- aCol[nCol].FindUsed( nStartRow, nEndRow, pUsed );
+ aCol[nCol].FindUsed(nStartRow, nEndRow, aUsed);
+ aUsed.build_tree();
pArray = pOutlineTable->GetRowArray();
for (nRow=nStartRow; nRow<=nEndRow; nRow++)
- if (pUsed[nRow-nStartRow])
+ {
+ bool bUsed = false;
+ SCROW nLastRow = nRow;
+ aUsed.search_tree(nRow, bUsed, NULL, &nLastRow);
+ if (!bUsed)
{
- bFound = false;
- for (nCol=nStartCol; nCol<=nEndCol && !bFound; nCol++)
- if (!aCol[nCol].IsEmptyData())
- {
- pCell = aCol[nCol].GetCell( nRow );
- if (pCell)
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( aRef ))
- if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol &&
- aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
- DiffSign( aRef.aStart.Row(), nRow ) ==
- DiffSign( aRef.aEnd.Row(), nRow ) )
- {
- if (pArray->Insert( aRef.aStart.Row(), aRef.aEnd.Row(), bSizeChanged ))
- {
- bFound = true;
- }
- }
- }
+ nRow = nLastRow;
+ continue;
}
- delete[] pUsed;
+ bFound = false;
+ for (nCol=nStartCol; nCol<=nEndCol && !bFound; nCol++)
+ {
+ ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
- // Spalten
+ if (aCell.meType != CELLTYPE_FORMULA)
+ continue;
- pArray = pOutlineTable->GetColArray();
- for (nCol=nStartCol; nCol<=nEndCol; nCol++)
- {
- if (!aCol[nCol].IsEmptyData())
- {
- bFound = false;
- ScColumnIterator aIter( &aCol[nCol], nStartRow, nEndRow );
- while ( aIter.Next( nRow, pCell ) && !bFound )
+ if (!aCell.mpFormula->HasRefListExpressibleAsOneReference(aRef))
+ continue;
+
+ if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol &&
+ aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
+ DiffSign( aRef.aStart.Row(), nRow ) ==
+ DiffSign( aRef.aEnd.Row(), nRow ) )
{
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( aRef ))
- if ( aRef.aStart.Row() == nRow && aRef.aEnd.Row() == nRow &&
- aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
- DiffSign( aRef.aStart.Col(), nCol ) ==
- DiffSign( aRef.aEnd.Col(), nCol ) )
- {
- if (pArray->Insert( aRef.aStart.Col(), aRef.aEnd.Col(), bSizeChanged ))
- {
- bFound = true;
- }
- }
+ if (pArray->Insert( aRef.aStart.Row(), aRef.aEnd.Row(), bSizeChanged ))
+ {
+ bFound = true;
+ }
}
}
}
+
+ // Column
+ pArray = pOutlineTable->GetColArray();
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ if (aCol[nCol].IsEmptyData())
+ continue;
+
+ OutlineArrayFinder aFunc(aRef, nCol, nTab, pArray, bSizeChanged);
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
+ sc::FindFormula(aCol[nCol].maCells, nStartRow, nEndRow, aFunc);
+ }
}
// CopyData - fuer Query in anderen Bereich
@@ -3433,27 +3512,26 @@ void ScTable::CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW n
{
aSrc.SetCol( nCol );
aDest.SetCol( nDestX );
- ScBaseCell* pCell = GetCell( nCol, nRow );
- if (pCell)
+ ScCellValue aCell;
+ aCell.assign(*pDocument, ScAddress(nCol, nRow, nTab));
+
+ if (aCell.meType == CELLTYPE_FORMULA)
{
- pCell = pCell->Clone( *pDocument );
- if (pCell->GetCellType() == CELLTYPE_FORMULA)
- {
- ((ScFormulaCell*)pCell)->UpdateReference( URM_COPY, aRange,
- ((SCsCOL) nDestCol) - ((SCsCOL) nStartCol),
- ((SCsROW) nDestRow) - ((SCsROW) nStartRow),
- ((SCsTAB) nDestTab) - ((SCsTAB) nTab) );
- ((ScFormulaCell*)pCell)->aPos = aDest;
- }
+ aCell.mpFormula->UpdateReference( URM_COPY, aRange,
+ ((SCsCOL) nDestCol) - ((SCsCOL) nStartCol),
+ ((SCsROW) nDestRow) - ((SCsROW) nStartRow),
+ ((SCsTAB) nDestTab) - ((SCsTAB) nTab) );
+ aCell.mpFormula->aPos = aDest;
}
+
if (bThisTab)
{
- PutCell( nDestX, nDestY, pCell );
+ aCell.release(aCol[nDestX], nDestY);
SetPattern( nDestX, nDestY, *GetPattern( nCol, nRow ), true );
}
else
{
- pDocument->PutCell( aDest, pCell );
+ aCell.release(*pDocument, aDest);
pDocument->SetPattern( aDest, *GetPattern( nCol, nRow ), true );
}
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 0058cacd44b2..e003aa714b43 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -54,6 +54,7 @@
#include "docpool.hxx"
#include "cellvalue.hxx"
#include "tokenarray.hxx"
+#include "mtvcellfunc.hxx"
#include <vector>
#include <boost/unordered_set.hpp>
@@ -199,7 +200,7 @@ short Compare( const String &sInput1, const String &sInput2,
struct ScSortInfo
{
- ScBaseCell* pCell;
+ ScRefCellValue maCell;
SCCOLROW nOrg;
DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo );
};
@@ -275,9 +276,8 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
ScColumn* pCol = &aCol[nCol];
for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ )
{
-//2do: FillSortInfo an ScColumn und Array abklappern statt Search in GetCell
ScSortInfo* pInfo = pArray->Get( nSort, nRow );
- pInfo->pCell = pCol->GetCell( nRow );
+ pInfo->maCell = pCol->GetCellValue(nRow);
pInfo->nOrg = nRow;
}
}
@@ -291,7 +291,7 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
nCol <= static_cast<SCCOL>(nInd2); nCol++ )
{
ScSortInfo* pInfo = pArray->Get( nSort, nCol );
- pInfo->pCell = GetCell( nCol, nRow );
+ pInfo->maCell = GetCellValue(nCol, nRow);
pInfo->nOrg = nCol;
}
}
@@ -370,27 +370,24 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
}
}
-short ScTable::CompareCell( sal_uInt16 nSort,
- ScBaseCell* pCell1, SCCOL nCell1Col, SCROW nCell1Row,
- ScBaseCell* pCell2, SCCOL nCell2Col, SCROW nCell2Row ) const
+short ScTable::CompareCell(
+ sal_uInt16 nSort,
+ ScRefCellValue& rCell1, SCCOL nCell1Col, SCROW nCell1Row,
+ ScRefCellValue& rCell2, SCCOL nCell2Col, SCROW nCell2Row ) const
{
short nRes = 0;
- CellType eType1 = CELLTYPE_NONE, eType2 = CELLTYPE_NONE;
- if (pCell1)
- eType1 = pCell1->GetCellType();
- if (pCell2)
- eType2 = pCell2->GetCellType();
+ CellType eType1 = rCell1.meType, eType2 = rCell2.meType;
- if (pCell1)
+ if (!rCell1.isEmpty())
{
- if (pCell2)
+ if (!rCell2.isEmpty())
{
bool bStr1 = ( eType1 != CELLTYPE_VALUE );
- if ( eType1 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell1)->IsValue() )
+ if (eType1 == CELLTYPE_FORMULA && rCell1.mpFormula->IsValue())
bStr1 = false;
bool bStr2 = ( eType2 != CELLTYPE_VALUE );
- if ( eType2 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell2)->IsValue() )
+ if (eType2 == CELLTYPE_FORMULA && rCell2.mpFormula->IsValue())
bStr2 = false;
if ( bStr1 && bStr2 ) // nur Strings untereinander als String vergleichen!
@@ -398,11 +395,11 @@ short ScTable::CompareCell( sal_uInt16 nSort,
OUString aStr1;
OUString aStr2;
if (eType1 == CELLTYPE_STRING)
- aStr1 = ((ScStringCell*)pCell1)->GetString();
+ aStr1 = *rCell1.mpString;
else
GetString(nCell1Col, nCell1Row, aStr1);
if (eType2 == CELLTYPE_STRING)
- aStr2 = ((ScStringCell*)pCell2)->GetString();
+ aStr2 = *rCell2.mpString;
else
GetString(nCell2Col, nCell2Row, aStr2);
@@ -445,20 +442,8 @@ short ScTable::CompareCell( sal_uInt16 nSort,
nRes = -1; // Zahl vorne
else // Zahlen untereinander
{
- double nVal1;
- double nVal2;
- if (eType1 == CELLTYPE_VALUE)
- nVal1 = ((ScValueCell*)pCell1)->GetValue();
- else if (eType1 == CELLTYPE_FORMULA)
- nVal1 = ((ScFormulaCell*)pCell1)->GetValue();
- else
- nVal1 = 0;
- if (eType2 == CELLTYPE_VALUE)
- nVal2 = ((ScValueCell*)pCell2)->GetValue();
- else if (eType2 == CELLTYPE_FORMULA)
- nVal2 = ((ScFormulaCell*)pCell2)->GetValue();
- else
- nVal2 = 0;
+ double nVal1 = rCell1.getValue();
+ double nVal2 = rCell2.getValue();
if (nVal1 < nVal2)
nRes = -1;
else if (nVal1 > nVal2)
@@ -472,7 +457,7 @@ short ScTable::CompareCell( sal_uInt16 nSort,
}
else
{
- if ( pCell2 )
+ if (!rCell2.isEmpty())
nRes = 1;
else
nRes = 0; // beide leer
@@ -490,12 +475,12 @@ short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nInd
ScSortInfo* pInfo2 = pArray->Get( nSort, nIndex2 );
if ( aSortParam.bByRow )
nRes = CompareCell( nSort,
- pInfo1->pCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo1->nOrg,
- pInfo2->pCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo2->nOrg );
+ pInfo1->maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo1->nOrg,
+ pInfo2->maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo2->nOrg );
else
nRes = CompareCell( nSort,
- pInfo1->pCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.maKeyState[nSort].nField,
- pInfo2->pCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.maKeyState[nSort].nField );
+ pInfo1->maCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.maKeyState[nSort].nField,
+ pInfo2->maCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.maKeyState[nSort].nField );
} while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
if( nRes == 0 )
{
@@ -692,9 +677,9 @@ short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
do
{
SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
- ScBaseCell* pCell1 = aCol[nCol].GetCell( nIndex1 );
- ScBaseCell* pCell2 = aCol[nCol].GetCell( nIndex2 );
- nRes = CompareCell( nSort, pCell1, nCol, nIndex1, pCell2, nCol, nIndex2 );
+ ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1);
+ ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2);
+ nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2);
} while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
}
else
@@ -702,10 +687,10 @@ short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
do
{
SCROW nRow = aSortParam.maKeyState[nSort].nField;
- ScBaseCell* pCell1 = aCol[nIndex1].GetCell( nRow );
- ScBaseCell* pCell2 = aCol[nIndex2].GetCell( nRow );
- nRes = CompareCell( nSort, pCell1, static_cast<SCCOL>(nIndex1),
- nRow, pCell2, static_cast<SCCOL>(nIndex2), nRow );
+ ScRefCellValue aCell1 = aCol[nIndex1].GetCellValue(nRow);
+ ScRefCellValue aCell2 = aCol[nIndex2].GetCellValue(nRow);
+ nRes = CompareCell( nSort, aCell1, static_cast<SCCOL>(nIndex1),
+ nRow, aCell2, static_cast<SCCOL>(nIndex2), nRow );
} while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
}
return nRes;
@@ -783,9 +768,39 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p
DestroySortCollator();
}
+namespace {
+
+class SubTotalRowFinder
+{
+ const ScTable& mrTab;
+ const ScSubTotalParam& mrParam;
+
+public:
+ SubTotalRowFinder(const ScTable& rTab, const ScSubTotalParam& rParam) :
+ mrTab(rTab), mrParam(rParam) {}
+
+ bool operator() (size_t nRow, const ScFormulaCell* pCell)
+ {
+ if (!pCell->IsSubTotal())
+ return false;
-// Testen, ob beim Loeschen von Zwischenergebnissen andere Daten mit geloescht werden
-// (fuer Hinweis-Box)
+ SCCOL nStartCol = mrParam.nCol1;
+ SCCOL nEndCol = mrParam.nCol2;
+
+ for (SCCOL i = 0; i <= MAXCOL; ++i)
+ {
+ if (nStartCol <= i && i <= nEndCol)
+ continue;
+
+ if (mrTab.HasData(i, nRow))
+ return true;
+ }
+
+ return false;
+ }
+};
+
+}
bool ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam )
{
@@ -794,31 +809,43 @@ bool ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam )
SCCOL nEndCol = rParam.nCol2;
SCROW nEndRow = rParam.nRow2;
- SCCOL nCol;
- SCROW nRow;
- ScBaseCell* pCell;
-
- bool bWillDelete = false;
- for ( nCol=nStartCol; nCol<=nEndCol && !bWillDelete; nCol++ )
+ for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
{
- ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
- while ( aIter.Next( nRow, pCell ) && !bWillDelete )
- {
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- if (((ScFormulaCell*)pCell)->IsSubTotal())
- {
- for (SCCOL nTestCol=0; nTestCol<=MAXCOL; nTestCol++)
- if (nTestCol<nStartCol || nTestCol>nEndCol)
- if (aCol[nTestCol].HasDataAt(nRow))
- bWillDelete = true;
- }
- }
+ const sc::CellStoreType& rCells = aCol[nCol].maCells;
+ SubTotalRowFinder aFunc(*this, rParam);
+ std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
+ sc::FindFormula(rCells, nStartRow, nEndRow, aFunc);
+ if (aPos.first != rCells.end())
+ return true;
}
- return bWillDelete;
+ return false;
}
-// alte Ergebnisse loeschen
-// rParam.nRow2 wird veraendert !
+namespace {
+
+class RemoveSubTotalsHandler
+{
+ std::vector<SCROW> maRemoved;
+public:
+
+ void operator() (size_t nRow, const ScFormulaCell* p)
+ {
+ if (p->IsSubTotal())
+ maRemoved.push_back(nRow);
+ }
+
+ void getRows(std::vector<SCROW>& rRows)
+ {
+ // Sort and remove duplicates.
+ std::sort(maRemoved.begin(), maRemoved.end());
+ std::vector<SCROW>::iterator it = std::unique(maRemoved.begin(), maRemoved.end());
+ maRemoved.erase(it, maRemoved.end());
+
+ maRemoved.swap(rRows);
+ }
+};
+
+}
void ScTable::RemoveSubTotals( ScSubTotalParam& rParam )
{
@@ -827,27 +854,25 @@ void ScTable::RemoveSubTotals( ScSubTotalParam& rParam )
SCCOL nEndCol = rParam.nCol2;
SCROW nEndRow = rParam.nRow2; // wird veraendert
- SCCOL nCol;
- SCROW nRow;
- ScBaseCell* pCell;
+ RemoveSubTotalsHandler aFunc;
+ for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
+ {
+ const sc::CellStoreType& rCells = aCol[nCol].maCells;
+ sc::ParseFormula(rCells.begin(), rCells, nStartRow, nEndRow, aFunc);
+ }
+
+ std::vector<SCROW> aRows;
+ aFunc.getRows(aRows);
- for ( nCol=nStartCol; nCol<=nEndCol; nCol++ )
+ std::vector<SCROW>::reverse_iterator it = aRows.rbegin(), itEnd = aRows.rend();
+ for (; it != itEnd; ++it)
{
- ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
- while ( aIter.Next( nRow, pCell ) )
- {
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- if (((ScFormulaCell*)pCell)->IsSubTotal())
- {
- RemoveRowBreak(nRow+1, false, true);
- pDocument->DeleteRow( 0,nTab, MAXCOL,nTab, nRow, 1 );
- --nEndRow;
- aIter = ScColumnIterator( &aCol[nCol],nRow,nEndRow );
- }
- }
+ SCROW nRow = *it;
+ RemoveRowBreak(nRow+1, false, true);
+ pDocument->DeleteRow(0, nTab, MAXCOL, nTab, nRow, 1);
}
- rParam.nRow2 = nEndRow; // neues Ende
+ rParam.nRow2 -= aRows.size();
}
// harte Zahlenformate loeschen (fuer Ergebnisformeln)
@@ -1104,9 +1129,10 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
aArr.AddDoubleReference( aRef );
aArr.AddOpCode( ocClose );
aArr.AddOpCode( ocStop );
- ScBaseCell* pCell = new ScFormulaCell( pDocument, ScAddress(
- nResCols[nResult], iEntry->nDestRow, nTab), &aArr );
- PutCell( nResCols[nResult], iEntry->nDestRow, pCell );
+ ScFormulaCell* pCell = new ScFormulaCell(
+ pDocument, ScAddress(nResCols[nResult], iEntry->nDestRow, nTab), &aArr);
+
+ SetFormulaCell(nResCols[nResult], iEntry->nDestRow, pCell);
if ( nResCols[nResult] != nGroupCol[iEntry->nGroupNo] )
{
@@ -1221,19 +1247,18 @@ public:
}
bool isQueryByValue(
- const ScQueryEntry::Item& rItem, SCCOL nCol, SCROW nRow, ScBaseCell* pCell)
+ const ScQueryEntry::Item& rItem, SCCOL nCol, SCROW nRow, ScRefCellValue& rCell)
{
if (rItem.meType == ScQueryEntry::ByString)
return false;
- if (pCell)
+ if (!rCell.isEmpty())
{
- if (pCell->GetCellType() == CELLTYPE_FORMULA &&
- static_cast<ScFormulaCell*>(pCell)->GetErrCode())
+ if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode())
// Error values are compared as string.
return false;
- return pCell->HasValueData();
+ return rCell.hasNumeric();
}
return mrTab.HasValueData(nCol, nRow);
@@ -1241,7 +1266,7 @@ public:
bool isQueryByString(
const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
- SCCOL nCol, SCROW nRow, const ScBaseCell* pCell)
+ SCCOL nCol, SCROW nRow, ScRefCellValue& rCell)
{
if (isTextMatchOp(rEntry))
return true;
@@ -1249,28 +1274,28 @@ public:
if (rItem.meType != ScQueryEntry::ByString)
return false;
- if (pCell)
- return pCell->HasStringData();
+ if (!rCell.isEmpty())
+ return rCell.hasString();
return mrTab.HasStringData(nCol, nRow);
}
std::pair<bool,bool> compareByValue(
- const ScBaseCell* pCell, SCCOL nCol, SCROW nRow,
+ const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow,
const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
{
bool bOk = false;
bool bTestEqual = false;
double nCellVal;
- if ( pCell )
+ if (!rCell.isEmpty())
{
- switch ( pCell->GetCellType() )
+ switch (rCell.meType)
{
case CELLTYPE_VALUE :
- nCellVal = ((ScValueCell*)pCell)->GetValue();
+ nCellVal = rCell.mfValue;
break;
case CELLTYPE_FORMULA :
- nCellVal = ((ScFormulaCell*)pCell)->GetValue();
+ nCellVal = rCell.mpFormula->GetValue();
break;
default:
nCellVal = 0.0;
@@ -1342,7 +1367,7 @@ public:
}
std::pair<bool,bool> compareByString(
- ScBaseCell* pCell, SCROW nRow, const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
+ ScRefCellValue& rCell, SCROW nRow, const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
{
bool bOk = false;
bool bTestEqual = false;
@@ -1352,19 +1377,17 @@ public:
// may have to do partial textural comparison.
bMatchWholeCell = false;
- if ( pCell )
+ if (!rCell.isEmpty())
{
- if (pCell->GetCellType() == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode())
+ if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode())
{
// Error cell is evaluated as string (for now).
- aCellStr = ScGlobal::GetErrorString(static_cast<ScFormulaCell*>(pCell)->GetErrCode());
+ aCellStr = ScGlobal::GetErrorString(rCell.mpFormula->GetErrCode());
}
else
{
sal_uLong nFormat = mrTab.GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow );
- ScRefCellValue aCell;
- aCell.assign(*pCell);
- ScCellFormat::GetInputString(aCell, nFormat, aCellStr, *mrDoc.GetFormatTable());
+ ScCellFormat::GetInputString(rCell, nFormat, aCellStr, *mrDoc.GetFormatTable());
}
}
else
@@ -1524,8 +1547,7 @@ public:
}
bool ScTable::ValidQuery(
- SCROW nRow, const ScQueryParam& rParam, ScBaseCell* pCell,
- bool* pbTestEqualCondition)
+ SCROW nRow, const ScQueryParam& rParam, ScRefCellValue* pCell, bool* pbTestEqualCondition)
{
if (!rParam.GetEntry(0).bDoQuery)
return true;
@@ -1546,8 +1568,11 @@ bool ScTable::ValidQuery(
SCCOL nCol = static_cast<SCCOL>(rEntry.nField);
// we can only handle one single direct query
- if (!pCell || it != itBeg)
- pCell = GetCell(nCol, nRow);
+ ScRefCellValue aCell;
+ if (pCell && it == itBeg)
+ aCell = *pCell;
+ else
+ aCell = GetCellValue(nCol, nRow);
std::pair<bool,bool> aRes(false, false);
@@ -1568,17 +1593,17 @@ bool ScTable::ValidQuery(
for (; itr != itrEnd; ++itr)
{
- if (aEval.isQueryByValue(*itr, nCol, nRow, pCell))
+ if (aEval.isQueryByValue(*itr, nCol, nRow, aCell))
{
std::pair<bool,bool> aThisRes =
- aEval.compareByValue(pCell, nCol, nRow, rEntry, *itr);
+ aEval.compareByValue(aCell, nCol, nRow, rEntry, *itr);
aRes.first |= aThisRes.first;
aRes.second |= aThisRes.second;
}
- else if (aEval.isQueryByString(rEntry, *itr, nCol, nRow, pCell))
+ else if (aEval.isQueryByString(rEntry, *itr, nCol, nRow, aCell))
{
std::pair<bool,bool> aThisRes =
- aEval.compareByString(pCell, nRow, rEntry, *itr);
+ aEval.compareByString(aCell, nRow, rEntry, *itr);
aRes.first |= aThisRes.first;
aRes.second |= aThisRes.second;
}
@@ -1652,11 +1677,10 @@ void ScTable::TopTenQuery( ScQueryParam& rParam )
ScSortInfo** ppInfo = pArray->GetFirstArray();
SCSIZE nValidCount = nCount;
// keine Note-/Leerzellen zaehlen, sind ans Ende sortiert
- while ( nValidCount > 0 && (ppInfo[nValidCount-1]->pCell == NULL) )
+ while (nValidCount > 0 && ppInfo[nValidCount-1]->maCell.isEmpty())
nValidCount--;
// keine Strings zaehlen, sind zwischen Value und Leer
- while ( nValidCount > 0
- && ppInfo[nValidCount-1]->pCell->HasStringData() )
+ while (nValidCount > 0 && ppInfo[nValidCount-1]->maCell.hasString())
nValidCount--;
if ( nValidCount > 0 )
{
@@ -1710,14 +1734,9 @@ void ScTable::TopTenQuery( ScQueryParam& rParam )
// added to avoid warnings
}
}
- ScBaseCell* pCell = ppInfo[nOffset]->pCell;
- if ( pCell->HasValueData() )
- {
- if ( pCell->GetCellType() == CELLTYPE_VALUE )
- rItem.mfVal = ((ScValueCell*)pCell)->GetValue();
- else
- rItem.mfVal = ((ScFormulaCell*)pCell)->GetValue();
- }
+ ScRefCellValue aCell = ppInfo[nOffset]->maCell;
+ if (aCell.hasNumeric())
+ rItem.mfVal = aCell.getValue();
else
{
OSL_FAIL( "TopTenQuery: pCell no ValueData" );
@@ -1870,13 +1889,15 @@ SCSIZE ScTable::Query(ScQueryParam& rParamOrg, bool bKeepSub)
{
for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
{
- ScBaseCell* pCell;
- pCell = GetCell( nCol, j );
- if ( pCell )
- if ( pCell->GetCellType() == CELLTYPE_FORMULA )
- if (((ScFormulaCell*)pCell)->IsSubTotal())
- if (RefVisible((ScFormulaCell*)pCell))
- bValid = true;
+ ScRefCellValue aCell = GetCellValue(nCol, j);
+ if (aCell.meType != CELLTYPE_FORMULA)
+ continue;
+
+ if (!aCell.mpFormula->IsSubTotal())
+ continue;
+
+ if (RefVisible(aCell.mpFormula))
+ bValid = true;
}
}
if (bValid)
@@ -2212,6 +2233,16 @@ bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& r
return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit );
}
+ScDocument& ScTable::GetDoc()
+{
+ return *pDocument;
+}
+
+const ScDocument& ScTable::GetDoc() const
+{
+ return *pDocument;
+}
+
SCSIZE ScTable::GetCellCount(SCCOL nCol) const
{
return aCol[nCol].GetCellCount();
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index df6f52cb502b..4c835b2d436e 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -59,6 +59,7 @@
#include "progress.hxx"
#include "segmenttree.hxx"
#include "conditio.hxx"
+#include "editutil.hxx"
#include <math.h>
#include <boost/scoped_ptr.hpp>
@@ -69,9 +70,9 @@
extern sal_uInt16 nScFillModeMouseModifier; // global.cxx
-// -----------------------------------------------------------------------
+namespace {
-static short lcl_DecompValueString( String& aValue, sal_Int32& nVal, sal_uInt16* pMinDigits = NULL )
+short lcl_DecompValueString( String& aValue, sal_Int32& nVal, sal_uInt16* pMinDigits = NULL )
{
if ( !aValue.Len() )
{
@@ -126,7 +127,7 @@ static short lcl_DecompValueString( String& aValue, sal_Int32& nVal, sal_uInt16*
return 0;
}
-static OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
+OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
{
if ( nMinDigits <= 1 )
return OUString::number( nValue ); // simple case...
@@ -146,31 +147,43 @@ static OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
}
}
-static ScBaseCell * lcl_getSuffixCell( ScDocument* pDocument, sal_Int32 nValue,
- sal_uInt16 nDigits, const String& rSuffix, CellType eCellType,
- bool bIsOrdinalSuffix )
+void setSuffixCell(
+ ScColumn& rColumn, SCROW nRow, sal_Int32 nValue, sal_uInt16 nDigits, const OUString& rSuffix,
+ CellType eCellType, bool bIsOrdinalSuffix )
{
- String aValue( lcl_ValueString( nValue, nDigits ));
+ ScDocument& rDoc = rColumn.GetDoc();
+ OUString aValue = lcl_ValueString(nValue, nDigits);
if (!bIsOrdinalSuffix)
- return new ScStringCell( aValue += rSuffix);
+ {
+ rColumn.SetRawString(nRow, aValue += rSuffix);
+ return;
+ }
- String aOrdinalSuffix( ScGlobal::GetOrdinalSuffix( nValue));
+ OUString aOrdinalSuffix = ScGlobal::GetOrdinalSuffix(nValue);
if (eCellType != CELLTYPE_EDIT)
- return new ScStringCell( aValue += aOrdinalSuffix);
+ {
+ rColumn.SetRawString(nRow, aValue += aOrdinalSuffix);
+ return;
+ }
- EditEngine aEngine( pDocument->GetEnginePool() );
- aEngine.SetEditTextObjectPool(pDocument->GetEditPool());
+ EditEngine aEngine(rDoc.GetEnginePool());
+ aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
SfxItemSet aAttr = aEngine.GetEmptyItemSet();
aAttr.Put( SvxEscapementItem( SVX_ESCAPEMENT_SUPERSCRIPT, EE_CHAR_ESCAPEMENT));
aEngine.SetText( aValue );
- aEngine.QuickInsertText( aOrdinalSuffix, ESelection( 0, aValue.Len(), 0,
- aValue.Len() + aOrdinalSuffix.Len()));
- aEngine.QuickSetAttribs( aAttr, ESelection( 0, aValue.Len(), 0, aValue.Len() +
- aOrdinalSuffix.Len()));
+ aEngine.QuickInsertText(
+ aOrdinalSuffix,
+ ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
+
+ aEngine.QuickSetAttribs(
+ aAttr,
+ ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
// Text object instance will be owned by the cell.
- return new ScEditCell(aEngine.CreateTextObject(), pDocument);
+ rColumn.SetEditText(nRow, aEngine.CreateTextObject());
+}
+
}
void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
@@ -206,8 +219,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
SCCOL nCol = nCol1;
SCROW nRow = nRow1;
- ScBaseCell* pFirstCell = GetCell( nCol, nRow );
- CellType eCellType = pFirstCell ? pFirstCell->GetCellType() : CELLTYPE_NONE;
+ ScRefCellValue aFirstCell = GetCellValue(nCol, nRow);
+ CellType eCellType = aFirstCell.meType;
if (eCellType == CELLTYPE_VALUE)
{
@@ -220,7 +233,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
double nVal;
Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
Date aDate1 = aNullDate;
- nVal = ((ScValueCell*)pFirstCell)->GetValue();
+ nVal = aFirstCell.mfValue;
aDate1 += (long)nVal;
Date aDate2 = aNullDate;
nVal = GetValue(nCol+nAddX, nRow+nAddY);
@@ -248,10 +261,10 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bool bVal = true;
for (sal_uInt16 i=1; i<nCount && bVal; i++)
{
- ScBaseCell* pCell = GetCell(nCol,nRow);
- if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
+ ScRefCellValue aCell = GetCellValue(nCol,nRow);
+ if (aCell.meType == CELLTYPE_VALUE)
{
- nVal = ((ScValueCell*)pCell)->GetValue();
+ nVal = aCell.mfValue;
aDate2 = aNullDate + (long) nVal;
if ( eType == FILL_DAY )
{
@@ -297,7 +310,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
{
if (nCount > 1)
{
- double nVal1 = ((ScValueCell*)pFirstCell)->GetValue();
+ double nVal1 = aFirstCell.mfValue;
double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
rInc = nVal2 - nVal1;
nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
@@ -305,10 +318,10 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bool bVal = true;
for (sal_uInt16 i=1; i<nCount && bVal; i++)
{
- ScBaseCell* pCell = GetCell(nCol,nRow);
- if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
+ ScRefCellValue aCell = GetCellValue(nCol,nRow);
+ if (aCell.meType == CELLTYPE_VALUE)
{
- nVal2 = ((ScValueCell*)pCell)->GetValue();
+ nVal2 = aCell.mfValue;
double nDiff = nVal2 - nVal1;
if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
bVal = false;
@@ -383,14 +396,11 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bool bVal = true;
for (sal_uInt16 i=1; i<nCount && bVal; i++)
{
- ScBaseCell* pCell = GetCell(nCol,nRow);
- CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE;
+ ScRefCellValue aCell = GetCellValue(nCol, nRow);
+ CellType eType = aCell.meType;
if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
{
- if ( eType == CELLTYPE_STRING )
- aStr = ((ScStringCell*)pCell)->GetString();
- else
- aStr = ((ScEditCell*)pCell)->GetString();
+ aStr = aCell.getString();
aString = aStr;
nFlag2 = lcl_DecompValueString( aString, nVal2, &rMinDigits );
aStr = aString;
@@ -431,7 +441,7 @@ void ScTable::FillFormula(sal_uLong& /* nFormulaCounter */, bool /* bFirst */, S
pDocument->SetNoListening( true ); // still the wrong reference
ScAddress aAddr( nDestCol, nDestRow, nTab );
ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, *pDocument, aAddr );
- aCol[nDestCol].Insert(nDestRow, pDestCell);
+ aCol[nDestCol].SetFormulaCell(nDestRow, pDestCell);
if ( bLast && pDestCell->GetMatrixFlag() )
{
@@ -697,9 +707,6 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
nInc,nMinDigits, pListData,nListIndex);
- if (bVertical)
- aCol[nCol].ReserveSize(aCol[nCol].GetCellCount() + nFillCount);
-
if (pListData)
{
sal_uInt16 nListCount = pListData->GetSubCount();
@@ -729,7 +736,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (nListIndex == 0) nListIndex = nListCount;
--nListIndex;
}
- aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScStringCell(pListData->GetSubStr(nListIndex)));
+ aCol[nCol].SetRawString(static_cast<SCROW>(nRow), pListData->GetSubStr(nListIndex));
}
if (rInner == nIEnd) break;
@@ -759,7 +766,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
short nHeadNoneTail = 0;
sal_Int32 nStringValue = 0;
String aValue;
- ScBaseCell* pSrcCell = NULL;
+ ScRefCellValue aSrcCell;
CellType eCellType = CELLTYPE_NONE;
bool bIsOrdinalSuffix = false;
@@ -771,24 +778,25 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if ( bGetCell )
{
if (bVertical) // rInner&:=nRow, rOuter&:=nCol
- pSrcCell = aCol[nCol].GetCell( static_cast<SCROW>(nSource) );
+ aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nSource));
else // rInner&:=nCol, rOuter&:=nRow
- pSrcCell = aCol[nSource].GetCell( static_cast<SCROW>(nRow) );
+ aSrcCell = aCol[nSource].GetCellValue(static_cast<SCROW>(nRow));
+
bGetCell = false;
- if ( pSrcCell )
+ if (!aSrcCell.isEmpty())
{
- eCellType = pSrcCell->GetCellType();
- switch ( eCellType )
+ eCellType = aSrcCell.meType;
+ switch (eCellType)
{
case CELLTYPE_VALUE:
- nVal = ((ScValueCell*)pSrcCell)->GetValue();
+ nVal = aSrcCell.mfValue;
break;
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
if ( eCellType == CELLTYPE_STRING )
- aValue = ((ScStringCell*)pSrcCell)->GetString();
+ aValue = *aSrcCell.mpString;
else
- aValue = ((ScEditCell*)pSrcCell)->GetString();
+ aValue = ScEditUtil::GetString(*aSrcCell.mpEditText);
if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered )
{
nCellDigits = 0; // look at each source cell individually
@@ -812,7 +820,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
switch (eCellType)
{
case CELLTYPE_VALUE:
- aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta));
+ aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal + nDelta);
break;
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
@@ -826,16 +834,15 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
OUString aStr;
if ( nHeadNoneTail < 0 )
{
- aCol[nCol].Insert( static_cast<SCROW>(nRow),
- lcl_getSuffixCell( pDocument,
- nNextValue, nCellDigits, aValue,
- eCellType, bIsOrdinalSuffix));
+ setSuffixCell(
+ aCol[nCol], static_cast<SCROW>(nRow),
+ nNextValue, nCellDigits, aValue,
+ eCellType, bIsOrdinalSuffix);
}
else
{
aStr = aValue + lcl_ValueString( nNextValue, nCellDigits );
- aCol[nCol].Insert( static_cast<SCROW>(nRow),
- new ScStringCell( aStr));
+ aCol[nCol].SetRawString(static_cast<SCROW>(nRow), aStr);
}
}
else
@@ -844,8 +851,9 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
switch ( eCellType )
{
case CELLTYPE_STRING:
+ aCol[nCol].SetRawString(aDestPos.Row(), *aSrcCell.mpString);
case CELLTYPE_EDIT:
- aCol[nCol].Insert( aDestPos.Row(), pSrcCell->Clone( *pDocument ) );
+ aCol[nCol].SetEditText(aDestPos.Row(), aSrcCell.mpEditText->Clone());
break;
default:
{
@@ -855,8 +863,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
break;
case CELLTYPE_FORMULA :
- FillFormula( nFormulaCounter, bFirst,
- (ScFormulaCell*) pSrcCell,
+ FillFormula( nFormulaCounter, bFirst, aSrcCell.mpFormula,
static_cast<SCCOL>(nCol),
static_cast<SCROW>(nRow), (rInner == nIEnd) );
if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
@@ -1031,8 +1038,8 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n
else
nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
- ScBaseCell* pCell = GetCell( nSrcX, nSrcY );
- if ( pCell )
+ ScRefCellValue aCell = GetCellValue(nSrcX, nSrcY);
+ if (!aCell.isEmpty())
{
sal_Int32 nDelta;
if (nIndex >= 0)
@@ -1040,16 +1047,14 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n
else
nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
- CellType eType = pCell->GetCellType();
+ CellType eType = aCell.meType;
switch ( eType )
{
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
{
- if ( eType == CELLTYPE_STRING )
- aValue = ((ScStringCell*)pCell)->GetString();
- else
- aValue = ((ScEditCell*)pCell)->GetString();
+ aValue = aCell.getString();
+
if ( !(nScFillModeMouseModifier & KEY_MOD1) )
{
sal_Int32 nVal;
@@ -1070,7 +1075,7 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n
case CELLTYPE_VALUE:
{
// overflow is possible...
- double nVal = ((ScValueCell*)pCell)->GetValue();
+ double nVal = aCell.mfValue;
if ( !(nScFillModeMouseModifier & KEY_MOD1) )
nVal += (double) nDelta;
@@ -1094,19 +1099,16 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n
double nStart;
sal_Int32 nVal = 0;
short nHeadNoneTail = 0;
- ScBaseCell* pCell = GetCell( nCol1, nRow1 );
- if ( pCell )
+ ScRefCellValue aCell = GetCellValue(nCol1, nRow1);
+ if (!aCell.isEmpty())
{
- CellType eType = pCell->GetCellType();
+ CellType eType = aCell.meType;
switch ( eType )
{
case CELLTYPE_STRING:
case CELLTYPE_EDIT:
{
- if ( eType == CELLTYPE_STRING )
- aValue = ((ScStringCell*)pCell)->GetString();
- else
- aValue = ((ScEditCell*)pCell)->GetString();
+ aValue = aCell.getString();
nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
if ( nHeadNoneTail )
nStart = (double)nVal;
@@ -1115,10 +1117,10 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n
}
break;
case CELLTYPE_VALUE:
- nStart = ((ScValueCell*)pCell)->GetValue();
+ nStart = aCell.mfValue;
break;
case CELLTYPE_FORMULA:
- nStart = ((ScFormulaCell*)pCell)->GetValue();
+ nStart = aCell.mpFormula->GetValue();
break;
default:
nStart = 0.0;
@@ -1388,10 +1390,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
{
rInner = nISource;
- ScBaseCell* pSrcCell = aCol[nCol].GetCell(static_cast<SCROW>(nRow));
-
- if (bVertical && bAttribs)
- aCol[nCol].ReserveSize(aCol[nCol].GetCellCount() + nFillCount);
+ ScRefCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));
if (bAttribs)
{
@@ -1455,9 +1454,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
}
- if (pSrcCell)
+ if (!aSrcCell.isEmpty())
{
- CellType eCellType = pSrcCell->GetCellType();
+ CellType eCellType = aSrcCell.meType;
if (eFillCmd == FILL_SIMPLE) // copy
{
@@ -1469,7 +1468,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if(HiddenRowColumn(rInner, bVertical, this))
continue;
sal_uLong nInd = nActFormCnt;
- FillFormula(nInd, bFirst, (ScFormulaCell*)pSrcCell,
+ FillFormula(nInd, bFirst, aSrcCell.mpFormula,
static_cast<SCCOL>(nCol), nRow, (rInner == nIEnd) );
bFirst = false;
if(pProgress)
@@ -1483,7 +1482,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if(HiddenRowColumn(rInner, bVertical, this))
continue;
ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
- aCol[nCol].Insert( aDestPos.Row(), pSrcCell->Clone( *pDocument ) );
+ aSrcCell.commit(aCol[nCol], aDestPos.Row());
}
nProgress += nIMax - nIMin + 1;
if(pProgress)
@@ -1494,9 +1493,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
{
double nStartVal;
if (eCellType == CELLTYPE_VALUE)
- nStartVal = ((ScValueCell*)pSrcCell)->GetValue();
+ nStartVal = aSrcCell.mfValue;
else
- nStartVal = ((ScFormulaCell*)pSrcCell)->GetValue();
+ nStartVal = aSrcCell.mpFormula->GetValue();
double nVal = nStartVal;
long nIndex = 0;
@@ -1595,9 +1594,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
String aValue;
if (eCellType == CELLTYPE_STRING)
- aValue = ((ScStringCell*)pSrcCell)->GetString();
+ aValue = *aSrcCell.mpString;
else
- aValue = ((ScEditCell*)pSrcCell)->GetString();
+ aValue = ScEditUtil::GetString(*aSrcCell.mpEditText);
sal_Int32 nStringValue;
sal_uInt16 nMinDigits = nArgMinDigits;
short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
@@ -1670,17 +1669,16 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
String aStr;
if ( nHeadNoneTail < 0 )
{
- aCol[nCol].Insert( static_cast<SCROW>(nRow),
- lcl_getSuffixCell( pDocument,
- nStringValue, nMinDigits, aValue,
- eCellType, bIsOrdinalSuffix ));
+ setSuffixCell(
+ aCol[nCol], static_cast<SCROW>(nRow),
+ nStringValue, nMinDigits, aValue,
+ eCellType, bIsOrdinalSuffix);
}
else
{
aStr = aValue;
aStr += lcl_ValueString( nStringValue, nMinDigits );
- ScStringCell* pCell = new ScStringCell( aStr );
- aCol[nCol].Insert( static_cast<SCROW>(nRow), pCell );
+ aCol[nCol].SetRawString(static_cast<SCROW>(nRow), aStr);
}
}
}
diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
index ed150867ee6d..6d68aaffebba 100644
--- a/sc/source/core/data/table5.cxx
+++ b/sc/source/core/data/table5.cxx
@@ -1168,8 +1168,8 @@ void ScTable::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* p
SCCOL nCol = pAdrFrom->Col();
SCROW nRow = pAdrFrom->Row();
ScColumn& rCol = aCol[nCol];
- ScBaseCell* pCell = rCol.GetCell(nRow);
- if (!pCell)
+ ScRefCellValue aCell = rCol.GetCellValue(nRow);
+ if (aCell.isEmpty())
return;
rCol.SetTextWidth(nRow, TEXTWIDTH_DIRTY);
@@ -1179,13 +1179,13 @@ void ScTable::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* p
if ( bBroadcast )
{ // nur bei CalcAsShown
- switch ( pCell->GetCellType() )
+ switch (aCell.meType)
{
case CELLTYPE_VALUE :
pDocument->Broadcast(ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
break;
case CELLTYPE_FORMULA :
- ((ScFormulaCell*)pCell)->SetDirty();
+ aCell.mpFormula->SetDirty();
break;
default:
{
@@ -1210,25 +1210,23 @@ void ScTable::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* p
{
SCROW nRow = aIter.getPos();
aIter.setValue(TEXTWIDTH_DIRTY);
- ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
- if (pCell == 0)
- {
+ ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
+ if (aCell.isEmpty())
continue;
- }
if ( bNumFormatChanged )
aCol[nCol].SetScriptType(nRow, SC_SCRIPTTYPE_UNKNOWN);
if ( bBroadcast )
{ // nur bei CalcAsShown
- switch ( pCell->GetCellType() )
+ switch (aCell.meType)
{
case CELLTYPE_VALUE :
pDocument->Broadcast(
ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
break;
case CELLTYPE_FORMULA :
- ((ScFormulaCell*)pCell)->SetDirty();
+ aCell.mpFormula->SetDirty();
break;
default:
{
diff --git a/sc/source/core/data/table6.cxx b/sc/source/core/data/table6.cxx
index 17f62da32837..7ee1b37ca853 100644
--- a/sc/source/core/data/table6.cxx
+++ b/sc/source/core/data/table6.cxx
@@ -40,13 +40,12 @@ using ::com::sun::star::util::SearchOptions;
namespace {
-bool lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, OUString& rVal )
+bool lcl_GetTextWithBreaks( const EditTextObject& rData, ScDocument* pDoc, OUString& rVal )
{
// true = more than 1 paragraph
- const EditTextObject* pData = rCell.GetData();
EditEngine& rEngine = pDoc->GetEditEngine();
- rEngine.SetText( *pData );
+ rEngine.SetText(rData);
rVal = rEngine.GetText( LINEEND_LF );
return ( rEngine.GetParagraphCount() > 1 );
}
@@ -61,177 +60,179 @@ bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRo
bool bDoBack = rSearchItem.GetBackward();
OUString aString;
- ScBaseCell* pCell;
+ ScRefCellValue aCell;
if (rSearchItem.GetSelection())
bDoSearch = rMark.IsCellMarked(nCol, nRow);
- if ( bDoSearch && ((pCell = aCol[nCol].GetCell( nRow )) != NULL) )
+
+ if (!bDoSearch)
+ return false;
+
+ aCell = aCol[nCol].GetCellValue(nRow);
+ if (aCell.isEmpty())
+ return false;
+
+ bool bMultiLine = false;
+ CellType eCellType = aCell.meType;
+ switch (rSearchItem.GetCellType())
{
- bool bMultiLine = false;
- CellType eCellType = pCell->GetCellType();
- switch (rSearchItem.GetCellType())
+ case SVX_SEARCHIN_FORMULA:
{
- case SVX_SEARCHIN_FORMULA:
+ if ( eCellType == CELLTYPE_FORMULA )
+ aCell.mpFormula->GetFormula(aString, pDocument->GetGrammar());
+ else if ( eCellType == CELLTYPE_EDIT )
+ bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, pDocument, aString);
+ else
{
- if ( eCellType == CELLTYPE_FORMULA )
- static_cast<ScFormulaCell*>(pCell)->GetFormula(aString, pDocument->GetGrammar());
- else if ( eCellType == CELLTYPE_EDIT )
- bMultiLine = lcl_GetTextWithBreaks(
- *(const ScEditCell*)pCell, pDocument, aString );
- else
- {
- aCol[nCol].GetInputString( nRow, aString );
- }
+ aCol[nCol].GetInputString( nRow, aString );
}
- break;
- case SVX_SEARCHIN_VALUE:
- if ( eCellType == CELLTYPE_EDIT )
- bMultiLine = lcl_GetTextWithBreaks(
- *(const ScEditCell*)pCell, pDocument, aString );
- else
- {
- aCol[nCol].GetInputString( nRow, aString );
- }
- break;
- case SVX_SEARCHIN_NOTE:
- break; // don't search this case here
- default:
- break;
}
- xub_StrLen nStart = 0;
- xub_StrLen nEnd = aString.getLength();
- ::com::sun::star::util::SearchResult aSearchResult;
- if (pSearchText)
- {
- if ( bDoBack )
- {
- xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
- bFound = (bool)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult));
- // change results to definition before 614:
- --nEnd;
- }
+ break;
+ case SVX_SEARCHIN_VALUE:
+ if ( eCellType == CELLTYPE_EDIT )
+ bMultiLine = lcl_GetTextWithBreaks(*aCell.mpEditText, pDocument, aString);
else
{
- bFound = (bool)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult));
- // change results to definition before 614:
- --nEnd;
+ aCol[nCol].GetInputString( nRow, aString );
}
-
- if (bFound && rSearchItem.GetWordOnly())
- bFound = (nStart == 0 && nEnd == aString.getLength() - 1);
+ break;
+ case SVX_SEARCHIN_NOTE:
+ break; // don't search this case here
+ default:
+ break;
+ }
+ xub_StrLen nStart = 0;
+ xub_StrLen nEnd = aString.getLength();
+ ::com::sun::star::util::SearchResult aSearchResult;
+ if (pSearchText)
+ {
+ if ( bDoBack )
+ {
+ xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
+ bFound = (bool)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult));
+ // change results to definition before 614:
+ --nEnd;
}
else
{
- OSL_FAIL("pSearchText == NULL");
- return bFound;
+ bFound = (bool)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult));
+ // change results to definition before 614:
+ --nEnd;
}
- sal_uInt8 cMatrixFlag = MM_NONE;
- if ( bFound &&
- ( (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE)
- ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) ) &&
- // Matrix nicht zerreissen, nur Matrixformel ersetzen
- !( (eCellType == CELLTYPE_FORMULA &&
- ((cMatrixFlag = ((ScFormulaCell*)pCell)->GetMatrixFlag()) == MM_REFERENCE))
- // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
- || (cMatrixFlag != MM_NONE && !pUndoDoc) ) &&
- IsBlockEditable(nCol, nRow, nCol, nRow)
- )
+ if (bFound && rSearchItem.GetWordOnly())
+ bFound = (nStart == 0 && nEnd == aString.getLength() - 1);
+ }
+ else
+ {
+ OSL_FAIL("pSearchText == NULL");
+ return bFound;
+ }
+
+ sal_uInt8 cMatrixFlag = MM_NONE;
+ if ( bFound &&
+ ( (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE)
+ ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) ) &&
+ // Matrix nicht zerreissen, nur Matrixformel ersetzen
+ !( (eCellType == CELLTYPE_FORMULA &&
+ ((cMatrixFlag = aCell.mpFormula->GetMatrixFlag()) == MM_REFERENCE))
+ // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
+ || (cMatrixFlag != MM_NONE && !pUndoDoc) ) &&
+ IsBlockEditable(nCol, nRow, nCol, nRow)
+ )
+ {
+ if ( cMatrixFlag == MM_NONE && rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE )
+ rUndoStr = aString;
+ else if (pUndoDoc)
+ {
+ ScAddress aAdr( nCol, nRow, nTab );
+ aCell.commit(*pUndoDoc, aAdr);
+ }
+ bool bRepeat = !rSearchItem.GetWordOnly();
+ do
{
- if ( cMatrixFlag == MM_NONE && rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE )
- rUndoStr = aString;
- else if (pUndoDoc)
+ // wenn der gefundene Text leer ist, nicht weitersuchen,
+ // sonst wuerde man nie mehr aufhoeren (#35410#)
+ if ( nEnd < nStart || nEnd == STRING_MAXLEN )
+ bRepeat = false;
+
+ String sReplStr = rSearchItem.GetReplaceString();
+ if (rSearchItem.GetRegExp())
{
- ScAddress aAdr( nCol, nRow, nTab );
- ScBaseCell* pUndoCell = pCell->Clone( *pUndoDoc );
- pUndoDoc->PutCell( aAdr, pUndoCell);
+ pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
+ OUStringBuffer aStrBuffer(aString);
+ aStrBuffer.remove(nStart, nEnd-nStart+1);
+ aStrBuffer.insert(nStart, sReplStr);
+ aString = aStrBuffer.makeStringAndClear();
}
- bool bRepeat = !rSearchItem.GetWordOnly();
- do
+ else
{
- // wenn der gefundene Text leer ist, nicht weitersuchen,
- // sonst wuerde man nie mehr aufhoeren (#35410#)
- if ( nEnd < nStart || nEnd == STRING_MAXLEN )
- bRepeat = false;
+ OUStringBuffer aStrBuffer(aString);
+ aStrBuffer.remove(nStart, nEnd-nStart+1);
+ aStrBuffer.insert(nStart, rSearchItem.GetReplaceString());
+ aString = aStrBuffer.makeStringAndClear();
+ }
- String sReplStr = rSearchItem.GetReplaceString();
- if (rSearchItem.GetRegExp())
- {
- pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
- OUStringBuffer aStrBuffer(aString);
- aStrBuffer.remove(nStart, nEnd-nStart+1);
- aStrBuffer.insert(nStart, sReplStr);
- aString = aStrBuffer.makeStringAndClear();
- }
- else
- {
- OUStringBuffer aStrBuffer(aString);
- aStrBuffer.remove(nStart, nEnd-nStart+1);
- aStrBuffer.insert(nStart, rSearchItem.GetReplaceString());
- aString = aStrBuffer.makeStringAndClear();
- }
+ // Indizes anpassen
+ if (bDoBack)
+ {
+ nEnd = nStart;
+ nStart = 0;
+ }
+ else
+ {
+ nStart = sal::static_int_cast<xub_StrLen>( nStart + sReplStr.Len() );
+ nEnd = aString.getLength();
+ }
- // Indizes anpassen
- if (bDoBack)
+ // weitersuchen ?
+ if (bRepeat)
+ {
+ if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
+ bRepeat = false;
+ else if (bDoBack)
{
- nEnd = nStart;
- nStart = 0;
+ xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
+ bRepeat = ((bool)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult)));
+ // change results to definition before 614:
+ --nEnd;
}
else
{
- nStart = sal::static_int_cast<xub_StrLen>( nStart + sReplStr.Len() );
- nEnd = aString.getLength();
- }
-
- // weitersuchen ?
- if (bRepeat)
- {
- if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
- bRepeat = false;
- else if (bDoBack)
- {
- xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
- bRepeat = ((bool)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult)));
- // change results to definition before 614:
- --nEnd;
- }
- else
- {
- bRepeat = ((bool)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult)));
- // change results to definition before 614:
- --nEnd;
- }
+ bRepeat = ((bool)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult)));
+ // change results to definition before 614:
+ --nEnd;
}
}
- while (bRepeat);
-
- if ( cMatrixFlag != MM_NONE )
- { // Matrix nicht zerreissen
- if ( aString.getLength() > 2 )
- { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
- if ( aString[ aString.getLength()-1 ] == '}' )
- aString = aString.copy( 0, aString.getLength()-1 );
- if ( aString[0] == '{' )
- aString = aString.copy( 1 );
- }
- ScAddress aAdr( nCol, nRow, nTab );
- ScFormulaCell* pFCell = new ScFormulaCell( pDocument, aAdr,
- aString, pDocument->GetGrammar(), cMatrixFlag );
- SCCOL nMatCols;
- SCROW nMatRows;
- ((ScFormulaCell*)pCell)->GetMatColsRows( nMatCols, nMatRows );
- pFCell->SetMatColsRows( nMatCols, nMatRows );
- aCol[nCol].Insert( nRow, pFCell );
- }
- else if ( bMultiLine && aString.indexOf('\n') != -1 )
- {
- ScFieldEditEngine& rEngine = pDocument->GetEditEngine();
- rEngine.SetText(aString);
- SetEditText(nCol, nRow, rEngine.CreateTextObject());
+ }
+ while (bRepeat);
+
+ if ( cMatrixFlag != MM_NONE )
+ { // Matrix nicht zerreissen
+ if ( aString.getLength() > 2 )
+ { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
+ if ( aString[ aString.getLength()-1 ] == '}' )
+ aString = aString.copy( 0, aString.getLength()-1 );
+ if ( aString[0] == '{' )
+ aString = aString.copy( 1 );
}
- else
- aCol[nCol].SetString(nRow, nTab, aString, pDocument->GetAddressConvention());
- // pCell is invalid now (deleted)
+ ScAddress aAdr( nCol, nRow, nTab );
+ ScFormulaCell* pFCell = new ScFormulaCell( pDocument, aAdr,
+ aString, pDocument->GetGrammar(), cMatrixFlag );
+ SCCOL nMatCols;
+ SCROW nMatRows;
+ aCell.mpFormula->GetMatColsRows(nMatCols, nMatRows);
+ pFCell->SetMatColsRows( nMatCols, nMatRows );
+ aCol[nCol].SetFormulaCell(nRow, pFCell);
}
+ else if ( bMultiLine && aString.indexOf('\n') != -1 )
+ {
+ ScFieldEditEngine& rEngine = pDocument->GetEditEngine();
+ rEngine.SetText(aString);
+ SetEditText(nCol, nRow, rEngine.CreateTextObject());
+ }
+ else
+ aCol[nCol].SetString(nRow, nTab, aString, pDocument->GetAddressConvention());
+ // pCell is invalid now (deleted)
}
return bFound;
}
@@ -816,8 +817,8 @@ namespace {
bool lcl_maybeReplaceCellString(
ScColumn& rColObj, SCCOL& rCol, SCROW& rRow, OUString& rUndoStr, SCCOL nCol, SCROW nRow, const SvxSearchItem& rSearchItem)
{
- ScBaseCell* pCell = rColObj.GetCell(nRow);
- if (!pCell)
+ ScRefCellValue aCell = rColObj.GetCellValue(nRow);
+ if (aCell.isEmpty())
{
// empty cell found.
rCol = nCol;
@@ -825,7 +826,7 @@ bool lcl_maybeReplaceCellString(
if (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE &&
rSearchItem.GetReplaceString().Len())
{
- rColObj.Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
+ rColObj.SetRawString(nRow, rSearchItem.GetReplaceString());
rUndoStr = OUString();
}
return true;
@@ -971,7 +972,7 @@ bool ScTable::SearchRangeForAllEmptyCells(
const String& rNewStr = rSearchItem.GetReplaceString();
for (SCROW i = nRow; i <= nLastRow; ++i)
{
- aCol[nCol].Insert(i, new ScStringCell(rNewStr));
+ aCol[nCol].SetRawString(i, rNewStr);
if (pUndoDoc)
{
// TODO: I'm using a string cell with empty content to
@@ -999,8 +1000,8 @@ bool ScTable::SearchRangeForAllEmptyCells(
if (nRow > rRange.aEnd.Row())
break;
- ScBaseCell* pCell = aCol[nCol].GetCell(nRow);
- if (!pCell)
+ ScRefCellValue aCell = aCol[nCol].GetCellValue(nRow);
+ if (aCell.isEmpty())
{
// empty cell found
rMatchedRanges.Join(ScRange(nCol, nRow, nTab));
@@ -1008,7 +1009,7 @@ bool ScTable::SearchRangeForAllEmptyCells(
if (bReplace)
{
- aCol[nCol].Insert(nRow, new ScStringCell(rSearchItem.GetReplaceString()));
+ aCol[nCol].SetRawString(nRow, rSearchItem.GetReplaceString());
if (pUndoDoc)
{
// TODO: I'm using a string cell with empty content to
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index df9ffaac9c29..4c8dd4b568ef 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -35,7 +35,6 @@
class ScDocument;
class SbxVariable;
-class ScValueCell;
class ScFormulaCell;
class SvNumberFormatter;
class ScDBRangeBase;
diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx
index 903d06bf1eca..80724405e76e 100644
--- a/sc/source/core/tool/chgtrack.cxx
+++ b/sc/source/core/tool/chgtrack.cxx
@@ -2899,22 +2899,21 @@ void ScChangeTrack::AppendContentRange( const ScRange& rRange,
void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument* pRefDoc,
sal_uLong& nStartAction, sal_uLong& nEndAction )
{
- ScDocumentIterator aIter( pRefDoc, 0, MAXTAB );
- if ( aIter.GetFirst() )
+ ScCellIterator aIter(pRefDoc, ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB));
+ if (aIter.first())
{
nStartAction = GetActionMax() + 1;
StartBlockModify( SC_CTM_APPEND, nStartAction );
SvNumberFormatter* pFormatter = pRefDoc->GetFormatTable();
do
{
- SCCOL nCol;
- SCROW nRow;
- SCTAB nTab;
- aIter.GetPos( nCol, nRow, nTab );
- ScAddress aPos( nCol, nRow, nTab );
- AppendContent( aPos, aIter.GetCellValue(),
- aIter.GetPattern()->GetNumberFormat( pFormatter ), pRefDoc );
- } while ( aIter.GetNext() );
+ const ScAddress& rPos = aIter.GetPos();
+ const ScPatternAttr* pPat = pRefDoc->GetPattern(rPos);
+ AppendContent(
+ rPos, aIter.getCellValue(), pPat->GetNumberFormat(pFormatter), pRefDoc);
+ }
+ while (aIter.next());
+
nEndAction = GetActionMax();
EndBlockModify( nEndAction );
}
diff --git a/sc/source/core/tool/editutil.cxx b/sc/source/core/tool/editutil.cxx
index bf0a7252ba21..a74b62a299b0 100644
--- a/sc/source/core/tool/editutil.cxx
+++ b/sc/source/core/tool/editutil.cxx
@@ -137,6 +137,32 @@ void ScEditUtil::RemoveCharAttribs( EditTextObject& rEditText, const ScPatternAt
}
}
+EditTextObject* ScEditUtil::Clone( const EditTextObject& rObj, ScDocument& rDestDoc )
+{
+ EditTextObject* pNew = NULL;
+
+ EditEngine& rEngine = rDestDoc.GetEditEngine();
+ if (rObj.HasOnlineSpellErrors())
+ {
+ sal_uLong nControl = rEngine.GetControlWord();
+ const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
+ bool bNewControl = ( (nControl & nSpellControl) != nSpellControl );
+ if (bNewControl)
+ rEngine.SetControlWord(nControl | nSpellControl);
+ rEngine.SetText(rObj);
+ pNew = rEngine.CreateTextObject();
+ if (bNewControl)
+ rEngine.SetControlWord(nControl);
+ }
+ else
+ {
+ rEngine.SetText(rObj);
+ pNew = rEngine.CreateTextObject();
+ }
+
+ return pNew;
+}
+
//------------------------------------------------------------------------
Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, sal_Bool bForceToTop )
diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx
index eea3a71db53e..9b2c634d959d 100644
--- a/sc/source/core/tool/scmatrix.cxx
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -23,6 +23,8 @@
#include "address.hxx"
#include "formula/errorcodes.hxx"
#include "interpre.hxx"
+#include "mtvelements.hxx"
+
#include <svl/zforlist.hxx>
#include <tools/stream.hxx>
#include <rtl/math.hxx>
@@ -41,18 +43,6 @@ using ::std::count_if;
using ::std::advance;
using ::std::unary_function;
-const mdds::mtv::element_t element_type_custom_string = mdds::mtv::element_type_user_start;
-typedef mdds::mtv::default_element_block<element_type_custom_string, OUString> custom_string_block;
-
-namespace rtl {
-
-// Callback functions required for supporting OUString in
-// mdds::multi_type_vector. They must be in the rtl namespace to satisfy
-// argument dependent lookup that mdds::multi_type_vector requires.
-MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(OUString, element_type_custom_string, OUString(), custom_string_block)
-
-}
-
/**
* Custom string trait struct to tell mdds::multi_type_matrix about the
* custom string type and how to handle blocks storing them.
@@ -60,168 +50,11 @@ MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(OUString, element_type_custom_string, OUString
struct custom_string_trait
{
typedef OUString string_type;
- typedef custom_string_block string_element_block;
-
- static const mdds::mtv::element_t string_type_identifier = element_type_custom_string;
-
- struct element_block_func
- {
- static mdds::mtv::base_element_block* create_new_block(
- mdds::mtv::element_t type, size_t init_size)
- {
- switch (type)
- {
- case element_type_custom_string:
- return string_element_block::create_block(init_size);
- default:
- return mdds::mtv::element_block_func::create_new_block(type, init_size);
- }
- }
-
- static mdds::mtv::base_element_block* clone_block(const mdds::mtv::base_element_block& block)
- {
- switch (mdds::mtv::get_block_type(block))
- {
- case element_type_custom_string:
- return string_element_block::clone_block(block);
- default:
- return mdds::mtv::element_block_func::clone_block(block);
- }
- }
-
- static void delete_block(mdds::mtv::base_element_block* p)
- {
- if (!p)
- return;
-
- switch (mdds::mtv::get_block_type(*p))
- {
- case element_type_custom_string:
- string_element_block::delete_block(p);
- break;
- default:
- mdds::mtv::element_block_func::delete_block(p);
- }
- }
-
- static void resize_block(mdds::mtv::base_element_block& block, size_t new_size)
- {
- switch (mdds::mtv::get_block_type(block))
- {
- case element_type_custom_string:
- string_element_block::resize_block(block, new_size);
- break;
- default:
- mdds::mtv::element_block_func::resize_block(block, new_size);
- }
- }
-
- static void print_block(const mdds::mtv::base_element_block& block)
- {
- switch (mdds::mtv::get_block_type(block))
- {
- case element_type_custom_string:
- string_element_block::print_block(block);
- break;
- default:
- mdds::mtv::element_block_func::print_block(block);
- }
- }
-
- static void erase(mdds::mtv::base_element_block& block, size_t pos)
- {
- switch (mdds::mtv::get_block_type(block))
- {
- case element_type_custom_string:
- string_element_block::erase_block(block, pos);
- break;
- default:
- mdds::mtv::element_block_func::erase(block, pos);
- }
- }
-
- static void erase(mdds::mtv::base_element_block& block, size_t pos, size_t size)
- {
- switch (mdds::mtv::get_block_type(block))
- {
- case element_type_custom_string:
- string_element_block::erase_block(block, pos, size);
- break;
- default:
- mdds::mtv::element_block_func::erase(block, pos, size);
- }
- }
+ typedef sc::string_block string_element_block;
- static void append_values_from_block(
- mdds::mtv::base_element_block& dest, const mdds::mtv::base_element_block& src)
- {
- switch (mdds::mtv::get_block_type(dest))
- {
- case element_type_custom_string:
- string_element_block::append_values_from_block(dest, src);
- break;
- default:
- mdds::mtv::element_block_func::append_values_from_block(dest, src);
- }
- }
+ static const mdds::mtv::element_t string_type_identifier = sc::element_type_string;
- static void append_values_from_block(
- mdds::mtv::base_element_block& dest, const mdds::mtv::base_element_block& src,
- size_t begin_pos, size_t len)
- {
- switch (mdds::mtv::get_block_type(dest))
- {
- case element_type_custom_string:
- string_element_block::append_values_from_block(dest, src, begin_pos, len);
- break;
- default:
- mdds::mtv::element_block_func::append_values_from_block(dest, src, begin_pos, len);
- }
- }
-
- static void assign_values_from_block(
- mdds::mtv::base_element_block& dest, const mdds::mtv::base_element_block& src,
- size_t begin_pos, size_t len)
- {
- switch (mdds::mtv::get_block_type(dest))
- {
- case element_type_custom_string:
- string_element_block::assign_values_from_block(dest, src, begin_pos, len);
- break;
- default:
- mdds::mtv::element_block_func::assign_values_from_block(dest, src, begin_pos, len);
- }
- }
-
- static bool equal_block(
- const mdds::mtv::base_element_block& left, const mdds::mtv::base_element_block& right)
- {
- if (mdds::mtv::get_block_type(left) == element_type_custom_string)
- {
- if (mdds::mtv::get_block_type(right) != element_type_custom_string)
- return false;
-
- return string_element_block::get(left) == string_element_block::get(right);
- }
- else if (mdds::mtv::get_block_type(right) == element_type_custom_string)
- return false;
-
- return mdds::mtv::element_block_func::equal_block(left, right);
- }
-
- static void overwrite_values(mdds::mtv::base_element_block& block, size_t pos, size_t len)
- {
- switch (mdds::mtv::get_block_type(block))
- {
- case element_type_custom_string:
- // Do nothing. One needs to handle this only when the
- // block stores pointers and manages their life cycles.
- break;
- default:
- mdds::mtv::element_block_func::overwrite_values(block, pos, len);
- }
- }
- };
+ typedef mdds::mtv::custom_block_func1<sc::string_block> element_block_func;
};
// ============================================================================
@@ -314,7 +147,6 @@ class ScMatrixImpl
MatrixImplType maMatFlag;
ScInterpreter* pErrorInterpreter;
bool mbCloneIfConst; // Whether the matrix is cloned with a CloneIfConst() call.
- MatrixImplType::size_pair_type maCachedSize;
ScMatrixImpl();
ScMatrixImpl(const ScMatrixImpl&);
diff --git a/sc/source/core/tool/scopetools.cxx b/sc/source/core/tool/scopetools.cxx
new file mode 100644
index 000000000000..5a317bbdac2d
--- /dev/null
+++ b/sc/source/core/tool/scopetools.cxx
@@ -0,0 +1,28 @@
+/* -*- 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 "scopetools.hxx"
+#include "document.hxx"
+
+namespace sc {
+
+AutoCalcSwitch::AutoCalcSwitch(ScDocument& rDoc, bool bAutoCalc) :
+ mrDoc(rDoc), mbOldValue(rDoc.GetAutoCalc())
+{
+ mrDoc.SetAutoCalc(bAutoCalc);
+}
+
+AutoCalcSwitch::~AutoCalcSwitch()
+{
+ mrDoc.SetAutoCalc(mbOldValue);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/xml/XMLExportIterator.cxx b/sc/source/filter/xml/XMLExportIterator.cxx
index c5a7451388a2..b192bab70202 100644
--- a/sc/source/filter/xml/XMLExportIterator.cxx
+++ b/sc/source/filter/xml/XMLExportIterator.cxx
@@ -675,7 +675,7 @@ void ScMyNotEmptyCellsIterator::Clear()
void ScMyNotEmptyCellsIterator::UpdateAddress( table::CellAddress& rAddress )
{
- if( pCellItr->ReturnNext( nCellCol, nCellRow ) )
+ if( pCellItr->GetPos( nCellCol, nCellRow ) )
{
rAddress.Column = nCellCol;
rAddress.Row = nCellRow;
diff --git a/sc/source/ui/docshell/dbdocimp.cxx b/sc/source/ui/docshell/dbdocimp.cxx
index 9108fb88adec..858f45935059 100644
--- a/sc/source/ui/docshell/dbdocimp.cxx
+++ b/sc/source/ui/docshell/dbdocimp.cxx
@@ -401,8 +401,6 @@ bool ScDBDocFunc::DoImport( SCTAB nTab, const ScImportParam& rParam,
OSL_FAIL("Unexpected exception in database");
}
- pImportDoc->DoColResize( nTab, rParam.nCol1,nEndCol, 0 );
-
//
// test for cell protection
//
@@ -565,7 +563,6 @@ bool ScDBDocFunc::DoImport( SCTAB nTab, const ScImportParam& rParam,
pImportDoc->CopyToDocument( nCopyCol, rParam.nRow1, nTab, nCopyCol, nEndRow, nTab,
IDF_ALL, false, pDoc );
pImportDoc->DeleteAreaTab( nCopyCol, rParam.nRow1, nCopyCol, nEndRow, nTab, IDF_CONTENTS );
- pImportDoc->DoColResize( nTab, nCopyCol, nCopyCol, 0 );
}
pDoc->SetAutoCalc( bOldAutoCalc );
diff --git a/sc/source/ui/docshell/docsh8.cxx b/sc/source/ui/docshell/docsh8.cxx
index 2eb7b253dd7d..ae259c21608a 100644
--- a/sc/source/ui/docshell/docsh8.cxx
+++ b/sc/source/ui/docshell/docsh8.cxx
@@ -465,9 +465,6 @@ sal_uLong ScDocShell::DBaseImport( const String& rFullFileName, CharSet eCharSet
nErr = ERRCODE_IO_GENERAL;
}
- if ( nColCount > 0 )
- aDocument.DoColResize( 0, 0, static_cast<SCCOL>(nColCount) - 1, 0 );
-
return nErr;
#endif // !DISABLE_DBCONNECTIVITY
}
diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx
index 4a74487b2487..8629a03871ff 100644
--- a/sc/source/ui/docshell/impex.cxx
+++ b/sc/source/ui/docshell/impex.cxx
@@ -1470,8 +1470,6 @@ bool ScImportExport::ExtText2Doc( SvStream& rStrm )
bDetermineRange = !bDetermineRange; // toggle
} while (!bDetermineRange);
- pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 );
-
xProgress.reset(); // make room for AdjustRowHeight progress
if (bRangeIsDetermined)
EndPaste();
diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx
index 2a631d5a8c44..83b06d55f437 100644
--- a/sc/source/ui/undo/undodat.cxx
+++ b/sc/source/ui/undo/undodat.cxx
@@ -1236,7 +1236,6 @@ void ScUndoImportData::Undo()
pDoc->CopyToDocument( nCopyCol,nRow1,nTab, nCopyCol,nRow2,nTab,
IDF_CONTENTS & ~IDF_NOTE, false, pRedoDoc );
pDoc->DeleteAreaTab( nCopyCol,nRow1, nCopyCol,nRow2, nTab, IDF_CONTENTS & ~IDF_NOTE );
- pDoc->DoColResize( nTab, nCopyCol, nCopyCol, 0 );
}
pDoc->SetAutoCalc( bOldAutoCalc );
bRedoFilled = sal_True;