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