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