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