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