LibreOffice Module sc (master)  1
columnspanset.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <columnspanset.hxx>
11 #include <column.hxx>
12 #include <table.hxx>
13 #include <document.hxx>
14 #include <mtvfunctions.hxx>
15 #include <markdata.hxx>
16 #include <rangelst.hxx>
17 #include <fstalgorithm.hxx>
18 
19 #include <algorithm>
20 #include <memory>
21 
22 #include <o3tl/safeint.hxx>
23 
24 namespace sc {
25 
26 namespace {
27 
28 class ColumnScanner
29 {
31  bool mbVal;
32 public:
33  ColumnScanner(ColumnSpanSet::ColumnSpansType& rRanges, bool bVal) :
34  mrRanges(rRanges), mbVal(bVal) {}
35 
36  void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
37  {
38  if (node.type == sc::element_type_empty)
39  return;
40 
41  size_t nRow = node.position + nOffset;
42  size_t nEndRow = nRow + nDataSize; // Last row of current block plus 1
43  mrRanges.insert_back(nRow, nEndRow, mbVal);
44  }
45 };
46 
47 }
48 
49 RowSpan::RowSpan(SCROW nRow1, SCROW nRow2) : mnRow1(nRow1), mnRow2(nRow2) {}
50 
51 ColRowSpan::ColRowSpan(SCCOLROW nStart, SCCOLROW nEnd) : mnStart(nStart), mnEnd(nEnd) {}
52 
54  maSpans(nStart, nEnd+1, bInit), miPos(maSpans.begin()) {}
55 
57 void ColumnSpanSet::Action::startColumn(SCTAB /*nTab*/, SCCOL /*nCol*/) {}
58 
60 
62 
64 {
65 }
66 
68 {
69  if (o3tl::make_unsigned(nTab) >= maTables.size())
70  maTables.resize(nTab+1);
71 
72  if (!maTables[nTab])
73  maTables[nTab].reset(new TableType);
74 
75  TableType& rTab = *maTables[nTab];
76  if (o3tl::make_unsigned(nCol) >= rTab.size())
77  rTab.resize(nCol+1);
78 
79  if (!rTab[nCol])
80  rTab[nCol].reset(new ColumnType(0, rDoc.MaxRow(), /*bInit*/false));
81 
82  return *rTab[nCol];
83 }
84 
85 void ColumnSpanSet::set(const ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
86 {
87  if (!ValidTab(nTab) || !rDoc.ValidCol(nCol) || !rDoc.ValidRow(nRow))
88  return;
89 
90  ColumnType& rCol = getColumn(rDoc, nTab, nCol);
91  rCol.miPos = rCol.maSpans.insert(rCol.miPos, nRow, nRow+1, bVal).first;
92 }
93 
94 void ColumnSpanSet::set(const ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal)
95 {
96  if (!ValidTab(nTab) || !rDoc.ValidCol(nCol) || !rDoc.ValidRow(nRow1) || !rDoc.ValidRow(nRow2))
97  return;
98 
99  ColumnType& rCol = getColumn(rDoc, nTab, nCol);
100  rCol.miPos = rCol.maSpans.insert(rCol.miPos, nRow1, nRow2+1, bVal).first;
101 }
102 
103 void ColumnSpanSet::set(const ScDocument& rDoc, const ScRange& rRange, bool bVal)
104 {
105  for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
106  {
107  for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
108  {
109  ColumnType& rCol = getColumn(rDoc, nTab, nCol);
110  rCol.miPos = rCol.maSpans.insert(rCol.miPos, rRange.aStart.Row(), rRange.aEnd.Row()+1, bVal).first;
111  }
112  }
113 }
114 
115 void ColumnSpanSet::set( const ScDocument& rDoc, SCTAB nTab, SCCOL nCol, const SingleColumnSpanSet& rSingleSet, bool bVal )
116 {
118  rSingleSet.getSpans(aSpans);
119  for (const auto& rSpan : aSpans)
120  set(rDoc, nTab, nCol, rSpan.mnRow1, rSpan.mnRow2, bVal);
121 }
122 
124  const ScDocument& rDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal)
125 {
126  if (!rDoc.ValidColRow(nCol1, nRow1) || !rDoc.ValidColRow(nCol2, nRow2))
127  return;
128 
129  if (nCol1 > nCol2 || nRow1 > nRow2)
130  return;
131 
132  const ScTable* pTab = rDoc.FetchTable(nTab);
133  if (!pTab)
134  return;
135 
136  nCol2 = pTab->ClampToAllocatedColumns(nCol2);
137  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
138  {
139  ColumnType& rCol = getColumn(rDoc, nTab, nCol);
140 
141  const CellStoreType& rSrcCells = pTab->aCol[nCol].maCells;
142 
143  ColumnScanner aScanner(rCol.maSpans, bVal);
144  ParseBlock(rSrcCells.begin(), rSrcCells, aScanner, nRow1, nRow2);
145  }
146 }
147 
149 {
150  for (size_t nTab = 0; nTab < maTables.size(); ++nTab)
151  {
152  if (!maTables[nTab])
153  continue;
154 
155  const TableType& rTab = *maTables[nTab];
156  for (size_t nCol = 0; nCol < rTab.size(); ++nCol)
157  {
158  if (!rTab[nCol])
159  continue;
160 
161  ac.startColumn(nTab, nCol);
162  ColumnType& rCol = *rTab[nCol];
163  ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end();
164  SCROW nRow1, nRow2;
165  nRow1 = it->first;
166  bool bVal = it->second;
167  for (++it; it != itEnd; ++it)
168  {
169  nRow2 = it->first-1;
170  ac.execute(ScAddress(nCol, nRow1, nTab), nRow2-nRow1+1, bVal);
171 
172  nRow1 = nRow2+1; // for the next iteration.
173  bVal = it->second;
174  }
175  }
176  }
177 }
178 
180 {
181  for (size_t nTab = 0; nTab < maTables.size(); ++nTab)
182  {
183  if (!maTables[nTab])
184  continue;
185 
186  const TableType& rTab = *maTables[nTab];
187  for (SCCOL nCol = 0; nCol < static_cast<SCCOL>(rTab.size()); ++nCol)
188  {
189  if (!rTab[nCol])
190  continue;
191 
192  ScTable* pTab = rDoc.FetchTable(nTab);
193  if (!pTab)
194  continue;
195 
196  if (!rDoc.ValidCol(nCol) || nCol >= pTab->GetAllocatedColumnsCount())
197  {
198  // End the loop.
199  nCol = rTab.size();
200  continue;
201  }
202 
203  ScColumn& rColumn = pTab->aCol[nCol];
204  ac.startColumn(&rColumn);
205  ColumnType& rCol = *rTab[nCol];
206  ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end();
207  SCROW nRow1, nRow2;
208  nRow1 = it->first;
209  bool bVal = it->second;
210  for (++it; it != itEnd; ++it)
211  {
212  nRow2 = it->first-1;
213  ac.execute(nRow1, nRow2, bVal);
214 
215  nRow1 = nRow2+1; // for the next iteration.
216  bVal = it->second;
217  }
218  }
219  }
220 }
221 
222 namespace {
223 
224 class Scanner
225 {
227 public:
228  explicit Scanner(SingleColumnSpanSet::ColumnSpansType& rRanges) : mrRanges(rRanges) {}
229 
230  void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
231  {
232  if (node.type == sc::element_type_empty)
233  return;
234 
235  size_t nRow = node.position + nOffset;
236  size_t nEndRow = nRow + nDataSize; // Last row of current block plus 1
237  mrRanges.insert_back(nRow, nEndRow, true);
238  }
239 };
240 
241 }
242 
244  : mrSheetLimits(rSheetLimits),
245  maSpans(0, rSheetLimits.GetMaxRowCount(), false) {}
246 
248 {
249  const CellStoreType& rCells = rColumn.maCells;
250  SCROW nCurRow = 0;
251  for (const auto& rCell : rCells)
252  {
253  SCROW nEndRow = nCurRow + rCell.size; // Last row of current block plus 1.
254  if (rCell.type != sc::element_type_empty)
255  maSpans.insert_back(nCurRow, nEndRow, true);
256 
257  nCurRow = nEndRow;
258  }
259 }
260 
261 void SingleColumnSpanSet::scan(const ScColumn& rColumn, SCROW nStart, SCROW nEnd)
262 {
263  const CellStoreType& rCells = rColumn.maCells;
264  Scanner aScanner(maSpans);
265  sc::ParseBlock(rCells.begin(), rCells, aScanner, nStart, nEnd);
266 }
267 
269  ColumnBlockConstPosition& rBlockPos, const ScColumn& rColumn, SCROW nStart, SCROW nEnd)
270 {
271  const CellStoreType& rCells = rColumn.maCells;
272  Scanner aScanner(maSpans);
273  rBlockPos.miCellPos = sc::ParseBlock(rBlockPos.miCellPos, rCells, aScanner, nStart, nEnd);
274 }
275 
276 void SingleColumnSpanSet::scan(const ScMarkData& rMark, SCTAB nTab, SCCOL nCol)
277 {
278  if (!rMark.GetTableSelect(nTab))
279  // This table is not selected. Nothing to scan.
280  return;
281 
282  ScRangeList aRanges = rMark.GetMarkedRangesForTab(nTab);
283  scan(aRanges, nTab, nCol);
284 }
285 
286 void SingleColumnSpanSet::scan(const ScRangeList& rRanges, SCTAB nTab, SCCOL nCol)
287 {
288  for (size_t i = 0, n = rRanges.size(); i < n; ++i)
289  {
290  const ScRange & rRange = rRanges[i];
291  if (nTab < rRange.aStart.Tab() || rRange.aEnd.Tab() < nTab)
292  continue;
293 
294  if (nCol < rRange.aStart.Col() || rRange.aEnd.Col() < nCol)
295  // This column is not in this range. Skip it.
296  continue;
297 
298  maSpans.insert_back(rRange.aStart.Row(), rRange.aEnd.Row()+1, true);
299  }
300 }
301 
302 void SingleColumnSpanSet::set(SCROW nRow1, SCROW nRow2, bool bVal)
303 {
304  maSpans.insert_back(nRow1, nRow2+1, bVal);
305 }
306 
307 void SingleColumnSpanSet::getRows(std::vector<SCROW> &rRows) const
308 {
309  std::vector<SCROW> aRows;
310 
311  SpansType aRanges;
312  getSpans(aRanges);
313  for (const auto& rRange : aRanges)
314  {
315  for (SCROW nRow = rRange.mnRow1; nRow <= rRange.mnRow2; ++nRow)
316  aRows.push_back(nRow);
317  }
318 
319  rRows.swap(aRows);
320 }
321 
323 {
324  SpansType aSpans = toSpanArray<SCROW,RowSpan>(maSpans);
325  rSpans.swap(aSpans);
326 }
327 
329 {
330  maSpans.swap(r.maSpans);
331 }
332 
334 {
335  // Empty if there's only the 0..rDoc.MaxRow() span with false.
336  ColumnSpansType::const_iterator it = maSpans.begin();
337  return (it->first == 0) && !(it->second) && (++it != maSpans.end()) && (it->first == mrSheetLimits.GetMaxRowCount());
338 }
339 
340 
342 {
343  for (SCTAB nTab = range.aStart.Tab(); nTab <= range.aEnd.Tab(); ++nTab)
344  {
345  ScTable* pTab = rDoc.FetchTable(nTab);
346  if (!pTab)
347  continue;
348 
349  SCCOL nEndCol = pTab->ClampToAllocatedColumns(range.aEnd.Col());
350  for (SCCOL nCol = range.aStart.Col(); nCol <= nEndCol; ++nCol)
351  {
352  if (!rDoc.ValidCol(nCol))
353  break;
354 
355  ScColumn& rColumn = pTab->aCol[nCol];
356  ac.startColumn(&rColumn);
357  ac.execute( range.aStart.Row(), range.aEnd.Row(), true );
358  }
359  }
360 }
361 
363 {
364  for (SCTAB nTab = range.aStart.Tab(); nTab <= range.aEnd.Tab(); ++nTab)
365  {
366  ScTable* pTab = rDoc.FetchTable(nTab);
367  if (!pTab)
368  continue;
369 
370  SCCOL nEndCol = pTab->ClampToAllocatedColumns(range.aEnd.Col());
371  for (SCCOL nCol = range.aStart.Col(); nCol <= nEndCol; ++nCol)
372  {
373  if (!rDoc.ValidCol(nCol))
374  break;
375 
376  ScColumn& rColumn = pTab->aCol[nCol];
377  ac.startColumn(&rColumn);
378  ac.executeSum( range.aStart.Row(), range.aEnd.Row(), true, fMem );
379  }
380  }
381 }
382 
383 } // namespace sc
384 
385 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
CellStoreType::const_iterator miCellPos
ScAddress aStart
Definition: address.hxx:500
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
ColumnType & getColumn(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol)
SCROW Row() const
Definition: address.hxx:262
size_t mnEnd
Definition: cellvalues.cxx:24
virtual void execute(const ScAddress &rPos, SCROW nLength, bool bVal)=0
virtual void startColumn(SCTAB nTab, SCCOL nCol)
ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2505
void scan(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal)
Scan specified range in a specified sheet and mark all non-empty cells with specified boolean value...
mdds::flat_segment_tree< SCROW, bool > ColumnSpansType
StoreT::const_iterator ParseBlock(const typename StoreT::const_iterator &itPos, const StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Generic algorithm to parse blocks of multi_type_vector either partially or fully. ...
sal_Int64 n
mdds::flat_segment_tree< SCROW, bool > ColumnSpansType
ScAddress aEnd
Definition: address.hxx:501
SCROW GetMaxRowCount() const
Definition: sheetlimits.hxx:61
bool empty() const
Whether there isn't any row tagged.
mdds::multi_type_vector< CellFunc, CellStoreEvent > CellStoreType
ScSheetLimits const & mrSheetLimits
Keep track of spans in a single column only.
enumrange< T >::Iterator begin(enumrange< T >)
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:873
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:24
sc::CellStoreType maCells
Definition: column.hxx:129
void set(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
SCTAB Tab() const
Definition: address.hxx:271
ColRowSpan(SCCOLROW nStart, SCCOLROW nEnd)
void executeColumnAction(ScDocument &rDoc, ColumnAction &ac) const
void getSpans(SpansType &rSpans) const
int i
sal_Int16 SCCOL
Definition: types.hxx:22
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:875
void getRows(std::vector< SCROW > &rRows) const
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:56
size_t size() const
Definition: rangelst.hxx:90
void set(SCROW nRow1, SCROW nRow2, bool bVal)
ScColContainer aCol
Definition: table.hxx:156
ColumnSpansType::const_iterator miPos
SCCOL Col() const
Definition: address.hxx:267
size_t mnStart
Definition: cellvalues.cxx:23
bool ValidColRow(SCCOL nCol, SCROW nRow) const
Definition: document.hxx:877
sal_Int32 SCROW
Definition: types.hxx:18
RowSpan(SCROW nRow1, SCROW nRow2)
virtual void executeSum(SCROW, SCROW, bool, double &)
bool ValidRow(SCROW nRow) const
Definition: document.hxx:876
ScRangeList GetMarkedRangesForTab(SCTAB nTab) const
Get marked ranges with sheet-tab set to nTab.
Definition: markdata.cxx:472
std::vector< RowSpan > SpansType
ColumnType(SCROW nStart, SCROW nEnd, bool bInit)
void scan(const ScColumn &rColumn)
Scan an entire column and tag all non-empty cell positions.
void executeColumnAction(ScDocument &rDoc, sc::ColumnSpanSet::ColumnAction &ac) const
SCCOL ClampToAllocatedColumns(SCCOL nCol) const
Definition: table.hxx:1084
bool GetTableSelect(SCTAB nTab) const
Definition: markdata.cxx:184
SingleColumnSpanSet(ScSheetLimits const &)
void swap(SingleColumnSpanSet &r)
SCCOL GetAllocatedColumnsCount() const
Definition: table.hxx:1085
virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)=0
std::vector< std::unique_ptr< TableType > > maTables
std::vector< std::unique_ptr< ColumnType > > TableType
bool ValidTab(SCTAB nTab)
Definition: address.hxx:105
virtual void startColumn(ScColumn *pCol)=0
void executeAction(Action &ac) const
sal_Int16 SCTAB
Definition: types.hxx:23
const char first[]