Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / sc / source / core / data / table4.cxx
blob9f33d0dc6d2426aac457d773a0f0e0f51a92023a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <scitems.hxx>
21 #include <comphelper/string.hxx>
22 #include <editeng/boxitem.hxx>
23 #include <editeng/editeng.hxx>
24 #include <editeng/eeitem.hxx>
25 #include <editeng/escapementitem.hxx>
26 #include <editeng/brushitem.hxx>
27 #include <svl/numformat.hxx>
28 #include <svl/zforlist.hxx>
29 #include <vcl/keycodes.hxx>
30 #include <rtl/math.hxx>
31 #include <unotools/charclass.hxx>
32 #include <tools/duration.hxx>
33 #include <osl/diagnose.h>
35 #include <attrib.hxx>
36 #include <patattr.hxx>
37 #include <formulacell.hxx>
38 #include <table.hxx>
39 #include <global.hxx>
40 #include <document.hxx>
41 #include <autoform.hxx>
42 #include <userlist.hxx>
43 #include <zforauto.hxx>
44 #include <subtotal.hxx>
45 #include <formula/errorcodes.hxx>
46 #include <docpool.hxx>
47 #include <progress.hxx>
48 #include <conditio.hxx>
49 #include <editutil.hxx>
50 #include <listenercontext.hxx>
51 #include <scopetools.hxx>
52 #include <o3tl/string_view.hxx>
54 #include <math.h>
55 #include <memory>
56 #include <list>
57 #include <string_view>
59 #define D_MAX_LONG_ double(0x7fffffff)
61 namespace {
63 short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMinDigits = nullptr )
65 if ( rValue.isEmpty() )
67 nVal = 0;
68 return 0;
70 const sal_Unicode* p = rValue.getStr();
71 sal_Int32 nSign = 0;
72 sal_Int32 nNum = 0;
73 if ( p[nNum] == '-' || p[nNum] == '+' )
74 nNum = nSign = 1;
75 while ( p[nNum] && CharClass::isAsciiNumeric( std::u16string_view(&p[nNum], 1) ) )
76 nNum++;
78 sal_Unicode cNext = p[nNum]; // 0 if at the end
79 sal_Unicode cLast = p[rValue.getLength()-1];
81 // #i5550# If there are numbers at the beginning and the end,
82 // prefer the one at the beginning only if it's followed by a space.
83 // Otherwise, use the number at the end, to enable things like IP addresses.
84 if ( nNum > nSign && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(std::u16string_view(&cLast, 1)) ) )
85 { // number at the beginning
86 nVal = o3tl::toInt32(rValue.subView( 0, nNum ));
87 // any number with a leading zero sets the minimum number of digits
88 if ( p[nSign] == '0' && pMinDigits && ( nNum - nSign > *pMinDigits ) )
89 *pMinDigits = nNum - nSign;
90 rValue = rValue.copy(nNum);
91 return -1;
93 else
95 nSign = 0;
96 sal_Int32 nEnd = nNum = rValue.getLength() - 1;
97 while ( nNum && CharClass::isAsciiNumeric( std::u16string_view(&p[nNum], 1) ) )
98 nNum--;
99 if ( p[nNum] == '-' || p[nNum] == '+' )
101 nNum--;
102 nSign = 1;
104 if ( nNum < nEnd - nSign )
105 { // number at the end
106 nVal = o3tl::toInt32(rValue.subView( nNum + 1 ));
107 // any number with a leading zero sets the minimum number of digits
108 if ( p[nNum+1+nSign] == '0' && pMinDigits && ( nEnd - nNum - nSign > *pMinDigits ) )
109 *pMinDigits = nEnd - nNum - nSign;
110 rValue = rValue.copy(0, nNum + 1);
111 if (nSign) // use the return value = 2 to put back the '+'
112 return 2;
113 else
114 return 1;
117 nVal = 0;
118 return 0;
121 OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
123 if ( nMinDigits <= 1 )
124 return OUString::number( nValue ); // simple case...
125 else
127 OUString aStr = OUString::number( std::abs( nValue ) );
128 if ( aStr.getLength() < nMinDigits )
130 OUStringBuffer aZero(nMinDigits);
131 comphelper::string::padToLength(aZero, nMinDigits - aStr.getLength(), '0');
132 aStr = aZero.append(aStr).makeStringAndClear();
134 // nMinDigits doesn't include the '-' sign -> add after inserting zeros
135 if ( nValue < 0 )
136 aStr = "-" + aStr;
137 return aStr;
141 void setSuffixCell(
142 ScColumn& rColumn, SCROW nRow, sal_Int32 nValue, sal_uInt16 nDigits,
143 std::u16string_view rSuffix,
144 CellType eCellType, bool bIsOrdinalSuffix )
146 ScDocument& rDoc = rColumn.GetDoc();
147 OUString aValue = lcl_ValueString(nValue, nDigits);
148 if (!bIsOrdinalSuffix)
150 aValue += rSuffix;
151 rColumn.SetRawString(nRow, aValue);
152 return;
155 OUString aOrdinalSuffix = ScGlobal::GetOrdinalSuffix(nValue);
156 if (eCellType != CELLTYPE_EDIT)
158 aValue += aOrdinalSuffix;
159 rColumn.SetRawString(nRow, aValue);
160 return;
163 EditEngine aEngine(rDoc.GetEnginePool());
164 aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
166 SfxItemSet aAttr = aEngine.GetEmptyItemSet();
167 aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT));
168 aEngine.SetText( aValue );
169 aEngine.QuickInsertText(
170 aOrdinalSuffix,
171 ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
173 aEngine.QuickSetAttribs(
174 aAttr,
175 ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
177 // Text object instance will be owned by the cell.
178 rColumn.SetEditText(nRow, aEngine.CreateTextObject());
183 namespace {
184 /* TODO: move this to rtl::math::approxDiff() ? Though the name is funny, the
185 * approx is expected to be more correct than the raw diff. */
186 /** Calculate a-b trying to diminish precision errors such as for 0.11-0.12
187 not return -0.009999999999999995 but -0.01 instead.
189 double approxDiff( double a, double b )
191 if (a == b)
192 return 0.0;
193 if (a == 0.0)
194 return -b;
195 if (b == 0.0)
196 return a;
197 const double c = a - b;
198 const double aa = fabs(a);
199 const double ab = fabs(b);
200 if (aa < 1e-16 || aa > 1e+16 || ab < 1e-16 || ab > 1e+16)
201 // This is going nowhere, live with the result.
202 return c;
204 const double q = aa < ab ? b / a : a / b;
205 const double d = (a * q - b * q) / q;
206 if (d == c)
207 // No differing error, live with the result.
208 return c;
210 // We now have two subtractions with a similar but not equal error. Obtain
211 // the exponent of the error magnitude and round accordingly.
212 const double e = fabs(d - c);
213 const int nExp = static_cast<int>(floor(log10(e))) + 1;
214 // tdf#129606: Limit precision to the 16th significant digit of the least precise argument.
215 // Cf. mnMaxGeneralPrecision in sc/source/core/data/column3.cxx.
216 const int nExpArg = static_cast<int>(floor(log10(std::max(aa, ab)))) - 15;
217 return rtl::math::round(c, -std::max(nExp, nExpArg));
220 double approxTypedDiff( double a, double b, bool bTime, tools::Duration& rDuration )
222 if (bTime)
224 rDuration = tools::Duration(a - b);
225 return rDuration.GetInDays();
227 return approxDiff( a, b);
231 void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
232 FillCmd& rCmd, FillDateCmd& rDateCmd,
233 double& rInc, tools::Duration& rDuration, sal_uInt16& rMinDigits,
234 ScUserListData*& rListData, sal_uInt16& rListIndex,
235 bool bHasFiltered, bool& rSkipOverlappedCells,
236 std::vector<sal_Int32>& rNonOverlappedCellIdx)
238 OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
240 rInc = 0.0;
241 rDuration = tools::Duration();
242 rMinDigits = 0;
243 rListData = nullptr;
244 rCmd = FILL_SIMPLE;
245 rSkipOverlappedCells = false;
246 if ( nScFillModeMouseModifier & KEY_MOD1 )
247 return ; // Ctrl-key: Copy
249 SCCOL nAddX;
250 SCROW nAddY;
251 SCSIZE nCount;
252 if (nCol1 == nCol2)
254 nAddX = 0;
255 nAddY = 1;
256 nCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
258 else
260 nAddX = 1;
261 nAddY = 0;
262 nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
265 // Try to analyse the merged cells only if there are no filtered rows in the destination area
266 // Else fallback to the old way to avoid regression.
267 // Filling merged cells into an area with filtered (hidden) rows, is a very complex task
268 // that is not implemented, but not even decided how to do, even excel can't handle that well
269 if (!bHasFiltered)
271 bool bHasOverlappedCells = false;
272 bool bSkipOverlappedCells = true;
273 SCCOL nColCurr = nCol1;
274 SCROW nRowCurr = nRow1;
276 // collect cells that are not empty or not overlapped
277 rNonOverlappedCellIdx.resize(nCount);
278 SCSIZE nValueCount = 0;
279 for (SCSIZE i = 0; i < nCount; ++i)
281 const ScPatternAttr* pPattern = GetPattern(nColCurr, nRowCurr);
282 const ScMergeFlagAttr* pMergeFlagItem = nullptr;
283 bool bOverlapped
284 = pPattern->GetItemSet().GetItemState(ATTR_MERGE_FLAG, false, &pMergeFlagItem) == SfxItemState::SET
285 && pMergeFlagItem->IsOverlapped();
287 if (bOverlapped)
288 bHasOverlappedCells = true;
290 if (!bOverlapped || GetCellValue(nColCurr, nRowCurr).getType() != CELLTYPE_NONE)
292 rNonOverlappedCellIdx[nValueCount++] = i;
293 // if there is at least 1 non empty overlapped cell, then no cell should be skipped
294 if (bOverlapped)
295 bSkipOverlappedCells = false;
298 nColCurr += nAddX;
299 nRowCurr += nAddY;
301 rNonOverlappedCellIdx.resize(nValueCount);
303 // if all the values are overlapped CELLTYPE_NONE, then there is no need to analyse it.
304 if (nValueCount == 0)
305 return;
307 // if there is no overlapped cells, there is nothing to skip
308 if (!bHasOverlappedCells)
309 bSkipOverlappedCells = false;
311 if (bSkipOverlappedCells)
313 nColCurr = nCol1 + rNonOverlappedCellIdx[0] * nAddX;
314 nRowCurr = nRow1 + rNonOverlappedCellIdx[0] * nAddY;
315 ScRefCellValue aPrevCell, aCurrCell;
316 aCurrCell = GetCellValue(nColCurr, nRowCurr);
317 CellType eCellType = aCurrCell.getType();
318 if (eCellType == CELLTYPE_VALUE)
320 bool bVal = true;
321 double fVal;
322 SvNumFormatType nCurrCellFormatType
323 = rDocument.GetFormatTable()->GetType(GetNumberFormat(nColCurr, nRowCurr));
324 if (nCurrCellFormatType == SvNumFormatType::DATE)
326 if (nValueCount >= 2)
328 tools::Long nCmpInc = 0;
329 FillDateCmd eType = FILL_YEAR; // just some temporary default values
330 tools::Long nDDiff = 0, nMDiff = 0, nYDiff = 0; // to avoid warnings
331 Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
332 Date aCurrDate = aNullDate, aPrevDate = aNullDate;
333 aCurrDate.AddDays(aCurrCell.getDouble());
334 for (SCSIZE i = 1; i < nValueCount && bVal; i++)
336 aPrevCell = aCurrCell;
337 aPrevDate = aCurrDate;
338 nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
339 nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
340 aCurrCell = GetCellValue(nColCurr, nRowCurr);
341 if (aCurrCell.getType() == CELLTYPE_VALUE)
343 aCurrDate = aNullDate + static_cast<sal_Int32>(aCurrCell.getDouble());
344 if (eType != FILL_DAY) {
345 nDDiff = aCurrDate.GetDay()
346 - static_cast<tools::Long>(aPrevDate.GetDay());
347 nMDiff = aCurrDate.GetMonth()
348 - static_cast<tools::Long>(aPrevDate.GetMonth());
349 nYDiff = aCurrDate.GetYear()
350 - static_cast<tools::Long>(aPrevDate.GetYear());
352 if (i == 1)
354 if (nDDiff != 0)
356 eType = FILL_DAY;
357 nCmpInc = aCurrDate - aPrevDate;
359 else
361 eType = FILL_MONTH;
362 nCmpInc = nMDiff + 12 * nYDiff;
365 else if (eType == FILL_DAY)
367 if (aCurrDate - aPrevDate != nCmpInc)
368 bVal = false;
370 else
372 if (nDDiff || (nMDiff + 12 * nYDiff != nCmpInc))
373 bVal = false;
376 else
377 bVal = false; // No date is also not ok
379 if (bVal)
381 if (eType == FILL_MONTH && (nCmpInc % 12 == 0))
383 eType = FILL_YEAR;
384 nCmpInc /= 12;
386 rCmd = FILL_DATE;
387 rDateCmd = eType;
388 rInc = nCmpInc;
389 rSkipOverlappedCells = true;
390 return;
393 else
395 rCmd = FILL_DATE;
396 rDateCmd = FILL_DAY;
397 rInc = 1.0;
398 rSkipOverlappedCells = true;
399 return;
402 else if (nCurrCellFormatType == SvNumFormatType::LOGICAL
403 && ((fVal = aCurrCell.getDouble()) == 0.0 || fVal == 1.0))
406 else if (nValueCount >= 2)
408 tools::Duration aDuration;
409 for (SCSIZE i = 1; i < nValueCount && bVal; i++)
411 aPrevCell = aCurrCell;
412 nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
413 nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
414 aCurrCell = GetCellValue(nColCurr, nRowCurr);
415 if (aCurrCell.getType() == CELLTYPE_VALUE)
417 const bool bTime = (nCurrCellFormatType == SvNumFormatType::TIME ||
418 nCurrCellFormatType == SvNumFormatType::DATETIME);
419 double nDiff = approxTypedDiff(aCurrCell.getDouble(), aPrevCell.getDouble(),
420 bTime, aDuration);
421 if (i == 1)
423 rInc = nDiff;
424 if (bTime)
425 rDuration = aDuration;
427 if (!::rtl::math::approxEqual(nDiff, rInc, 13))
428 bVal = false;
429 else if ((aCurrCell.getDouble() == 0.0 || aCurrCell.getDouble() == 1.0)
430 && (rDocument.GetFormatTable()->GetType(
431 GetNumberFormat(nColCurr, nRowCurr))
432 == SvNumFormatType::LOGICAL))
433 bVal = false;
435 else
436 bVal = false;
438 if (bVal)
440 rCmd = FILL_LINEAR;
441 rSkipOverlappedCells = true;
442 return;
446 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
448 OUString aStr = GetString(nColCurr, nRowCurr );
449 OUString aStr2;
451 rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList().GetData(aStr));
452 if (rListData)
454 bool bMatchCase = false;
455 (void)rListData->GetSubIndex(aStr, rListIndex, bMatchCase);
456 size_t nListStrCount = rListData->GetSubCount();
457 sal_uInt16 nPrevListIndex, nInc = 1;
458 for (SCSIZE i = 1; i < nValueCount && rListData; i++)
460 nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
461 nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
462 aStr2 = GetString(nColCurr, nRowCurr);
464 nPrevListIndex = rListIndex;
465 if (!rListData->GetSubIndex(aStr2, rListIndex, bMatchCase))
466 rListData = nullptr;
467 else
469 sal_Int32 nIncCurr = rListIndex - nPrevListIndex;
470 if (nIncCurr < 0)
471 nIncCurr += nListStrCount;
472 if (i == 1)
473 nInc = nIncCurr;
474 else if (nInc != nIncCurr)
475 rListData = nullptr;
478 if (rListData) {
479 rInc = nInc;
480 rSkipOverlappedCells = true;
481 return;
484 short nFlag1, nFlag2;
485 sal_Int32 nVal1, nVal2;
486 nFlag1 = lcl_DecompValueString(aStr, nVal1, &rMinDigits);
487 if (nFlag1)
489 bool bVal = true;
490 rInc = 1;
491 for (SCSIZE i = 1; i < nValueCount && bVal; i++)
493 nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
494 nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
495 ScRefCellValue aCell = GetCellValue(nColCurr, nRowCurr);
496 CellType eType = aCell.getType();
497 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
499 aStr2 = aCell.getString(&rDocument);
500 nFlag2 = lcl_DecompValueString(aStr2, nVal2, &rMinDigits);
501 if (nFlag1 == nFlag2 && aStr == aStr2)
503 double nDiff = approxDiff(nVal2, nVal1);
504 if (i == 1)
505 rInc = nDiff;
506 else if (!::rtl::math::approxEqual(nDiff, rInc, 13))
507 bVal = false;
508 nVal1 = nVal2;
510 else
511 bVal = false;
513 else
514 bVal = false;
516 if (bVal)
518 rCmd = FILL_LINEAR;
519 rSkipOverlappedCells = true;
520 return;
527 //if it is not a FILL_LINEAR - CELLTYPE_VALUE - with merged cells [without hidden values]
528 //then do it in the old way
530 SCCOL nCol = nCol1;
531 SCROW nRow = nRow1;
533 ScRefCellValue aFirstCell = GetCellValue(nCol, nRow);
534 CellType eCellType = aFirstCell.getType();
536 if (eCellType == CELLTYPE_VALUE)
538 double fVal;
539 sal_uInt32 nFormat = GetAttr(nCol,nRow,ATTR_VALUE_FORMAT)->GetValue();
540 const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(nFormat);
541 bool bDate = (nFormatType == SvNumFormatType::DATE); // date without time
542 bool bTime = (nFormatType == SvNumFormatType::TIME || nFormatType == SvNumFormatType::DATETIME);
543 bool bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
544 if (bDate)
546 if (nCount > 1)
548 double nVal;
549 Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
550 Date aDate1 = aNullDate;
551 nVal = aFirstCell.getDouble();
552 aDate1.AddDays(nVal);
553 Date aDate2 = aNullDate;
554 nVal = GetValue(nCol+nAddX, nRow+nAddY);
555 aDate2.AddDays(nVal);
556 if ( aDate1 != aDate2 )
558 tools::Long nCmpInc = 0;
559 FillDateCmd eType;
560 tools::Long nDDiff = aDate2.GetDay() - static_cast<tools::Long>(aDate1.GetDay());
561 tools::Long nMDiff = aDate2.GetMonth() - static_cast<tools::Long>(aDate1.GetMonth());
562 tools::Long nYDiff = aDate2.GetYear() - static_cast<tools::Long>(aDate1.GetYear());
563 if (nMDiff && aDate1.IsEndOfMonth() && aDate2.IsEndOfMonth())
565 eType = FILL_END_OF_MONTH;
566 nCmpInc = nMDiff + 12 * nYDiff;
568 else if (nDDiff)
570 eType = FILL_DAY;
571 nCmpInc = aDate2 - aDate1;
573 else
575 eType = FILL_MONTH;
576 nCmpInc = nMDiff + 12 * nYDiff;
579 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
580 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
581 bool bVal = true;
582 for (SCSIZE i=1; i<nCount && bVal; i++)
584 ScRefCellValue aCell = GetCellValue(nCol,nRow);
585 if (aCell.getType() == CELLTYPE_VALUE)
587 nVal = aCell.getDouble();
588 aDate2 = aNullDate + static_cast<sal_Int32>(nVal);
589 if ( eType == FILL_DAY )
591 if ( aDate2-aDate1 != nCmpInc )
592 bVal = false;
594 else
596 nDDiff = aDate2.GetDay() - static_cast<tools::Long>(aDate1.GetDay());
597 nMDiff = aDate2.GetMonth() - static_cast<tools::Long>(aDate1.GetMonth());
598 nYDiff = aDate2.GetYear() - static_cast<tools::Long>(aDate1.GetYear());
599 if ((nDDiff && !aDate1.IsEndOfMonth() && !aDate2.IsEndOfMonth())
600 || (nMDiff + 12 * nYDiff != nCmpInc))
601 bVal = false;
603 aDate1 = aDate2;
604 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
605 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
607 else
608 bVal = false; // No date is also not ok
610 if (bVal)
612 if ((eType == FILL_MONTH || eType == FILL_END_OF_MONTH)
613 && (nCmpInc % 12 == 0))
615 eType = FILL_YEAR;
616 nCmpInc /= 12;
618 rCmd = FILL_DATE;
619 rDateCmd = eType;
620 rInc = nCmpInc;
623 else
625 // tdf#89754 - don't increment non different consecutive date cells
626 rCmd = FILL_DATE;
627 rDateCmd = FILL_DAY;
628 rInc = 0.0;
631 else // single date -> increment by days
633 rCmd = FILL_DATE;
634 rDateCmd = FILL_DAY;
635 rInc = 1.0;
638 else if (bBooleanCell && ((fVal = aFirstCell.getDouble()) == 0.0 || fVal == 1.0))
640 // Nothing, rInc stays 0.0, no specific fill mode.
642 else
644 if (nCount > 1)
646 tools::Duration aDuration;
647 double nVal1 = aFirstCell.getDouble();
648 double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
649 rInc = approxTypedDiff( nVal2, nVal1, bTime, aDuration);
650 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
651 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
652 bool bVal = true;
653 for (SCSIZE i=1; i<nCount && bVal; i++)
655 ScRefCellValue aCell = GetCellValue(nCol,nRow);
656 if (aCell.getType() == CELLTYPE_VALUE)
658 nVal2 = aCell.getDouble();
659 double nDiff = approxTypedDiff( nVal2, nVal1, bTime, aDuration);
660 if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
661 bVal = false;
662 else if ((nVal2 == 0.0 || nVal2 == 1.0) &&
663 (rDocument.GetFormatTable()->GetType(GetNumberFormat(nCol,nRow)) ==
664 SvNumFormatType::LOGICAL))
665 bVal = false;
666 nVal1 = nVal2;
668 else
669 bVal = false;
670 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
671 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
672 if (bVal && bTime)
673 rDuration = aDuration;
675 if (bVal)
676 rCmd = FILL_LINEAR;
678 else if(nFormatType == SvNumFormatType::PERCENT)
680 rInc = 0.01; // tdf#89998 increment by 1% at a time
684 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
686 OUString aStr = GetString(nCol, nRow);
688 rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList().GetData(aStr));
689 if (rListData)
691 bool bMatchCase = false;
692 (void)rListData->GetSubIndex(aStr, rListIndex, bMatchCase);
693 size_t nListStrCount = rListData->GetSubCount();
694 sal_uInt16 nPrevListIndex, nInc = 1;
695 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
696 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
697 for (SCSIZE i=1; i<nCount && rListData; i++)
699 nPrevListIndex = rListIndex;
700 aStr = GetString(nCol, nRow);
701 if (!rListData->GetSubIndex(aStr, rListIndex, bMatchCase))
702 rListData = nullptr;
703 else
705 sal_Int32 nIncCurr = rListIndex - nPrevListIndex;
706 if (nIncCurr < 0)
707 nIncCurr += nListStrCount;
708 if (i == 1)
709 nInc = nIncCurr;
710 else if (nInc != nIncCurr)
711 rListData = nullptr;
713 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
714 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
716 if (rListData)
717 rInc = nInc;
719 else if ( nCount > 1 )
721 // pass rMinDigits to all DecompValueString calls
722 // -> longest number defines rMinDigits
724 sal_Int32 nVal1;
725 short nFlag1 = lcl_DecompValueString( aStr, nVal1, &rMinDigits );
726 if ( nFlag1 )
728 sal_Int32 nVal2;
729 aStr = GetString( nCol+nAddX, nRow+nAddY );
730 short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
731 if ( nFlag1 == nFlag2 )
733 rInc = approxDiff( nVal2, nVal1);
734 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
735 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
736 bool bVal = true;
737 for (SCSIZE i=1; i<nCount && bVal; i++)
739 ScRefCellValue aCell = GetCellValue(nCol, nRow);
740 CellType eType = aCell.getType();
741 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
743 aStr = aCell.getString(&rDocument);
744 nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
745 if ( nFlag1 == nFlag2 )
747 double nDiff = approxDiff( nVal2, nVal1);
748 if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
749 bVal = false;
750 nVal1 = nVal2;
752 else
753 bVal = false;
755 else
756 bVal = false;
757 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
758 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
760 if (bVal)
761 rCmd = FILL_LINEAR;
765 else
767 // call DecompValueString to set rMinDigits
768 sal_Int32 nDummy;
769 lcl_DecompValueString( aStr, nDummy, &rMinDigits );
774 void ScTable::FillFormula(
775 const ScFormulaCell* pSrcCell, SCCOL nDestCol, SCROW nDestRow, bool bLast )
778 rDocument.SetNoListening( true ); // still the wrong reference
779 ScAddress aAddr( nDestCol, nDestRow, nTab );
780 ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, rDocument, aAddr );
781 aCol[nDestCol].SetFormulaCell(nDestRow, pDestCell);
783 if ( bLast && pDestCell->GetMatrixFlag() != ScMatrixMode::NONE )
785 ScAddress aOrg;
786 if ( pDestCell->GetMatrixOrigin( GetDoc(), aOrg ) )
788 if ( nDestCol >= aOrg.Col() && nDestRow >= aOrg.Row() )
790 ScFormulaCell* pOrgCell = rDocument.GetFormulaCell(aOrg);
791 if (pOrgCell && pOrgCell->GetMatrixFlag() == ScMatrixMode::Formula)
793 pOrgCell->SetMatColsRows(
794 nDestCol - aOrg.Col() + 1,
795 nDestRow - aOrg.Row() + 1 );
797 else
799 OSL_FAIL( "FillFormula: MatrixOrigin no formula cell with ScMatrixMode::Formula" );
802 else
804 OSL_FAIL( "FillFormula: MatrixOrigin bottom right" );
807 else
809 OSL_FAIL( "FillFormula: no MatrixOrigin" );
812 rDocument.SetNoListening( false );
813 pDestCell->StartListeningTo( rDocument );
816 void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
817 sal_uInt64 nFillCount, FillDir eFillDir, ScProgress* pProgress )
819 if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
820 return;
822 // Detect direction
824 bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
825 bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
827 SCCOLROW nCol = 0;
828 SCCOLROW nRow = 0;
829 SCCOLROW& rInner = bVertical ? nRow : nCol; // loop variables
830 SCCOLROW& rOuter = bVertical ? nCol : nRow;
831 SCCOLROW nOStart;
832 SCCOLROW nOEnd;
833 SCCOLROW nIStart;
834 SCCOLROW nIEnd;
835 SCCOLROW nISrcStart;
836 SCCOLROW nISrcEnd;
837 ScRange aFillRange;
839 if (bVertical)
841 nOStart = nCol1;
842 nOEnd = nCol2;
843 if (bPositive)
845 nISrcStart = nRow1;
846 nISrcEnd = nRow2;
847 nIStart = nRow2 + 1;
848 nIEnd = nRow2 + nFillCount;
849 aFillRange = ScRange(nCol1, nRow2+1, 0, nCol2, nRow2 + nFillCount, 0);
851 else
853 nISrcStart = nRow2;
854 nISrcEnd = nRow1;
855 nIStart = nRow1 - 1;
856 nIEnd = nRow1 - nFillCount;
857 aFillRange = ScRange(nCol1, nRow1-1, 0, nCol2, nRow2 - nFillCount, 0);
860 else
862 nOStart = nRow1;
863 nOEnd = nRow2;
864 if (bPositive)
866 nISrcStart = nCol1;
867 nISrcEnd = nCol2;
868 nIStart = nCol2 + 1;
869 nIEnd = nCol2 + nFillCount;
870 aFillRange = ScRange(nCol2 + 1, nRow1, 0, nCol2 + nFillCount, nRow2, 0);
872 else
874 nISrcStart = nCol2;
875 nISrcEnd = nCol1;
876 nIStart = nCol1 - 1;
877 nIEnd = nCol1 - nFillCount;
878 aFillRange = ScRange(nCol1 - 1, nRow1, 0, nCol1 - nFillCount, nRow2, 0);
881 sal_uInt64 nIMin = nIStart;
882 sal_uInt64 nIMax = nIEnd;
883 PutInOrder(nIMin,nIMax);
884 bool bHasFiltered = IsDataFiltered(aFillRange);
886 if (!bHasFiltered)
888 if (bVertical)
889 DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), InsertDeleteFlags::AUTOFILL);
890 else
891 DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, InsertDeleteFlags::AUTOFILL);
894 sal_uInt64 nProgress = 0;
895 if (pProgress)
896 nProgress = pProgress->GetState();
898 // Avoid possible repeated calls to StartListeningFormulaCells() (tdf#132165).
899 std::list< sc::DelayStartListeningFormulaCells > delayStartListening;
900 SCCOL delayStartColumn, delayEndColumn;
901 if(bVertical)
903 delayStartColumn = std::min( nOStart, nOEnd );
904 delayEndColumn = std::max( nOStart, nOEnd );
906 else
908 delayStartColumn = std::min( nIStart, nIEnd );
909 delayEndColumn = std::max( nIStart, nIEnd );
911 for( SCROW col = delayStartColumn; col <= delayEndColumn; ++col )
913 if( ScColumn* column = FetchColumn( col ))
914 delayStartListening.emplace_back( *column, true );
917 // execute
919 sal_uInt64 nActFormCnt = 0;
920 for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
922 sal_uInt64 nMaxFormCnt = 0; // for formulas
924 // transfer attributes
926 const ScPatternAttr* pSrcPattern = nullptr;
927 const ScStyleSheet* pStyleSheet = nullptr;
928 SCCOLROW nAtSrc = nISrcStart;
929 std::unique_ptr<ScPatternAttr> pNewPattern;
930 bool bGetPattern = true;
931 rInner = nIStart;
932 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
934 if (!ColHidden(nCol) && !RowHidden(nRow))
936 if ( bGetPattern )
938 if (bVertical) // rInner&:=nRow, rOuter&:=nCol
939 pSrcPattern = GetColumnData(nCol).GetPattern(static_cast<SCROW>(nAtSrc));
940 else // rInner&:=nCol, rOuter&:=nRow
941 pSrcPattern = GetColumnData(nAtSrc).GetPattern(static_cast<SCROW>(nRow));
942 bGetPattern = false;
943 pStyleSheet = pSrcPattern->GetStyleSheet();
944 // do transfer ATTR_MERGE / ATTR_MERGE_FLAG
946 // Note: ATTR_MERGE is an attribute of the top left cell of a merged area
947 // containing the size of the area. ATTR_MERGE_FLAGs are attributes of the
948 // other cells of a merged area, containing the information about also
949 // overlapping, i.e. visibility of their content.
951 // TODO: extend the similar incomplete selections to a bounding rectangle to
952 // avoid incomplete fill, where not all AUTO_MERGE_FLAGs are synchronized with
953 // the copied ATTR_MERGE, resulting broken grid and visibility during run-time.
955 // +--+ +--+--+
956 // | | | | |
957 // +--+--+ +--+--+
958 // | | -> | |
959 // +--+--+ +--+--+
960 // | | | | |
961 // +--+ +--+--+
963 // TODO: protect incompatible merged cells of the destination area, for example
964 // by skipping the fill operation.
966 // TODO: by dragging the fill handle select only the multiples of the height
967 // of the originally selected area which is merged vertically to avoid of
968 // incomplete fill.
970 // +--+ +--+
971 // |XX| |XX|
972 // +XX+ +XX+
973 // |XX| -> |XX|
974 // +--+ +--+
975 // | | | |
976 // +--+ +--+
977 // | |
978 // +--+
980 // Other things stored in ATTR_MERGE_FLAG, like autofilter button, will be
981 // deleted now, but may need to be repaired later, like at ScDocument::Fill.
982 const SfxItemSet& rSet = pSrcPattern->GetItemSet();
983 if ( rSet.GetItemState(ATTR_MERGE_FLAG, false) == SfxItemState::SET )
985 ScMF nOldValue = pSrcPattern->GetItem(ATTR_MERGE_FLAG).GetValue();
986 ScMF nOldValueMerge = nOldValue & (ScMF::Hor | ScMF::Ver);
987 // keep only the merge flags
988 if ( nOldValue != nOldValueMerge )
990 pNewPattern.reset(new ScPatternAttr(*pSrcPattern));
991 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
992 if ( nOldValueMerge == ScMF::NONE )
993 rNewSet.ClearItem(ATTR_MERGE_FLAG);
994 else
995 rNewSet.Put(ScMergeFlagAttr(nOldValueMerge));
997 else
998 pNewPattern.reset();
1000 else
1001 pNewPattern.reset();
1004 const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
1005 const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
1007 if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
1009 // set all attributes at once (en bloc)
1010 if (pNewPattern || !pSrcPattern->isDefault())
1012 // Default is already present (DeleteArea)
1013 SCROW nY1 = static_cast<SCROW>(std::min( nIStart, nIEnd ));
1014 SCROW nY2 = static_cast<SCROW>(std::max( nIStart, nIEnd ));
1015 if ( pStyleSheet )
1016 aCol[nCol].ApplyStyleArea( nY1, nY2, *pStyleSheet );
1017 if ( pNewPattern )
1018 aCol[nCol].ApplyPatternArea( nY1, nY2, *pNewPattern );
1019 else
1020 aCol[nCol].ApplyPatternArea( nY1, nY2, *pSrcPattern );
1022 for(const auto& rIndex : rCondFormatIndex)
1024 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
1025 if (pCondFormat)
1027 ScRangeList aRange = pCondFormat->GetRange();
1028 aRange.Join(ScRange(nCol, nY1, nTab, nCol, nY2, nTab));
1029 pCondFormat->SetRange(aRange);
1034 break;
1037 if ( bHasFiltered )
1038 DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow),
1039 static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), InsertDeleteFlags::AUTOFILL);
1041 if ( !ScPatternAttr::areSame(pSrcPattern, aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) )
1043 // Transfer template too
1044 //TODO: Merge ApplyPattern to AttrArray ??
1045 if ( pStyleSheet )
1046 aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), pStyleSheet );
1048 // Use ApplyPattern instead of SetPattern to keep old MergeFlags
1049 if ( pNewPattern )
1050 aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern );
1051 else
1052 aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern );
1054 for(const auto& rIndex : rCondFormatIndex)
1056 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
1057 if (pCondFormat)
1059 ScRangeList aRange = pCondFormat->GetRange();
1060 aRange.Join(ScRange(nCol, nRow, nTab, nCol, nRow, nTab));
1061 pCondFormat->SetRange(aRange);
1066 if (nAtSrc==nISrcEnd)
1068 if ( nAtSrc != nISrcStart )
1069 { // More than one source cell
1070 nAtSrc = nISrcStart;
1071 bGetPattern = true;
1074 else if (bPositive)
1076 ++nAtSrc;
1077 bGetPattern = true;
1079 else
1081 --nAtSrc;
1082 bGetPattern = true;
1086 if (rInner == nIEnd) break;
1087 if (bPositive) ++rInner; else --rInner;
1089 pNewPattern.reset();
1091 // Analyse
1093 FillCmd eFillCmd;
1094 FillDateCmd eDateCmd = {};
1095 double nInc;
1096 tools::Duration aDurationInc;
1097 sal_uInt16 nMinDigits;
1098 ScUserListData* pListData = nullptr;
1099 sal_uInt16 nListIndex;
1100 bool bSkipOverlappedCells;
1101 std::vector<sal_Int32> aNonOverlappedCellIdx;
1102 if (bVertical)
1103 FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
1104 static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
1105 nInc, aDurationInc, nMinDigits, pListData, nListIndex,
1106 bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
1107 else
1108 FillAnalyse(nCol1,static_cast<SCROW>(nRow),
1109 nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
1110 nInc, aDurationInc, nMinDigits, pListData, nListIndex,
1111 bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
1113 if (pListData)
1115 sal_uInt16 nListCount = pListData->GetSubCount();
1116 if (bSkipOverlappedCells)
1118 int nFillerCount = 1 + ( nISrcEnd - nISrcStart ) * (bPositive ? 1 : -1);
1119 std::vector<bool> aIsNonEmptyCell(nFillerCount, false);
1120 SCCOLROW nLastValueIdx;
1121 if (bPositive)
1123 nLastValueIdx = nISrcEnd - (nFillerCount - 1 - aNonOverlappedCellIdx.back());
1124 for (auto i : aNonOverlappedCellIdx)
1125 aIsNonEmptyCell[i] = true;
1127 else
1129 nLastValueIdx = nISrcEnd + aNonOverlappedCellIdx[0];
1130 for (auto i : aNonOverlappedCellIdx)
1131 aIsNonEmptyCell[nFillerCount - 1 - i] = true;
1134 OUString aStr;
1135 if (bVertical)
1136 aStr = GetString(rOuter, nLastValueIdx);
1137 else
1138 aStr = GetString(nLastValueIdx, rOuter);
1140 bool bMatchCase = false;
1141 (void)pListData->GetSubIndex(aStr, nListIndex, bMatchCase);
1143 sal_Int32 nFillerIdx = 0;
1144 rInner = nIStart;
1145 while (true)
1147 if (aIsNonEmptyCell[nFillerIdx])
1149 if (bPositive)
1151 nListIndex += nInc;
1152 if (nListIndex >= nListCount) nListIndex -= nListCount;
1154 else
1156 if (nListIndex < nInc) nListIndex += nListCount;
1157 nListIndex -= nInc;
1159 aCol[nCol].SetRawString(static_cast<SCROW>(nRow), pListData->GetSubStr(nListIndex));
1162 if (rInner == nIEnd) break;
1163 nFillerIdx = (nFillerIdx + 1) % nFillerCount;
1164 if (bPositive)
1165 ++rInner;
1166 else
1167 --rInner;
1170 else
1172 if (!bPositive)
1174 // nListIndex of FillAnalyse points to the last entry -> adjust
1175 sal_Int64 nAdjust = nListIndex - (nISrcStart - nISrcEnd) * nInc;
1176 nAdjust = nAdjust % nListCount;
1177 if (nAdjust < 0)
1178 nAdjust += nListCount;
1179 nListIndex = nAdjust;
1182 rInner = nIStart;
1183 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1185 if (!ColHidden(nCol) && !RowHidden(nRow))
1187 if (bPositive)
1189 nListIndex += nInc;
1190 if (nListIndex >= nListCount) nListIndex -= nListCount;
1192 else
1194 if (nListIndex < nInc) nListIndex += nListCount;
1195 nListIndex -= nInc;
1197 aCol[nCol].SetRawString(static_cast<SCROW>(nRow), pListData->GetSubStr(nListIndex));
1200 if (rInner == nIEnd) break;
1201 if (bPositive) ++rInner; else --rInner;
1204 if(pProgress)
1206 nProgress += nIMax - nIMin + 1;
1207 pProgress->SetStateOnPercent( nProgress );
1210 else if (eFillCmd == FILL_SIMPLE) // fill with pattern/sample
1212 FillAutoSimple(
1213 nISrcStart, nISrcEnd, nIStart, nIEnd, rInner, nCol, nRow,
1214 nActFormCnt, nMaxFormCnt, bHasFiltered, bVertical, bPositive, pProgress, nProgress);
1216 else
1218 if (!bPositive)
1220 nInc = -nInc;
1221 aDurationInc = -aDurationInc;
1223 double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
1224 if (bVertical)
1225 FillSeries( static_cast<SCCOL>(nCol), nRow1,
1226 static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
1227 eFillCmd, eDateCmd, nInc, aDurationInc, nEndVal, nMinDigits, false,
1228 pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
1229 else
1230 FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
1231 static_cast<SCROW>(nRow), nFillCount, eFillDir,
1232 eFillCmd, eDateCmd, nInc, aDurationInc, nEndVal, nMinDigits, false,
1233 pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
1234 if (pProgress)
1235 nProgress = pProgress->GetState();
1238 if (bVertical)
1239 FillSparkline(bVertical, nCol, nRow1, nRow2, nIStart, nIEnd);
1240 else
1241 FillSparkline(bVertical, nRow, nCol1, nCol2, nIStart, nIEnd);
1243 nActFormCnt += nMaxFormCnt;
1247 void ScTable::FillSparkline(bool bVertical, SCCOLROW nFixed,
1248 SCCOLROW nStart, SCCOLROW nEnd,
1249 SCCOLROW nFillStart, SCCOLROW nFillEnd)
1251 bool bHasSparklines = false;
1252 std::vector<std::shared_ptr<sc::Sparkline>> aSparklineSeries;
1254 for (SCROW nCurrent = nStart; nCurrent <= nEnd; nCurrent++)
1256 auto pSparkline = bVertical ? GetSparkline(nFixed, nCurrent) : GetSparkline(nCurrent, nFixed);
1257 bHasSparklines = bHasSparklines || pSparkline;
1258 aSparklineSeries.push_back(pSparkline);
1261 if (bHasSparklines)
1263 for (SCCOLROW nCurrent = nFillStart; nCurrent <= nFillEnd; nCurrent++)
1265 size_t nIndex = size_t(nFillStart - nCurrent) % aSparklineSeries.size();
1266 if (auto& rpSparkline = aSparklineSeries[nIndex])
1268 auto pGroup = rpSparkline->getSparklineGroup();
1270 auto* pNewSparkline = bVertical ? CreateSparkline(nFixed, nCurrent, pGroup)
1271 : CreateSparkline(nCurrent, nFixed, pGroup);
1272 if (pNewSparkline)
1274 SCCOLROW nPosition = bVertical ? rpSparkline->getRow()
1275 : rpSparkline->getColumn();
1276 SCCOLROW nDelta = nCurrent - nPosition;
1277 ScRangeList aRangeList(rpSparkline->getInputRange());
1278 for (ScRange& rRange : aRangeList)
1280 if (bVertical)
1282 rRange.aStart.IncRow(nDelta);
1283 rRange.aEnd.IncRow(nDelta);
1285 else
1287 rRange.aStart.IncCol(nDelta);
1288 rRange.aEnd.IncCol(nDelta);
1291 pNewSparkline->setInputRange(aRangeList);
1298 void ScTable::GetBackColorArea(SCCOL& rStartCol, SCROW& /*rStartRow*/,
1299 SCCOL& rEndCol, SCROW& rEndRow ) const
1301 bool bExtend;
1302 const SvxBrushItem* pDefBackground = &rDocument.GetPool()->GetUserOrPoolDefaultItem(ATTR_BACKGROUND);
1304 rStartCol = std::min<SCCOL>(rStartCol, aCol.size() - 1);
1305 rEndCol = std::min<SCCOL>(rEndCol, aCol.size() - 1);
1309 bExtend = false;
1311 if (rEndRow < rDocument.MaxRow())
1313 for (SCCOL nCol = rStartCol; nCol <= rEndCol; ++nCol)
1315 const ScPatternAttr* pPattern = GetColumnData(nCol).GetPattern(rEndRow + 1);
1316 const SvxBrushItem* pBackground = &pPattern->GetItem(ATTR_BACKGROUND);
1317 if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty() ||
1318 (pBackground->GetColor() != COL_TRANSPARENT && pBackground != pDefBackground))
1320 bExtend = true;
1321 break;
1325 if (bExtend)
1326 ++rEndRow;
1328 } while (bExtend);
1331 OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
1333 OUString aValue;
1335 SCCOL nCol1 = rSource.aStart.Col();
1336 SCROW nRow1 = rSource.aStart.Row();
1337 SCCOL nCol2 = rSource.aEnd.Col();
1338 SCROW nRow2 = rSource.aEnd.Row();
1339 bool bOk = true;
1340 tools::Long nIndex = 0;
1341 sal_uInt64 nSrcCount = 0;
1342 FillDir eFillDir = FILL_TO_BOTTOM;
1343 if ( nEndX == nCol2 && nEndY == nRow2 ) // empty
1344 bOk = false;
1345 else if ( nEndX == nCol2 ) // to up / down
1347 nCol2 = nCol1; // use only first column
1348 nSrcCount = nRow2 - nRow1 + 1;
1349 nIndex = static_cast<tools::Long>(nEndY) - nRow1; // can be negative
1350 if ( nEndY >= nRow1 )
1351 eFillDir = FILL_TO_BOTTOM;
1352 else
1353 eFillDir = FILL_TO_TOP;
1355 else if ( nEndY == nRow2 ) // to left / right
1357 nEndY = nRow2 = nRow1; // use only first row
1358 nSrcCount = nCol2 - nCol1 + 1;
1359 nIndex = static_cast<tools::Long>(nEndX) - nCol1; // can be negative
1360 if ( nEndX >= nCol1 )
1361 eFillDir = FILL_TO_RIGHT;
1362 else
1363 eFillDir = FILL_TO_LEFT;
1365 else // direction not clear
1366 bOk = false;
1368 if ( bOk )
1370 tools::Long nBegin = 0;
1371 tools::Long nEnd = 0;
1372 tools::Long nHidden = 0;
1373 if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
1375 if (nEndY > nRow1)
1377 nBegin = nRow2+1;
1378 nEnd = nEndY;
1380 else
1382 nBegin = nEndY;
1383 nEnd = nRow1 -1;
1386 tools::Long nVisible = CountVisibleRows(nBegin, nEnd);
1387 nHidden = nEnd + 1 - nBegin - nVisible;
1389 else
1391 if (nEndX > nCol1)
1393 nBegin = nCol2+1;
1394 nEnd = nEndX;
1396 else
1398 nBegin = nEndX;
1399 nEnd = nCol1 -1;
1402 tools::Long nVisible = CountVisibleCols(nBegin, nEnd);
1403 nHidden = nEnd + 1 - nBegin - nVisible;
1405 if (nHidden)
1407 if (nIndex > 0)
1408 nIndex = nIndex - nHidden;
1409 else
1410 nIndex = nIndex + nHidden;
1413 FillCmd eFillCmd;
1414 FillDateCmd eDateCmd;
1415 double nInc;
1416 tools::Duration aDurationInc;
1417 sal_uInt16 nMinDigits;
1418 ScUserListData* pListData = nullptr;
1419 sal_uInt16 nListIndex;
1420 bool bSkipOverlappedCells;
1421 std::vector<sal_Int32> aNonOverlappedCellIdx;
1423 // Todo: update this function to calculate with merged cell fills,
1424 // after FillAnalyse / FillSeries fully handle them.
1425 // Now FillAnalyse called as if there are filtered rows, so it will work in the old way.
1426 FillAnalyse(nCol1, nRow1, nCol2, nRow2, eFillCmd, eDateCmd,
1427 nInc, aDurationInc, nMinDigits, pListData, nListIndex,
1428 true, bSkipOverlappedCells, aNonOverlappedCellIdx);
1430 if ( pListData ) // user defined list
1432 sal_uInt16 nListCount = pListData->GetSubCount();
1433 if ( nListCount )
1435 sal_uInt64 nSub = nSrcCount - 1; // nListIndex is from last source entry
1436 while ( nIndex < sal::static_int_cast<tools::Long>(nSub) )
1437 nIndex += nListCount;
1438 sal_uInt64 nPos = ( nListIndex + nIndex - nSub ) % nListCount;
1439 aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
1442 else if ( eFillCmd == FILL_SIMPLE ) // fill with pattern/sample
1444 tools::Long nPosIndex = nIndex;
1445 while ( nPosIndex < 0 )
1446 nPosIndex += nSrcCount;
1447 sal_uInt64 nPos = nPosIndex % nSrcCount;
1448 SCCOL nSrcX = nCol1;
1449 SCROW nSrcY = nRow1;
1450 if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
1451 nSrcY = sal::static_int_cast<SCROW>( nSrcY + static_cast<SCROW>(nPos) );
1452 else
1453 nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
1455 ScRefCellValue aCell = GetCellValue(nSrcX, nSrcY);
1456 if (!aCell.isEmpty())
1458 sal_Int32 nDelta;
1459 if (nIndex >= 0)
1460 nDelta = nIndex / nSrcCount;
1461 else
1462 nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
1464 CellType eType = aCell.getType();
1465 switch ( eType )
1467 case CELLTYPE_STRING:
1468 case CELLTYPE_EDIT:
1470 aValue = aCell.getString(&rDocument);
1472 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
1474 sal_Int32 nVal;
1475 sal_uInt16 nCellDigits = 0; // look at each source cell individually
1476 short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits );
1477 if ( nFlag < 0 )
1479 if (aValue == ScGlobal::GetOrdinalSuffix( nVal))
1480 aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta);
1481 aValue = lcl_ValueString( nVal + nDelta, nCellDigits ) + aValue;
1483 else if ( nFlag > 0 )
1485 sal_Int32 nNextValue;
1486 if ( nVal < 0 )
1487 nNextValue = nVal - nDelta;
1488 else
1489 nNextValue = nVal + nDelta;
1490 if ( nFlag == 2 && nNextValue >= 0 ) // Put back the '+'
1491 aValue += "+";
1492 aValue += lcl_ValueString( nNextValue, nCellDigits );
1496 break;
1497 case CELLTYPE_VALUE:
1499 sal_uInt32 nNumFmt = GetNumberFormat( nSrcX, nSrcY );
1500 // overflow is possible...
1501 double nVal = aCell.getDouble();
1502 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
1504 const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(nNumFmt);
1505 bool bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
1506 if (bPercentCell)
1508 // tdf#89998 increment by 1% at a time
1509 nVal += static_cast<double>(nDelta) * 0.01;
1511 else if (nVal == 0.0 || nVal == 1.0)
1513 bool bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
1514 if (!bBooleanCell)
1515 nVal += static_cast<double>(nDelta);
1517 else
1519 nVal += static_cast<double>(nDelta);
1523 const Color* pColor;
1524 rDocument.GetFormatTable()->GetOutputString( nVal, nNumFmt, aValue, &pColor );
1526 break;
1527 // not for formulas
1528 default:
1530 // added to avoid warnings
1535 else if ( eFillCmd == FILL_LINEAR || eFillCmd == FILL_DATE ) // values
1537 bool bValueOk;
1538 double nStart;
1539 sal_Int32 nVal = 0;
1540 short nHeadNoneTail = 0;
1541 ScRefCellValue aCell = GetCellValue(nCol1, nRow1);
1542 if (!aCell.isEmpty())
1544 CellType eType = aCell.getType();
1545 switch ( eType )
1547 case CELLTYPE_STRING:
1548 case CELLTYPE_EDIT:
1550 aValue = aCell.getString(&rDocument);
1551 nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
1552 if ( nHeadNoneTail )
1553 nStart = static_cast<double>(nVal);
1554 else
1555 nStart = 0.0;
1557 break;
1558 case CELLTYPE_VALUE:
1559 nStart = aCell.getDouble();
1560 break;
1561 case CELLTYPE_FORMULA:
1562 nStart = aCell.getFormula()->GetValue();
1563 break;
1564 default:
1565 nStart = 0.0;
1568 else
1569 nStart = 0.0;
1570 if ( eFillCmd == FILL_LINEAR )
1572 if (aDurationInc)
1574 bool bOverflow;
1575 tools::Duration aDuration( aDurationInc.Mult( nIndex, bOverflow));
1576 bValueOk = SubTotal::SafePlus( nStart, aDuration.GetInDays()) && !bOverflow;
1578 else
1580 double nAdd = nInc;
1581 bValueOk = ( SubTotal::SafeMult( nAdd, static_cast<double>(nIndex) ) &&
1582 SubTotal::SafePlus( nStart, nAdd ) );
1585 else // date
1587 bValueOk = true;
1588 sal_uInt16 nDayOfMonth = 0;
1589 if ( nIndex < 0 )
1591 nIndex = -nIndex;
1592 nInc = -nInc;
1594 for (tools::Long i=0; i<nIndex; i++)
1595 IncDate( nStart, nDayOfMonth, nInc, eDateCmd );
1598 if (bValueOk)
1600 if ( nHeadNoneTail )
1602 if ( nHeadNoneTail < 0 )
1604 if (aValue == ScGlobal::GetOrdinalSuffix( nVal))
1605 aValue = ScGlobal::GetOrdinalSuffix( static_cast<sal_Int32>(nStart) );
1607 aValue = lcl_ValueString( static_cast<sal_Int32>(nStart), nMinDigits ) + aValue;
1609 else
1611 if ( nHeadNoneTail == 2 && nStart >= 0 ) // Put back the '+'
1612 aValue += "+";
1613 aValue += lcl_ValueString( static_cast<sal_Int32>(nStart), nMinDigits );
1616 else
1618 //TODO: get number format according to Index?
1619 const Color* pColor;
1620 sal_uInt32 nNumFmt = GetNumberFormat( nCol1, nRow1 );
1621 rDocument.GetFormatTable()->GetOutputString( nStart, nNumFmt, aValue, &pColor );
1625 else
1627 OSL_FAIL("GetAutoFillPreview: invalid mode");
1631 return aValue;
1634 void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillDateCmd eCmd)
1636 if (eCmd == FILL_DAY)
1638 rVal += nStep;
1639 return;
1642 // class Date limits
1643 const sal_uInt16 nMinYear = 1583;
1644 const sal_uInt16 nMaxYear = 9956;
1646 tools::Long nInc = static_cast<tools::Long>(nStep); // upper/lower limits ?
1647 Date aNullDate = rDocument.GetFormatTable()->GetNullDate();
1648 Date aDate = aNullDate;
1649 aDate.AddDays(rVal);
1650 switch (eCmd)
1652 case FILL_WEEKDAY:
1654 aDate.AddDays(nInc);
1655 DayOfWeek eWeekDay = aDate.GetDayOfWeek();
1656 if (nInc >= 0)
1658 if (eWeekDay == SATURDAY)
1659 aDate.AddDays(2);
1660 else if (eWeekDay == SUNDAY)
1661 aDate.AddDays(1);
1663 else
1665 if (eWeekDay == SATURDAY)
1666 aDate.AddDays(-1);
1667 else if (eWeekDay == SUNDAY)
1668 aDate.AddDays(-2);
1671 break;
1672 case FILL_MONTH:
1673 case FILL_END_OF_MONTH:
1675 if ( nDayOfMonth == 0 )
1676 nDayOfMonth = aDate.GetDay(); // init
1677 tools::Long nMonth = aDate.GetMonth();
1678 tools::Long nYear = aDate.GetYear();
1680 nMonth += nInc;
1682 if (nInc >= 0)
1684 if (nMonth > 12)
1686 tools::Long nYAdd = (nMonth-1) / 12;
1687 nMonth -= nYAdd * 12;
1688 nYear += nYAdd;
1691 else
1693 if (nMonth < 1)
1695 tools::Long nYAdd = 1 - nMonth / 12; // positive
1696 nMonth += nYAdd * 12;
1697 nYear -= nYAdd;
1701 if ( nYear < nMinYear )
1702 aDate = Date( 1,1, nMinYear );
1703 else if ( nYear > nMaxYear )
1704 aDate = Date( 31,12, nMaxYear );
1705 else
1707 aDate.SetMonth(static_cast<sal_uInt16>(nMonth));
1708 aDate.SetYear(static_cast<sal_uInt16>(nYear));
1709 if (eCmd == FILL_END_OF_MONTH)
1711 aDate.SetDay(Date::GetDaysInMonth(nMonth, nYear));
1713 else
1715 aDate.SetDay(std::min(Date::GetDaysInMonth(nMonth, nYear), nDayOfMonth));
1719 break;
1720 case FILL_YEAR:
1722 tools::Long nYear = aDate.GetYear();
1723 nYear += nInc;
1724 if ( nYear < nMinYear )
1725 aDate = Date( 1,1, nMinYear );
1726 else if ( nYear > nMaxYear )
1727 aDate = Date( 31,12, nMaxYear );
1728 else
1729 aDate.SetYear(static_cast<sal_uInt16>(nYear));
1731 break;
1732 default:
1734 // added to avoid warnings
1738 rVal = aDate - aNullDate;
1741 namespace {
1743 bool HiddenRowColumn(const ScTable* pTable, SCCOLROW nRowColumn, bool bVertical, SCCOLROW& rLastPos)
1745 bool bHidden = false;
1746 if(bVertical)
1748 SCROW nLast;
1749 bHidden = pTable->RowHidden(nRowColumn, nullptr, &nLast);
1750 rLastPos = nLast;
1752 else
1754 SCCOL nLast;
1755 bHidden = pTable->ColHidden(static_cast<SCCOL>(nRowColumn), nullptr, &nLast);
1756 rLastPos = nLast;
1758 return bHidden;
1763 void ScTable::FillFormulaVertical(
1764 const ScFormulaCell& rSrcCell,
1765 SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2,
1766 ScProgress* pProgress, sal_uInt64& rProgress )
1768 // rInner is the row position when filling vertically. Also, when filling
1769 // across hidden regions, it may create multiple dis-jointed spans of
1770 // formula cells.
1772 bool bHidden = false;
1773 SCCOLROW nHiddenLast = -1;
1775 SCCOLROW nRowStart = -1, nRowEnd = -1;
1776 std::vector<sc::RowSpan> aSpans;
1777 PutInOrder(nRow1, nRow2);
1778 for (rInner = nRow1; rInner <= nRow2; ++rInner)
1780 if (rInner > nHiddenLast)
1781 bHidden = HiddenRowColumn(this, rInner, true, nHiddenLast);
1783 if (bHidden)
1785 if (nRowStart >= 0)
1787 nRowEnd = rInner - 1;
1788 aSpans.emplace_back(nRowStart, nRowEnd);
1789 nRowStart = -1;
1791 rInner = nHiddenLast;
1792 continue;
1795 if (nRowStart < 0)
1796 nRowStart = rInner;
1799 if (nRowStart >= 0)
1801 nRowEnd = rInner - 1;
1802 aSpans.emplace_back(nRowStart, nRowEnd);
1805 if (aSpans.empty())
1806 return;
1808 aCol[nCol].DeleteRanges(aSpans, InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING | InsertDeleteFlags::FORMULA | InsertDeleteFlags::OUTLINE);
1809 aCol[nCol].CloneFormulaCell(rSrcCell, sc::CellTextAttr(), aSpans);
1811 const auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(rDocument);
1812 sc::StartListeningContext aStartCxt(rDocument, pSet);
1813 sc::EndListeningContext aEndCxt(rDocument, pSet);
1815 SCROW nStartRow = aSpans.front().mnRow1;
1816 SCROW nEndRow = aSpans.back().mnRow2;
1817 aCol[nCol].EndListeningFormulaCells(aEndCxt, nStartRow, nEndRow, &nStartRow, &nEndRow);
1818 aCol[nCol].StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
1820 for (const auto& rSpan : aSpans)
1821 aCol[nCol].SetDirty(rSpan.mnRow1, rSpan.mnRow2, ScColumn::BROADCAST_NONE);
1823 rProgress += nRow2 - nRow1 + 1;
1824 if (pProgress)
1825 pProgress->SetStateOnPercent(rProgress);
1828 void ScTable::FillSeriesSimple(
1829 const ScCellValue& rSrcCell, SCCOLROW& rInner, SCCOLROW nIMin, SCCOLROW nIMax,
1830 const SCCOLROW& rCol, const SCCOLROW& rRow, bool bVertical, ScProgress* pProgress, sal_uInt64& rProgress )
1832 bool bHidden = false;
1833 SCCOLROW nHiddenLast = -1;
1835 if (bVertical)
1837 switch (rSrcCell.getType())
1839 case CELLTYPE_FORMULA:
1841 FillFormulaVertical(
1842 *rSrcCell.getFormula(), rInner, rCol, nIMin, nIMax, pProgress, rProgress);
1844 break;
1845 default:
1847 for (rInner = nIMin; rInner <= nIMax; ++rInner)
1849 if (rInner > nHiddenLast)
1850 bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1852 if (bHidden)
1854 rInner = nHiddenLast;
1855 continue;
1858 ScAddress aDestPos(rCol, rRow, nTab);
1859 rSrcCell.commit(aCol[rCol], aDestPos.Row());
1861 rProgress += nIMax - nIMin + 1;
1862 if (pProgress)
1863 pProgress->SetStateOnPercent(rProgress);
1867 else
1869 switch (rSrcCell.getType())
1871 case CELLTYPE_FORMULA:
1873 for (rInner = nIMin; rInner <= nIMax; ++rInner)
1875 if (rInner > nHiddenLast)
1876 bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1878 if (bHidden)
1879 continue;
1881 FillFormula(rSrcCell.getFormula(), rCol, rRow, (rInner == nIMax));
1882 if (pProgress)
1883 pProgress->SetStateOnPercent(++rProgress);
1886 break;
1887 default:
1889 for (rInner = nIMin; rInner <= nIMax; ++rInner)
1891 if (rInner > nHiddenLast)
1892 bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1894 if (bHidden)
1895 continue;
1897 ScAddress aDestPos(rCol, rRow, nTab);
1898 rSrcCell.commit(aCol[rCol], aDestPos.Row());
1900 rProgress += nIMax - nIMin + 1;
1901 if (pProgress)
1902 pProgress->SetStateOnPercent(rProgress);
1908 void ScTable::FillAutoSimple(
1909 SCCOLROW nISrcStart, SCCOLROW nISrcEnd, SCCOLROW nIStart, SCCOLROW nIEnd,
1910 SCCOLROW& rInner, const SCCOLROW& rCol, const SCCOLROW& rRow, sal_uInt64 nActFormCnt,
1911 sal_uInt64 nMaxFormCnt, bool bHasFiltered, bool bVertical, bool bPositive,
1912 ScProgress* pProgress, sal_uInt64& rProgress )
1914 SCCOLROW nSource = nISrcStart;
1915 double nDelta;
1916 if ( nScFillModeMouseModifier & KEY_MOD1 )
1917 nDelta = 0.0;
1918 else if ( bPositive )
1919 nDelta = 1.0;
1920 else
1921 nDelta = -1.0;
1922 sal_uInt64 nFormulaCounter = nActFormCnt;
1923 bool bGetCell = true;
1924 bool bBooleanCell = false;
1925 bool bPercentCell = false;
1926 sal_uInt16 nCellDigits = 0;
1927 short nHeadNoneTail = 0;
1928 sal_Int32 nStringValue = 0;
1929 OUString aValue;
1930 ScCellValue aSrcCell;
1931 bool bIsOrdinalSuffix = false;
1933 bool bColHidden = false, bRowHidden = false;
1934 SCCOL nColHiddenFirst = rDocument.MaxCol();
1935 SCCOL nColHiddenLast = -1;
1936 SCROW nRowHiddenFirst = rDocument.MaxRow();
1937 SCROW nRowHiddenLast = -1;
1939 rInner = nIStart;
1940 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1942 if (bPositive)
1944 if (rCol > nColHiddenLast)
1945 bColHidden = ColHidden(rCol, nullptr, &nColHiddenLast);
1946 if (rRow > nRowHiddenLast)
1947 bRowHidden = RowHidden(rRow, nullptr, &nRowHiddenLast);
1949 else
1951 if (rCol < nColHiddenFirst)
1952 bColHidden = ColHidden(rCol, &nColHiddenFirst);
1953 if (rRow < nRowHiddenFirst)
1954 bRowHidden = RowHidden(rRow, &nRowHiddenFirst);
1957 if (!bColHidden && !bRowHidden)
1959 if ( bGetCell )
1961 if (bVertical) // rInner&:=nRow, rOuter&:=nCol
1963 aSrcCell = GetCellValue(rCol, nSource);
1964 if (nISrcStart == nISrcEnd && aSrcCell.getType() == CELLTYPE_FORMULA)
1966 FillFormulaVertical(*aSrcCell.getFormula(), rInner, rCol, nIStart, nIEnd, pProgress, rProgress);
1967 return;
1969 const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(
1970 GetColumnData(rCol).GetNumberFormat( rDocument.GetNonThreadedContext(), nSource));
1971 bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
1972 bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
1975 else // rInner&:=nCol, rOuter&:=nRow
1977 aSrcCell = GetCellValue(nSource, rRow);
1978 const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType(
1979 GetColumnData(nSource).GetNumberFormat( rDocument.GetNonThreadedContext(), rRow));
1980 bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
1981 bPercentCell = (nFormatType == SvNumFormatType::PERCENT);
1984 bGetCell = false;
1985 if (!aSrcCell.isEmpty())
1987 switch (aSrcCell.getType())
1989 case CELLTYPE_STRING:
1990 case CELLTYPE_EDIT:
1991 if (aSrcCell.getType() == CELLTYPE_STRING)
1992 aValue = aSrcCell.getSharedString()->getString();
1993 else
1994 aValue = ScEditUtil::GetString(*aSrcCell.getEditText(), &rDocument);
1995 if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered )
1997 nCellDigits = 0; // look at each source cell individually
1998 nHeadNoneTail = lcl_DecompValueString(
1999 aValue, nStringValue, &nCellDigits );
2001 bIsOrdinalSuffix = aValue ==
2002 ScGlobal::GetOrdinalSuffix(nStringValue);
2004 break;
2005 default:
2007 // added to avoid warnings
2013 switch (aSrcCell.getType())
2015 case CELLTYPE_VALUE:
2017 double fVal;
2018 if (bBooleanCell && ((fVal = aSrcCell.getDouble()) == 0.0 || fVal == 1.0))
2019 aCol[rCol].SetValue(rRow, aSrcCell.getDouble());
2020 else if(bPercentCell)
2021 aCol[rCol].SetValue(rRow, aSrcCell.getDouble() + nDelta * 0.01); // tdf#89998 increment by 1% at a time
2022 else
2023 aCol[rCol].SetValue(rRow, aSrcCell.getDouble() + nDelta);
2025 break;
2026 case CELLTYPE_STRING:
2027 case CELLTYPE_EDIT:
2028 if ( nHeadNoneTail )
2030 sal_Int32 nNextValue;
2031 if (nStringValue < 0)
2032 nNextValue = nStringValue - static_cast<sal_Int32>(nDelta);
2033 else
2034 nNextValue = nStringValue + static_cast<sal_Int32>(nDelta);
2036 if ( nHeadNoneTail < 0 )
2038 setSuffixCell(
2039 aCol[rCol], rRow,
2040 nNextValue, nCellDigits, aValue,
2041 aSrcCell.getType(), bIsOrdinalSuffix);
2043 else
2045 OUString aStr;
2046 if (nHeadNoneTail == 2 && nNextValue >= 0) // Put back the '+'
2047 aStr = aValue + "+" + lcl_ValueString(nNextValue, nCellDigits);
2048 else
2049 aStr = aValue + lcl_ValueString(nNextValue, nCellDigits);
2051 aCol[rCol].SetRawString(rRow, aStr);
2054 else
2055 aSrcCell.commit(aCol[rCol], rRow);
2057 break;
2058 case CELLTYPE_FORMULA :
2059 FillFormula(
2060 aSrcCell.getFormula(), rCol, rRow, (rInner == nIEnd));
2061 if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
2062 nMaxFormCnt = nFormulaCounter - nActFormCnt;
2063 break;
2064 default:
2066 // added to avoid warnings
2070 if (nSource == nISrcEnd)
2072 if ( nSource != nISrcStart )
2073 { // More than one source cell
2074 nSource = nISrcStart;
2075 bGetCell = true;
2077 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
2079 if ( bPositive )
2080 nDelta += 1.0;
2081 else
2082 nDelta -= 1.0;
2084 nFormulaCounter = nActFormCnt;
2086 else if (bPositive)
2088 ++nSource;
2089 bGetCell = true;
2091 else
2093 --nSource;
2094 bGetCell = true;
2098 if (rInner == nIEnd)
2099 break;
2100 if (bPositive)
2101 ++rInner;
2102 else
2103 --rInner;
2105 // Progress in inner loop only for expensive cells,
2106 // and even then not individually for each one
2108 ++rProgress;
2109 if ( pProgress && (aSrcCell.getType() == CELLTYPE_FORMULA || aSrcCell.getType() == CELLTYPE_EDIT) )
2110 pProgress->SetStateOnPercent( rProgress );
2113 if (pProgress)
2114 pProgress->SetStateOnPercent( rProgress );
2117 namespace
2119 // Target value exceeded?
2120 inline bool isOverflow( const double& rVal, const double& rMax, const double& rStep,
2121 const double& rStartVal, FillCmd eFillCmd )
2123 switch (eFillCmd)
2125 case FILL_LINEAR:
2126 case FILL_DATE:
2127 if (rStep >= 0.0)
2128 return rVal > rMax;
2129 else
2130 return rVal < rMax;
2131 case FILL_GROWTH:
2132 if (rStep > 0.0)
2134 if (rStep >= 1.0)
2136 // Growing away from zero, including zero growth (1.0).
2137 if (rVal >= 0.0)
2138 return rVal > rMax;
2139 else
2140 return rVal < rMax;
2142 else
2144 // Shrinking towards zero.
2145 if (rVal >= 0.0)
2146 return rVal < rMax;
2147 else
2148 return rVal > rMax;
2151 else if (rStep < 0.0)
2153 // Alternating positive and negative values.
2154 if (rStep <= -1.0)
2156 // Growing away from zero, including zero growth (-1.0).
2157 if (rVal >= 0.0)
2159 if (rMax >= 0.0)
2160 return rVal > rMax;
2161 else
2162 // Regard negative rMax as lower limit, which will
2163 // be reached only by a negative rVal.
2164 return false;
2166 else
2168 if (rMax <= 0.0)
2169 return rVal < rMax;
2170 else
2171 // Regard positive rMax as upper limit, which will
2172 // be reached only by a positive rVal.
2173 return false;
2176 else
2178 // Shrinking towards zero.
2179 if (rVal >= 0.0)
2180 return rVal < rMax;
2181 else
2182 return rVal > rMax;
2185 else // if (rStep == 0.0)
2187 // All values become zero.
2188 // Corresponds with bEntireArea in FillSeries().
2189 if (rMax > 0.0)
2190 return rMax < rStartVal;
2191 else if (rMax < 0.0)
2192 return rStartVal < rMax;
2194 break;
2195 default:
2196 assert(!"eFillCmd");
2198 return false;
2202 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2203 sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
2204 double nStepValue, const tools::Duration& rDurationStep,
2205 double nMaxValue, sal_uInt16 nArgMinDigits,
2206 bool bAttribs, ScProgress* pProgress,
2207 bool bSkipOverlappedCells, std::vector<sal_Int32>* pNonOverlappedCellIdx )
2209 // The term 'inner' here refers to the loop in the filling direction i.e.
2210 // when filling vertically, the inner position is the row position whereas
2211 // when filling horizontally the column position becomes the inner
2212 // position. The term 'outer' refers to the column position when filling
2213 // vertically, or the row position when filling horizontally. The fill is
2214 // performed once in each 'outer' position e.g. when filling vertically,
2215 // we perform the fill once in each column.
2217 // Detect direction
2219 bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
2220 bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
2222 SCCOLROW nCol = 0;
2223 SCCOLROW nRow = 0;
2224 SCCOLROW& rInner = bVertical ? nRow : nCol; // loop variables
2225 SCCOLROW& rOuter = bVertical ? nCol : nRow;
2226 SCCOLROW nOStart;
2227 SCCOLROW nOEnd;
2228 SCCOLROW nIStart;
2229 SCCOLROW nIEnd;
2230 SCCOLROW nISource;
2231 ScRange aFillRange;
2232 sal_uInt64 nFillerCount;
2233 std::vector<bool> aIsNonEmptyCell;
2235 if (bVertical)
2237 nFillerCount = (nRow2 - nRow1) + 1;
2238 nFillCount += (nRow2 - nRow1);
2239 if (nFillCount == 0)
2240 return;
2241 nOStart = nCol1;
2242 nOEnd = nCol2;
2243 if (bPositive)
2245 // downward fill
2246 nISource = nRow1; // top row of the source range.
2247 nIStart = nRow1 + 1; // first row where we start filling.
2248 nIEnd = nRow1 + nFillCount;
2249 aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab);
2251 else
2253 // upward fill
2254 nISource = nRow2;
2255 nIStart = nRow2 - 1;
2256 nIEnd = nRow2 - nFillCount;
2257 aFillRange = ScRange(nCol1, nRow2 -1, nTab, nCol2, nRow2 - nFillCount, nTab);
2260 else
2262 nFillerCount = (nCol2 - nCol1) + 1;
2263 nFillCount += (nCol2 - nCol1);
2264 if (nFillCount == 0)
2265 return;
2266 nOStart = nRow1;
2267 nOEnd = nRow2;
2268 if (bPositive)
2270 // to the right
2271 nISource = nCol1;
2272 nIStart = nCol1 + 1;
2273 nIEnd = nCol1 + nFillCount;
2274 aFillRange = ScRange(nCol1 + 1, nRow1, nTab, nCol1 + nFillCount, nRow2, nTab);
2276 else
2278 // to the left
2279 nISource = nCol2;
2280 nIStart = nCol2 - 1;
2281 nIEnd = nCol2 - nFillCount;
2282 aFillRange = ScRange(nCol2 - 1, nRow1, nTab, nCol2 - nFillCount, nRow2, nTab);
2286 SCCOLROW nIMin = nIStart;
2287 SCCOLROW nIMax = nIEnd;
2288 PutInOrder(nIMin,nIMax);
2290 const bool bIsFiltered = IsDataFiltered(aFillRange);
2291 bool bEntireArea = (!bIsFiltered && eFillCmd == FILL_SIMPLE);
2292 if (!bIsFiltered && !bEntireArea && (eFillCmd == FILL_LINEAR || eFillCmd == FILL_GROWTH)
2293 && (nOEnd - nOStart == 0))
2295 // For the usual case of one col/row determine if a numeric series is
2296 // at least as long as the area to be filled and does not end earlier,
2297 // so we can treat it as entire area for performance reasons at least
2298 // in the vertical case.
2299 // This is not exact in case of merged cell fills with skipping overlapped parts, but
2300 // it is still a good upper estimation.
2301 ScCellValue aSrcCell;
2302 if (bVertical)
2303 aSrcCell = GetCellValue(static_cast<SCCOL>(nOStart), static_cast<SCROW>(nISource));
2304 else
2305 aSrcCell = GetCellValue(static_cast<SCCOL>(nISource), static_cast<SCROW>(nOStart));
2306 // Same logic as for the actual series.
2307 if (!aSrcCell.isEmpty() && (aSrcCell.getType() == CELLTYPE_VALUE || aSrcCell.getType() == CELLTYPE_FORMULA))
2309 double nStartVal;
2310 if (aSrcCell.getType() == CELLTYPE_VALUE)
2311 nStartVal = aSrcCell.getDouble();
2312 else
2313 nStartVal = aSrcCell.getFormula()->GetValue();
2314 if (eFillCmd == FILL_LINEAR)
2316 if (nStepValue == 0.0)
2317 bEntireArea = (nStartVal <= nMaxValue); // fill with same value
2318 else if (((nMaxValue - nStartVal) / nStepValue) >= nFillCount)
2319 bEntireArea = true;
2321 else if (eFillCmd == FILL_GROWTH)
2323 if (nStepValue == 1.0)
2324 bEntireArea = (nStartVal <= nMaxValue); // fill with same value
2325 else if (nStepValue == -1.0)
2326 bEntireArea = (fabs(nStartVal) <= fabs(nMaxValue)); // fill with alternating value
2327 else if (nStepValue == 0.0)
2328 bEntireArea = (nStartVal == 0.0
2329 || (nStartVal < 0.0 && nMaxValue >= 0.0)
2330 || (nStartVal > 0.0 && nMaxValue <= 0.0)); // fill with 0.0
2334 if (bEntireArea)
2336 InsertDeleteFlags nDel = (bAttribs ? InsertDeleteFlags::AUTOFILL :
2337 (InsertDeleteFlags::AUTOFILL & InsertDeleteFlags::CONTENTS));
2338 if (bVertical)
2339 DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
2340 else
2341 DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
2344 sal_uInt64 nProgress = 0;
2345 if (pProgress)
2346 nProgress = pProgress->GetState();
2348 // Perform the fill once per each 'outer' position i.e. one per column
2349 // when filling vertically.
2351 for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
2353 rInner = nISource;
2355 CreateColumnIfNotExists(nCol);
2357 // Source cell value. We need to clone the value since it may be inserted repeatedly.
2358 ScCellValue aSrcCell = GetCellValue(nCol, static_cast<SCROW>(nRow));
2360 // Maybe another source cell need to be searched, if the fill is going through merged cells,
2361 // where overlapped parts does not contain any information, so they can be skipped.
2362 if (bSkipOverlappedCells)
2364 // create a vector to make it easier to decide if a cell need to be filled, or skipped.
2365 aIsNonEmptyCell.resize(nFillerCount, false);
2367 SCCOLROW nFirstValueIdx;
2368 if (bPositive)
2370 nFirstValueIdx = nISource + (*pNonOverlappedCellIdx)[0];
2371 for (auto i : (*pNonOverlappedCellIdx))
2372 aIsNonEmptyCell[i] = true;
2374 else
2376 nFirstValueIdx = nISource - (nFillerCount - 1 - (*pNonOverlappedCellIdx).back());
2377 for (auto i : (*pNonOverlappedCellIdx))
2378 aIsNonEmptyCell[nFillerCount - 1 - i] = true;
2381 //Set the real source cell
2382 if (bVertical)
2383 aSrcCell = GetCellValue(nOStart, static_cast<SCROW>(nFirstValueIdx));
2384 else
2385 aSrcCell = GetCellValue(nFirstValueIdx, static_cast<SCROW>(nOStart));
2388 const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
2389 const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
2390 const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
2392 if (bAttribs)
2394 if (bVertical)
2396 // If entire area (not filtered and simple fill) use the faster
2397 // method, else hidden cols/rows should be skipped and series
2398 // fill needs to determine the end row dynamically.
2399 if (bEntireArea)
2401 SetPatternAreaCondFormat( nCol, static_cast<SCROW>(nIMin),
2402 static_cast<SCROW>(nIMax), *pSrcPattern, rCondFormatIndex);
2404 else if (eFillCmd == FILL_SIMPLE)
2406 assert(bIsFiltered);
2407 for(SCROW nAtRow = static_cast<SCROW>(nIMin); nAtRow <= static_cast<SCROW>(nIMax); ++nAtRow)
2409 if(!RowHidden(nAtRow))
2411 SetPatternAreaCondFormat( nCol, nAtRow, nAtRow, *pSrcPattern, rCondFormatIndex);
2417 else if (bEntireArea || eFillCmd == FILL_SIMPLE)
2419 for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
2421 if(!ColHidden(nAtCol))
2423 SetPatternAreaCondFormat( nAtCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
2429 if (!aSrcCell.isEmpty())
2431 CellType eCellType = aSrcCell.getType();
2433 if (eFillCmd == FILL_SIMPLE) // copy
2435 FillSeriesSimple(aSrcCell, rInner, nIMin, nIMax, nCol, nRow, bVertical, pProgress, nProgress);
2437 else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
2439 const double nStartVal = (eCellType == CELLTYPE_VALUE ? aSrcCell.getDouble() :
2440 aSrcCell.getFormula()->GetValue());
2441 double nVal = nStartVal;
2442 tools::Long nIndex = 0;
2444 bool bError = false;
2445 bool bOverflow = false;
2446 bool bNonEmpty = true;
2448 sal_uInt16 nDayOfMonth = 0;
2449 sal_Int32 nFillerIdx = 0;
2450 if (bSkipOverlappedCells && !aIsNonEmptyCell[0])
2451 --nIndex;
2452 rInner = nIStart;
2453 while (true)
2455 if (bSkipOverlappedCells)
2457 nFillerIdx = (nFillerIdx + 1) % nFillerCount;
2458 bNonEmpty = aIsNonEmptyCell[nFillerIdx];
2461 if(!ColHidden(nCol) && !RowHidden(nRow))
2463 if (!bError && bNonEmpty)
2465 switch (eFillCmd)
2467 case FILL_LINEAR:
2469 // use multiplication instead of repeated addition
2470 // to avoid accumulating rounding errors
2471 nVal = nStartVal;
2472 if (rDurationStep)
2474 tools::Duration aDuration( rDurationStep.Mult( ++nIndex, bError));
2475 bError |= !SubTotal::SafePlus( nVal, aDuration.GetInDays());
2477 else
2479 double nAdd = nStepValue;
2480 if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
2481 !SubTotal::SafePlus( nVal, nAdd ) )
2482 bError = true;
2485 break;
2486 case FILL_GROWTH:
2487 if (!SubTotal::SafeMult(nVal, nStepValue))
2488 bError = true;
2489 break;
2490 case FILL_DATE:
2491 if (fabs(nVal) > D_MAX_LONG_)
2492 bError = true;
2493 else
2494 IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
2495 break;
2496 default:
2498 // added to avoid warnings
2502 if (!bError)
2503 bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
2506 CreateColumnIfNotExists(nCol);
2507 if (bError)
2508 aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
2509 else if (!bOverflow && bNonEmpty)
2510 aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
2512 if (bAttribs && !bEntireArea && !bOverflow)
2513 SetPatternAreaCondFormat( nCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
2516 if (rInner == nIEnd || bOverflow)
2517 break;
2518 if (bPositive)
2520 ++rInner;
2522 else
2524 --rInner;
2527 nProgress += nIMax - nIMin + 1;
2528 if(pProgress)
2529 pProgress->SetStateOnPercent( nProgress );
2531 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
2533 if ( nStepValue >= 0 )
2535 if ( nMaxValue >= double(LONG_MAX) )
2536 nMaxValue = double(LONG_MAX) - 1;
2538 else
2540 if ( nMaxValue <= double(LONG_MIN) )
2541 nMaxValue = double(LONG_MIN) + 1;
2543 OUString aValue;
2544 if (eCellType == CELLTYPE_STRING)
2545 aValue = aSrcCell.getSharedString()->getString();
2546 else
2547 aValue = ScEditUtil::GetString(*aSrcCell.getEditText(), &rDocument);
2548 sal_Int32 nStringValue;
2549 sal_uInt16 nMinDigits = nArgMinDigits;
2550 short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
2551 if ( nHeadNoneTail )
2553 const double nStartVal = static_cast<double>(nStringValue);
2554 double nVal = nStartVal;
2555 tools::Long nIndex = 0;
2556 bool bError = false;
2557 bool bOverflow = false;
2558 bool bNonEmpty = true;
2560 bool bIsOrdinalSuffix = aValue == ScGlobal::GetOrdinalSuffix(
2561 static_cast<sal_Int32>(nStartVal));
2563 sal_Int32 nFillerIdx = 0;
2564 if (bSkipOverlappedCells && !aIsNonEmptyCell[0])
2565 --nIndex;
2566 rInner = nIStart;
2567 while (true)
2569 if (bSkipOverlappedCells)
2571 nFillerIdx = (nFillerIdx + 1) % nFillerCount;
2572 bNonEmpty = aIsNonEmptyCell[nFillerIdx];
2574 if(!ColHidden(nCol) && !RowHidden(nRow))
2576 if (!bError && bNonEmpty)
2578 switch (eFillCmd)
2580 case FILL_LINEAR:
2582 // use multiplication instead of repeated addition
2583 // to avoid accumulating rounding errors
2584 nVal = nStartVal;
2585 if (rDurationStep)
2587 tools::Duration aDuration( rDurationStep.Mult( ++nIndex, bError));
2588 bError |= !SubTotal::SafePlus( nVal, aDuration.GetInDays());
2590 else
2592 double nAdd = nStepValue;
2593 if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
2594 !SubTotal::SafePlus( nVal, nAdd ) )
2595 bError = true;
2598 break;
2599 case FILL_GROWTH:
2600 if (!SubTotal::SafeMult(nVal, nStepValue))
2601 bError = true;
2602 break;
2603 default:
2605 // added to avoid warnings
2609 if (!bError)
2610 bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
2613 if (bError)
2614 aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
2615 else if (!bOverflow && bNonEmpty)
2617 nStringValue = static_cast<sal_Int32>(nVal);
2618 if ( nHeadNoneTail < 0 )
2620 setSuffixCell(
2621 aCol[nCol], static_cast<SCROW>(nRow),
2622 nStringValue, nMinDigits, aValue,
2623 eCellType, bIsOrdinalSuffix);
2625 else
2627 OUString aStr;
2628 if (nHeadNoneTail == 2 && nStringValue >= 0) // Put back the '+'
2629 aStr = aValue + "+";
2630 else
2631 aStr = aValue;
2632 aStr += lcl_ValueString( nStringValue, nMinDigits );
2633 aCol[nCol].SetRawString(static_cast<SCROW>(nRow), aStr);
2637 if (bAttribs && !bEntireArea && !bOverflow)
2638 SetPatternAreaCondFormat( nCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
2641 if (rInner == nIEnd || bOverflow)
2642 break;
2643 if (bPositive)
2644 ++rInner;
2645 else
2646 --rInner;
2649 if(pProgress)
2651 nProgress += nIMax - nIMin + 1;
2652 pProgress->SetStateOnPercent( nProgress );
2656 else if(pProgress)
2658 nProgress += nIMax - nIMin + 1;
2659 pProgress->SetStateOnPercent( nProgress );
2664 void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2665 sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
2666 double nStepValue, const tools::Duration& rDurationStep,
2667 double nMaxValue, ScProgress* pProgress)
2669 if (eFillCmd == FILL_AUTO)
2670 FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, pProgress);
2671 else
2672 FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
2673 eFillCmd, eFillDateCmd, nStepValue, rDurationStep, nMaxValue, 0, true, pProgress);
2676 void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2677 const ScPatternAttr& rAttr, sal_uInt16 nFormatNo)
2679 ScAutoFormat& rFormat = *ScGlobal::GetOrCreateAutoFormat();
2680 ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
2681 if (pData)
2683 ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
2687 void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2688 sal_uInt16 nFormatNo, ScProgress* pProgress )
2690 if (!(ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow)))
2691 return;
2693 ScAutoFormat& rFormat = *ScGlobal::GetOrCreateAutoFormat();
2694 ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
2695 if (!pData)
2696 return;
2698 std::unique_ptr<ScPatternAttr> pPatternAttrs[16];
2699 for (sal_uInt8 i = 0; i < 16; ++i)
2701 pPatternAttrs[i].reset(new ScPatternAttr(rDocument.getCellAttributeHelper()));
2702 pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), rDocument);
2705 // Important special case: when the whole rows are selected. Then applying autoformat to right
2706 // column individually would create all columns. In this case, assume that right column isn't
2707 // needed, to allow "to the end of row" format optimization (which doesn't create columns).
2708 // Keep left column in this case, because it may be pre-formatted for categories. To enable the
2709 // optimization, apply uniform format row by row where possible, not column by column.
2711 const bool isWholeRows = nStartCol == 0 && nEndCol == rDocument.MaxCol();
2713 ////////////////////////////////////////////////////////////////////////////////////////////////
2714 // Top row data indexes:
2715 // 0 - left corner style
2716 // 1 - odd columns style
2717 // 2 - even column style
2718 // 3 - right corner style
2719 ////////////////////////////////////////////////////////////////////////////////////////////////
2721 SCCOL startOffset = 1;
2722 // Left top corner
2723 if (pData->HasSameData(0, 1) && pData->HasSameData(0, 2))
2724 startOffset = 0; // Left corner is same as the rest of the row
2725 else
2726 AutoFormatArea(nStartCol, nStartRow, nStartCol, nStartRow, *pPatternAttrs[0], nFormatNo);
2728 SCCOL endOffset = 1;
2729 // Right top corner: ignore when whole rows selected
2730 if (isWholeRows || (pData->HasSameData(3, 1) && pData->HasSameData(3, 2)))
2731 endOffset = 0; // Right corner is same as the rest of the row (most important case)
2732 else
2733 AutoFormatArea(nEndCol, nStartRow, nEndCol, nStartRow, *pPatternAttrs[3], nFormatNo);
2735 // Top row
2736 if (pData->HasSameData(1, 2))
2737 AutoFormatArea(nStartCol + startOffset, nStartRow, nEndCol - endOffset, nStartRow, *pPatternAttrs[1], nFormatNo);
2738 else
2740 sal_uInt16 nIndex = 1;
2741 for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - endOffset; nCol++)
2743 AutoFormatArea(nCol, nStartRow, nCol, nStartRow, *pPatternAttrs[nIndex], nFormatNo);
2744 if (nIndex == 1)
2745 nIndex = 2;
2746 else
2747 nIndex = 1;
2751 ////////////////////////////////////////////////////////////////////////////////////////////////
2752 // Body data indexes:
2753 // 4 - left column odd row style
2754 // 8 - left column even row style
2755 // 7 - right column odd row style
2756 // 11 - right column even row style
2757 // 5 - body odd column odd row style
2758 // 6 - body even column odd row style
2759 // 9 - body odd column even row style
2760 // 10 - body even column even row style
2761 ////////////////////////////////////////////////////////////////////////////////////////////////
2763 startOffset = 1;
2764 // Left column
2765 if (pData->HasSameData(4, 5) && pData->HasSameData(4, 6) && pData->HasSameData(8, 9) && pData->HasSameData(8, 10))
2766 startOffset = 0; // Left column is same as the lines of the body
2767 else
2769 if (pData->HasSameData(4, 8)) // even and odd rows are same
2770 AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
2771 else
2773 sal_uInt16 nIndex = 4;
2774 for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2776 AutoFormatArea(nStartCol, nRow, nStartCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2777 if (nIndex == 4)
2778 nIndex = 8;
2779 else
2780 nIndex = 4;
2785 endOffset = 1;
2786 // Right column: ignore when whole rows selected
2787 if (isWholeRows || (pData->HasSameData(7, 5) && pData->HasSameData(7, 6) && pData->HasSameData(11, 9) && pData->HasSameData(11, 10)))
2788 endOffset = 0; // Right column is same as the lines of the body (most important case)
2789 else
2791 if (pData->HasSameData(7, 11)) // even and odd rows are same
2792 AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
2793 else
2795 sal_uInt16 nIndex = 7;
2796 for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2798 AutoFormatArea(nEndCol, nRow, nEndCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2799 if (nIndex == 7)
2800 nIndex = 11;
2801 else
2802 nIndex = 7;
2807 // Body
2808 if (pData->HasSameData(5, 6) && pData->HasSameData(9, 10)) // Odd and even columns are same (most important case)
2810 if (pData->HasSameData(5, 9)) // Everything is the same
2811 AutoFormatArea(nStartCol + startOffset, nStartRow + 1, nEndCol - endOffset, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
2812 else // Odd and even rows differ
2814 if (pProgress)
2815 pProgress->SetState(1, nEndRow - nStartRow + 3); // account for elements outside the "Body" block
2816 sal_uInt16 nIndex = 5;
2817 for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2819 AutoFormatArea(nStartCol + startOffset, nRow, nEndCol - endOffset, nRow, *pPatternAttrs[nIndex], nFormatNo);
2820 if (nIndex == 5)
2821 nIndex = 9;
2822 else
2823 nIndex = 5;
2824 if (pProgress)
2825 pProgress->SetStateOnPercent(nRow - nStartRow + 1);
2829 else if (pData->HasSameData(5, 9) && pData->HasSameData(6, 10)) // odd and even rows are same
2831 if (pProgress)
2832 pProgress->SetState(1, nEndCol - nStartCol + 3); // account for elements outside the "Body" block
2833 sal_uInt16 nIndex = 5;
2834 for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - endOffset; nCol++)
2836 AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, *pPatternAttrs[nIndex], nFormatNo);
2837 if (nIndex == 5)
2838 nIndex = 6;
2839 else
2840 nIndex = 5;
2841 if (pProgress)
2842 pProgress->SetStateOnPercent(nCol - nStartCol + 1);
2845 else // Everything is different
2847 if (pProgress)
2848 pProgress->SetState(1, nEndCol - nStartCol + 3); // account for elements outside the "Body" block
2849 sal_uInt16 nIndex = 5;
2850 for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - endOffset; nCol++)
2852 for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
2854 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
2855 if ((nIndex == 5) || (nIndex == 9))
2857 if (nIndex == 5)
2858 nIndex = 9;
2859 else
2860 nIndex = 5;
2862 else
2864 if (nIndex == 6)
2865 nIndex = 10;
2866 else
2867 nIndex = 6;
2869 } // for nRow
2870 if ((nIndex == 5) || (nIndex == 9))
2871 nIndex = 6;
2872 else
2873 nIndex = 5;
2874 if (pProgress)
2875 pProgress->SetStateOnPercent(nCol - nStartCol + 1);
2877 } // for nCol
2878 } // if not all equal
2880 ////////////////////////////////////////////////////////////////////////////////////////////////
2881 // Bottom row data indexes:
2882 // 12 - left corner style
2883 // 13 - odd columns style
2884 // 14 - even column style
2885 // 15 - right corner style
2886 ////////////////////////////////////////////////////////////////////////////////////////////////
2888 startOffset = 1;
2889 // Left bottom corner
2890 if (pData->HasSameData(12, 13) && pData->HasSameData(12, 14))
2891 startOffset = 0;
2892 else
2893 AutoFormatArea(nStartCol, nEndRow, nStartCol, nEndRow, *pPatternAttrs[12], nFormatNo);
2895 endOffset = 1;
2896 // Right bottom corner: ignore when whole rows selected
2897 if (isWholeRows || (pData->HasSameData(15, 13) && pData->HasSameData(15, 14)))
2898 endOffset = 0;
2899 else
2900 AutoFormatArea(nEndCol, nEndRow, nEndCol, nEndRow, *pPatternAttrs[15], nFormatNo);
2902 // Bottom row
2903 if (pData->HasSameData(13, 14))
2904 AutoFormatArea(nStartCol + startOffset, nEndRow, nEndCol - endOffset, nEndRow, *pPatternAttrs[13], nFormatNo);
2905 else
2907 sal_uInt16 nIndex = 13;
2908 for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - endOffset; nCol++)
2910 AutoFormatArea(nCol, nEndRow, nCol, nEndRow, *pPatternAttrs[nIndex], nFormatNo);
2911 if (nIndex == 13)
2912 nIndex = 14;
2913 else
2914 nIndex = 13;
2919 void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, ScAutoFormatData& rData)
2921 sal_uInt32 nFormatIndex = GetNumberFormat( nCol, nRow );
2922 ScNumFormatAbbrev aNumFormat( nFormatIndex, *rDocument.GetFormatTable() );
2923 rData.GetFromItemSet( nIndex, GetPattern( nCol, nRow )->GetItemSet(), aNumFormat );
2926 #define LF_LEFT 1
2927 #define LF_TOP 2
2928 #define LF_RIGHT 4
2929 #define LF_BOTTOM 8
2930 #define LF_ALL (LF_LEFT | LF_TOP | LF_RIGHT | LF_BOTTOM)
2932 void ScTable::GetAutoFormatFrame(SCCOL nCol, SCROW nRow, sal_uInt16 nFlags, sal_uInt16 nIndex, ScAutoFormatData& rData)
2934 const SvxBoxItem* pTheBox = GetAttr(nCol, nRow, ATTR_BORDER);
2935 const SvxBoxItem* pLeftBox = GetAttr(nCol - 1, nRow, ATTR_BORDER);
2936 const SvxBoxItem* pTopBox = GetAttr(nCol, nRow - 1, ATTR_BORDER);
2937 const SvxBoxItem* pRightBox = GetAttr(nCol + 1, nRow, ATTR_BORDER);
2938 const SvxBoxItem* pBottomBox = GetAttr(nCol, nRow + 1, ATTR_BORDER);
2940 SvxBoxItem aBox( ATTR_BORDER );
2941 if (nFlags & LF_LEFT)
2943 if (pLeftBox)
2945 if (ScHasPriority(pTheBox->GetLeft(), pLeftBox->GetRight()))
2946 aBox.SetLine(pTheBox->GetLeft(), SvxBoxItemLine::LEFT);
2947 else
2948 aBox.SetLine(pLeftBox->GetRight(), SvxBoxItemLine::LEFT);
2950 else
2951 aBox.SetLine(pTheBox->GetLeft(), SvxBoxItemLine::LEFT);
2953 if (nFlags & LF_TOP)
2955 if (pTopBox)
2957 if (ScHasPriority(pTheBox->GetTop(), pTopBox->GetBottom()))
2958 aBox.SetLine(pTheBox->GetTop(), SvxBoxItemLine::TOP);
2959 else
2960 aBox.SetLine(pTopBox->GetBottom(), SvxBoxItemLine::TOP);
2962 else
2963 aBox.SetLine(pTheBox->GetTop(), SvxBoxItemLine::TOP);
2965 if (nFlags & LF_RIGHT)
2967 if (pRightBox)
2969 if (ScHasPriority(pTheBox->GetRight(), pRightBox->GetLeft()))
2970 aBox.SetLine(pTheBox->GetRight(), SvxBoxItemLine::RIGHT);
2971 else
2972 aBox.SetLine(pRightBox->GetLeft(), SvxBoxItemLine::RIGHT);
2974 else
2975 aBox.SetLine(pTheBox->GetRight(), SvxBoxItemLine::RIGHT);
2977 if (nFlags & LF_BOTTOM)
2979 if (pBottomBox)
2981 if (ScHasPriority(pTheBox->GetBottom(), pBottomBox->GetTop()))
2982 aBox.SetLine(pTheBox->GetBottom(), SvxBoxItemLine::BOTTOM);
2983 else
2984 aBox.SetLine(pBottomBox->GetTop(), SvxBoxItemLine::BOTTOM);
2986 else
2987 aBox.SetLine(pTheBox->GetBottom(), SvxBoxItemLine::BOTTOM);
2989 rData.PutItem( nIndex, aBox );
2992 void ScTable::GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData& rData)
2994 if (!(ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow)))
2995 return;
2997 if ((nEndCol - nStartCol < 3) || (nEndRow - nStartRow < 3))
2998 return;
3000 // Left top corner
3001 GetAutoFormatAttr(nStartCol, nStartRow, 0, rData);
3002 GetAutoFormatFrame(nStartCol, nStartRow, LF_ALL, 0, rData);
3003 // Left column
3004 GetAutoFormatAttr(nStartCol, nStartRow + 1, 4, rData);
3005 GetAutoFormatAttr(nStartCol, nStartRow + 2, 8, rData);
3006 GetAutoFormatFrame(nStartCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 4, rData);
3007 if (nEndRow - nStartRow >= 4)
3008 GetAutoFormatFrame(nStartCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 8, rData);
3009 else
3010 rData.CopyItem( 8, 4, ATTR_BORDER );
3011 // Left bottom corner
3012 GetAutoFormatAttr(nStartCol, nEndRow, 12, rData);
3013 GetAutoFormatFrame(nStartCol, nEndRow, LF_ALL, 12, rData);
3014 // Right top corner
3015 GetAutoFormatAttr(nEndCol, nStartRow, 3, rData);
3016 GetAutoFormatFrame(nEndCol, nStartRow, LF_ALL, 3, rData);
3017 // Right column
3018 GetAutoFormatAttr(nEndCol, nStartRow + 1, 7, rData);
3019 GetAutoFormatAttr(nEndCol, nStartRow + 2, 11, rData);
3020 GetAutoFormatFrame(nEndCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 7, rData);
3021 if (nEndRow - nStartRow >= 4)
3022 GetAutoFormatFrame(nEndCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 11, rData);
3023 else
3024 rData.CopyItem( 11, 7, ATTR_BORDER );
3025 // Right bottom corner
3026 GetAutoFormatAttr(nEndCol, nEndRow, 15, rData);
3027 GetAutoFormatFrame(nEndCol, nEndRow, LF_ALL, 15, rData);
3028 // Top row
3029 GetAutoFormatAttr(nStartCol + 1, nStartRow, 1, rData);
3030 GetAutoFormatAttr(nStartCol + 2, nStartRow, 2, rData);
3031 GetAutoFormatFrame(nStartCol + 1, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 1, rData);
3032 if (nEndCol - nStartCol >= 4)
3033 GetAutoFormatFrame(nStartCol + 2, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 2, rData);
3034 else
3035 rData.CopyItem( 2, 1, ATTR_BORDER );
3036 // Bottom row
3037 GetAutoFormatAttr(nStartCol + 1, nEndRow, 13, rData);
3038 GetAutoFormatAttr(nStartCol + 2, nEndRow, 14, rData);
3039 GetAutoFormatFrame(nStartCol + 1, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 13, rData);
3040 if (nEndCol - nStartCol >= 4)
3041 GetAutoFormatFrame(nStartCol + 2, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 14, rData);
3042 else
3043 rData.CopyItem( 14, 13, ATTR_BORDER );
3044 // Body
3045 GetAutoFormatAttr(nStartCol + 1, nStartRow + 1, 5, rData);
3046 GetAutoFormatAttr(nStartCol + 2, nStartRow + 1, 6, rData);
3047 GetAutoFormatAttr(nStartCol + 1, nStartRow + 2, 9, rData);
3048 GetAutoFormatAttr(nStartCol + 2, nStartRow + 2, 10, rData);
3049 GetAutoFormatFrame(nStartCol + 1, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 5, rData);
3050 if ((nEndCol - nStartCol >= 4) && (nEndRow - nStartRow >= 4))
3052 GetAutoFormatFrame(nStartCol + 2, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 6, rData);
3053 GetAutoFormatFrame(nStartCol + 1, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 9, rData);
3054 GetAutoFormatFrame(nStartCol + 2, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 10, rData);
3056 else
3058 rData.CopyItem( 6, 5, ATTR_BORDER );
3059 rData.CopyItem( 9, 5, ATTR_BORDER );
3060 rData.CopyItem( 10, 5, ATTR_BORDER );
3064 void ScTable::SetError( SCCOL nCol, SCROW nRow, FormulaError nError)
3066 if (ValidColRow(nCol, nRow))
3067 CreateColumnIfNotExists(nCol).SetError(nRow, nError);
3070 void ScTable::UpdateInsertTabAbs(SCTAB nTable)
3072 for (SCCOL i=0; i < aCol.size(); i++)
3073 aCol[i].UpdateInsertTabAbs(nTable);
3076 bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, bool bInSel,
3077 const ScMarkData& rMark) const
3079 if (rRow == rDocument.MaxRow()+2) // end of table
3081 rRow = 0;
3082 rCol = 0;
3084 else
3086 rRow++;
3087 if (rRow == rDocument.MaxRow()+1)
3089 rCol++;
3090 rRow = 0;
3093 if (rCol == rDocument.MaxCol()+1)
3094 return true;
3095 for (;;)
3097 if (!ValidCol(rCol))
3098 return true;
3099 if (rCol >= GetAllocatedColumnsCount())
3100 return true;
3101 if (aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark))
3102 return true;
3103 /*else (rRow == rDocument.MaxRow()+1) */
3104 rCol++;
3105 rRow = 0;
3109 void ScTable::TestTabRefAbs(SCTAB nTable) const
3111 for (SCCOL i=0; i < aCol.size(); i++)
3112 if (aCol[i].TestTabRefAbs(nTable))
3113 return;
3116 void ScTable::CompileDBFormula( sc::CompileFormulaContext& rCxt )
3118 for (SCCOL i = 0; i < aCol.size(); ++i)
3119 aCol[i].CompileDBFormula(rCxt);
3122 void ScTable::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
3124 for (SCCOL i = 0; i < aCol.size(); ++i)
3125 aCol[i].CompileColRowNameFormula(rCxt);
3128 SCSIZE ScTable::GetPatternCount( SCCOL nCol ) const
3130 if( ValidCol( nCol ) )
3131 return aCol[nCol].GetPatternCount();
3132 else
3133 return 0;
3136 SCSIZE ScTable::GetPatternCount( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
3138 if( ValidCol( nCol ) && ValidRow( nRow1 ) && ValidRow( nRow2 ) )
3139 return aCol[nCol].GetPatternCount( nRow1, nRow2 );
3140 else
3141 return 0;
3144 bool ScTable::ReservePatternCount( SCCOL nCol, SCSIZE nReserve )
3146 if( ValidCol( nCol ) )
3147 return aCol[nCol].ReservePatternCount( nReserve );
3148 else
3149 return false;
3152 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */