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