LibreOffice Module sc (master)  1
table4.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  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <scitems.hxx>
21 #include <comphelper/string.hxx>
22 #include <editeng/boxitem.hxx>
23 #include <editeng/editeng.hxx>
24 #include <editeng/eeitem.hxx>
26 #include <svl/numformat.hxx>
27 #include <svl/zforlist.hxx>
28 #include <vcl/keycodes.hxx>
29 #include <rtl/math.hxx>
30 #include <unotools/charclass.hxx>
31 #include <osl/diagnose.h>
32 
33 #include <attrib.hxx>
34 #include <patattr.hxx>
35 #include <formulacell.hxx>
36 #include <table.hxx>
37 #include <global.hxx>
38 #include <document.hxx>
39 #include <autoform.hxx>
40 #include <userlist.hxx>
41 #include <zforauto.hxx>
42 #include <subtotal.hxx>
43 #include <formula/errorcodes.hxx>
44 #include <docpool.hxx>
45 #include <progress.hxx>
46 #include <conditio.hxx>
47 #include <editutil.hxx>
48 #include <listenercontext.hxx>
49 #include <scopetools.hxx>
50 #include <o3tl/string_view.hxx>
51 
52 #include <math.h>
53 #include <memory>
54 #include <list>
55 #include <string_view>
56 
57 #define D_MAX_LONG_ double(0x7fffffff)
58 
59 namespace {
60 
61 short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMinDigits = nullptr )
62 {
63  if ( rValue.isEmpty() )
64  {
65  nVal = 0;
66  return 0;
67  }
68  const sal_Unicode* p = rValue.getStr();
69  sal_Int32 nSign = 0;
70  sal_Int32 nNum = 0;
71  if ( p[nNum] == '-' || p[nNum] == '+' )
72  nNum = nSign = 1;
73  while ( p[nNum] && CharClass::isAsciiNumeric( std::u16string_view(&p[nNum], 1) ) )
74  nNum++;
75 
76  sal_Unicode cNext = p[nNum]; // 0 if at the end
77  sal_Unicode cLast = p[rValue.getLength()-1];
78 
79  // #i5550# If there are numbers at the beginning and the end,
80  // prefer the one at the beginning only if it's followed by a space.
81  // Otherwise, use the number at the end, to enable things like IP addresses.
82  if ( nNum > nSign && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(std::u16string_view(&cLast, 1)) ) )
83  { // number at the beginning
84  nVal = o3tl::toInt32(rValue.subView( 0, nNum ));
85  // any number with a leading zero sets the minimum number of digits
86  if ( p[nSign] == '0' && pMinDigits && ( nNum - nSign > *pMinDigits ) )
87  *pMinDigits = nNum - nSign;
88  rValue = rValue.copy(nNum);
89  return -1;
90  }
91  else
92  {
93  nSign = 0;
94  sal_Int32 nEnd = nNum = rValue.getLength() - 1;
95  while ( nNum && CharClass::isAsciiNumeric( std::u16string_view(&p[nNum], 1) ) )
96  nNum--;
97  if ( p[nNum] == '-' || p[nNum] == '+' )
98  {
99  nNum--;
100  nSign = 1;
101  }
102  if ( nNum < nEnd - nSign )
103  { // number at the end
104  nVal = o3tl::toInt32(rValue.subView( nNum + 1 ));
105  // any number with a leading zero sets the minimum number of digits
106  if ( p[nNum+1+nSign] == '0' && pMinDigits && ( nEnd - nNum - nSign > *pMinDigits ) )
107  *pMinDigits = nEnd - nNum - nSign;
108  rValue = rValue.copy(0, nNum + 1);
109  if (nSign) // use the return value = 2 to put back the '+'
110  return 2;
111  else
112  return 1;
113  }
114  }
115  nVal = 0;
116  return 0;
117 }
118 
119 OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
120 {
121  if ( nMinDigits <= 1 )
122  return OUString::number( nValue ); // simple case...
123  else
124  {
125  OUString aStr = OUString::number( std::abs( nValue ) );
126  if ( aStr.getLength() < nMinDigits )
127  {
128  OUStringBuffer aZero(nMinDigits);
129  comphelper::string::padToLength(aZero, nMinDigits - aStr.getLength(), '0');
130  aStr = aZero.append(aStr).makeStringAndClear();
131  }
132  // nMinDigits doesn't include the '-' sign -> add after inserting zeros
133  if ( nValue < 0 )
134  aStr = "-" + aStr;
135  return aStr;
136  }
137 }
138 
139 void setSuffixCell(
140  ScColumn& rColumn, SCROW nRow, sal_Int32 nValue, sal_uInt16 nDigits,
141  std::u16string_view rSuffix,
142  CellType eCellType, bool bIsOrdinalSuffix )
143 {
144  ScDocument& rDoc = rColumn.GetDoc();
145  OUString aValue = lcl_ValueString(nValue, nDigits);
146  if (!bIsOrdinalSuffix)
147  {
148  aValue += rSuffix;
149  rColumn.SetRawString(nRow, aValue);
150  return;
151  }
152 
153  OUString aOrdinalSuffix = ScGlobal::GetOrdinalSuffix(nValue);
154  if (eCellType != CELLTYPE_EDIT)
155  {
156  aValue += aOrdinalSuffix;
157  rColumn.SetRawString(nRow, aValue);
158  return;
159  }
160 
161  EditEngine aEngine(rDoc.GetEnginePool());
162  aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
163 
164  SfxItemSet aAttr = aEngine.GetEmptyItemSet();
165  aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT));
166  aEngine.SetText( aValue );
167  aEngine.QuickInsertText(
168  aOrdinalSuffix,
169  ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
170 
171  aEngine.QuickSetAttribs(
172  aAttr,
173  ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
174 
175  // Text object instance will be owned by the cell.
176  rColumn.SetEditText(nRow, aEngine.CreateTextObject());
177 }
178 
179 }
180 
181 namespace {
182 /* TODO: move this to rtl::math::approxDiff() ? Though the name is funny, the
183  * approx is expected to be more correct than the raw diff. */
187 double approxDiff( double a, double b )
188 {
189  if (a == b)
190  return 0.0;
191  if (a == 0.0)
192  return -b;
193  if (b == 0.0)
194  return a;
195  const double c = a - b;
196  const double aa = fabs(a);
197  const double ab = fabs(b);
198  if (aa < 1e-16 || aa > 1e+16 || ab < 1e-16 || ab > 1e+16)
199  // This is going nowhere, live with the result.
200  return c;
201 
202  const double q = aa < ab ? b / a : a / b;
203  const double d = (a * q - b * q) / q;
204  if (d == c)
205  // No differing error, live with the result.
206  return c;
207 
208  // We now have two subtractions with a similar but not equal error. Obtain
209  // the exponent of the error magnitude and round accordingly.
210  const double e = fabs(d - c);
211  const int nExp = static_cast<int>(floor(log10(e))) + 1;
212  // tdf#129606: Limit precision to the 16th significant digit of the least precise argument.
213  // Cf. mnMaxGeneralPrecision in sc/source/core/data/column3.cxx.
214  const int nExpArg = static_cast<int>(floor(log10(std::max(aa, ab)))) - 15;
215  return rtl::math::round(c, -std::max(nExp, nExpArg));
216 }
217 }
218 
219 void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
220  FillCmd& rCmd, FillDateCmd& rDateCmd,
221  double& rInc, sal_uInt16& rMinDigits,
222  ScUserListData*& rListData, sal_uInt16& rListIndex,
223  bool bHasFiltered, bool& rSkipOverlappedCells,
224  std::vector<sal_Int32>& rNonOverlappedCellIdx)
225 {
226  OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
227 
228  rInc = 0.0;
229  rMinDigits = 0;
230  rListData = nullptr;
231  rCmd = FILL_SIMPLE;
232  rSkipOverlappedCells = false;
234  return ; // Ctrl-key: Copy
235 
236  SCCOL nAddX;
237  SCROW nAddY;
238  SCSIZE nCount;
239  if (nCol1 == nCol2)
240  {
241  nAddX = 0;
242  nAddY = 1;
243  nCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
244  }
245  else
246  {
247  nAddX = 1;
248  nAddY = 0;
249  nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
250  }
251 
252  // Try to analyse the merged cells only if there are no filtered rows in the destination area
253  // Else fallback to the old way to avoid regression.
254  // Filling merged cells into an area with filtered (hidden) rows, is a very complex task
255  // that is not implemented, but not even decided how to do, even excel can't handle that well
256  if (!bHasFiltered)
257  {
258  bool bHasOverlappedCells = false;
259  bool bSkipOverlappedCells = true;
260  SCCOL nColCurr = nCol1;
261  SCROW nRowCurr = nRow1;
262 
263  // collect cells that are not empty or not overlapped
264  rNonOverlappedCellIdx.resize(nCount);
265  SCSIZE nValueCount = 0;
266  for (SCSIZE i = 0; i < nCount; ++i)
267  {
268  const ScPatternAttr* pPattern = GetPattern(nColCurr, nRowCurr);
269  bool bOverlapped
270  = pPattern->GetItemSet().GetItemState(ATTR_MERGE_FLAG, false) == SfxItemState::SET
271  && pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped();
272 
273  if (bOverlapped)
274  bHasOverlappedCells = true;
275 
276  if (!bOverlapped || GetCellValue(nColCurr, nRowCurr).meType != CELLTYPE_NONE)
277  {
278  rNonOverlappedCellIdx[nValueCount++] = i;
279  // if there is at least 1 non empty overlapped cell, then no cell should be skipped
280  if (bOverlapped)
281  bSkipOverlappedCells = false;
282  }
283 
284  nColCurr += nAddX;
285  nRowCurr += nAddY;
286  }
287  rNonOverlappedCellIdx.resize(nValueCount);
288 
289  // if all the values are overlapped CELLTYPE_NONE, then there is no need to analyse it.
290  if (nValueCount == 0)
291  return;
292 
293  // if there is no overlapped cells, there is nothing to skip
294  if (!bHasOverlappedCells)
295  bSkipOverlappedCells = false;
296 
297  if (bSkipOverlappedCells)
298  {
299  nColCurr = nCol1 + rNonOverlappedCellIdx[0] * nAddX;
300  nRowCurr = nRow1 + rNonOverlappedCellIdx[0] * nAddY;
301  ScRefCellValue aPrevCell, aCurrCell;
302  aCurrCell = GetCellValue(nColCurr, nRowCurr);
303  CellType eCellType = aCurrCell.meType;
304  if (eCellType == CELLTYPE_VALUE)
305  {
306  bool bVal = true;
307  double fVal;
308  SvNumFormatType nCurrCellFormatType
309  = rDocument.GetFormatTable()->GetType(GetNumberFormat(nColCurr, nRowCurr));
310  if (nCurrCellFormatType == SvNumFormatType::DATE)
311  {
312  if (nValueCount >= 2)
313  {
314  tools::Long nCmpInc = 0;
315  FillDateCmd eType = FILL_YEAR; // just some temporary default values
316  tools::Long nDDiff = 0, nMDiff = 0, nYDiff = 0; // to avoid warnings
317  Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
318  Date aCurrDate = aNullDate, aPrevDate = aNullDate;
319  aCurrDate.AddDays(aCurrCell.mfValue);
320  for (SCSIZE i = 1; i < nValueCount && bVal; i++)
321  {
322  aPrevCell = aCurrCell;
323  aPrevDate = aCurrDate;
324  nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
325  nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
326  aCurrCell = GetCellValue(nColCurr, nRowCurr);
327  if (aCurrCell.meType == CELLTYPE_VALUE)
328  {
329  aCurrDate = aNullDate + static_cast<sal_Int32>(aCurrCell.mfValue);
330  if (eType != FILL_DAY) {
331  nDDiff = aCurrDate.GetDay()
332  - static_cast<tools::Long>(aPrevDate.GetDay());
333  nMDiff = aCurrDate.GetMonth()
334  - static_cast<tools::Long>(aPrevDate.GetMonth());
335  nYDiff = aCurrDate.GetYear()
336  - static_cast<tools::Long>(aPrevDate.GetYear());
337  }
338  if (i == 1)
339  {
340  if (nDDiff != 0)
341  {
342  eType = FILL_DAY;
343  nCmpInc = aCurrDate - aPrevDate;
344  }
345  else
346  {
347  eType = FILL_MONTH;
348  nCmpInc = nMDiff + 12 * nYDiff;
349  }
350  }
351  else if (eType == FILL_DAY)
352  {
353  if (aCurrDate - aPrevDate != nCmpInc)
354  bVal = false;
355  }
356  else
357  {
358  if (nDDiff || (nMDiff + 12 * nYDiff != nCmpInc))
359  bVal = false;
360  }
361  }
362  else
363  bVal = false; // No date is also not ok
364  }
365  if (bVal)
366  {
367  if (eType == FILL_MONTH && (nCmpInc % 12 == 0))
368  {
369  eType = FILL_YEAR;
370  nCmpInc /= 12;
371  }
372  rCmd = FILL_DATE;
373  rDateCmd = eType;
374  rInc = nCmpInc;
375  rSkipOverlappedCells = true;
376  return;
377  }
378  }
379  else
380  {
381  rCmd = FILL_DATE;
382  rDateCmd = FILL_DAY;
383  rInc = 1.0;
384  rSkipOverlappedCells = true;
385  return;
386  }
387  }
388  else if (nCurrCellFormatType == SvNumFormatType::LOGICAL
389  && ((fVal = aCurrCell.mfValue) == 0.0 || fVal == 1.0))
390  {
391  }
392  else if (nValueCount >= 2)
393  {
394  for (SCSIZE i = 1; i < nValueCount && bVal; i++)
395  {
396  aPrevCell = aCurrCell;
397  nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
398  nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
399  aCurrCell = GetCellValue(nColCurr, nRowCurr);
400  if (aCurrCell.meType == CELLTYPE_VALUE)
401  {
402  double nDiff = approxDiff(aCurrCell.mfValue, aPrevCell.mfValue);
403  if (i == 1)
404  rInc = nDiff;
405  if (!::rtl::math::approxEqual(nDiff, rInc, 13))
406  bVal = false;
407  else if ((aCurrCell.mfValue == 0.0 || aCurrCell.mfValue == 1.0)
409  GetNumberFormat(nColCurr, nRowCurr))
410  == SvNumFormatType::LOGICAL))
411  bVal = false;
412  }
413  else
414  bVal = false;
415  }
416  if (bVal)
417  {
418  rCmd = FILL_LINEAR;
419  rSkipOverlappedCells = true;
420  return;
421  }
422  }
423  }
424  else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
425  {
426  OUString aStr = GetString(nColCurr, nRowCurr );
427  OUString aStr2;
428 
429  rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList()->GetData(aStr));
430  if (rListData)
431  {
432  bool bMatchCase = false;
433  (void)rListData->GetSubIndex(aStr, rListIndex, bMatchCase);
434  size_t nListStrCount = rListData->GetSubCount();
435  sal_uInt16 nPrevListIndex, nInc = 1;
436  for (SCSIZE i = 1; i < nValueCount && rListData; i++)
437  {
438  nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
439  nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
440  aStr2 = GetString(nColCurr, nRowCurr);
441 
442  nPrevListIndex = rListIndex;
443  if (!rListData->GetSubIndex(aStr2, rListIndex, bMatchCase))
444  rListData = nullptr;
445  else
446  {
447  sal_Int32 nIncCurr = rListIndex - nPrevListIndex;
448  if (nIncCurr < 0)
449  nIncCurr += nListStrCount;
450  if (i == 1)
451  nInc = nIncCurr;
452  else if (nInc != nIncCurr)
453  rListData = nullptr;
454  }
455  }
456  if (rListData) {
457  rInc = nInc;
458  rSkipOverlappedCells = true;
459  return;
460  }
461  }
462  short nFlag1, nFlag2;
463  sal_Int32 nVal1, nVal2;
464  nFlag1 = lcl_DecompValueString(aStr, nVal1, &rMinDigits);
465  if (nFlag1)
466  {
467  bool bVal = true;
468  rInc = 1;
469  for (SCSIZE i = 1; i < nValueCount && bVal; i++)
470  {
471  nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
472  nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
473  ScRefCellValue aCell = GetCellValue(nColCurr, nRowCurr);
474  CellType eType = aCell.meType;
475  if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
476  {
477  aStr2 = aCell.getString(&rDocument);
478  nFlag2 = lcl_DecompValueString(aStr2, nVal2, &rMinDigits);
479  if (nFlag1 == nFlag2 && aStr == aStr2)
480  {
481  double nDiff = approxDiff(nVal2, nVal1);
482  if (i == 1)
483  rInc = nDiff;
484  else if (!::rtl::math::approxEqual(nDiff, rInc, 13))
485  bVal = false;
486  nVal1 = nVal2;
487  }
488  else
489  bVal = false;
490  }
491  else
492  bVal = false;
493  }
494  if (bVal)
495  {
496  rCmd = FILL_LINEAR;
497  rSkipOverlappedCells = true;
498  return;
499  }
500  }
501  }
502  }
503  }
504 
505  //if it is not a FILL_LINEAR - CELLTYPE_VALUE - with merged cells [without hidden values]
506  //then do it in the old way
507 
508  SCCOL nCol = nCol1;
509  SCROW nRow = nRow1;
510 
511  ScRefCellValue aFirstCell = GetCellValue(nCol, nRow);
512  CellType eCellType = aFirstCell.meType;
513 
514  if (eCellType == CELLTYPE_VALUE)
515  {
516  double fVal;
517  sal_uInt32 nFormat = GetAttr(nCol,nRow,ATTR_VALUE_FORMAT)->GetValue();
518  const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(nFormat);
519  bool bDate = (nFormatType == SvNumFormatType::DATE );
520  bool bBooleanCell = (!bDate && nFormatType == SvNumFormatType::LOGICAL);
521  if (bDate)
522  {
523  if (nCount > 1)
524  {
525  double nVal;
526  Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
527  Date aDate1 = aNullDate;
528  nVal = aFirstCell.mfValue;
529  aDate1.AddDays(nVal);
530  Date aDate2 = aNullDate;
531  nVal = GetValue(nCol+nAddX, nRow+nAddY);
532  aDate2.AddDays(nVal);
533  if ( aDate1 != aDate2 )
534  {
535  tools::Long nCmpInc = 0;
537  tools::Long nDDiff = aDate2.GetDay() - static_cast<tools::Long>(aDate1.GetDay());
538  tools::Long nMDiff = aDate2.GetMonth() - static_cast<tools::Long>(aDate1.GetMonth());
539  tools::Long nYDiff = aDate2.GetYear() - static_cast<tools::Long>(aDate1.GetYear());
540  if (nMDiff && aDate1.IsEndOfMonth() && aDate2.IsEndOfMonth())
541  {
542  eType = FILL_END_OF_MONTH;
543  nCmpInc = nMDiff + 12 * nYDiff;
544  }
545  else if (nDDiff)
546  {
547  eType = FILL_DAY;
548  nCmpInc = aDate2 - aDate1;
549  }
550  else
551  {
552  eType = FILL_MONTH;
553  nCmpInc = nMDiff + 12 * nYDiff;
554  }
555 
556  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
557  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
558  bool bVal = true;
559  for (SCSIZE i=1; i<nCount && bVal; i++)
560  {
561  ScRefCellValue aCell = GetCellValue(nCol,nRow);
562  if (aCell.meType == CELLTYPE_VALUE)
563  {
564  nVal = aCell.mfValue;
565  aDate2 = aNullDate + static_cast<sal_Int32>(nVal);
566  if ( eType == FILL_DAY )
567  {
568  if ( aDate2-aDate1 != nCmpInc )
569  bVal = false;
570  }
571  else
572  {
573  nDDiff = aDate2.GetDay() - static_cast<tools::Long>(aDate1.GetDay());
574  nMDiff = aDate2.GetMonth() - static_cast<tools::Long>(aDate1.GetMonth());
575  nYDiff = aDate2.GetYear() - static_cast<tools::Long>(aDate1.GetYear());
576  if ((nDDiff && !aDate1.IsEndOfMonth() && !aDate2.IsEndOfMonth())
577  || (nMDiff + 12 * nYDiff != nCmpInc))
578  bVal = false;
579  }
580  aDate1 = aDate2;
581  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
582  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
583  }
584  else
585  bVal = false; // No date is also not ok
586  }
587  if (bVal)
588  {
589  if ((eType == FILL_MONTH || eType == FILL_END_OF_MONTH)
590  && (nCmpInc % 12 == 0))
591  {
592  eType = FILL_YEAR;
593  nCmpInc /= 12;
594  }
595  rCmd = FILL_DATE;
596  rDateCmd = eType;
597  rInc = nCmpInc;
598  }
599  }
600  else
601  {
602  // tdf#89754 - don't increment non different consecutive date cells
603  rCmd = FILL_DATE;
604  rDateCmd = FILL_DAY;
605  rInc = 0.0;
606  }
607  }
608  else // single date -> increment by days
609  {
610  rCmd = FILL_DATE;
611  rDateCmd = FILL_DAY;
612  rInc = 1.0;
613  }
614  }
615  else if (bBooleanCell && ((fVal = aFirstCell.mfValue) == 0.0 || fVal == 1.0))
616  {
617  // Nothing, rInc stays 0.0, no specific fill mode.
618  }
619  else
620  {
621  if (nCount > 1)
622  {
623  double nVal1 = aFirstCell.mfValue;
624  double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
625  rInc = approxDiff( nVal2, nVal1);
626  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
627  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
628  bool bVal = true;
629  for (SCSIZE i=1; i<nCount && bVal; i++)
630  {
631  ScRefCellValue aCell = GetCellValue(nCol,nRow);
632  if (aCell.meType == CELLTYPE_VALUE)
633  {
634  nVal2 = aCell.mfValue;
635  double nDiff = approxDiff( nVal2, nVal1);
636  if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
637  bVal = false;
638  else if ((nVal2 == 0.0 || nVal2 == 1.0) &&
640  SvNumFormatType::LOGICAL))
641  bVal = false;
642  nVal1 = nVal2;
643  }
644  else
645  bVal = false;
646  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
647  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
648  }
649  if (bVal)
650  rCmd = FILL_LINEAR;
651  }
652  else if(nFormatType == SvNumFormatType::PERCENT)
653  {
654  rInc = 0.01; // tdf#89998 increment by 1% at a time
655  }
656  }
657  }
658  else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
659  {
660  OUString aStr = GetString(nCol, nRow);
661 
662  rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList()->GetData(aStr));
663  if (rListData)
664  {
665  bool bMatchCase = false;
666  (void)rListData->GetSubIndex(aStr, rListIndex, bMatchCase);
667  size_t nListStrCount = rListData->GetSubCount();
668  sal_uInt16 nPrevListIndex, nInc = 1;
669  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
670  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
671  for (SCSIZE i=1; i<nCount && rListData; i++)
672  {
673  nPrevListIndex = rListIndex;
674  aStr = GetString(nCol, nRow);
675  if (!rListData->GetSubIndex(aStr, rListIndex, bMatchCase))
676  rListData = nullptr;
677  else
678  {
679  sal_Int32 nIncCurr = rListIndex - nPrevListIndex;
680  if (nIncCurr < 0)
681  nIncCurr += nListStrCount;
682  if (i == 1)
683  nInc = nIncCurr;
684  else if (nInc != nIncCurr)
685  rListData = nullptr;
686  }
687  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
688  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
689  }
690  if (rListData)
691  rInc = nInc;
692  }
693  else if ( nCount > 1 )
694  {
695  // pass rMinDigits to all DecompValueString calls
696  // -> longest number defines rMinDigits
697 
698  sal_Int32 nVal1;
699  short nFlag1 = lcl_DecompValueString( aStr, nVal1, &rMinDigits );
700  if ( nFlag1 )
701  {
702  sal_Int32 nVal2;
703  aStr = GetString( nCol+nAddX, nRow+nAddY );
704  short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
705  if ( nFlag1 == nFlag2 )
706  {
707  rInc = approxDiff( nVal2, nVal1);
708  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
709  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
710  bool bVal = true;
711  for (SCSIZE i=1; i<nCount && bVal; i++)
712  {
713  ScRefCellValue aCell = GetCellValue(nCol, nRow);
714  CellType eType = aCell.meType;
715  if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
716  {
717  aStr = aCell.getString(&rDocument);
718  nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
719  if ( nFlag1 == nFlag2 )
720  {
721  double nDiff = approxDiff( nVal2, nVal1);
722  if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
723  bVal = false;
724  nVal1 = nVal2;
725  }
726  else
727  bVal = false;
728  }
729  else
730  bVal = false;
731  nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
732  nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
733  }
734  if (bVal)
735  rCmd = FILL_LINEAR;
736  }
737  }
738  }
739  else
740  {
741  // call DecompValueString to set rMinDigits
742  sal_Int32 nDummy;
743  lcl_DecompValueString( aStr, nDummy, &rMinDigits );
744  }
745  }
746 }
747 
749  const ScFormulaCell* pSrcCell, SCCOL nDestCol, SCROW nDestRow, bool bLast )
750 {
751 
752  rDocument.SetNoListening( true ); // still the wrong reference
753  ScAddress aAddr( nDestCol, nDestRow, nTab );
754  ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, rDocument, aAddr );
755  aCol[nDestCol].SetFormulaCell(nDestRow, pDestCell);
756 
757  if ( bLast && pDestCell->GetMatrixFlag() != ScMatrixMode::NONE )
758  {
759  ScAddress aOrg;
760  if ( pDestCell->GetMatrixOrigin( GetDoc(), aOrg ) )
761  {
762  if ( nDestCol >= aOrg.Col() && nDestRow >= aOrg.Row() )
763  {
764  ScFormulaCell* pOrgCell = rDocument.GetFormulaCell(aOrg);
765  if (pOrgCell && pOrgCell->GetMatrixFlag() == ScMatrixMode::Formula)
766  {
767  pOrgCell->SetMatColsRows(
768  nDestCol - aOrg.Col() + 1,
769  nDestRow - aOrg.Row() + 1 );
770  }
771  else
772  {
773  OSL_FAIL( "FillFormula: MatrixOrigin no formula cell with ScMatrixMode::Formula" );
774  }
775  }
776  else
777  {
778  OSL_FAIL( "FillFormula: MatrixOrigin bottom right" );
779  }
780  }
781  else
782  {
783  OSL_FAIL( "FillFormula: no MatrixOrigin" );
784  }
785  }
786  rDocument.SetNoListening( false );
787  pDestCell->StartListeningTo( rDocument );
788 }
789 
790 void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
791  sal_uInt64 nFillCount, FillDir eFillDir, ScProgress* pProgress )
792 {
793  if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
794  return;
795 
796  // Detect direction
797 
798  bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
799  bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
800 
801  SCCOLROW nCol = 0;
802  SCCOLROW nRow = 0;
803  SCCOLROW& rInner = bVertical ? nRow : nCol; // loop variables
804  SCCOLROW& rOuter = bVertical ? nCol : nRow;
805  SCCOLROW nOStart;
806  SCCOLROW nOEnd;
807  SCCOLROW nIStart;
808  SCCOLROW nIEnd;
809  SCCOLROW nISrcStart;
810  SCCOLROW nISrcEnd;
811  ScRange aFillRange;
812 
813  if (bVertical)
814  {
815  nOStart = nCol1;
816  nOEnd = nCol2;
817  if (bPositive)
818  {
819  nISrcStart = nRow1;
820  nISrcEnd = nRow2;
821  nIStart = nRow2 + 1;
822  nIEnd = nRow2 + nFillCount;
823  aFillRange = ScRange(nCol1, nRow2+1, 0, nCol2, nRow2 + nFillCount, 0);
824  }
825  else
826  {
827  nISrcStart = nRow2;
828  nISrcEnd = nRow1;
829  nIStart = nRow1 - 1;
830  nIEnd = nRow1 - nFillCount;
831  aFillRange = ScRange(nCol1, nRow1-1, 0, nCol2, nRow2 - nFillCount, 0);
832  }
833  }
834  else
835  {
836  nOStart = nRow1;
837  nOEnd = nRow2;
838  if (bPositive)
839  {
840  nISrcStart = nCol1;
841  nISrcEnd = nCol2;
842  nIStart = nCol2 + 1;
843  nIEnd = nCol2 + nFillCount;
844  aFillRange = ScRange(nCol2 + 1, nRow1, 0, nCol2 + nFillCount, nRow2, 0);
845  }
846  else
847  {
848  nISrcStart = nCol2;
849  nISrcEnd = nCol1;
850  nIStart = nCol1 - 1;
851  nIEnd = nCol1 - nFillCount;
852  aFillRange = ScRange(nCol1 - 1, nRow1, 0, nCol1 - nFillCount, nRow2, 0);
853  }
854  }
855  sal_uInt64 nIMin = nIStart;
856  sal_uInt64 nIMax = nIEnd;
857  PutInOrder(nIMin,nIMax);
858  bool bHasFiltered = IsDataFiltered(aFillRange);
859 
860  if (!bHasFiltered)
861  {
862  if (bVertical)
863  DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), InsertDeleteFlags::AUTOFILL);
864  else
865  DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, InsertDeleteFlags::AUTOFILL);
866  }
867 
868  sal_uInt64 nProgress = 0;
869  if (pProgress)
870  nProgress = pProgress->GetState();
871 
872  // Avoid possible repeated calls to StartListeningFormulaCells() (tdf#132165).
873  std::list< sc::DelayStartListeningFormulaCells > delayStartListening;
874  SCCOL delayStartColumn, delayEndColumn;
875  if(bVertical)
876  {
877  delayStartColumn = std::min( nOStart, nOEnd );
878  delayEndColumn = std::max( nOStart, nOEnd );
879  }
880  else
881  {
882  delayStartColumn = std::min( nIStart, nIEnd );
883  delayEndColumn = std::max( nIStart, nIEnd );
884  }
885  for( SCROW col = delayStartColumn; col <= delayEndColumn; ++col )
886  {
887  if( ScColumn* column = FetchColumn( col ))
888  delayStartListening.emplace_back( *column, true );
889  }
890 
891  // execute
892 
893  sal_uInt64 nActFormCnt = 0;
894  for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
895  {
896  sal_uInt64 nMaxFormCnt = 0; // for formulas
897 
898  // transfer attributes
899 
900  const ScPatternAttr* pSrcPattern = nullptr;
901  const ScStyleSheet* pStyleSheet = nullptr;
902  SCCOLROW nAtSrc = nISrcStart;
903  std::unique_ptr<ScPatternAttr> pNewPattern;
904  bool bGetPattern = true;
905  rInner = nIStart;
906  while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
907  {
908  if (!ColHidden(nCol) && !RowHidden(nRow))
909  {
910  if ( bGetPattern )
911  {
912  if (bVertical) // rInner&:=nRow, rOuter&:=nCol
913  pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nAtSrc));
914  else // rInner&:=nCol, rOuter&:=nRow
915  pSrcPattern = aCol[nAtSrc].GetPattern(static_cast<SCROW>(nRow));
916  bGetPattern = false;
917  pStyleSheet = pSrcPattern->GetStyleSheet();
918  // do transfer ATTR_MERGE / ATTR_MERGE_FLAG
919  //
920  // Note: ATTR_MERGE is an attribute of the top left cell of a merged area
921  // containing the size of the area. ATTR_MERGE_FLAGs are attributes of the
922  // other cells of a merged area, containing the information about also
923  // overlapping, i.e. visibility of their content.
924  //
925  // TODO: extend the similar incomplete selections to a bounding rectangle to
926  // avoid incomplete fill, where not all AUTO_MERGE_FLAGs are synchronized with
927  // the copied ATTR_MERGE, resulting broken grid and visibility during run-time.
928  //
929  // +--+ +--+--+
930  // | | | | |
931  // +--+--+ +--+--+
932  // | | -> | |
933  // +--+--+ +--+--+
934  // | | | | |
935  // +--+ +--+--+
936  //
937  // TODO: protect incompatible merged cells of the destination area, for example
938  // by skipping the fill operation.
939  //
940  // TODO: by dragging the fill handle select only the multiples of the height
941  // of the originally selected area which is merged vertically to avoid of
942  // incomplete fill.
943  //
944  // +--+ +--+
945  // |XX| |XX|
946  // +XX+ +XX+
947  // |XX| -> |XX|
948  // +--+ +--+
949  // | | | |
950  // +--+ +--+
951  // | |
952  // +--+
953  //
954  // Other things stored in ATTR_MERGE_FLAG, like autofilter button, will be
955  // deleted now, but may need to be repaired later, like at ScDocument::Fill.
956  const SfxItemSet& rSet = pSrcPattern->GetItemSet();
957  if ( rSet.GetItemState(ATTR_MERGE_FLAG, false) == SfxItemState::SET )
958  {
959  ScMF nOldValue = pSrcPattern->GetItem(ATTR_MERGE_FLAG).GetValue();
960  ScMF nOldValueMerge = nOldValue & (ScMF::Hor | ScMF::Ver);
961  // keep only the merge flags
962  if ( nOldValue != nOldValueMerge )
963  {
964  pNewPattern.reset(new ScPatternAttr(*pSrcPattern));
965  SfxItemSet& rNewSet = pNewPattern->GetItemSet();
966  if ( nOldValueMerge == ScMF::NONE )
967  rNewSet.ClearItem(ATTR_MERGE_FLAG);
968  else
969  rNewSet.Put(ScMergeFlagAttr(nOldValueMerge));
970  }
971  else
972  pNewPattern.reset();
973  }
974  else
975  pNewPattern.reset();
976  }
977 
978  const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
979  const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
980 
981  if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
982  {
983  // set all attributes at once (en bloc)
984  if (pNewPattern || pSrcPattern != rDocument.GetDefPattern())
985  {
986  // Default is already present (DeleteArea)
987  SCROW nY1 = static_cast<SCROW>(std::min( nIStart, nIEnd ));
988  SCROW nY2 = static_cast<SCROW>(std::max( nIStart, nIEnd ));
989  if ( pStyleSheet )
990  aCol[nCol].ApplyStyleArea( nY1, nY2, *pStyleSheet );
991  if ( pNewPattern )
992  aCol[nCol].ApplyPatternArea( nY1, nY2, *pNewPattern );
993  else
994  aCol[nCol].ApplyPatternArea( nY1, nY2, *pSrcPattern );
995 
996  for(const auto& rIndex : rCondFormatIndex)
997  {
998  ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
999  if (pCondFormat)
1000  {
1001  ScRangeList aRange = pCondFormat->GetRange();
1002  aRange.Join(ScRange(nCol, nY1, nTab, nCol, nY2, nTab));
1003  pCondFormat->SetRange(aRange);
1004  }
1005  }
1006  }
1007 
1008  break;
1009  }
1010 
1011  if ( bHasFiltered )
1012  DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow),
1013  static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), InsertDeleteFlags::AUTOFILL);
1014 
1015  if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) )
1016  {
1017  // Transfer template too
1018  //TODO: Merge ApplyPattern to AttrArray ??
1019  if ( pStyleSheet )
1020  aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), pStyleSheet );
1021 
1022  // Use ApplyPattern instead of SetPattern to keep old MergeFlags
1023  if ( pNewPattern )
1024  aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern );
1025  else
1026  aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern );
1027 
1028  for(const auto& rIndex : rCondFormatIndex)
1029  {
1030  ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
1031  if (pCondFormat)
1032  {
1033  ScRangeList aRange = pCondFormat->GetRange();
1034  aRange.Join(ScRange(nCol, nRow, nTab, nCol, nRow, nTab));
1035  pCondFormat->SetRange(aRange);
1036  }
1037  }
1038  }
1039 
1040  if (nAtSrc==nISrcEnd)
1041  {
1042  if ( nAtSrc != nISrcStart )
1043  { // More than one source cell
1044  nAtSrc = nISrcStart;
1045  bGetPattern = true;
1046  }
1047  }
1048  else if (bPositive)
1049  {
1050  ++nAtSrc;
1051  bGetPattern = true;
1052  }
1053  else
1054  {
1055  --nAtSrc;
1056  bGetPattern = true;
1057  }
1058  }
1059 
1060  if (rInner == nIEnd) break;
1061  if (bPositive) ++rInner; else --rInner;
1062  }
1063  pNewPattern.reset();
1064 
1065  // Analyse
1066 
1067  FillCmd eFillCmd;
1068  FillDateCmd eDateCmd = {};
1069  double nInc;
1070  sal_uInt16 nMinDigits;
1071  ScUserListData* pListData = nullptr;
1072  sal_uInt16 nListIndex;
1073  bool bSkipOverlappedCells;
1074  std::vector<sal_Int32> aNonOverlappedCellIdx;
1075  if (bVertical)
1076  FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
1077  static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
1078  nInc, nMinDigits, pListData, nListIndex,
1079  bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
1080  else
1081  FillAnalyse(nCol1,static_cast<SCROW>(nRow),
1082  nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
1083  nInc, nMinDigits, pListData, nListIndex,
1084  bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
1085 
1086  if (pListData)
1087  {
1088  sal_uInt16 nListCount = pListData->GetSubCount();
1089  if (bSkipOverlappedCells)
1090  {
1091  int nFillerCount = 1 + ( nISrcEnd - nISrcStart ) * (bPositive ? 1 : -1);
1092  std::vector<bool> aIsNonEmptyCell(nFillerCount, false);
1093  SCCOLROW nLastValueIdx;
1094  if (bPositive)
1095  {
1096  nLastValueIdx = nISrcEnd - (nFillerCount - 1 - aNonOverlappedCellIdx.back());
1097  for (auto i : aNonOverlappedCellIdx)
1098  aIsNonEmptyCell[i] = true;
1099  }
1100  else
1101  {
1102  nLastValueIdx = nISrcEnd + aNonOverlappedCellIdx[0];
1103  for (auto i : aNonOverlappedCellIdx)
1104  aIsNonEmptyCell[nFillerCount - 1 - i] = true;
1105  }
1106 
1107  OUString aStr;
1108  if (bVertical)
1109  aStr = GetString(rOuter, nLastValueIdx);
1110  else
1111  aStr = GetString(nLastValueIdx, rOuter);
1112 
1113  bool bMatchCase = false;
1114  (void)pListData->GetSubIndex(aStr, nListIndex, bMatchCase);
1115 
1116  sal_Int32 nFillerIdx = 0;
1117  rInner = nIStart;
1118  while (true)
1119  {
1120  if (aIsNonEmptyCell[nFillerIdx])
1121  {
1122  if (bPositive)
1123  {
1124  nListIndex += nInc;
1125  if (nListIndex >= nListCount) nListIndex -= nListCount;
1126  }
1127  else
1128  {
1129  if (nListIndex < nInc) nListIndex += nListCount;
1130  nListIndex -= nInc;
1131  }
1132  aCol[nCol].SetRawString(static_cast<SCROW>(nRow), pListData->GetSubStr(nListIndex));
1133 
1134  }
1135  if (rInner == nIEnd) break;
1136  nFillerIdx = (nFillerIdx + 1) % nFillerCount;
1137  if (bPositive)
1138  ++rInner;
1139  else
1140  --rInner;
1141  }
1142  }
1143  else
1144  {
1145  if (!bPositive)
1146  {
1147  // nListIndex of FillAnalyse points to the last entry -> adjust
1148  sal_Int64 nAdjust = nListIndex - (nISrcStart - nISrcEnd) * nInc;
1149  nAdjust = nAdjust % nListCount;
1150  if (nAdjust < 0)
1151  nAdjust += nListCount;
1152  nListIndex = nAdjust;
1153  }
1154 
1155  rInner = nIStart;
1156  while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1157  {
1158  if (!ColHidden(nCol) && !RowHidden(nRow))
1159  {
1160  if (bPositive)
1161  {
1162  nListIndex += nInc;
1163  if (nListIndex >= nListCount) nListIndex -= nListCount;
1164  }
1165  else
1166  {
1167  if (nListIndex < nInc) nListIndex += nListCount;
1168  nListIndex -= nInc;
1169  }
1170  aCol[nCol].SetRawString(static_cast<SCROW>(nRow), pListData->GetSubStr(nListIndex));
1171  }
1172 
1173  if (rInner == nIEnd) break;
1174  if (bPositive) ++rInner; else --rInner;
1175  }
1176  }
1177  if(pProgress)
1178  {
1179  nProgress += nIMax - nIMin + 1;
1180  pProgress->SetStateOnPercent( nProgress );
1181  }
1182  }
1183  else if (eFillCmd == FILL_SIMPLE) // fill with pattern/sample
1184  {
1186  nISrcStart, nISrcEnd, nIStart, nIEnd, rInner, nCol, nRow,
1187  nActFormCnt, nMaxFormCnt, bHasFiltered, bVertical, bPositive, pProgress, nProgress);
1188  }
1189  else
1190  {
1191  if (!bPositive)
1192  nInc = -nInc;
1193  double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
1194  if (bVertical)
1195  FillSeries( static_cast<SCCOL>(nCol), nRow1,
1196  static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
1197  eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
1198  pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
1199  else
1200  FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
1201  static_cast<SCROW>(nRow), nFillCount, eFillDir,
1202  eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
1203  pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
1204  if (pProgress)
1205  nProgress = pProgress->GetState();
1206  }
1207 
1208  if (bVertical)
1209  FillSparkline(bVertical, nCol, nRow1, nRow2, nIStart, nIEnd);
1210  else
1211  FillSparkline(bVertical, nRow, nCol1, nCol2, nIStart, nIEnd);
1212 
1213  nActFormCnt += nMaxFormCnt;
1214  }
1215 }
1216 
1217 void ScTable::FillSparkline(bool bVertical, SCCOLROW nFixed,
1218  SCCOLROW nStart, SCCOLROW nEnd,
1219  SCCOLROW nFillStart, SCCOLROW nFillEnd)
1220 {
1221  bool bHasSparklines = false;
1222  std::vector<std::shared_ptr<sc::Sparkline>> aSparklineSeries;
1223 
1224  for (SCROW nCurrent = nStart; nCurrent <= nEnd; nCurrent++)
1225  {
1226  auto pSparkline = bVertical ? GetSparkline(nFixed, nCurrent) : GetSparkline(nCurrent, nFixed);
1227  bHasSparklines = bHasSparklines || bool(pSparkline);
1228  aSparklineSeries.push_back(pSparkline);
1229  }
1230 
1231  if (bHasSparklines)
1232  {
1233  for (SCCOLROW nCurrent = nFillStart; nCurrent <= nFillEnd; nCurrent++)
1234  {
1235  size_t nIndex = size_t(nFillStart - nCurrent) % aSparklineSeries.size();
1236  if (auto& rpSparkline = aSparklineSeries[nIndex])
1237  {
1238  auto pGroup = rpSparkline->getSparklineGroup();
1239 
1240  auto* pNewSparkline = bVertical ? CreateSparkline(nFixed, nCurrent, pGroup)
1241  : CreateSparkline(nCurrent, nFixed, pGroup);
1242  if (pNewSparkline)
1243  {
1244  SCCOLROW nPosition = bVertical ? rpSparkline->getRow()
1245  : rpSparkline->getColumn();
1246  SCCOLROW nDelta = nCurrent - nPosition;
1247  ScRangeList aRangeList(rpSparkline->getInputRange());
1248  for (ScRange& rRange : aRangeList)
1249  {
1250  if (bVertical)
1251  {
1252  rRange.aStart.IncRow(nDelta);
1253  rRange.aEnd.IncRow(nDelta);
1254  }
1255  else
1256  {
1257  rRange.aStart.IncCol(nDelta);
1258  rRange.aEnd.IncCol(nDelta);
1259  }
1260  }
1261  pNewSparkline->setInputRange(aRangeList);
1262  }
1263  }
1264  }
1265  }
1266 }
1267 
1268 OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
1269 {
1270  OUString aValue;
1271 
1272  SCCOL nCol1 = rSource.aStart.Col();
1273  SCROW nRow1 = rSource.aStart.Row();
1274  SCCOL nCol2 = rSource.aEnd.Col();
1275  SCROW nRow2 = rSource.aEnd.Row();
1276  bool bOk = true;
1277  tools::Long nIndex = 0;
1278  sal_uInt64 nSrcCount = 0;
1279  FillDir eFillDir = FILL_TO_BOTTOM;
1280  if ( nEndX == nCol2 && nEndY == nRow2 ) // empty
1281  bOk = false;
1282  else if ( nEndX == nCol2 ) // to up / down
1283  {
1284  nCol2 = nCol1; // use only first column
1285  nSrcCount = nRow2 - nRow1 + 1;
1286  nIndex = static_cast<tools::Long>(nEndY) - nRow1; // can be negative
1287  if ( nEndY >= nRow1 )
1288  eFillDir = FILL_TO_BOTTOM;
1289  else
1290  eFillDir = FILL_TO_TOP;
1291  }
1292  else if ( nEndY == nRow2 ) // to left / right
1293  {
1294  nEndY = nRow2 = nRow1; // use only first row
1295  nSrcCount = nCol2 - nCol1 + 1;
1296  nIndex = static_cast<tools::Long>(nEndX) - nCol1; // can be negative
1297  if ( nEndX >= nCol1 )
1298  eFillDir = FILL_TO_RIGHT;
1299  else
1300  eFillDir = FILL_TO_LEFT;
1301  }
1302  else // direction not clear
1303  bOk = false;
1304 
1305  if ( bOk )
1306  {
1307  tools::Long nBegin = 0;
1308  tools::Long nEnd = 0;
1309  tools::Long nHidden = 0;
1310  if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
1311  {
1312  if (nEndY > nRow1)
1313  {
1314  nBegin = nRow2+1;
1315  nEnd = nEndY;
1316  }
1317  else
1318  {
1319  nBegin = nEndY;
1320  nEnd = nRow1 -1;
1321  }
1322 
1323  tools::Long nVisible = CountVisibleRows(nBegin, nEnd);
1324  nHidden = nEnd + 1 - nBegin - nVisible;
1325  }
1326  else
1327  {
1328  if (nEndX > nCol1)
1329  {
1330  nBegin = nCol2+1;
1331  nEnd = nEndX;
1332  }
1333  else
1334  {
1335  nBegin = nEndX;
1336  nEnd = nCol1 -1;
1337  }
1338 
1339  tools::Long nVisible = CountVisibleCols(nBegin, nEnd);
1340  nHidden = nEnd + 1 - nBegin - nVisible;
1341  }
1342  if (nHidden)
1343  {
1344  if (nIndex > 0)
1345  nIndex = nIndex - nHidden;
1346  else
1347  nIndex = nIndex + nHidden;
1348  }
1349 
1350  FillCmd eFillCmd;
1351  FillDateCmd eDateCmd;
1352  double nInc;
1353  sal_uInt16 nMinDigits;
1354  ScUserListData* pListData = nullptr;
1355  sal_uInt16 nListIndex;
1356  bool bSkipOverlappedCells;
1357  std::vector<sal_Int32> aNonOverlappedCellIdx;
1358 
1359  // Todo: update this function to calculate with merged cell fills,
1360  // after FillAnalyse / FillSeries fully handle them.
1361  // Now FillAnalyse called as if there are filtered rows, so it will work in the old way.
1362  FillAnalyse(nCol1, nRow1, nCol2, nRow2, eFillCmd, eDateCmd,
1363  nInc, nMinDigits, pListData, nListIndex,
1364  true, bSkipOverlappedCells, aNonOverlappedCellIdx);
1365 
1366  if ( pListData ) // user defined list
1367  {
1368  sal_uInt16 nListCount = pListData->GetSubCount();
1369  if ( nListCount )
1370  {
1371  sal_uInt64 nSub = nSrcCount - 1; // nListIndex is from last source entry
1372  while ( nIndex < sal::static_int_cast<tools::Long>(nSub) )
1373  nIndex += nListCount;
1374  sal_uInt64 nPos = ( nListIndex + nIndex - nSub ) % nListCount;
1375  aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
1376  }
1377  }
1378  else if ( eFillCmd == FILL_SIMPLE ) // fill with pattern/sample
1379  {
1380  tools::Long nPosIndex = nIndex;
1381  while ( nPosIndex < 0 )
1382  nPosIndex += nSrcCount;
1383  sal_uInt64 nPos = nPosIndex % nSrcCount;
1384  SCCOL nSrcX = nCol1;
1385  SCROW nSrcY = nRow1;
1386  if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
1387  nSrcY = sal::static_int_cast<SCROW>( nSrcY + static_cast<SCROW>(nPos) );
1388  else
1389  nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
1390 
1391  ScRefCellValue aCell = GetCellValue(nSrcX, nSrcY);
1392  if (!aCell.isEmpty())
1393  {
1394  sal_Int32 nDelta;
1395  if (nIndex >= 0)
1396  nDelta = nIndex / nSrcCount;
1397  else
1398  nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
1399 
1400  CellType eType = aCell.meType;
1401  switch ( eType )
1402  {
1403  case CELLTYPE_STRING:
1404  case CELLTYPE_EDIT:
1405  {
1406  aValue = aCell.getString(&rDocument);
1407 
1409  {
1410  sal_Int32 nVal;
1411  sal_uInt16 nCellDigits = 0; // look at each source cell individually
1412  short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits );
1413  if ( nFlag < 0 )
1414  {
1415  if (aValue == ScGlobal::GetOrdinalSuffix( nVal))
1416  aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta);
1417  aValue = lcl_ValueString( nVal + nDelta, nCellDigits ) + aValue;
1418  }
1419  else if ( nFlag > 0 )
1420  {
1421  sal_Int32 nNextValue;
1422  if ( nVal < 0 )
1423  nNextValue = nVal - nDelta;
1424  else
1425  nNextValue = nVal + nDelta;
1426  if ( nFlag == 2 && nNextValue >= 0 ) // Put back the '+'
1427  aValue += "+";
1428  aValue += lcl_ValueString( nNextValue, nCellDigits );
1429  }
1430  }
1431  }
1432  break;
1433  case CELLTYPE_VALUE:
1434  {
1435  sal_uInt32 nNumFmt = GetNumberFormat( nSrcX, nSrcY );
1436  // overflow is possible...
1437  double nVal = aCell.mfValue;
1439  {
1440  const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(nNumFmt);
1441  bool bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
1442  if (bPercentCell)
1443  {
1444  // tdf#89998 increment by 1% at a time
1445  nVal += static_cast<double>(nDelta) * 0.01;
1446  }
1447  else if (nVal == 0.0 || nVal == 1.0)
1448  {
1449  bool bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
1450  if (!bBooleanCell)
1451  nVal += static_cast<double>(nDelta);
1452  }
1453  else
1454  {
1455  nVal += static_cast<double>(nDelta);
1456  }
1457  }
1458 
1459  const Color* pColor;
1460  rDocument.GetFormatTable()->GetOutputString( nVal, nNumFmt, aValue, &pColor );
1461  }
1462  break;
1463  // not for formulas
1464  default:
1465  {
1466  // added to avoid warnings
1467  }
1468  }
1469  }
1470  }
1471  else if ( eFillCmd == FILL_LINEAR || eFillCmd == FILL_DATE ) // values
1472  {
1473  bool bValueOk;
1474  double nStart;
1475  sal_Int32 nVal = 0;
1476  short nHeadNoneTail = 0;
1477  ScRefCellValue aCell = GetCellValue(nCol1, nRow1);
1478  if (!aCell.isEmpty())
1479  {
1480  CellType eType = aCell.meType;
1481  switch ( eType )
1482  {
1483  case CELLTYPE_STRING:
1484  case CELLTYPE_EDIT:
1485  {
1486  aValue = aCell.getString(&rDocument);
1487  nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
1488  if ( nHeadNoneTail )
1489  nStart = static_cast<double>(nVal);
1490  else
1491  nStart = 0.0;
1492  }
1493  break;
1494  case CELLTYPE_VALUE:
1495  nStart = aCell.mfValue;
1496  break;
1497  case CELLTYPE_FORMULA:
1498  nStart = aCell.mpFormula->GetValue();
1499  break;
1500  default:
1501  nStart = 0.0;
1502  }
1503  }
1504  else
1505  nStart = 0.0;
1506  if ( eFillCmd == FILL_LINEAR )
1507  {
1508  double nAdd = nInc;
1509  bValueOk = ( SubTotal::SafeMult( nAdd, static_cast<double>(nIndex) ) &&
1510  SubTotal::SafePlus( nStart, nAdd ) );
1511  }
1512  else // date
1513  {
1514  bValueOk = true;
1515  sal_uInt16 nDayOfMonth = 0;
1516  if ( nIndex < 0 )
1517  {
1518  nIndex = -nIndex;
1519  nInc = -nInc;
1520  }
1521  for (tools::Long i=0; i<nIndex; i++)
1522  IncDate( nStart, nDayOfMonth, nInc, eDateCmd );
1523  }
1524 
1525  if (bValueOk)
1526  {
1527  if ( nHeadNoneTail )
1528  {
1529  if ( nHeadNoneTail < 0 )
1530  {
1531  if (aValue == ScGlobal::GetOrdinalSuffix( nVal))
1532  aValue = ScGlobal::GetOrdinalSuffix( static_cast<sal_Int32>(nStart) );
1533 
1534  aValue = lcl_ValueString( static_cast<sal_Int32>(nStart), nMinDigits ) + aValue;
1535  }
1536  else
1537  {
1538  if ( nHeadNoneTail == 2 && nStart >= 0 ) // Put back the '+'
1539  aValue += "+";
1540  aValue += lcl_ValueString( static_cast<sal_Int32>(nStart), nMinDigits );
1541  }
1542  }
1543  else
1544  {
1545  //TODO: get number format according to Index?
1546  const Color* pColor;
1547  sal_uInt32 nNumFmt = GetNumberFormat( nCol1, nRow1 );
1548  rDocument.GetFormatTable()->GetOutputString( nStart, nNumFmt, aValue, &pColor );
1549  }
1550  }
1551  }
1552  else
1553  {
1554  OSL_FAIL("GetAutoFillPreview: invalid mode");
1555  }
1556  }
1557 
1558  return aValue;
1559 }
1560 
1561 void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillDateCmd eCmd)
1562 {
1563  if (eCmd == FILL_DAY)
1564  {
1565  rVal += nStep;
1566  return;
1567  }
1568 
1569  // class Date limits
1570  const sal_uInt16 nMinYear = 1583;
1571  const sal_uInt16 nMaxYear = 9956;
1572 
1573  tools::Long nInc = static_cast<tools::Long>(nStep); // upper/lower limits ?
1574  Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
1575  Date aDate = aNullDate;
1576  aDate.AddDays(rVal);
1577  switch (eCmd)
1578  {
1579  case FILL_WEEKDAY:
1580  {
1581  aDate.AddDays(nInc);
1582  DayOfWeek eWeekDay = aDate.GetDayOfWeek();
1583  if (nInc >= 0)
1584  {
1585  if (eWeekDay == SATURDAY)
1586  aDate.AddDays(2);
1587  else if (eWeekDay == SUNDAY)
1588  aDate.AddDays(1);
1589  }
1590  else
1591  {
1592  if (eWeekDay == SATURDAY)
1593  aDate.AddDays(-1);
1594  else if (eWeekDay == SUNDAY)
1595  aDate.AddDays(-2);
1596  }
1597  }
1598  break;
1599  case FILL_MONTH:
1600  case FILL_END_OF_MONTH:
1601  {
1602  if ( nDayOfMonth == 0 )
1603  nDayOfMonth = aDate.GetDay(); // init
1604  tools::Long nMonth = aDate.GetMonth();
1605  tools::Long nYear = aDate.GetYear();
1606 
1607  nMonth += nInc;
1608 
1609  if (nInc >= 0)
1610  {
1611  if (nMonth > 12)
1612  {
1613  tools::Long nYAdd = (nMonth-1) / 12;
1614  nMonth -= nYAdd * 12;
1615  nYear += nYAdd;
1616  }
1617  }
1618  else
1619  {
1620  if (nMonth < 1)
1621  {
1622  tools::Long nYAdd = 1 - nMonth / 12; // positive
1623  nMonth += nYAdd * 12;
1624  nYear -= nYAdd;
1625  }
1626  }
1627 
1628  if ( nYear < nMinYear )
1629  aDate = Date( 1,1, nMinYear );
1630  else if ( nYear > nMaxYear )
1631  aDate = Date( 31,12, nMaxYear );
1632  else
1633  {
1634  aDate.SetMonth(static_cast<sal_uInt16>(nMonth));
1635  aDate.SetYear(static_cast<sal_uInt16>(nYear));
1636  if (eCmd == FILL_END_OF_MONTH)
1637  {
1638  aDate.SetDay(Date::GetDaysInMonth(nMonth, nYear));
1639  }
1640  else
1641  {
1642  aDate.SetDay(std::min(Date::GetDaysInMonth(nMonth, nYear), nDayOfMonth));
1643  }
1644  }
1645  }
1646  break;
1647  case FILL_YEAR:
1648  {
1649  tools::Long nYear = aDate.GetYear();
1650  nYear += nInc;
1651  if ( nYear < nMinYear )
1652  aDate = Date( 1,1, nMinYear );
1653  else if ( nYear > nMaxYear )
1654  aDate = Date( 31,12, nMaxYear );
1655  else
1656  aDate.SetYear(static_cast<sal_uInt16>(nYear));
1657  }
1658  break;
1659  default:
1660  {
1661  // added to avoid warnings
1662  }
1663  }
1664 
1665  rVal = aDate - aNullDate;
1666 }
1667 
1668 namespace {
1669 
1670 bool HiddenRowColumn(const ScTable* pTable, SCCOLROW nRowColumn, bool bVertical, SCCOLROW& rLastPos)
1671 {
1672  bool bHidden = false;
1673  if(bVertical)
1674  {
1675  SCROW nLast;
1676  bHidden = pTable->RowHidden(nRowColumn, nullptr, &nLast);
1677  rLastPos = nLast;
1678  }
1679  else
1680  {
1681  SCCOL nLast;
1682  bHidden = pTable->ColHidden(static_cast<SCCOL>(nRowColumn), nullptr, &nLast);
1683  rLastPos = nLast;
1684  }
1685  return bHidden;
1686 }
1687 
1688 }
1689 
1691  const ScFormulaCell& rSrcCell,
1692  SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2,
1693  ScProgress* pProgress, sal_uInt64& rProgress )
1694 {
1695  // rInner is the row position when filling vertically. Also, when filling
1696  // across hidden regions, it may create multiple dis-jointed spans of
1697  // formula cells.
1698 
1699  bool bHidden = false;
1700  SCCOLROW nHiddenLast = -1;
1701 
1702  SCCOLROW nRowStart = -1, nRowEnd = -1;
1703  std::vector<sc::RowSpan> aSpans;
1704  PutInOrder(nRow1, nRow2);
1705  for (rInner = nRow1; rInner <= nRow2; ++rInner)
1706  {
1707  if (rInner > nHiddenLast)
1708  bHidden = HiddenRowColumn(this, rInner, true, nHiddenLast);
1709 
1710  if (bHidden)
1711  {
1712  if (nRowStart >= 0)
1713  {
1714  nRowEnd = rInner - 1;
1715  aSpans.emplace_back(nRowStart, nRowEnd);
1716  nRowStart = -1;
1717  }
1718  rInner = nHiddenLast;
1719  continue;
1720  }
1721 
1722  if (nRowStart < 0)
1723  nRowStart = rInner;
1724  }
1725 
1726  if (nRowStart >= 0)
1727  {
1728  nRowEnd = rInner - 1;
1729  aSpans.emplace_back(nRowStart, nRowEnd);
1730  }
1731 
1732  if (aSpans.empty())
1733  return;
1734 
1736  aCol[nCol].CloneFormulaCell(rSrcCell, sc::CellTextAttr(), aSpans);
1737 
1738  auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(rDocument);
1739  sc::StartListeningContext aStartCxt(rDocument, pSet);
1740  sc::EndListeningContext aEndCxt(rDocument, pSet);
1741 
1742  SCROW nStartRow = aSpans.front().mnRow1;
1743  SCROW nEndRow = aSpans.back().mnRow2;
1744  aCol[nCol].EndListeningFormulaCells(aEndCxt, nStartRow, nEndRow, &nStartRow, &nEndRow);
1745  aCol[nCol].StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
1746 
1747  for (const auto& rSpan : aSpans)
1748  aCol[nCol].SetDirty(rSpan.mnRow1, rSpan.mnRow2, ScColumn::BROADCAST_NONE);
1749 
1750  rProgress += nRow2 - nRow1 + 1;
1751  if (pProgress)
1752  pProgress->SetStateOnPercent(rProgress);
1753 }
1754 
1756  const ScCellValue& rSrcCell, SCCOLROW& rInner, SCCOLROW nIMin, SCCOLROW nIMax,
1757  const SCCOLROW& rCol, const SCCOLROW& rRow, bool bVertical, ScProgress* pProgress, sal_uInt64& rProgress )
1758 {
1759  bool bHidden = false;
1760  SCCOLROW nHiddenLast = -1;
1761 
1762  if (bVertical)
1763  {
1764  switch (rSrcCell.meType)
1765  {
1766  case CELLTYPE_FORMULA:
1767  {
1769  *rSrcCell.mpFormula, rInner, rCol, nIMin, nIMax, pProgress, rProgress);
1770  }
1771  break;
1772  default:
1773  {
1774  for (rInner = nIMin; rInner <= nIMax; ++rInner)
1775  {
1776  if (rInner > nHiddenLast)
1777  bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1778 
1779  if (bHidden)
1780  {
1781  rInner = nHiddenLast;
1782  continue;
1783  }
1784 
1785  ScAddress aDestPos(rCol, rRow, nTab);
1786  rSrcCell.commit(aCol[rCol], aDestPos.Row());
1787  }
1788  rProgress += nIMax - nIMin + 1;
1789  if (pProgress)
1790  pProgress->SetStateOnPercent(rProgress);
1791  }
1792  }
1793  }
1794  else
1795  {
1796  switch (rSrcCell.meType)
1797  {
1798  case CELLTYPE_FORMULA:
1799  {
1800  for (rInner = nIMin; rInner <= nIMax; ++rInner)
1801  {
1802  if (rInner > nHiddenLast)
1803  bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1804 
1805  if (bHidden)
1806  continue;
1807 
1808  FillFormula(rSrcCell.mpFormula, rCol, rRow, (rInner == nIMax));
1809  if (pProgress)
1810  pProgress->SetStateOnPercent(++rProgress);
1811  }
1812  }
1813  break;
1814  default:
1815  {
1816  for (rInner = nIMin; rInner <= nIMax; ++rInner)
1817  {
1818  if (rInner > nHiddenLast)
1819  bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1820 
1821  if (bHidden)
1822  continue;
1823 
1824  ScAddress aDestPos(rCol, rRow, nTab);
1825  rSrcCell.commit(aCol[rCol], aDestPos.Row());
1826  }
1827  rProgress += nIMax - nIMin + 1;
1828  if (pProgress)
1829  pProgress->SetStateOnPercent(rProgress);
1830  }
1831  }
1832  }
1833 }
1834 
1836  SCCOLROW nISrcStart, SCCOLROW nISrcEnd, SCCOLROW nIStart, SCCOLROW nIEnd,
1837  SCCOLROW& rInner, const SCCOLROW& rCol, const SCCOLROW& rRow, sal_uInt64 nActFormCnt,
1838  sal_uInt64 nMaxFormCnt, bool bHasFiltered, bool bVertical, bool bPositive,
1839  ScProgress* pProgress, sal_uInt64& rProgress )
1840 {
1841  SCCOLROW nSource = nISrcStart;
1842  double nDelta;
1844  nDelta = 0.0;
1845  else if ( bPositive )
1846  nDelta = 1.0;
1847  else
1848  nDelta = -1.0;
1849  sal_uInt64 nFormulaCounter = nActFormCnt;
1850  bool bGetCell = true;
1851  bool bBooleanCell = false;
1852  bool bPercentCell = false;
1853  sal_uInt16 nCellDigits = 0;
1854  short nHeadNoneTail = 0;
1855  sal_Int32 nStringValue = 0;
1856  OUString aValue;
1857  ScCellValue aSrcCell;
1858  bool bIsOrdinalSuffix = false;
1859 
1860  bool bColHidden = false, bRowHidden = false;
1861  SCCOL nColHiddenFirst = rDocument.MaxCol();
1862  SCCOL nColHiddenLast = -1;
1863  SCROW nRowHiddenFirst = rDocument.MaxRow();
1864  SCROW nRowHiddenLast = -1;
1865 
1866  rInner = nIStart;
1867  while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1868  {
1869  if (bPositive)
1870  {
1871  if (rCol > nColHiddenLast)
1872  bColHidden = ColHidden(rCol, nullptr, &nColHiddenLast);
1873  if (rRow > nRowHiddenLast)
1874  bRowHidden = RowHidden(rRow, nullptr, &nRowHiddenLast);
1875  }
1876  else
1877  {
1878  if (rCol < nColHiddenFirst)
1879  bColHidden = ColHidden(rCol, &nColHiddenFirst);
1880  if (rRow < nRowHiddenFirst)
1881  bRowHidden = RowHidden(rRow, &nRowHiddenFirst);
1882  }
1883 
1884  if (!bColHidden && !bRowHidden)
1885  {
1886  if ( bGetCell )
1887  {
1888  if (bVertical) // rInner&:=nRow, rOuter&:=nCol
1889  {
1890  aSrcCell = GetCellValue(rCol, nSource);
1891  if (nISrcStart == nISrcEnd && aSrcCell.meType == CELLTYPE_FORMULA)
1892  {
1893  FillFormulaVertical(*aSrcCell.mpFormula, rInner, rCol, nIStart, nIEnd, pProgress, rProgress);
1894  return;
1895  }
1896  const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(
1898  bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
1899  bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
1900 
1901  }
1902  else // rInner&:=nCol, rOuter&:=nRow
1903  {
1904  aSrcCell = GetCellValue(nSource, rRow);
1905  const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(
1907  bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
1908  bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
1909  }
1910 
1911  bGetCell = false;
1912  if (!aSrcCell.isEmpty())
1913  {
1914  switch (aSrcCell.meType)
1915  {
1916  case CELLTYPE_STRING:
1917  case CELLTYPE_EDIT:
1918  if (aSrcCell.meType == CELLTYPE_STRING)
1919  aValue = aSrcCell.mpString->getString();
1920  else
1921  aValue = ScEditUtil::GetString(*aSrcCell.mpEditText, &rDocument);
1922  if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered )
1923  {
1924  nCellDigits = 0; // look at each source cell individually
1925  nHeadNoneTail = lcl_DecompValueString(
1926  aValue, nStringValue, &nCellDigits );
1927 
1928  bIsOrdinalSuffix = aValue ==
1929  ScGlobal::GetOrdinalSuffix(nStringValue);
1930  }
1931  break;
1932  default:
1933  {
1934  // added to avoid warnings
1935  }
1936  }
1937  }
1938  }
1939 
1940  switch (aSrcCell.meType)
1941  {
1942  case CELLTYPE_VALUE:
1943  {
1944  double fVal;
1945  if (bBooleanCell && ((fVal = aSrcCell.mfValue) == 0.0 || fVal == 1.0))
1946  aCol[rCol].SetValue(rRow, aSrcCell.mfValue);
1947  else if(bPercentCell)
1948  aCol[rCol].SetValue(rRow, aSrcCell.mfValue + nDelta * 0.01); // tdf#89998 increment by 1% at a time
1949  else
1950  aCol[rCol].SetValue(rRow, aSrcCell.mfValue + nDelta);
1951  }
1952  break;
1953  case CELLTYPE_STRING:
1954  case CELLTYPE_EDIT:
1955  if ( nHeadNoneTail )
1956  {
1957  sal_Int32 nNextValue;
1958  if (nStringValue < 0)
1959  nNextValue = nStringValue - static_cast<sal_Int32>(nDelta);
1960  else
1961  nNextValue = nStringValue + static_cast<sal_Int32>(nDelta);
1962 
1963  if ( nHeadNoneTail < 0 )
1964  {
1965  setSuffixCell(
1966  aCol[rCol], rRow,
1967  nNextValue, nCellDigits, aValue,
1968  aSrcCell.meType, bIsOrdinalSuffix);
1969  }
1970  else
1971  {
1972  OUString aStr;
1973  if (nHeadNoneTail == 2 && nNextValue >= 0) // Put back the '+'
1974  aStr = aValue + "+" + lcl_ValueString(nNextValue, nCellDigits);
1975  else
1976  aStr = aValue + lcl_ValueString(nNextValue, nCellDigits);
1977 
1978  aCol[rCol].SetRawString(rRow, aStr);
1979  }
1980  }
1981  else
1982  aSrcCell.commit(aCol[rCol], rRow);
1983 
1984  break;
1985  case CELLTYPE_FORMULA :
1986  FillFormula(
1987  aSrcCell.mpFormula, rCol, rRow, (rInner == nIEnd));
1988  if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
1989  nMaxFormCnt = nFormulaCounter - nActFormCnt;
1990  break;
1991  default:
1992  {
1993  // added to avoid warnings
1994  }
1995  }
1996 
1997  if (nSource == nISrcEnd)
1998  {
1999  if ( nSource != nISrcStart )
2000  { // More than one source cell
2001  nSource = nISrcStart;
2002  bGetCell = true;
2003  }
2004  if ( !(nScFillModeMouseModifier & KEY_MOD1) )
2005  {
2006  if ( bPositive )
2007  nDelta += 1.0;
2008  else
2009  nDelta -= 1.0;
2010  }
2011  nFormulaCounter = nActFormCnt;
2012  }
2013  else if (bPositive)
2014  {
2015  ++nSource;
2016  bGetCell = true;
2017  }
2018  else
2019  {
2020  --nSource;
2021  bGetCell = true;
2022  }
2023  }
2024 
2025  if (rInner == nIEnd)
2026  break;
2027  if (bPositive)
2028  ++rInner;
2029  else
2030  --rInner;
2031 
2032  // Progress in inner loop only for expensive cells,
2033  // and even then not individually for each one
2034 
2035  ++rProgress;
2036  if ( pProgress && (aSrcCell.meType == CELLTYPE_FORMULA || aSrcCell.meType == CELLTYPE_EDIT) )
2037  pProgress->SetStateOnPercent( rProgress );
2038 
2039  }
2040  if (pProgress)
2041  pProgress->SetStateOnPercent( rProgress );
2042 }
2043 
2044 namespace
2045 {
2046 // Target value exceeded?
2047 inline bool isOverflow( const double& rVal, const double& rMax, const double& rStep,
2048  const double& rStartVal, FillCmd eFillCmd )
2049 {
2050  switch (eFillCmd)
2051  {
2052  case FILL_LINEAR:
2053  case FILL_DATE:
2054  if (rStep >= 0.0)
2055  return rVal > rMax;
2056  else
2057  return rVal < rMax;
2058  case FILL_GROWTH:
2059  if (rStep > 0.0)
2060  {
2061  if (rStep >= 1.0)
2062  {
2063  // Growing away from zero, including zero growth (1.0).
2064  if (rVal >= 0.0)
2065  return rVal > rMax;
2066  else
2067  return rVal < rMax;
2068  }
2069  else
2070  {
2071  // Shrinking towards zero.
2072  if (rVal >= 0.0)
2073  return rVal < rMax;
2074  else
2075  return rVal > rMax;
2076  }
2077  }
2078  else if (rStep < 0.0)
2079  {
2080  // Alternating positive and negative values.
2081  if (rStep <= -1.0)
2082  {
2083  // Growing away from zero, including zero growth (-1.0).
2084  if (rVal >= 0.0)
2085  {
2086  if (rMax >= 0.0)
2087  return rVal > rMax;
2088  else
2089  // Regard negative rMax as lower limit, which will
2090  // be reached only by a negative rVal.
2091  return false;
2092  }
2093  else
2094  {
2095  if (rMax <= 0.0)
2096  return rVal < rMax;
2097  else
2098  // Regard positive rMax as upper limit, which will
2099  // be reached only by a positive rVal.
2100  return false;
2101  }
2102  }
2103  else
2104  {
2105  // Shrinking towards zero.
2106  if (rVal >= 0.0)
2107  return rVal < rMax;
2108  else
2109  return rVal > rMax;
2110  }
2111  }
2112  else // if (rStep == 0.0)
2113  {
2114  // All values become zero.
2115  // Corresponds with bEntireArea in FillSeries().
2116  if (rMax > 0.0)
2117  return rMax < rStartVal;
2118  else if (rMax < 0.0)
2119  return rStartVal < rMax;
2120  }
2121  break;
2122  default:
2123  assert(!"eFillCmd");
2124  }
2125  return false;
2126 }
2127 }
2128 
2129 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2130  sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
2131  double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
2132  bool bAttribs, ScProgress* pProgress,
2133  bool bSkipOverlappedCells, std::vector<sal_Int32>* pNonOverlappedCellIdx )
2134 {
2135  // The term 'inner' here refers to the loop in the filling direction i.e.
2136  // when filling vertically, the inner position is the row position whereas
2137  // when filling horizontally the column position becomes the inner
2138  // position. The term 'outer' refers to the column position when filling
2139  // vertically, or the row position when filling horizontally. The fill is
2140  // performed once in each 'outer' position e.g. when filling vertically,
2141  // we perform the fill once in each column.
2142 
2143  // Detect direction
2144 
2145  bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
2146  bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
2147 
2148  SCCOLROW nCol = 0;
2149  SCCOLROW nRow = 0;
2150  SCCOLROW& rInner = bVertical ? nRow : nCol; // loop variables
2151  SCCOLROW& rOuter = bVertical ? nCol : nRow;
2152  SCCOLROW nOStart;
2153  SCCOLROW nOEnd;
2154  SCCOLROW nIStart;
2155  SCCOLROW nIEnd;
2156  SCCOLROW nISource;
2157  ScRange aFillRange;
2158  sal_uInt64 nFillerCount;
2159  std::vector<bool> aIsNonEmptyCell;
2160 
2161  if (bVertical)
2162  {
2163  nFillerCount = (nRow2 - nRow1) + 1;
2164  nFillCount += (nRow2 - nRow1);
2165  if (nFillCount == 0)
2166  return;
2167  nOStart = nCol1;
2168  nOEnd = nCol2;
2169  if (bPositive)
2170  {
2171  // downward fill
2172  nISource = nRow1; // top row of the source range.
2173  nIStart = nRow1 + 1; // first row where we start filling.
2174  nIEnd = nRow1 + nFillCount;
2175  aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab);
2176  }
2177  else
2178  {
2179  // upward fill
2180  nISource = nRow2;
2181  nIStart = nRow2 - 1;
2182  nIEnd = nRow2 - nFillCount;
2183  aFillRange = ScRange(nCol1, nRow2 -1, nTab, nCol2, nRow2 - nFillCount, nTab);
2184  }
2185  }
2186  else
2187  {
2188  nFillerCount = (nCol2 - nCol1) + 1;
2189  nFillCount += (nCol2 - nCol1);
2190  if (nFillCount == 0)
2191  return;
2192  nOStart = nRow1;
2193  nOEnd = nRow2;
2194  if (bPositive)
2195  {
2196  // to the right
2197  nISource = nCol1;
2198  nIStart = nCol1 + 1;
2199  nIEnd = nCol1 + nFillCount;
2200  aFillRange = ScRange(nCol1 + 1, nRow1, nTab, nCol1 + nFillCount, nRow2, nTab);
2201  }
2202  else
2203  {
2204  // to the left
2205  nISource = nCol2;
2206  nIStart = nCol2 - 1;
2207  nIEnd = nCol2 - nFillCount;
2208  aFillRange = ScRange(nCol2 - 1, nRow1, nTab, nCol2 - nFillCount, nRow2, nTab);
2209  }
2210  }
2211 
2212  SCCOLROW nIMin = nIStart;
2213  SCCOLROW nIMax = nIEnd;
2214  PutInOrder(nIMin,nIMax);
2215 
2216  const bool bIsFiltered = IsDataFiltered(aFillRange);
2217  bool bEntireArea = (!bIsFiltered && eFillCmd == FILL_SIMPLE);
2218  if (!bIsFiltered && !bEntireArea && (eFillCmd == FILL_LINEAR || eFillCmd == FILL_GROWTH)
2219  && (nOEnd - nOStart == 0))
2220  {
2221  // For the usual case of one col/row determine if a numeric series is
2222  // at least as long as the area to be filled and does not end earlier,
2223  // so we can treat it as entire area for performance reasons at least
2224  // in the vertical case.
2225  // This is not exact in case of merged cell fills with skipping overlapped parts, but
2226  // it is still a good upper estimation.
2227  ScCellValue aSrcCell;
2228  if (bVertical)
2229  aSrcCell = GetCellValue(static_cast<SCCOL>(nOStart), static_cast<SCROW>(nISource));
2230  else
2231  aSrcCell = GetCellValue(static_cast<SCCOL>(nISource), static_cast<SCROW>(nOStart));
2232  // Same logic as for the actual series.
2233  if (!aSrcCell.isEmpty() && (aSrcCell.meType == CELLTYPE_VALUE || aSrcCell.meType == CELLTYPE_FORMULA))
2234  {
2235  double nStartVal;
2236  if (aSrcCell.meType == CELLTYPE_VALUE)
2237  nStartVal = aSrcCell.mfValue;
2238  else
2239  nStartVal = aSrcCell.mpFormula->GetValue();
2240  if (eFillCmd == FILL_LINEAR)
2241  {
2242  if (nStepValue == 0.0)
2243  bEntireArea = (nStartVal <= nMaxValue); // fill with same value
2244  else if (((nMaxValue - nStartVal) / nStepValue) >= nFillCount)
2245  bEntireArea = true;
2246  }
2247  else if (eFillCmd == FILL_GROWTH)
2248  {
2249  if (nStepValue == 1.0)
2250  bEntireArea = (nStartVal <= nMaxValue); // fill with same value
2251  else if (nStepValue == -1.0)
2252  bEntireArea = (fabs(nStartVal) <= fabs(nMaxValue)); // fill with alternating value
2253  else if (nStepValue == 0.0)
2254  bEntireArea = (nStartVal == 0.0
2255  || (nStartVal < 0.0 && nMaxValue >= 0.0)
2256  || (nStartVal > 0.0 && nMaxValue <= 0.0)); // fill with 0.0
2257  }
2258  }
2259  }
2260  if (bEntireArea)
2261  {
2262  InsertDeleteFlags nDel = (bAttribs ? InsertDeleteFlags::AUTOFILL :
2264  if (bVertical)
2265  DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
2266  else
2267  DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
2268  }
2269 
2270  sal_uInt64 nProgress = 0;
2271  if (pProgress)
2272  nProgress = pProgress->GetState();
2273 
2274  // Perform the fill once per each 'outer' position i.e. one per column
2275  // when filling vertically.
2276 
2277  for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
2278  {
2279  rInner = nISource;
2280 
2282 
2283  // Source cell value. We need to clone the value since it may be inserted repeatedly.
2284  ScCellValue aSrcCell = GetCellValue(nCol, static_cast<SCROW>(nRow));
2285 
2286  // Maybe another source cell need to be searched, if the fill is going through merged cells,
2287  // where overlapped parts does not contain any information, so they can be skipped.
2288  if (bSkipOverlappedCells)
2289  {
2290  // create a vector to make it easier to decide if a cell need to be filled, or skipped.
2291  aIsNonEmptyCell.resize(nFillerCount, false);
2292 
2293  SCCOLROW nFirstValueIdx;
2294  if (bPositive)
2295  {
2296  nFirstValueIdx = nISource + (*pNonOverlappedCellIdx)[0];
2297  for (auto i : (*pNonOverlappedCellIdx))
2298  aIsNonEmptyCell[i] = true;
2299  }
2300  else
2301  {
2302  nFirstValueIdx = nISource - (nFillerCount - 1 - (*pNonOverlappedCellIdx).back());
2303  for (auto i : (*pNonOverlappedCellIdx))
2304  aIsNonEmptyCell[nFillerCount - 1 - i] = true;
2305  }
2306 
2307  //Set the real source cell
2308  if (bVertical)
2309  aSrcCell = GetCellValue(nOStart, static_cast<SCROW>(nFirstValueIdx));
2310  else
2311  aSrcCell = GetCellValue(nFirstValueIdx, static_cast<SCROW>(nOStart));
2312  }
2313 
2314  const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
2315  const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
2316  const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
2317 
2318  if (bAttribs)
2319  {
2320  if (bVertical)
2321  {
2322  // If entire area (not filtered and simple fill) use the faster
2323  // method, else hidden cols/rows should be skipped and series
2324  // fill needs to determine the end row dynamically.
2325  if (bEntireArea)
2326  {
2327  SetPatternAreaCondFormat( nCol, static_cast<SCROW>(nIMin),
2328  static_cast<SCROW>(nIMax), *pSrcPattern, rCondFormatIndex);
2329  }
2330  else if (eFillCmd == FILL_SIMPLE)
2331  {
2332  assert(bIsFiltered);
2333  for(SCROW nAtRow = static_cast<SCROW>(nIMin); nAtRow <= static_cast<SCROW>(nIMax); ++nAtRow)
2334  {
2335  if(!RowHidden(nAtRow))
2336  {
2337  SetPatternAreaCondFormat( nCol, nAtRow, nAtRow, *pSrcPattern, rCondFormatIndex);
2338  }
2339  }
2340 
2341  }
2342  }
2343  else if (bEntireArea || eFillCmd == FILL_SIMPLE)
2344  {
2345  for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
2346  {
2347  if(!ColHidden(nAtCol))
2348  {
2349  SetPatternAreaCondFormat( nAtCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
2350  }
2351  }
2352  }
2353  }
2354 
2355  if (!aSrcCell.isEmpty())
2356  {
2357  CellType eCellType = aSrcCell.meType;
2358 
2359  if (eFillCmd == FILL_SIMPLE) // copy
2360  {
2361  FillSeriesSimple(aSrcCell, rInner, nIMin, nIMax, nCol, nRow, bVertical, pProgress, nProgress);
2362  }
2363  else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
2364  {
2365  const double nStartVal = (eCellType == CELLTYPE_VALUE ? aSrcCell.mfValue :
2366  aSrcCell.mpFormula->GetValue());
2367  double nVal = nStartVal;
2368  tools::Long nIndex = 0;
2369 
2370  bool bError = false;
2371  bool bOverflow = false;
2372  bool bNonEmpty = true;
2373 
2374  sal_uInt16 nDayOfMonth = 0;
2375  sal_Int32 nFillerIdx = 0;
2376  if (bSkipOverlappedCells && !aIsNonEmptyCell[0])
2377  --nIndex;
2378  rInner = nIStart;
2379  while (true)
2380  {
2381  if (bSkipOverlappedCells)
2382  {
2383  nFillerIdx = (nFillerIdx + 1) % nFillerCount;
2384  bNonEmpty = aIsNonEmptyCell[nFillerIdx];
2385  }
2386 
2387  if(!ColHidden(nCol) && !RowHidden(nRow))
2388  {
2389  if (!bError && bNonEmpty)
2390  {
2391  switch (eFillCmd)
2392  {
2393  case FILL_LINEAR:
2394  {
2395  // use multiplication instead of repeated addition
2396  // to avoid accumulating rounding errors
2397  nVal = nStartVal;
2398  double nAdd = nStepValue;
2399  if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
2400  !SubTotal::SafePlus( nVal, nAdd ) )
2401  bError = true;
2402  }
2403  break;
2404  case FILL_GROWTH:
2405  if (!SubTotal::SafeMult(nVal, nStepValue))
2406  bError = true;
2407  break;
2408  case FILL_DATE:
2409  if (fabs(nVal) > D_MAX_LONG_)
2410  bError = true;
2411  else
2412  IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
2413  break;
2414  default:
2415  {
2416  // added to avoid warnings
2417  }
2418  }
2419 
2420  if (!bError)
2421  bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
2422  }
2423 
2425  if (bError)
2426  aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
2427  else if (!bOverflow && bNonEmpty)
2428  aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
2429 
2430  if (bAttribs && !bEntireArea && !bOverflow)
2431  SetPatternAreaCondFormat( nCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
2432  }
2433 
2434  if (rInner == nIEnd || bOverflow)
2435  break;
2436  if (bPositive)
2437  {
2438  ++rInner;
2439  }
2440  else
2441  {
2442  --rInner;
2443  }
2444  }
2445  nProgress += nIMax - nIMin + 1;
2446  if(pProgress)
2447  pProgress->SetStateOnPercent( nProgress );
2448  }
2449  else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
2450  {
2451  if ( nStepValue >= 0 )
2452  {
2453  if ( nMaxValue >= double(LONG_MAX) )
2454  nMaxValue = double(LONG_MAX) - 1;
2455  }
2456  else
2457  {
2458  if ( nMaxValue <= double(LONG_MIN) )
2459  nMaxValue = double(LONG_MIN) + 1;
2460  }
2461  OUString aValue;
2462  if (eCellType == CELLTYPE_STRING)
2463  aValue = aSrcCell.mpString->getString();
2464  else
2465  aValue = ScEditUtil::GetString(*aSrcCell.mpEditText, &rDocument);
2466  sal_Int32 nStringValue;
2467  sal_uInt16 nMinDigits = nArgMinDigits;
2468  short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
2469  if ( nHeadNoneTail )
2470  {
2471  const double nStartVal = static_cast<double>(nStringValue);
2472  double nVal = nStartVal;
2473  tools::Long nIndex = 0;
2474  bool bError = false;
2475  bool bOverflow = false;
2476  bool bNonEmpty = true;
2477 
2478  bool bIsOrdinalSuffix = aValue == ScGlobal::GetOrdinalSuffix(
2479  static_cast<sal_Int32>(nStartVal));
2480 
2481  sal_Int32 nFillerIdx = 0;
2482  if (bSkipOverlappedCells && !aIsNonEmptyCell[0])
2483  --nIndex;
2484  rInner = nIStart;
2485  while (true)
2486  {
2487  if (bSkipOverlappedCells)
2488  {
2489  nFillerIdx = (nFillerIdx + 1) % nFillerCount;
2490  bNonEmpty = aIsNonEmptyCell[nFillerIdx];
2491  }
2492  if(!ColHidden(nCol) && !RowHidden(nRow))
2493  {
2494  if (!bError && bNonEmpty)
2495  {
2496  switch (eFillCmd)
2497  {
2498  case FILL_LINEAR:
2499  {
2500  // use multiplication instead of repeated addition
2501  // to avoid accumulating rounding errors
2502  nVal = nStartVal;
2503  double nAdd = nStepValue;
2504  if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
2505  !SubTotal::SafePlus( nVal, nAdd ) )
2506  bError = true;
2507  }
2508  break;
2509  case FILL_GROWTH:
2510  if (!SubTotal::SafeMult(nVal, nStepValue))
2511  bError = true;
2512  break;
2513  default:
2514  {
2515  // added to avoid warnings
2516  }
2517  }
2518 
2519  if (!bError)
2520  bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
2521  }
2522 
2523  if (bError)
2524  aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
2525  else if (!bOverflow && bNonEmpty)
2526  {
2527  nStringValue = static_cast<sal_Int32>(nVal);
2528  if ( nHeadNoneTail < 0 )
2529  {
2530  setSuffixCell(
2531  aCol[nCol], static_cast<SCROW>(nRow),
2532  nStringValue, nMinDigits, aValue,
2533  eCellType, bIsOrdinalSuffix);
2534  }
2535  else
2536  {
2537  OUString aStr;
2538  if (nHeadNoneTail == 2 && nStringValue >= 0) // Put back the '+'
2539  aStr = aValue + "+";
2540  else
2541  aStr = aValue;
2542  aStr += lcl_ValueString( nStringValue, nMinDigits );
2543  aCol[nCol].SetRawString(static_cast<SCROW>(nRow), aStr);
2544  }
2545  }
2546 
2547  if (bAttribs && !bEntireArea && !bOverflow)
2548  SetPatternAreaCondFormat( nCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
2549  }
2550 
2551  if (rInner == nIEnd || bOverflow)
2552  break;
2553  if (bPositive)
2554  ++rInner;
2555  else
2556  --rInner;
2557  }
2558  }
2559  if(pProgress)
2560  {
2561  nProgress += nIMax - nIMin + 1;
2562  pProgress->SetStateOnPercent( nProgress );
2563  }
2564  }
2565  }
2566  else if(pProgress)
2567  {
2568  nProgress += nIMax - nIMin + 1;
2569  pProgress->SetStateOnPercent( nProgress );
2570  }
2571  }
2572 }
2573 
2574 void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2575  sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
2576  double nStepValue, double nMaxValue, ScProgress* pProgress)
2577 {
2578  if (eFillCmd == FILL_AUTO)
2579  FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, pProgress);
2580  else
2581  FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
2582  eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, true, pProgress);
2583 }
2584 
2585 void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2586  const ScPatternAttr& rAttr, sal_uInt16 nFormatNo)
2587 {
2589  ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
2590  if (pData)
2591  {
2592  ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
2593  }
2594 }
2595 
2596 void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2597  sal_uInt16 nFormatNo )
2598 {
2599  if (!(ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow)))
2600  return;
2601 
2603  ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
2604  if (!pData)
2605  return;
2606 
2607  std::unique_ptr<ScPatternAttr> pPatternAttrs[16];
2608  for (sal_uInt8 i = 0; i < 16; ++i)
2609  {
2610  pPatternAttrs[i].reset(new ScPatternAttr(rDocument.GetPool()));
2611  pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), rDocument);
2612  }
2613 
2614  SCCOL nCol = nStartCol;
2615  SCROW nRow = nStartRow;
2616  sal_uInt16 nIndex = 0;
2617  // Left top corner
2618  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2619  // Left column
2620  if (pData->IsEqualData(4, 8))
2621  AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
2622  else
2623  {
2624  nIndex = 4;
2625  for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2626  {
2627  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2628  if (nIndex == 4)
2629  nIndex = 8;
2630  else
2631  nIndex = 4;
2632  }
2633  }
2634  // Left bottom corner
2635  nRow = nEndRow;
2636  nIndex = 12;
2637  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2638  // Right top corner
2639  nCol = nEndCol;
2640  nRow = nStartRow;
2641  nIndex = 3;
2642  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2643  // Right column
2644  if (pData->IsEqualData(7, 11))
2645  AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
2646  else
2647  {
2648  nIndex = 7;
2649  for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2650  {
2651  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2652  if (nIndex == 7)
2653  nIndex = 11;
2654  else
2655  nIndex = 7;
2656  }
2657  }
2658  // Right bottom corner
2659  nRow = nEndRow;
2660  nIndex = 15;
2661  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2662  nRow = nStartRow;
2663  nIndex = 1;
2664  for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
2665  {
2666  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2667  if (nIndex == 1)
2668  nIndex = 2;
2669  else
2670  nIndex = 1;
2671  }
2672  // Bottom row
2673  nRow = nEndRow;
2674  nIndex = 13;
2675  for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
2676  {
2677  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2678  if (nIndex == 13)
2679  nIndex = 14;
2680  else
2681  nIndex = 13;
2682  }
2683  // Body
2684  if ((pData->IsEqualData(5, 6)) && (pData->IsEqualData(9, 10)) && (pData->IsEqualData(5, 9)))
2685  AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
2686  else
2687  {
2688  if ((pData->IsEqualData(5, 9)) && (pData->IsEqualData(6, 10)))
2689  {
2690  nIndex = 5;
2691  for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
2692  {
2693  AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, *pPatternAttrs[nIndex], nFormatNo);
2694  if (nIndex == 5)
2695  nIndex = 6;
2696  else
2697  nIndex = 5;
2698  }
2699  }
2700  else
2701  {
2702  nIndex = 5;
2703  for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
2704  {
2705  for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2706  {
2707  AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2708  if ((nIndex == 5) || (nIndex == 9))
2709  {
2710  if (nIndex == 5)
2711  nIndex = 9;
2712  else
2713  nIndex = 5;
2714  }
2715  else
2716  {
2717  if (nIndex == 6)
2718  nIndex = 10;
2719  else
2720  nIndex = 6;
2721  }
2722  } // for nRow
2723  if ((nIndex == 5) || (nIndex == 9))
2724  nIndex = 6;
2725  else
2726  nIndex = 5;
2727  } // for nCol
2728  } // if not equal Column
2729  } // if not all equal
2730 }
2731 
2732 void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, ScAutoFormatData& rData)
2733 {
2734  sal_uInt32 nFormatIndex = GetNumberFormat( nCol, nRow );
2735  ScNumFormatAbbrev aNumFormat( nFormatIndex, *rDocument.GetFormatTable() );
2736  rData.GetFromItemSet( nIndex, GetPattern( nCol, nRow )->GetItemSet(), aNumFormat );
2737 }
2738 
2739 #define LF_LEFT 1
2740 #define LF_TOP 2
2741 #define LF_RIGHT 4
2742 #define LF_BOTTOM 8
2743 #define LF_ALL (LF_LEFT | LF_TOP | LF_RIGHT | LF_BOTTOM)
2744 
2745 void ScTable::GetAutoFormatFrame(SCCOL nCol, SCROW nRow, sal_uInt16 nFlags, sal_uInt16 nIndex, ScAutoFormatData& rData)
2746 {
2747  const SvxBoxItem* pTheBox = GetAttr(nCol, nRow, ATTR_BORDER);
2748  const SvxBoxItem* pLeftBox = GetAttr(nCol - 1, nRow, ATTR_BORDER);
2749  const SvxBoxItem* pTopBox = GetAttr(nCol, nRow - 1, ATTR_BORDER);
2750  const SvxBoxItem* pRightBox = GetAttr(nCol + 1, nRow, ATTR_BORDER);
2751  const SvxBoxItem* pBottomBox = GetAttr(nCol, nRow + 1, ATTR_BORDER);
2752 
2753  SvxBoxItem aBox( ATTR_BORDER );
2754  if (nFlags & LF_LEFT)
2755  {
2756  if (pLeftBox)
2757  {
2758  if (ScHasPriority(pTheBox->GetLeft(), pLeftBox->GetRight()))
2759  aBox.SetLine(pTheBox->GetLeft(), SvxBoxItemLine::LEFT);
2760  else
2761  aBox.SetLine(pLeftBox->GetRight(), SvxBoxItemLine::LEFT);
2762  }
2763  else
2764  aBox.SetLine(pTheBox->GetLeft(), SvxBoxItemLine::LEFT);
2765  }
2766  if (nFlags & LF_TOP)
2767  {
2768  if (pTopBox)
2769  {
2770  if (ScHasPriority(pTheBox->GetTop(), pTopBox->GetBottom()))
2771  aBox.SetLine(pTheBox->GetTop(), SvxBoxItemLine::TOP);
2772  else
2773  aBox.SetLine(pTopBox->GetBottom(), SvxBoxItemLine::TOP);
2774  }
2775  else
2776  aBox.SetLine(pTheBox->GetTop(), SvxBoxItemLine::TOP);
2777  }
2778  if (nFlags & LF_RIGHT)
2779  {
2780  if (pRightBox)
2781  {
2782  if (ScHasPriority(pTheBox->GetRight(), pRightBox->GetLeft()))
2783  aBox.SetLine(pTheBox->GetRight(), SvxBoxItemLine::RIGHT);
2784  else
2785  aBox.SetLine(pRightBox->GetLeft(), SvxBoxItemLine::RIGHT);
2786  }
2787  else
2788  aBox.SetLine(pTheBox->GetRight(), SvxBoxItemLine::RIGHT);
2789  }
2790  if (nFlags & LF_BOTTOM)
2791  {
2792  if (pBottomBox)
2793  {
2794  if (ScHasPriority(pTheBox->GetBottom(), pBottomBox->GetTop()))
2795  aBox.SetLine(pTheBox->GetBottom(), SvxBoxItemLine::BOTTOM);
2796  else
2797  aBox.SetLine(pBottomBox->GetTop(), SvxBoxItemLine::BOTTOM);
2798  }
2799  else
2800  aBox.SetLine(pTheBox->GetBottom(), SvxBoxItemLine::BOTTOM);
2801  }
2802  rData.PutItem( nIndex, aBox );
2803 }
2804 
2805 void ScTable::GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData& rData)
2806 {
2807  if (!(ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow)))
2808  return;
2809 
2810  if ((nEndCol - nStartCol < 3) || (nEndRow - nStartRow < 3))
2811  return;
2812 
2813  // Left top corner
2814  GetAutoFormatAttr(nStartCol, nStartRow, 0, rData);
2815  GetAutoFormatFrame(nStartCol, nStartRow, LF_ALL, 0, rData);
2816  // Left column
2817  GetAutoFormatAttr(nStartCol, nStartRow + 1, 4, rData);
2818  GetAutoFormatAttr(nStartCol, nStartRow + 2, 8, rData);
2819  GetAutoFormatFrame(nStartCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 4, rData);
2820  if (nEndRow - nStartRow >= 4)
2821  GetAutoFormatFrame(nStartCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 8, rData);
2822  else
2823  rData.CopyItem( 8, 4, ATTR_BORDER );
2824  // Left bottom corner
2825  GetAutoFormatAttr(nStartCol, nEndRow, 12, rData);
2826  GetAutoFormatFrame(nStartCol, nEndRow, LF_ALL, 12, rData);
2827  // Right top corner
2828  GetAutoFormatAttr(nEndCol, nStartRow, 3, rData);
2829  GetAutoFormatFrame(nEndCol, nStartRow, LF_ALL, 3, rData);
2830  // Right column
2831  GetAutoFormatAttr(nEndCol, nStartRow + 1, 7, rData);
2832  GetAutoFormatAttr(nEndCol, nStartRow + 2, 11, rData);
2833  GetAutoFormatFrame(nEndCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 7, rData);
2834  if (nEndRow - nStartRow >= 4)
2835  GetAutoFormatFrame(nEndCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 11, rData);
2836  else
2837  rData.CopyItem( 11, 7, ATTR_BORDER );
2838  // Right bottom corner
2839  GetAutoFormatAttr(nEndCol, nEndRow, 15, rData);
2840  GetAutoFormatFrame(nEndCol, nEndRow, LF_ALL, 15, rData);
2841  // Top row
2842  GetAutoFormatAttr(nStartCol + 1, nStartRow, 1, rData);
2843  GetAutoFormatAttr(nStartCol + 2, nStartRow, 2, rData);
2844  GetAutoFormatFrame(nStartCol + 1, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 1, rData);
2845  if (nEndCol - nStartCol >= 4)
2846  GetAutoFormatFrame(nStartCol + 2, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 2, rData);
2847  else
2848  rData.CopyItem( 2, 1, ATTR_BORDER );
2849  // Bottom row
2850  GetAutoFormatAttr(nStartCol + 1, nEndRow, 13, rData);
2851  GetAutoFormatAttr(nStartCol + 2, nEndRow, 14, rData);
2852  GetAutoFormatFrame(nStartCol + 1, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 13, rData);
2853  if (nEndCol - nStartCol >= 4)
2854  GetAutoFormatFrame(nStartCol + 2, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 14, rData);
2855  else
2856  rData.CopyItem( 14, 13, ATTR_BORDER );
2857  // Body
2858  GetAutoFormatAttr(nStartCol + 1, nStartRow + 1, 5, rData);
2859  GetAutoFormatAttr(nStartCol + 2, nStartRow + 1, 6, rData);
2860  GetAutoFormatAttr(nStartCol + 1, nStartRow + 2, 9, rData);
2861  GetAutoFormatAttr(nStartCol + 2, nStartRow + 2, 10, rData);
2862  GetAutoFormatFrame(nStartCol + 1, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 5, rData);
2863  if ((nEndCol - nStartCol >= 4) && (nEndRow - nStartRow >= 4))
2864  {
2865  GetAutoFormatFrame(nStartCol + 2, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 6, rData);
2866  GetAutoFormatFrame(nStartCol + 1, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 9, rData);
2867  GetAutoFormatFrame(nStartCol + 2, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 10, rData);
2868  }
2869  else
2870  {
2871  rData.CopyItem( 6, 5, ATTR_BORDER );
2872  rData.CopyItem( 9, 5, ATTR_BORDER );
2873  rData.CopyItem( 10, 5, ATTR_BORDER );
2874  }
2875 }
2876 
2877 void ScTable::SetError( SCCOL nCol, SCROW nRow, FormulaError nError)
2878 {
2879  if (ValidColRow(nCol, nRow))
2880  aCol[nCol].SetError( nRow, nError );
2881 }
2882 
2884 {
2885  for (SCCOL i=0; i < aCol.size(); i++)
2886  aCol[i].UpdateInsertTabAbs(nTable);
2887 }
2888 
2889 bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, bool bInSel,
2890  const ScMarkData& rMark) const
2891 {
2892  if (rRow == rDocument.MaxRow()+2) // end of table
2893  {
2894  rRow = 0;
2895  rCol = 0;
2896  }
2897  else
2898  {
2899  rRow++;
2900  if (rRow == rDocument.MaxRow()+1)
2901  {
2902  rCol++;
2903  rRow = 0;
2904  }
2905  }
2906  if (rCol == rDocument.MaxCol()+1)
2907  return true;
2908  for (;;)
2909  {
2910  if (!ValidCol(rCol))
2911  return true;
2912  if (rCol >= GetAllocatedColumnsCount())
2913  return true;
2914  if (aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark))
2915  return true;
2916  /*else (rRow == rDocument.MaxRow()+1) */
2917  rCol++;
2918  rRow = 0;
2919  }
2920 }
2921 
2922 void ScTable::TestTabRefAbs(SCTAB nTable) const
2923 {
2924  for (SCCOL i=0; i < aCol.size(); i++)
2925  if (aCol[i].TestTabRefAbs(nTable))
2926  return;
2927 }
2928 
2930 {
2931  for (SCCOL i = 0; i < aCol.size(); ++i)
2932  aCol[i].CompileDBFormula(rCxt);
2933 }
2934 
2936 {
2937  for (SCCOL i = 0; i < aCol.size(); ++i)
2939 }
2940 
2942 {
2943  if( ValidCol( nCol ) )
2944  return aCol[nCol].GetPatternCount();
2945  else
2946  return 0;
2947 }
2948 
2949 SCSIZE ScTable::GetPatternCount( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
2950 {
2951  if( ValidCol( nCol ) && ValidRow( nRow1 ) && ValidRow( nRow2 ) )
2952  return aCol[nCol].GetPatternCount( nRow1, nRow2 );
2953  else
2954  return 0;
2955 }
2956 
2958 {
2959  if( ValidCol( nCol ) )
2960  return aCol[nCol].ReservePatternCount( nReserve );
2961  else
2962  return false;
2963 }
2964 
2965 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString GetAutoFillPreview(const ScRange &rSource, SCCOL nEndX, SCROW nEndY)
Definition: table4.cxx:1268
Numeric values (and numeric results if InsertDeleteFlags::FORMULA is not set).
SCTAB nTab
Definition: table.hxx:207
const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow) const
Definition: table2.cxx:2273
sal_Int32 nIndex
CellType meType
Definition: cellvalue.hxx:37
OUString getString() const
void FillAutoSimple(SCCOLROW nISrcStart, SCCOLROW nISrcEnd, SCCOLROW nIStart, SCCOLROW nIEnd, SCCOLROW &rInner, const SCCOLROW &rCol, const SCCOLROW &rRow, sal_uInt64 nActFormCnt, sal_uInt64 nMaxFormCnt, bool bHasFiltered, bool bVertical, bool bPositive, ScProgress *pProgress, sal_uInt64 &rProgress)
Definition: table4.cxx:1835
ScAddress aStart
Definition: address.hxx:497
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
DayOfWeek GetDayOfWeek() const
void CompileColRowNameFormula(sc::CompileFormulaContext &rCxt)
Definition: table4.cxx:2935
constexpr sal_uInt16 KEY_MOD1
#define LF_LEFT
Definition: table4.cxx:2739
void SetStateOnPercent(sal_uInt64 nVal)
Definition: progress.hxx:96
constexpr TypedWhichId< SvxBoxItem > ATTR_BORDER(150)
void CopyItem(sal_uInt16 nToIndex, sal_uInt16 nFromIndex, sal_uInt16 nWhich)
Definition: autoform.cxx:369
void SetPatternAreaCondFormat(SCCOL nCol, SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &rAttr, const ScCondFormatIndexes &rCondFormatIndexes)
Definition: table2.cxx:2969
SCROW Row() const
Definition: address.hxx:274
void Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, double nStepValue, double nMaxValue, ScProgress *pProgress)
Definition: table4.cxx:2574
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:660
sc::Sparkline * CreateSparkline(SCCOL nCol, SCROW nRow, std::shared_ptr< sc::SparklineGroup > const &pSparklineGroup)
Definition: table2.cxx:1851
FillDir
Definition: global.hxx:306
void TestTabRefAbs(SCTAB nTable) const
Definition: table4.cxx:2922
bool GetNextSpellingCell(SCCOL &rCol, SCROW &rRow, bool bInSel, const ScMarkData &rMark) const
Definition: table4.cxx:2889
bool IsDataFiltered(SCCOL nColStart, SCROW nRowStart, SCCOL nColEnd, SCROW nRowEnd) const
Definition: table2.cxx:3833
bool isEmpty() const
Definition: cellvalue.cxx:670
ScColumn * FetchColumn(SCCOL nCol)
Definition: table2.cxx:1235
void FillSeriesSimple(const ScCellValue &rSrcCell, SCCOLROW &rInner, SCCOLROW nIMin, SCCOLROW nIMax, const SCCOLROW &rCol, const SCCOLROW &rRow, bool bVertical, ScProgress *pProgress, sal_uInt64 &rProgress)
Definition: table4.cxx:1755
std::unique_ptr< sal_Int32[]> pData
SC_DLLPUBLIC const ScFormulaCell * GetFormulaCell(const ScAddress &rPos) const
Definition: document.cxx:3757
SATURDAY
SCCOL size() const
static OUString GetOrdinalSuffix(sal_Int32 nNumber)
Obtain the ordinal suffix for a number according to the system locale.
Definition: globalx.cxx:120
long Long
ScColumn & CreateColumnIfNotExists(const SCCOL nScCol)
Definition: table.hxx:289
void SetEditText(SCROW nRow, std::unique_ptr< EditTextObject > pEditText)
Definition: column3.cxx:2273
Rich-text attributes.
#define LF_TOP
Definition: table4.cxx:2740
SvNumFormatType GetType(sal_uInt32 nFIndex) const
double mfValue
Definition: cellvalue.hxx:39
ScAddress aEnd
Definition: address.hxx:498
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
#define MAXDOUBLE
Definition: global.hxx:76
const editeng::SvxBorderLine * GetRight() const
bool IsEqualData(sal_uInt16 nIndex1, sal_uInt16 nIndex2) const
Definition: autoform.cxx:381
bool IsEndOfMonth() const
bool GetSubIndex(const OUString &rSubStr, sal_uInt16 &rIndex, bool &bMatchCase) const
Definition: userlist.cxx:114
void FillFormula(const ScFormulaCell *pSrcCell, SCCOL nDestCol, SCROW nDestRow, bool bLast)
Definition: table4.cxx:748
bool ValidRow(SCROW nRow) const
Definition: table.hxx:335
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6156
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:35
const ScRangeList & GetRange() const
Definition: conditio.hxx:558
sal_uInt16 sal_Unicode
void FillToItemSet(sal_uInt16 nIndex, SfxItemSet &rItemSet, const ScDocument &rDoc) const
Definition: autoform.cxx:440
Stores individual user-defined sort list.
Definition: userlist.hxx:32
static bool isAsciiNumeric(std::u16string_view rStr)
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:42
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:891
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
sal_uInt16 GetMonth() const
void StartListeningTo(ScDocument &rDoc)
double GetValue()
int nCount
FillDateCmd
Definition: global.hxx:331
std::shared_ptr< sc::Sparkline > GetSparkline(SCCOL nCol, SCROW nRow)
Definition: table2.cxx:1839
void SetNoListening(bool bVal)
Definition: document.hxx:2222
static bool SafeMult(double &fVal1, double fVal2)
Definition: subtotal.cxx:40
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
void SetYear(sal_Int16 nNewYear)
Copy flags for auto/series fill functions: do not touch notes and drawing objects.
size_t GetSubCount() const
Definition: userlist.cxx:109
double d
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:150
DocumentType eType
sal_Int16 GetYear() const
void SetRange(const ScRangeList &rRanges)
Definition: conditio.cxx:1745
void IncDate(double &rVal, sal_uInt16 &nDayOfMonth, double nStep, FillDateCmd eCmd)
Definition: table4.cxx:1561
const editeng::SvxBorderLine * GetTop() const
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:890
bool ColHidden(SCCOL nCol, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: table5.cxx:555
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:459
sal_uInt16 GetDaysInMonth() const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
bool ValidCol(SCCOL nCol) const
Definition: table.hxx:334
FillCmd
Definition: global.hxx:314
ScDocument & GetDoc()
Definition: table.hxx:283
const editeng::SvxBorderLine * GetLeft() const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
int i
void SetRawString(SCROW nRow, const OUString &rStr)
Definition: column3.cxx:2943
void SetDay(sal_uInt16 nNewDay)
void GetAutoFormatFrame(SCCOL nCol, SCROW nRow, sal_uInt16 nFlags, sal_uInt16 nIndex, ScAutoFormatData &rData)
Definition: table4.cxx:2745
sal_Int16 SCCOL
Definition: types.hxx:21
InsertDeleteFlags
Definition: global.hxx:147
sal_uInt64 GetState() const
Definition: progress.hxx:109
bool ScHasPriority(const ::editeng::SvxBorderLine *pThis, const ::editeng::SvxBorderLine *pOther)
General Help Function.
Definition: attrib.cxx:49
svl::SharedString * mpString
Definition: cellvalue.hxx:40
const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nWhich) const
Definition: table2.cxx:2231
const ScStyleSheet * GetStyleSheet() const
Definition: patattr.hxx:128
void AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScPatternAttr &rAttr, sal_uInt16 nFormatNo)
Definition: table4.cxx:2585
SCCOL CountVisibleCols(SCCOL nStartCol, SCCOL nEndCol) const
Definition: table5.cxx:795
SC_DLLPUBLIC SfxItemPool * GetEnginePool() const
Definition: documen2.cxx:470
const SfxItemSet * GetItemSet(const SfxPoolItem &rAttr)
SfxItemSet & GetItemSet()
Definition: patattr.hxx:155
ScDocument & GetDoc() const
Definition: column.hxx:127
void AutoFormat(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, sal_uInt16 nFormatNo)
Definition: table4.cxx:2596
void GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData &rData)
Definition: table4.cxx:2805
static SC_DLLPUBLIC ScUserList * GetUserList()
Definition: global.cxx:284
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
sal_uInt16 GetDay() const
SUNDAY
SvNumFormatType
void PutItem(sal_uInt16 nIndex, const SfxPoolItem &rItem)
Definition: autoform.cxx:332
ScColContainer aCol
Definition: table.hxx:160
void AddDays(sal_Int32 nAddDays)
const ScAutoFormatData * findByIndex(size_t nIndex) const
Definition: autoform.cxx:762
void SetMatColsRows(SCCOL nCols, SCROW nRows)
std::unique_ptr< ScConditionalFormatList > mpCondFormatList
Definition: table.hxx:231
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
void FillFormulaVertical(const ScFormulaCell &rSrcCell, SCCOLROW &rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2, ScProgress *pProgress, sal_uInt64 &rProgress)
Definition: table4.cxx:1690
#define D_MAX_LONG_
Definition: table4.cxx:57
bool ReservePatternCount(SCCOL nCol, SCSIZE nReserve)
Definition: table4.cxx:2957
#define LF_RIGHT
Definition: table4.cxx:2741
const long LONG_MAX
FormulaError
SCCOL Col() const
Definition: address.hxx:279
void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, InsertDeleteFlags nDelFlag, bool bBroadcast=true, sc::ColumnSpanSet *pBroadcastSpans=nullptr)
Definition: table2.cxx:421
static bool SafePlus(double &fVal1, double fVal2)
Definition: subtotal.cxx:24
SCSIZE GetPatternCount(SCCOL nCol) const
Definition: table4.cxx:2941
bool GetMatrixOrigin(const ScDocument &rDoc, ScAddress &rPos) const
OUString GetString(SCCOL nCol, SCROW nRow, const ScInterpreterContext *pContext=nullptr) const
Definition: table2.cxx:1766
CellType meType
Definition: cellvalue.hxx:105
SCROW CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const
Definition: table5.cxx:751
void GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, ScAutoFormatData &rData)
Definition: table4.cxx:2732
bool RowHidden(SCROW nRow, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: table5.cxx:480
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_Int32 SCROW
Definition: types.hxx:17
void UpdateInsertTabAbs(SCTAB nNewPos)
Definition: table4.cxx:2883
void GetFromItemSet(sal_uInt16 nIndex, const SfxItemSet &rItemSet, const ScNumFormatAbbrev &rNumFormat)
Definition: autoform.cxx:527
ScMF
Definition: attrib.hxx:34
void FillAnalyse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, FillCmd &rCmd, FillDateCmd &rDateCmd, double &rInc, sal_uInt16 &rMinDigits, ScUserListData *&rListData, sal_uInt16 &rListIndex, bool bHasFiltered, bool &rSkipOverlappedCells, std::vector< sal_Int32 > &rNonOverlappedCellIdx)
Definition: table4.cxx:219
bool isEmpty() const
Definition: cellvalue.cxx:499
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
unsigned char sal_uInt8
DayOfWeek
sal_uInt16 nScFillModeMouseModifier
Definition: global.cxx:117
constexpr TypedWhichId< SvxEscapementItem > EE_CHAR_ESCAPEMENT(EE_CHAR_START+10)
bool ValidColRow(SCCOL nCol, SCROW nRow) const
Definition: table.hxx:336
CellType
Definition: global.hxx:269
Dates, times, datetime values.
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
void * p
SC_DLLPUBLIC ScPatternAttr * GetDefPattern() const
Definition: document.cxx:6151
void FillSeries(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, double nStepValue, double nMaxValue, sal_uInt16 nMinDigits, bool bAttribs, ScProgress *pProgress, bool bSkipOverlappedCells=false, std::vector< sal_Int32 > *pNonOverlappedCellIdx=nullptr)
Definition: table4.cxx:2129
const ScCondFormatIndexes & GetCondFormatData() const
Definition: attrib.hxx:282
EditTextObject * mpEditText
Definition: cellvalue.hxx:41
SC_DLLPUBLIC SfxItemPool * GetEditPool() const
Definition: documen2.cxx:465
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:119
ScInterpreterContext & GetNonThreadedContext() const
Definition: document.hxx:615
void FillAuto(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt64 nFillCount, FillDir eFillDir, ScProgress *pProgress)
Definition: table4.cxx:790
ScDocument & rDocument
Definition: table.hxx:208
#define LF_ALL
Definition: table4.cxx:2743
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, const ScAddress &rPos) const
Definition: table2.cxx:2245
void FillSparkline(bool bVertical, SCCOLROW nFixed, SCCOLROW nIteratingStart, SCCOLROW nIteratingEnd, SCCOLROW nFillStart, SCCOLROW nFillEnd)
Definition: table4.cxx:1217
static SC_DLLPUBLIC ScAutoFormat * GetOrCreateAutoFormat()
Definition: global.cxx:262
const Date & GetNullDate() const
ScMatrixMode GetMatrixFlag() const
SCCOL GetAllocatedColumnsCount() const
Definition: table.hxx:1127
void ApplyPatternArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScPatternAttr &rAttr, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: table2.cxx:2871
void commit(ScDocument &rDoc, const ScAddress &rPos) const
Set cell value at specified position in specified document.
Definition: cellvalue.cxx:402
void CompileDBFormula(sc::CompileFormulaContext &rCxt)
Definition: table4.cxx:2929
double GetValue(SCCOL nCol, SCROW nRow) const
Definition: table2.cxx:1790
RedlineType meType
void SetError(SCCOL nCol, SCROW nRow, FormulaError nError)
Definition: table4.cxx:2877
aStr
const editeng::SvxBorderLine * GetBottom() const
void SetMonth(sal_uInt16 nNewMonth)
void SetEditTextObjectPool(SfxItemPool *pPool)
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
sal_uInt16 nPos
sal_Int16 SCTAB
Definition: types.hxx:22
ScRefCellValue GetCellValue(SCCOL nCol, sc::ColumnBlockPosition &rBlockPos, SCROW nRow)
Definition: table2.cxx:2021
sal_Int16 nValue
OUString GetSubStr(sal_uInt16 nIndex) const
Definition: userlist.cxx:140
const ScUserListData * GetData(const OUString &rSubStr) const
Definition: userlist.cxx:277
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
#define LF_BOTTOM
Definition: table4.cxx:2742
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill= '\0')
no broadcasting
Definition: column.hxx:244
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo