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