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