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