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