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 <column.hxx> 21 22 #include <scitems.hxx> 23 #include <formulacell.hxx> 24 #include <document.hxx> 25 #include <attarray.hxx> 26 #include <patattr.hxx> 27 #include <cellform.hxx> 28 #include <typedstrdata.hxx> 29 #include <formula/errorcodes.hxx> 30 #include <formula/token.hxx> 31 #include <brdcst.hxx> 32 #include <docoptio.hxx> 33 #include <subtotal.hxx> 34 #include <markdata.hxx> 35 #include <stringutil.hxx> 36 #include <docpool.hxx> 37 #include <cellvalue.hxx> 38 #include <tokenarray.hxx> 39 #include <clipcontext.hxx> 40 #include <columnspanset.hxx> 41 #include <mtvcellfunc.hxx> 42 #include <scopetools.hxx> 43 #include <editutil.hxx> 44 #include <sharedformula.hxx> 45 #include <listenercontext.hxx> 46 #include <filterentries.hxx> 47 48 #include <com/sun/star/i18n/LocaleDataItem2.hpp> 49 #include <com/sun/star/lang/IllegalArgumentException.hpp> 50 51 #include <memory> 52 53 #include <rtl/tencinfo.h> 54 55 #include <svl/zforlist.hxx> 56 #include <svl/zformat.hxx> 57 #include <svl/sharedstringpool.hxx> 58 59 #include <cstdio> 60 #include <refdata.hxx> 61 62 using ::com::sun::star::i18n::LocaleDataItem2; 63 64 using namespace formula; 65 66 void ScColumn::Broadcast( SCROW nRow ) 67 { 68 ScHint aHint(SfxHintId::ScDataChanged, ScAddress(nCol, nRow, nTab)); 69 GetDoc()->Broadcast(aHint); 70 } 71 72 void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, SfxHintId nHint ) 73 { 74 if (rRows.empty()) 75 return; 76 77 // Broadcast the changes. 78 ScDocument* pDocument = GetDoc(); 79 ScHint aHint(nHint, ScAddress(nCol, 0, nTab)); 80 for (const auto& rRow : rRows) 81 { 82 aHint.GetAddress().SetRow(rRow); 83 pDocument->Broadcast(aHint); 84 } 85 } 86 87 void ScColumn::BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint ) 88 { 89 sc::SingleColumnSpanSet aSpanSet; 90 aSpanSet.scan(*this, nStartRow, nEndRow); 91 std::vector<SCROW> aRows; 92 aSpanSet.getRows(aRows); 93 BroadcastCells(aRows, nHint); 94 } 95 96 namespace { 97 98 struct DirtyCellInterpreter 99 { 100 void operator() (size_t, ScFormulaCell* p) 101 { 102 if (p->GetDirty()) 103 p->Interpret(); 104 } 105 }; 106 107 } 108 109 void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 ) 110 { 111 if (!GetDoc()->ValidRow(nRow1) || !GetDoc()->ValidRow(nRow2) || nRow1 > nRow2) 112 return; 113 114 DirtyCellInterpreter aFunc; 115 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc); 116 } 117 118 void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast ) 119 { 120 sc::CellStoreType::position_type aPos = maCells.position(nRow); 121 sc::CellStoreType::iterator it = aPos.first; 122 if (it == maCells.end()) 123 return; 124 125 if (it->type == sc::element_type_formula) 126 { 127 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second); 128 p->EndListeningTo(GetDoc()); 129 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *p); 130 } 131 maCells.set_empty(nRow, nRow); 132 133 if (bBroadcast) 134 { 135 Broadcast(nRow); 136 CellStorageModified(); 137 } 138 } 139 140 void ScColumn::Delete( SCROW nRow ) 141 { 142 DeleteContent(nRow, false); 143 maCellTextAttrs.set_empty(nRow, nRow); 144 maCellNotes.set_empty(nRow, nRow); 145 146 Broadcast(nRow); 147 CellStorageModified(); 148 } 149 150 void ScColumn::FreeAll() 151 { 152 // Keep a logical empty range of 0-rDoc.MaxRow() at all times. 153 maCells.clear(); 154 maCells.resize(MAXROWCOUNT); 155 maCellTextAttrs.clear(); 156 maCellTextAttrs.resize(MAXROWCOUNT); 157 maCellNotes.clear(); 158 maCellNotes.resize(MAXROWCOUNT); 159 CellStorageModified(); 160 } 161 162 void ScColumn::FreeNotes() 163 { 164 maCellNotes.clear(); 165 maCellNotes.resize(MAXROWCOUNT); 166 } 167 168 namespace { 169 170 class ShiftFormulaPosHandler 171 { 172 public: 173 174 void operator() (size_t nRow, ScFormulaCell* pCell) 175 { 176 pCell->aPos.SetRow(nRow); 177 } 178 }; 179 180 } 181 182 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>* pGroupPos ) 183 { 184 pAttrArray->DeleteRow( nStartRow, nSize ); 185 186 SCROW nEndRow = nStartRow + nSize - 1; 187 188 maBroadcasters.erase(nStartRow, nEndRow); 189 maBroadcasters.resize(MAXROWCOUNT); 190 191 CellNotesDeleting(nStartRow, nEndRow, false); 192 maCellNotes.erase(nStartRow, nEndRow); 193 maCellNotes.resize(MAXROWCOUNT); 194 195 // See if we have any cells that would get deleted or shifted by deletion. 196 sc::CellStoreType::position_type aPos = maCells.position(nStartRow); 197 sc::CellStoreType::iterator itCell = aPos.first; 198 if (itCell->type == sc::element_type_empty) 199 { 200 // This is an empty block. If this is the last block, then there is no cells to delete or shift. 201 sc::CellStoreType::iterator itTest = itCell; 202 ++itTest; 203 if (itTest == maCells.end()) 204 { 205 // No cells are affected by this deletion. Bail out. 206 CellStorageModified(); // broadcast array has been modified. 207 return; 208 } 209 } 210 211 // Check if there are any cells below the end row that will get shifted. 212 bool bShiftCells = false; 213 if (nEndRow < GetDoc()->MaxRow()) //only makes sense to do this if there *is* a row after the end row 214 { 215 aPos = maCells.position(itCell, nEndRow+1); 216 itCell = aPos.first; 217 if (itCell->type == sc::element_type_empty) 218 { 219 // This block is empty. See if there is any block that follows. 220 sc::CellStoreType::iterator itTest = itCell; 221 ++itTest; 222 if (itTest != maCells.end()) 223 // Non-empty block follows -> cells that will get shifted. 224 bShiftCells = true; 225 } 226 else 227 bShiftCells = true; 228 } 229 230 sc::SingleColumnSpanSet aNonEmptySpans; 231 if (bShiftCells) 232 { 233 // Mark all non-empty cell positions below the end row. 234 sc::ColumnBlockConstPosition aBlockPos; 235 aBlockPos.miCellPos = itCell; 236 aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, GetDoc()->MaxRow()); 237 } 238 239 sc::AutoCalcSwitch aACSwitch(*GetDoc(), false); 240 241 // Remove the cells. 242 maCells.erase(nStartRow, nEndRow); 243 maCells.resize(MAXROWCOUNT); 244 245 // Get the position again after the container change. 246 aPos = maCells.position(nStartRow); 247 248 // Shift the formula cell positions below the start row. 249 ShiftFormulaPosHandler aShiftFormulaFunc; 250 sc::ProcessFormula(aPos.first, maCells, nStartRow, GetDoc()->MaxRow(), aShiftFormulaFunc); 251 252 bool bJoined = sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); 253 if (bJoined && pGroupPos) 254 pGroupPos->push_back(ScAddress(nCol, nStartRow, nTab)); 255 256 // Shift the text attribute array too (before the broadcast). 257 maCellTextAttrs.erase(nStartRow, nEndRow); 258 maCellTextAttrs.resize(MAXROWCOUNT); 259 260 CellStorageModified(); 261 } 262 263 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows, 264 bool bInsertFormula ) 265 { 266 return GetPositionToInsert(maCells.begin(), nRow, rNewSharedRows, bInsertFormula); 267 } 268 269 void ScColumn::JoinNewFormulaCell( 270 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) 271 { 272 // Check the previous row position for possible grouping. 273 if (aPos.first->type == sc::element_type_formula && aPos.second > 0) 274 { 275 ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1); 276 sc::CellStoreType::position_type aPosPrev = aPos; 277 --aPosPrev.second; 278 sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell); 279 } 280 281 // Check the next row position for possible grouping. 282 if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size) 283 { 284 ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1); 285 sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext); 286 } 287 } 288 289 void ScColumn::DetachFormulaCell( 290 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, std::vector<SCROW>& rNewSharedRows ) 291 { 292 if (!GetDoc()->IsClipOrUndo()) 293 { 294 #if USE_FORMULA_GROUP_LISTENER 295 if (rCell.IsShared() && rCell.GetSharedLength() > 1) 296 { 297 // Record new spans (shared or remaining single) that will result 298 // from unsharing to reestablish listeners. 299 // Same cases as in unshareFormulaCell(). 300 // XXX NOTE: this is not part of unshareFormulaCell() because that 301 // is called in other contexts as well, for which passing and 302 // determining the rows vector would be superfluous. If that was 303 // needed, move it there. 304 const SCROW nSharedTopRow = rCell.GetSharedTopRow(); 305 const SCROW nSharedLength = rCell.GetSharedLength(); 306 if (rCell.aPos.Row() == nSharedTopRow) 307 { 308 // Top cell. 309 // Next row will be new shared top or single cell. 310 rNewSharedRows.push_back( nSharedTopRow + 1); 311 rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1); 312 } 313 else if (rCell.aPos.Row() == nSharedTopRow + nSharedLength - 1) 314 { 315 // Bottom cell. 316 // Current shared top row will be new shared top again or 317 // single cell. 318 rNewSharedRows.push_back( nSharedTopRow); 319 rNewSharedRows.push_back( rCell.aPos.Row() - 1); 320 } 321 else 322 { 323 // Some mid cell. 324 // Current shared top row will be new shared top again or 325 // single cell, plus a new shared top below or single cell. 326 rNewSharedRows.push_back( nSharedTopRow); 327 rNewSharedRows.push_back( rCell.aPos.Row() - 1); 328 rNewSharedRows.push_back( rCell.aPos.Row() + 1); 329 rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1); 330 } 331 } 332 #endif 333 334 // Have the dying formula cell stop listening. 335 // If in a shared formula group this ends the group listening. 336 rCell.EndListeningTo(GetDoc()); 337 } 338 339 sc::SharedFormulaUtil::unshareFormulaCell(aPos, rCell); 340 } 341 342 void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows ) 343 { 344 assert(rNewSharedRows.empty() || rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4); 345 ScDocument* pDoc = GetDoc(); 346 if (!rNewSharedRows.empty() && !pDoc->IsDelayedFormulaGrouping()) 347 { 348 auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(*pDoc); 349 sc::StartListeningContext aStartCxt(*pDoc, pPosSet); 350 sc::EndListeningContext aEndCxt(*pDoc, pPosSet); 351 if (rNewSharedRows.size() >= 2) 352 { 353 if(!pDoc->CanDelayStartListeningFormulaCells( this, rNewSharedRows[0], rNewSharedRows[1])) 354 StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]); 355 } 356 if (rNewSharedRows.size() >= 4) 357 { 358 if(!pDoc->CanDelayStartListeningFormulaCells( this, rNewSharedRows[2], rNewSharedRows[3])) 359 StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]); 360 } 361 } 362 } 363 364 namespace { 365 366 class AttachFormulaCellsHandler 367 { 368 sc::StartListeningContext& mrCxt; 369 370 public: 371 explicit AttachFormulaCellsHandler(sc::StartListeningContext& rCxt) 372 : mrCxt(rCxt) {} 373 374 void operator() (size_t /*nRow*/, ScFormulaCell* pCell) 375 { 376 pCell->StartListeningTo(mrCxt); 377 } 378 }; 379 380 class DetachFormulaCellsHandler 381 { 382 ScDocument* mpDoc; 383 sc::EndListeningContext* mpCxt; 384 385 public: 386 DetachFormulaCellsHandler( ScDocument* pDoc, sc::EndListeningContext* pCxt ) : 387 mpDoc(pDoc), mpCxt(pCxt) {} 388 389 void operator() (size_t /*nRow*/, ScFormulaCell* pCell) 390 { 391 if (mpCxt) 392 pCell->EndListeningTo(*mpCxt); 393 else 394 pCell->EndListeningTo(mpDoc); 395 } 396 }; 397 398 } 399 400 void ScColumn::DetachFormulaCells( 401 const sc::CellStoreType::position_type& aPos, size_t nLength, std::vector<SCROW>* pNewSharedRows ) 402 { 403 const size_t nRow = aPos.first->position + aPos.second; 404 const size_t nNextTopRow = nRow + nLength; // start row of next formula group. 405 406 bool bLowerSplitOff = false; 407 if (pNewSharedRows && !GetDoc()->IsClipOrUndo()) 408 { 409 const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos); 410 if (pFC) 411 { 412 const SCROW nTopRow = pFC->GetSharedTopRow(); 413 const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1; 414 // nTopRow <= nRow <= nBotRow, because otherwise pFC would not exist. 415 if (nTopRow < static_cast<SCROW>(nRow)) 416 { 417 // Upper part will be split off. 418 pNewSharedRows->push_back(nTopRow); 419 pNewSharedRows->push_back(nRow - 1); 420 } 421 if (static_cast<SCROW>(nNextTopRow) <= nBotRow) 422 { 423 // Lower part will be split off. 424 pNewSharedRows->push_back(nNextTopRow); 425 pNewSharedRows->push_back(nBotRow); 426 bLowerSplitOff = true; 427 } 428 } 429 } 430 431 // Split formula grouping at the top and bottom boundaries. 432 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr); 433 434 if (nLength > 0 && GetDoc()->ValidRow(nNextTopRow)) 435 { 436 if (pNewSharedRows && !bLowerSplitOff && !GetDoc()->IsClipOrUndo()) 437 { 438 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow-1); 439 const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos2); 440 if (pFC) 441 { 442 const SCROW nTopRow = pFC->GetSharedTopRow(); 443 const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1; 444 // nRow < nTopRow < nNextTopRow <= nBotRow 445 if (static_cast<SCROW>(nNextTopRow) <= nBotRow) 446 { 447 // Lower part will be split off. 448 pNewSharedRows->push_back(nNextTopRow); 449 pNewSharedRows->push_back(nBotRow); 450 } 451 } 452 } 453 454 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow); 455 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos2, nullptr); 456 } 457 458 if (GetDoc()->IsClipOrUndo()) 459 return; 460 461 DetachFormulaCellsHandler aFunc(GetDoc(), nullptr); 462 sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc); 463 } 464 465 void ScColumn::AttachFormulaCells( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 ) 466 { 467 sc::CellStoreType::position_type aPos = maCells.position(nRow1); 468 sc::CellStoreType::iterator it = aPos.first; 469 470 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); 471 if (GetDoc()->ValidRow(nRow2+1)) 472 { 473 aPos = maCells.position(it, nRow2+1); 474 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); 475 } 476 477 if (GetDoc()->IsClipOrUndo()) 478 return; 479 480 AttachFormulaCellsHandler aFunc(rCxt); 481 sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc); 482 } 483 484 void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, 485 std::vector<SCROW>* pNewSharedRows ) 486 { 487 sc::CellStoreType::position_type aPos = maCells.position(nRow1); 488 sc::CellStoreType::iterator it = aPos.first; 489 490 bool bLowerSplitOff = false; 491 if (pNewSharedRows && !GetDoc()->IsClipOrUndo()) 492 { 493 const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos); 494 if (pFC) 495 { 496 const SCROW nTopRow = pFC->GetSharedTopRow(); 497 const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1; 498 // nTopRow <= nRow1 <= nBotRow, because otherwise pFC would not exist. 499 if (nTopRow < nRow1) 500 { 501 // Upper part will be split off. 502 pNewSharedRows->push_back(nTopRow); 503 pNewSharedRows->push_back(nRow1 - 1); 504 } 505 if (nRow2 < nBotRow) 506 { 507 // Lower part will be split off. 508 pNewSharedRows->push_back(nRow2 + 1); 509 pNewSharedRows->push_back(nBotRow); 510 bLowerSplitOff = true; 511 } 512 } 513 } 514 515 // Split formula grouping at the top and bottom boundaries. 516 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt); 517 if (GetDoc()->ValidRow(nRow2+1)) 518 { 519 if (pNewSharedRows && !bLowerSplitOff && !GetDoc()->IsClipOrUndo()) 520 { 521 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nRow2); 522 const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos2); 523 if (pFC) 524 { 525 const SCROW nTopRow = pFC->GetSharedTopRow(); 526 const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1; 527 // nRow1 < nTopRow <= nRow2 < nBotRow 528 if (nRow2 < nBotRow) 529 { 530 // Lower part will be split off. 531 pNewSharedRows->push_back(nRow2 + 1); 532 pNewSharedRows->push_back(nBotRow); 533 } 534 } 535 } 536 537 aPos = maCells.position(it, nRow2+1); 538 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt); 539 } 540 541 if (GetDoc()->IsClipOrUndo()) 542 return; 543 544 DetachFormulaCellsHandler aFunc(GetDoc(), &rCxt); 545 sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc); 546 } 547 548 static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type& rPos, 549 std::vector<SCROW>& rNewSharedRows ) 550 { 551 sc::CellStoreType::iterator itRet = rPos.first; 552 if (itRet->type != sc::element_type_formula) 553 return; 554 555 ScFormulaCell& rFC = *sc::formula_block::at(*itRet->data, rPos.second); 556 if ( rFC.IsShared() ) 557 { 558 const SCROW nSharedTopRow = rFC.GetSharedTopRow(); 559 const SCROW nSharedLength = rFC.GetSharedLength(); 560 rNewSharedRows.push_back( nSharedTopRow); 561 rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1); 562 } 563 else 564 { 565 const SCROW nRow = rFC.aPos.Row(); 566 rNewSharedRows.push_back( nRow); 567 rNewSharedRows.push_back( nRow); 568 } 569 } 570 571 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow, 572 std::vector<SCROW>& rNewSharedRows, bool bInsertFormula ) 573 { 574 // See if we are overwriting an existing formula cell. 575 sc::CellStoreType::position_type aPos = maCells.position(it, nRow); 576 sc::CellStoreType::iterator itRet = aPos.first; 577 578 if (itRet->type == sc::element_type_formula) 579 { 580 ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second); 581 DetachFormulaCell(aPos, rCell, rNewSharedRows); 582 } 583 else if (bInsertFormula && !GetDoc()->IsClipOrUndo()) 584 { 585 if (nRow > 0) 586 { 587 sc::CellStoreType::position_type aPosBefore = maCells.position(maCells.begin(), nRow-1); 588 lcl_AddFormulaGroupBoundaries(aPosBefore, rNewSharedRows); 589 } 590 if (nRow < GetDoc()->MaxRow()) 591 { 592 sc::CellStoreType::position_type aPosAfter = maCells.position(maCells.begin(), nRow+1); 593 lcl_AddFormulaGroupBoundaries(aPosAfter, rNewSharedRows); 594 } 595 } 596 597 return itRet; 598 } 599 600 void ScColumn::AttachNewFormulaCell( 601 const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, 602 const std::vector<SCROW>& rNewSharedRows, 603 bool bJoin, sc::StartListeningType eListenType ) 604 { 605 AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, rNewSharedRows, bJoin, eListenType); 606 } 607 608 void ScColumn::AttachNewFormulaCell( 609 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, 610 const std::vector<SCROW>& rNewSharedRows, 611 bool bJoin, sc::StartListeningType eListenType ) 612 { 613 if (bJoin) 614 // See if this new formula cell can join an existing shared formula group. 615 JoinNewFormulaCell(aPos, rCell); 616 617 // When we insert from the Clipboard we still have wrong (old) References! 618 // First they are rewired in CopyBlockFromClip via UpdateReference and the 619 // we call StartListeningFromClip and BroadcastFromClip. 620 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast. 621 // After Import we call CalcAfterLoad and in there Listening. 622 ScDocument* pDocument = GetDoc(); 623 if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) 624 return; 625 626 switch (eListenType) 627 { 628 case sc::ConvertToGroupListening: 629 { 630 auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(*pDocument); 631 sc::StartListeningContext aStartCxt(*pDocument, pPosSet); 632 sc::EndListeningContext aEndCxt(*pDocument, pPosSet); 633 SCROW nStartRow, nEndRow; 634 nStartRow = nEndRow = aPos.first->position + aPos.second; 635 for (const SCROW nR : rNewSharedRows) 636 { 637 if (nStartRow > nR) 638 nStartRow = nR; 639 if (nEndRow < nR) 640 nEndRow = nR; 641 } 642 StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow); 643 } 644 break; 645 case sc::SingleCellListening: 646 rCell.StartListeningTo(pDocument); 647 StartListeningUnshared( rNewSharedRows); 648 break; 649 case sc::NoListening: 650 default: 651 if (!rNewSharedRows.empty()) 652 { 653 assert(rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4); 654 // Calling SetNeedsListeningGroup() with a top row sets it to 655 // all affected formula cells of that group. 656 const ScFormulaCell* pFC = GetFormulaCell( rNewSharedRows[0]); 657 assert(pFC); // that *is* supposed to be a top row 658 if (pFC && !pFC->NeedsListening()) 659 SetNeedsListeningGroup( rNewSharedRows[0]); 660 if (rNewSharedRows.size() > 2) 661 { 662 pFC = GetFormulaCell( rNewSharedRows[2]); 663 assert(pFC); // that *is* supposed to be a top row 664 if (pFC && !pFC->NeedsListening()) 665 SetNeedsListeningGroup( rNewSharedRows[2]); 666 } 667 } 668 break; 669 } 670 671 if (!pDocument->IsCalcingAfterLoad()) 672 rCell.SetDirty(); 673 } 674 675 void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength, 676 std::vector<SCROW>& rNewSharedRows ) 677 { 678 // Make sure the whole length consists of formula cells. 679 if (aPos.first->type != sc::element_type_formula) 680 return; 681 682 if (aPos.first->size < aPos.second + nLength) 683 // Block is shorter than specified length. 684 return; 685 686 // Join the top and bottom cells only. 687 ScFormulaCell* pCell1 = sc::formula_block::at(*aPos.first->data, aPos.second); 688 JoinNewFormulaCell(aPos, *pCell1); 689 690 sc::CellStoreType::position_type aPosLast = aPos; 691 aPosLast.second += nLength - 1; 692 ScFormulaCell* pCell2 = sc::formula_block::at(*aPosLast.first->data, aPosLast.second); 693 JoinNewFormulaCell(aPosLast, *pCell2); 694 695 ScDocument* pDocument = GetDoc(); 696 if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc()) 697 { 698 const bool bShared = pCell1->IsShared() || pCell2->IsShared(); 699 if (bShared) 700 { 701 const SCROW nTopRow = (pCell1->IsShared() ? pCell1->GetSharedTopRow() : pCell1->aPos.Row()); 702 const SCROW nBotRow = (pCell2->IsShared() ? 703 pCell2->GetSharedTopRow() + pCell2->GetSharedLength() - 1 : pCell2->aPos.Row()); 704 if (rNewSharedRows.empty()) 705 { 706 rNewSharedRows.push_back( nTopRow); 707 rNewSharedRows.push_back( nBotRow); 708 } 709 else if (rNewSharedRows.size() == 2) 710 { 711 // Combine into one span. 712 if (rNewSharedRows[0] > nTopRow) 713 rNewSharedRows[0] = nTopRow; 714 if (rNewSharedRows[1] < nBotRow) 715 rNewSharedRows[1] = nBotRow; 716 } 717 else if (rNewSharedRows.size() == 4) 718 { 719 // Merge into one span. 720 // The original two spans are ordered from top to bottom. 721 std::vector<SCROW> aRows(2); 722 aRows[0] = std::min( rNewSharedRows[0], nTopRow); 723 aRows[1] = std::max( rNewSharedRows[3], nBotRow); 724 rNewSharedRows.swap( aRows); 725 } 726 else 727 { 728 assert(!"rNewSharedRows?"); 729 } 730 } 731 StartListeningUnshared( rNewSharedRows); 732 733 sc::StartListeningContext aCxt(*pDocument); 734 ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second); 735 ScFormulaCell** ppEnd = pp + nLength; 736 for (; pp != ppEnd; ++pp) 737 { 738 if (!bShared) 739 (*pp)->StartListeningTo(aCxt); 740 if (!pDocument->IsCalcingAfterLoad()) 741 (*pp)->SetDirty(); 742 } 743 } 744 } 745 746 void ScColumn::BroadcastNewCell( SCROW nRow ) 747 { 748 // When we insert from the Clipboard we still have wrong (old) References! 749 // First they are rewired in CopyBlockFromClip via UpdateReference and the 750 // we call StartListeningFromClip and BroadcastFromClip. 751 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast. 752 // After Import we call CalcAfterLoad and in there Listening. 753 if (GetDoc()->IsClipOrUndo() || GetDoc()->IsInsertingFromOtherDoc() || GetDoc()->IsCalcingAfterLoad()) 754 return; 755 756 Broadcast(nRow); 757 } 758 759 bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellStoreType::iterator& itr ) 760 { 761 if (rAttr.mnScriptType != SvtScriptType::UNKNOWN) 762 // Already updated. Nothing to do. 763 return false; 764 765 // Script type not yet determined. Determine the real script 766 // type, and store it. 767 const ScPatternAttr* pPattern = GetPattern(nRow); 768 if (!pPattern) 769 return false; 770 771 sc::CellStoreType::position_type pos = maCells.position(itr, nRow); 772 itr = pos.first; 773 size_t nOffset = pos.second; 774 ScRefCellValue aCell = GetCellValue( itr, nOffset ); 775 ScAddress aPos(nCol, nRow, nTab); 776 777 ScDocument* pDocument = GetDoc(); 778 const SfxItemSet* pCondSet = nullptr; 779 ScConditionalFormatList* pCFList = pDocument->GetCondFormList(nTab); 780 if (pCFList) 781 { 782 const ScCondFormatItem& rItem = 783 pPattern->GetItem(ATTR_CONDITIONAL); 784 const ScCondFormatIndexes& rData = rItem.GetCondFormatData(); 785 pCondSet = pDocument->GetCondResult(aCell, aPos, *pCFList, rData); 786 } 787 788 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 789 790 OUString aStr; 791 Color* pColor; 792 sal_uInt32 nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet); 793 ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter, pDocument); 794 795 // Store the real script type to the array. 796 rAttr.mnScriptType = pDocument->GetStringScriptType(aStr); 797 return true; 798 } 799 800 namespace { 801 802 class DeleteAreaHandler 803 { 804 ScDocument& mrDoc; 805 std::vector<ScFormulaCell*> maFormulaCells; 806 sc::SingleColumnSpanSet maDeleteRanges; 807 808 bool mbNumeric:1; 809 bool mbString:1; 810 bool mbFormula:1; 811 bool mbDateTime:1; 812 ScColumn& mrCol; 813 814 public: 815 DeleteAreaHandler(ScDocument& rDoc, InsertDeleteFlags nDelFlag, ScColumn& rCol) : 816 mrDoc(rDoc), 817 mbNumeric(nDelFlag & InsertDeleteFlags::VALUE), 818 mbString(nDelFlag & InsertDeleteFlags::STRING), 819 mbFormula(nDelFlag & InsertDeleteFlags::FORMULA), 820 mbDateTime(nDelFlag & InsertDeleteFlags::DATETIME), 821 mrCol(rCol) {} 822 823 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize) 824 { 825 switch (node.type) 826 { 827 case sc::element_type_numeric: 828 // Numeric type target datetime and number, thus we have a dedicated function 829 if (!mbNumeric && !mbDateTime) 830 return; 831 832 // If numeric and datetime selected, delete full range 833 if (mbNumeric && mbDateTime) 834 break; 835 836 deleteNumeric(node, nOffset, nDataSize); 837 return; 838 break; 839 case sc::element_type_string: 840 case sc::element_type_edittext: 841 if (!mbString) 842 return; 843 break; 844 case sc::element_type_formula: 845 { 846 if (!mbFormula) 847 return; 848 849 sc::formula_block::iterator it = sc::formula_block::begin(*node.data); 850 std::advance(it, nOffset); 851 sc::formula_block::iterator itEnd = it; 852 std::advance(itEnd, nDataSize); 853 854 for (; it != itEnd; ++it) 855 maFormulaCells.push_back(*it); 856 } 857 break; 858 case sc::element_type_empty: 859 default: 860 return; 861 } 862 863 // Tag these cells for deletion. 864 SCROW nRow1 = node.position + nOffset; 865 SCROW nRow2 = nRow1 + nDataSize - 1; 866 maDeleteRanges.set(nRow1, nRow2, true); 867 } 868 869 void deleteNumeric(const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize) 870 { 871 size_t nStart = node.position + nOffset; 872 size_t nElements = 1; 873 bool bLastTypeDateTime = isDateTime(nStart); // true = datetime, false = numeric 874 size_t nCount = nStart + nDataSize; 875 876 for (size_t i = nStart + 1; i < nCount; i++) 877 { 878 bool bIsDateTime = isDateTime(i); 879 880 // same type as previous 881 if (bIsDateTime == bLastTypeDateTime) 882 { 883 nElements++; 884 } 885 // type switching 886 else 887 { 888 deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime); 889 nStart += nElements; 890 nElements = 1; 891 } 892 893 bLastTypeDateTime = bIsDateTime; 894 } 895 896 // delete last cells 897 deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime); 898 } 899 900 void deleteNumberOrDateTime(SCROW nRow1, SCROW nRow2, bool dateTime) 901 { 902 if (!dateTime && !mbNumeric) // numeric flag must be selected 903 return; 904 if (dateTime && !mbDateTime) // datetime flag must be selected 905 return; 906 maDeleteRanges.set(nRow1, nRow2, true); 907 } 908 909 bool isDateTime(size_t position) 910 { 911 SvNumFormatType nType = mrDoc.GetFormatTable()->GetType( 912 mrCol.GetAttr(position, ATTR_VALUE_FORMAT).GetValue()); 913 914 return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) || 915 (nType == SvNumFormatType::DATETIME); 916 } 917 918 void endFormulas() 919 { 920 mrDoc.EndListeningFormulaCells(maFormulaCells); 921 } 922 923 sc::SingleColumnSpanSet& getSpans() 924 { 925 return maDeleteRanges; 926 } 927 }; 928 929 class EmptyCells 930 { 931 ScColumn& mrColumn; 932 sc::ColumnBlockPosition& mrPos; 933 934 static void splitFormulaGrouping(const sc::CellStoreType::position_type& rPos) 935 { 936 if (rPos.first->type == sc::element_type_formula) 937 { 938 ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, rPos.second); 939 sc::SharedFormulaUtil::unshareFormulaCell(rPos, rCell); 940 } 941 } 942 943 public: 944 EmptyCells( sc::ColumnBlockPosition& rPos, ScColumn& rColumn ) : 945 mrColumn(rColumn), mrPos(rPos) {} 946 947 void operator() (const sc::RowSpan& rSpan) 948 { 949 sc::CellStoreType& rCells = mrColumn.GetCellStore(); 950 951 // First, split formula grouping at the top and bottom boundaries 952 // before emptying the cells. 953 sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1); 954 splitFormulaGrouping(aPos); 955 aPos = rCells.position(aPos.first, rSpan.mnRow2); 956 splitFormulaGrouping(aPos); 957 958 mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2); 959 mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2); 960 } 961 }; 962 963 } 964 965 void ScColumn::DeleteCells( 966 sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag, 967 sc::SingleColumnSpanSet& rDeleted ) 968 { 969 // Determine which cells to delete based on the deletion flags. 970 DeleteAreaHandler aFunc(*GetDoc(), nDelFlag, *this); 971 sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first; 972 sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2); 973 aFunc.endFormulas(); // Have the formula cells stop listening. 974 975 // Get the deletion spans. 976 sc::SingleColumnSpanSet::SpansType aSpans; 977 aFunc.getSpans().getSpans(aSpans); 978 979 // Delete the cells for real. 980 std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(rBlockPos, *this)); 981 CellStorageModified(); 982 983 aFunc.getSpans().swap(rDeleted); 984 } 985 986 void ScColumn::DeleteArea( 987 SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast, 988 sc::ColumnSpanSet* pBroadcastSpans ) 989 { 990 InsertDeleteFlags nContMask = InsertDeleteFlags::CONTENTS; 991 // InsertDeleteFlags::NOCAPTIONS needs to be passed too, if InsertDeleteFlags::NOTE is set 992 if( nDelFlag & InsertDeleteFlags::NOTE ) 993 nContMask |= InsertDeleteFlags::NOCAPTIONS; 994 InsertDeleteFlags nContFlag = nDelFlag & nContMask; 995 996 sc::SingleColumnSpanSet aDeletedRows; 997 998 sc::ColumnBlockPosition aBlockPos; 999 InitBlockPosition(aBlockPos); 1000 1001 if (!IsEmptyData() && nContFlag != InsertDeleteFlags::NONE) 1002 { 1003 DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag, aDeletedRows); 1004 if (pBroadcastSpans) 1005 { 1006 sc::SingleColumnSpanSet::SpansType aSpans; 1007 aDeletedRows.getSpans(aSpans); 1008 for (const auto& rSpan : aSpans) 1009 pBroadcastSpans->set(*GetDoc(), nTab, nCol, rSpan.mnRow1, rSpan.mnRow2, true); 1010 } 1011 } 1012 1013 if (nDelFlag & InsertDeleteFlags::NOTE) 1014 { 1015 bool bForgetCaptionOwnership = ((nDelFlag & InsertDeleteFlags::FORGETCAPTIONS) != InsertDeleteFlags::NONE); 1016 DeleteCellNotes(aBlockPos, nStartRow, nEndRow, bForgetCaptionOwnership); 1017 } 1018 1019 if ( nDelFlag & InsertDeleteFlags::EDITATTR ) 1020 { 1021 OSL_ENSURE( nContFlag == InsertDeleteFlags::NONE, "DeleteArea: Wrong Flags" ); 1022 RemoveEditAttribs( nStartRow, nEndRow ); 1023 } 1024 1025 // Delete attributes just now 1026 if ((nDelFlag & InsertDeleteFlags::ATTRIB) == InsertDeleteFlags::ATTRIB) 1027 pAttrArray->DeleteArea( nStartRow, nEndRow ); 1028 else if ((nDelFlag & InsertDeleteFlags::HARDATTR) == InsertDeleteFlags::HARDATTR) 1029 pAttrArray->DeleteHardAttr( nStartRow, nEndRow ); 1030 1031 if (bBroadcast) 1032 { 1033 // Broadcast on only cells that were deleted; no point broadcasting on 1034 // cells that were already empty before the deletion. 1035 std::vector<SCROW> aRows; 1036 aDeletedRows.getRows(aRows); 1037 BroadcastCells(aRows, SfxHintId::ScDataChanged); 1038 } 1039 } 1040 1041 void ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos ) 1042 { 1043 rBlockPos.miBroadcasterPos = maBroadcasters.begin(); 1044 rBlockPos.miCellNotePos = maCellNotes.begin(); 1045 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin(); 1046 rBlockPos.miCellPos = maCells.begin(); 1047 } 1048 1049 void ScColumn::InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const 1050 { 1051 rBlockPos.miCellNotePos = maCellNotes.begin(); 1052 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin(); 1053 rBlockPos.miCellPos = maCells.begin(); 1054 } 1055 1056 namespace { 1057 1058 class CopyAttrArrayByRange 1059 { 1060 ScAttrArray& mrDestAttrArray; 1061 ScAttrArray& mrSrcAttrArray; 1062 long mnRowOffset; 1063 public: 1064 CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, long nRowOffset) : 1065 mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {} 1066 1067 void operator() (const sc::RowSpan& rSpan) 1068 { 1069 mrDestAttrArray.CopyAreaSafe( 1070 rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray); 1071 } 1072 }; 1073 1074 class CopyCellsFromClipHandler 1075 { 1076 sc::CopyFromClipContext& mrCxt; 1077 ScColumn& mrSrcCol; 1078 ScColumn& mrDestCol; 1079 SCTAB mnTab; 1080 SCCOL mnCol; 1081 SCTAB mnSrcTab; 1082 SCCOL mnSrcCol; 1083 long mnRowOffset; 1084 sc::ColumnBlockPosition maDestBlockPos; 1085 sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration. 1086 svl::SharedStringPool* mpSharedStringPool; 1087 1088 void insertRefCell(SCROW nSrcRow, SCROW nDestRow) 1089 { 1090 ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab); 1091 ScAddress aDestPos(mnCol, nDestRow, mnTab); 1092 ScSingleRefData aRef; 1093 aRef.InitAddress(aSrcPos); 1094 aRef.SetFlag3D(true); 1095 1096 ScTokenArray aArr(mrCxt.getDestDoc()); 1097 aArr.AddSingleReference(aRef); 1098 1099 mrDestCol.SetFormulaCell( 1100 maDestBlockPos, nDestRow, new ScFormulaCell(mrDestCol.GetDoc(), aDestPos, aArr)); 1101 } 1102 1103 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption ) 1104 { 1105 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset); 1106 } 1107 1108 public: 1109 CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, long nRowOffset, svl::SharedStringPool* pSharedStringPool) : 1110 mrCxt(rCxt), 1111 mrSrcCol(rSrcCol), 1112 mrDestCol(rDestCol), 1113 mnTab(nDestTab), 1114 mnCol(nDestCol), 1115 mnSrcTab(rSrcCol.GetTab()), 1116 mnSrcCol(rSrcCol.GetCol()), 1117 mnRowOffset(nRowOffset), 1118 mpDestBlockPos(mrCxt.getBlockPosition(nDestTab, nDestCol)), 1119 mpSharedStringPool(pSharedStringPool) 1120 { 1121 if (mpDestBlockPos) 1122 maDestBlockPos = *mpDestBlockPos; 1123 else 1124 mrDestCol.InitBlockPosition(maDestBlockPos); 1125 } 1126 1127 ~CopyCellsFromClipHandler() 1128 { 1129 if (mpDestBlockPos) 1130 // Don't forget to save this to the context! 1131 *mpDestBlockPos = maDestBlockPos; 1132 } 1133 1134 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize) 1135 { 1136 SCROW nSrcRow1 = node.position + nOffset; 1137 bool bCopyCellNotes = mrCxt.isCloneNotes(); 1138 1139 InsertDeleteFlags nFlags = mrCxt.getInsertFlag(); 1140 1141 if (node.type == sc::element_type_empty) 1142 { 1143 if (bCopyCellNotes && !mrCxt.isSkipAttrForEmptyCells()) 1144 { 1145 bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE; 1146 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption ); 1147 } 1148 return; 1149 } 1150 1151 bool bNumeric = (nFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE; 1152 bool bDateTime = (nFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE; 1153 bool bString = (nFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE; 1154 bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE; 1155 bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE; 1156 1157 bool bAsLink = mrCxt.isAsLink(); 1158 1159 switch (node.type) 1160 { 1161 case sc::element_type_numeric: 1162 { 1163 // We need to copy numeric cells individually because of date type check. 1164 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data); 1165 std::advance(it, nOffset); 1166 sc::numeric_block::const_iterator itEnd = it; 1167 std::advance(itEnd, nDataSize); 1168 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow) 1169 { 1170 bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric; 1171 if (!bCopy) 1172 continue; 1173 1174 if (bAsLink) 1175 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1176 else 1177 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it); 1178 } 1179 } 1180 break; 1181 case sc::element_type_string: 1182 { 1183 if (!bString) 1184 break; 1185 1186 sc::string_block::const_iterator it = sc::string_block::begin(*node.data); 1187 std::advance(it, nOffset); 1188 sc::string_block::const_iterator itEnd = it; 1189 std::advance(itEnd, nDataSize); 1190 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow) 1191 { 1192 if (bAsLink) 1193 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1194 else if (mpSharedStringPool) 1195 { 1196 // Re-intern the string if source is a different document. 1197 svl::SharedString aInterned = mpSharedStringPool->intern( (*it).getString()); 1198 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned); 1199 } 1200 else 1201 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it); 1202 } 1203 } 1204 break; 1205 case sc::element_type_edittext: 1206 { 1207 if (!bString) 1208 break; 1209 1210 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data); 1211 std::advance(it, nOffset); 1212 sc::edittext_block::const_iterator itEnd = it; 1213 std::advance(itEnd, nDataSize); 1214 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow) 1215 { 1216 1217 if (bAsLink) 1218 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1219 else 1220 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it); 1221 } 1222 } 1223 break; 1224 case sc::element_type_formula: 1225 { 1226 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data); 1227 std::advance(it, nOffset); 1228 sc::formula_block::const_iterator itEnd = it; 1229 std::advance(itEnd, nDataSize); 1230 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow) 1231 { 1232 ScFormulaCell& rSrcCell = **it; 1233 bool bForceFormula = false; 1234 if (bBoolean) 1235 { 1236 // See if the formula consists of =TRUE() or =FALSE(). 1237 const ScTokenArray* pCode = rSrcCell.GetCode(); 1238 if (pCode && pCode->GetLen() == 1) 1239 { 1240 const formula::FormulaToken* p = pCode->FirstToken(); 1241 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse) 1242 // This is a boolean formula. 1243 bForceFormula = true; 1244 } 1245 } 1246 1247 ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab); 1248 if (bFormula || bForceFormula) 1249 { 1250 if (bAsLink) 1251 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1252 else 1253 { 1254 mrDestCol.SetFormulaCell( 1255 maDestBlockPos, nSrcRow + mnRowOffset, 1256 new ScFormulaCell(rSrcCell, *mrDestCol.GetDoc(), aDestPos), 1257 sc::SingleCellListening, 1258 rSrcCell.NeedsNumberFormat()); 1259 } 1260 } 1261 else if (bNumeric || bDateTime || bString) 1262 { 1263 // Always just copy the original row to the Undo Document; 1264 // do not create Value/string cells from formulas 1265 1266 FormulaError nErr = rSrcCell.GetErrCode(); 1267 if (nErr != FormulaError::NONE) 1268 { 1269 // error codes are cloned with values 1270 if (bNumeric) 1271 { 1272 if (bAsLink) 1273 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1274 else 1275 { 1276 ScFormulaCell* pErrCell = new ScFormulaCell(mrDestCol.GetDoc(), aDestPos); 1277 pErrCell->SetErrCode(nErr); 1278 mrDestCol.SetFormulaCell( 1279 maDestBlockPos, nSrcRow + mnRowOffset, pErrCell); 1280 } 1281 } 1282 } 1283 else if (rSrcCell.IsEmptyDisplayedAsString()) 1284 { 1285 // Empty stays empty and doesn't become 0. 1286 continue; 1287 } 1288 else if (rSrcCell.IsValue()) 1289 { 1290 bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric; 1291 if (!bCopy) 1292 continue; 1293 1294 if (bAsLink) 1295 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1296 else 1297 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue()); 1298 } 1299 else if (bString) 1300 { 1301 svl::SharedString aStr = rSrcCell.GetString(); 1302 if (aStr.isEmpty()) 1303 // do not clone empty string 1304 continue; 1305 1306 if (bAsLink) 1307 insertRefCell(nSrcRow, nSrcRow + mnRowOffset); 1308 else if (rSrcCell.IsMultilineResult()) 1309 { 1310 // Clone as an edit text object. 1311 ScFieldEditEngine& rEngine = mrDestCol.GetDoc()->GetEditEngine(); 1312 rEngine.SetTextCurrentDefaults(aStr.getString()); 1313 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject()); 1314 } 1315 else if (mpSharedStringPool) 1316 { 1317 // Re-intern the string if source is a different document. 1318 svl::SharedString aInterned = mpSharedStringPool->intern( aStr.getString()); 1319 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned); 1320 } 1321 else 1322 { 1323 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr); 1324 } 1325 } 1326 } 1327 } 1328 } 1329 break; 1330 default: 1331 ; 1332 } 1333 if (bCopyCellNotes) 1334 { 1335 bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE; 1336 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption ); 1337 } 1338 } 1339 }; 1340 1341 class CopyTextAttrsFromClipHandler 1342 { 1343 sc::CellTextAttrStoreType& mrAttrs; 1344 size_t mnDelta; 1345 sc::ColumnBlockPosition maDestBlockPos; 1346 sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration. 1347 1348 public: 1349 CopyTextAttrsFromClipHandler( sc::CopyFromClipContext& rCxt, sc::CellTextAttrStoreType& rAttrs, 1350 ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, size_t nDelta ) : 1351 mrAttrs(rAttrs), 1352 mnDelta(nDelta), 1353 mpDestBlockPos(rCxt.getBlockPosition(nDestTab, nDestCol)) 1354 { 1355 if (mpDestBlockPos) 1356 maDestBlockPos = *mpDestBlockPos; 1357 else 1358 rDestCol.InitBlockPosition(maDestBlockPos); 1359 } 1360 1361 ~CopyTextAttrsFromClipHandler() 1362 { 1363 if (mpDestBlockPos) 1364 // Don't forget to save this to the context! 1365 *mpDestBlockPos = maDestBlockPos; 1366 } 1367 1368 void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize ) 1369 { 1370 if (aNode.type != sc::element_type_celltextattr) 1371 return; 1372 1373 sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data); 1374 std::advance(it, nOffset); 1375 sc::celltextattr_block::const_iterator itEnd = it; 1376 std::advance(itEnd, nDataSize); 1377 1378 size_t nPos = aNode.position + nOffset + mnDelta; 1379 maDestBlockPos.miCellTextAttrPos = mrAttrs.set(maDestBlockPos.miCellTextAttrPos, nPos, it, itEnd); 1380 } 1381 }; 1382 1383 } 1384 1385 // rColumn = source 1386 // nRow1, nRow2 = target position 1387 1388 void ScColumn::CopyFromClip( 1389 sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn ) 1390 { 1391 if ((rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB) != InsertDeleteFlags::NONE) 1392 { 1393 if (rCxt.isSkipAttrForEmptyCells()) 1394 { 1395 // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy. 1396 sc::SingleColumnSpanSet aSpanSet; 1397 aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy); 1398 sc::SingleColumnSpanSet::SpansType aSpans; 1399 aSpanSet.getSpans(aSpans); 1400 std::for_each( 1401 aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy)); 1402 } 1403 else 1404 rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray ); 1405 } 1406 if ((rCxt.getInsertFlag() & InsertDeleteFlags::CONTENTS) == InsertDeleteFlags::NONE) 1407 return; 1408 1409 ScDocument* pDocument = GetDoc(); 1410 if (rCxt.isAsLink() && rCxt.getInsertFlag() == InsertDeleteFlags::ALL) 1411 { 1412 // We also reference empty cells for "ALL" 1413 // InsertDeleteFlags::ALL must always contain more flags when compared to "Insert contents" as 1414 // contents can be selected one by one! 1415 1416 ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row 1417 1418 // Create reference (Source Position) 1419 ScSingleRefData aRef; 1420 aRef.InitFlags(); // -> All absolute 1421 aRef.SetAbsCol(rColumn.nCol); 1422 aRef.SetAbsTab(rColumn.nTab); 1423 aRef.SetFlag3D(true); 1424 1425 for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++) 1426 { 1427 aRef.SetAbsRow(nDestRow - nDy); // Source row 1428 aDestPos.SetRow( nDestRow ); 1429 1430 ScTokenArray aArr(GetDoc()); 1431 aArr.AddSingleReference( aRef ); 1432 SetFormulaCell(nDestRow, new ScFormulaCell(pDocument, aDestPos, aArr)); 1433 } 1434 1435 // Don't forget to copy the cell text attributes. 1436 CopyTextAttrsFromClipHandler aFunc(rCxt, maCellTextAttrs, *this, nTab, nCol, nDy); 1437 sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy); 1438 1439 return; 1440 } 1441 1442 // Compare the ScDocumentPool* to determine if we are copying within the 1443 // same document. If not, re-intern shared strings. 1444 svl::SharedStringPool* pSharedStringPool = (rColumn.GetDoc()->GetPool() != pDocument->GetPool()) ? 1445 &pDocument->GetSharedStringPool() : nullptr; 1446 1447 // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range. 1448 // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column. 1449 { 1450 CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy, pSharedStringPool); 1451 sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy); 1452 } 1453 1454 { 1455 // Don't forget to copy the cell text attributes. 1456 CopyTextAttrsFromClipHandler aFunc(rCxt, maCellTextAttrs, *this, nTab, nCol, nDy); 1457 sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy); 1458 } 1459 } 1460 1461 void ScColumn::MixMarked( 1462 sc::MixDocContext& rCxt, const ScMarkData& rMark, ScPasteFunc nFunction, 1463 bool bSkipEmpty, const ScColumn& rSrcCol ) 1464 { 1465 SCROW nRow1, nRow2; 1466 1467 if (rMark.IsMultiMarked()) 1468 { 1469 ScMultiSelIter aIter( rMark.GetMultiSelData(), nCol ); 1470 while (aIter.Next( nRow1, nRow2 )) 1471 MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol); 1472 } 1473 } 1474 1475 namespace { 1476 1477 // Result in rVal1 1478 bool lcl_DoFunction( double& rVal1, double nVal2, ScPasteFunc nFunction ) 1479 { 1480 bool bOk = false; 1481 switch (nFunction) 1482 { 1483 case ScPasteFunc::ADD: 1484 bOk = SubTotal::SafePlus( rVal1, nVal2 ); 1485 break; 1486 case ScPasteFunc::SUB: 1487 nVal2 = -nVal2; // FIXME: Can we do this always without error? 1488 bOk = SubTotal::SafePlus( rVal1, nVal2 ); 1489 break; 1490 case ScPasteFunc::MUL: 1491 bOk = SubTotal::SafeMult( rVal1, nVal2 ); 1492 break; 1493 case ScPasteFunc::DIV: 1494 bOk = SubTotal::SafeDiv( rVal1, nVal2 ); 1495 break; 1496 default: break; 1497 } 1498 return bOk; 1499 } 1500 1501 void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell ) 1502 { 1503 rArr.AddOpCode(ocOpen); 1504 1505 const ScTokenArray* pCode = pCell->GetCode(); 1506 if (pCode) 1507 { 1508 FormulaTokenArrayPlainIterator aIter(*pCode); 1509 const formula::FormulaToken* pToken = aIter.First(); 1510 while (pToken) 1511 { 1512 rArr.AddToken( *pToken ); 1513 pToken = aIter.Next(); 1514 } 1515 } 1516 1517 rArr.AddOpCode(ocClose); 1518 } 1519 1520 class MixDataHandler 1521 { 1522 ScColumn& mrDestColumn; 1523 sc::ColumnBlockPosition& mrBlockPos; 1524 1525 sc::CellStoreType maNewCells; 1526 sc::CellStoreType::iterator miNewCellsPos; 1527 1528 size_t mnRowOffset; 1529 ScPasteFunc mnFunction; 1530 1531 bool mbSkipEmpty; 1532 1533 void doFunction( size_t nDestRow, double fVal1, double fVal2 ) 1534 { 1535 bool bOk = lcl_DoFunction(fVal1, fVal2, mnFunction); 1536 1537 if (bOk) 1538 miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, fVal1); 1539 else 1540 { 1541 ScAddress aPos(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()); 1542 1543 ScFormulaCell* pFC = new ScFormulaCell(mrDestColumn.GetDoc(), aPos); 1544 pFC->SetErrCode(FormulaError::NoValue); 1545 1546 miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, pFC); 1547 } 1548 } 1549 1550 public: 1551 MixDataHandler( 1552 sc::ColumnBlockPosition& rBlockPos, 1553 ScColumn& rDestColumn, 1554 SCROW nRow1, SCROW nRow2, 1555 ScPasteFunc nFunction, bool bSkipEmpty) : 1556 mrDestColumn(rDestColumn), 1557 mrBlockPos(rBlockPos), 1558 maNewCells(nRow2 - nRow1 + 1), 1559 miNewCellsPos(maNewCells.begin()), 1560 mnRowOffset(nRow1), 1561 mnFunction(nFunction), 1562 mbSkipEmpty(bSkipEmpty) 1563 { 1564 } 1565 1566 void operator() (size_t nRow, double f) 1567 { 1568 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow); 1569 mrBlockPos.miCellPos = aPos.first; 1570 switch (aPos.first->type) 1571 { 1572 case sc::element_type_empty: 1573 case sc::element_type_numeric: 1574 { 1575 double fSrcVal = 0.0; 1576 if (aPos.first->type == sc::element_type_numeric) 1577 fSrcVal = sc::numeric_block::at(*aPos.first->data, aPos.second); 1578 1579 // Both src and dest are of numeric type. 1580 doFunction(nRow, f, fSrcVal); 1581 } 1582 break; 1583 case sc::element_type_formula: 1584 { 1585 // Combination of value and at least one formula -> Create formula 1586 ScTokenArray aArr(mrDestColumn.GetDoc()); 1587 1588 // First row 1589 aArr.AddDouble(f); 1590 1591 // Operator 1592 OpCode eOp = ocAdd; 1593 switch (mnFunction) 1594 { 1595 case ScPasteFunc::ADD: eOp = ocAdd; break; 1596 case ScPasteFunc::SUB: eOp = ocSub; break; 1597 case ScPasteFunc::MUL: eOp = ocMul; break; 1598 case ScPasteFunc::DIV: eOp = ocDiv; break; 1599 default: break; 1600 } 1601 aArr.AddOpCode(eOp); // Function 1602 1603 // Second row 1604 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second); 1605 lcl_AddCode(aArr, pDest); 1606 1607 miNewCellsPos = maNewCells.set( 1608 miNewCellsPos, nRow-mnRowOffset, 1609 new ScFormulaCell( 1610 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr)); 1611 } 1612 break; 1613 case sc::element_type_string: 1614 case sc::element_type_edittext: 1615 { 1616 // Destination cell is not a number. Just take the source cell. 1617 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f); 1618 } 1619 break; 1620 default: 1621 ; 1622 } 1623 } 1624 1625 void operator() (size_t nRow, const svl::SharedString& rStr) 1626 { 1627 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr); 1628 } 1629 1630 void operator() (size_t nRow, const EditTextObject* p) 1631 { 1632 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone().release()); 1633 } 1634 1635 void operator() (size_t nRow, const ScFormulaCell* p) 1636 { 1637 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow); 1638 mrBlockPos.miCellPos = aPos.first; 1639 switch (aPos.first->type) 1640 { 1641 case sc::element_type_numeric: 1642 { 1643 // Source is formula, and dest is value. 1644 ScTokenArray aArr(mrDestColumn.GetDoc()); 1645 1646 // First row 1647 lcl_AddCode(aArr, p); 1648 1649 // Operator 1650 OpCode eOp = ocAdd; 1651 switch (mnFunction) 1652 { 1653 case ScPasteFunc::ADD: eOp = ocAdd; break; 1654 case ScPasteFunc::SUB: eOp = ocSub; break; 1655 case ScPasteFunc::MUL: eOp = ocMul; break; 1656 case ScPasteFunc::DIV: eOp = ocDiv; break; 1657 default: break; 1658 } 1659 aArr.AddOpCode(eOp); // Function 1660 1661 // Second row 1662 aArr.AddDouble(sc::numeric_block::at(*aPos.first->data, aPos.second)); 1663 1664 miNewCellsPos = maNewCells.set( 1665 miNewCellsPos, nRow-mnRowOffset, 1666 new ScFormulaCell( 1667 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr)); 1668 } 1669 break; 1670 case sc::element_type_formula: 1671 { 1672 // Both are formulas. 1673 ScTokenArray aArr(mrDestColumn.GetDoc()); 1674 1675 // First row 1676 lcl_AddCode(aArr, p); 1677 1678 // Operator 1679 OpCode eOp = ocAdd; 1680 switch (mnFunction) 1681 { 1682 case ScPasteFunc::ADD: eOp = ocAdd; break; 1683 case ScPasteFunc::SUB: eOp = ocSub; break; 1684 case ScPasteFunc::MUL: eOp = ocMul; break; 1685 case ScPasteFunc::DIV: eOp = ocDiv; break; 1686 default: break; 1687 } 1688 aArr.AddOpCode(eOp); // Function 1689 1690 // Second row 1691 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second); 1692 lcl_AddCode(aArr, pDest); 1693 1694 miNewCellsPos = maNewCells.set( 1695 miNewCellsPos, nRow-mnRowOffset, 1696 new ScFormulaCell( 1697 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr)); 1698 } 1699 break; 1700 case sc::element_type_string: 1701 case sc::element_type_edittext: 1702 case sc::element_type_empty: 1703 { 1704 // Destination cell is not a number. Just take the source cell. 1705 ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()); 1706 miNewCellsPos = maNewCells.set( 1707 miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, *mrDestColumn.GetDoc(), aDestPos)); 1708 } 1709 break; 1710 default: 1711 ; 1712 } 1713 } 1714 1715 /** 1716 * Empty cell series in the source (clip) document. 1717 */ 1718 void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize) 1719 { 1720 if (mbSkipEmpty) 1721 return; 1722 1723 // Source cells are empty. Treat them as if they have a value of 0.0. 1724 for (size_t i = 0; i < nDataSize; ++i) 1725 { 1726 size_t nDestRow = nTopRow + i; 1727 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nDestRow); 1728 mrBlockPos.miCellPos = aPos.first; 1729 switch (aPos.first->type) 1730 { 1731 case sc::element_type_numeric: 1732 { 1733 double fVal2 = sc::numeric_block::at(*aPos.first->data, aPos.second); 1734 doFunction(nDestRow, 0.0, fVal2); 1735 } 1736 break; 1737 case sc::element_type_string: 1738 { 1739 const svl::SharedString& aVal = sc::string_block::at(*aPos.first->data, aPos.second); 1740 miNewCellsPos = maNewCells.set( 1741 miNewCellsPos, nDestRow-mnRowOffset, aVal); 1742 } 1743 break; 1744 case sc::element_type_edittext: 1745 { 1746 EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second); 1747 miNewCellsPos = maNewCells.set( 1748 miNewCellsPos, nDestRow-mnRowOffset, pObj->Clone().release()); 1749 } 1750 break; 1751 case sc::element_type_formula: 1752 { 1753 ScTokenArray aArr(mrDestColumn.GetDoc()); 1754 1755 // First row 1756 ScFormulaCell* pSrc = sc::formula_block::at(*aPos.first->data, aPos.second); 1757 lcl_AddCode( aArr, pSrc); 1758 1759 // Operator 1760 OpCode eOp = ocAdd; 1761 switch (mnFunction) 1762 { 1763 case ScPasteFunc::ADD: eOp = ocAdd; break; 1764 case ScPasteFunc::SUB: eOp = ocSub; break; 1765 case ScPasteFunc::MUL: eOp = ocMul; break; 1766 case ScPasteFunc::DIV: eOp = ocDiv; break; 1767 default: break; 1768 } 1769 1770 aArr.AddOpCode(eOp); // Function 1771 aArr.AddDouble(0.0); 1772 1773 miNewCellsPos = maNewCells.set( 1774 miNewCellsPos, nDestRow-mnRowOffset, 1775 new ScFormulaCell( 1776 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), aArr)); 1777 } 1778 break; 1779 default: 1780 ; 1781 } 1782 } 1783 } 1784 1785 /** 1786 * Set the new cells to the destination (this) column. 1787 */ 1788 void commit() 1789 { 1790 sc::CellStoreType& rDestCells = mrDestColumn.GetCellStore(); 1791 1792 // Stop all formula cells in the destination range first. 1793 sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset); 1794 mrDestColumn.DetachFormulaCells(aPos, maNewCells.size(), nullptr); 1795 1796 // Move the new cells to the destination range. 1797 sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos; 1798 sc::CellTextAttrStoreType::iterator& itDestAttrPos = mrBlockPos.miCellTextAttrPos; 1799 1800 for (const auto& rNewCell : maNewCells) 1801 { 1802 bool bHasContent = true; 1803 size_t nDestRow = mnRowOffset + rNewCell.position; 1804 1805 switch (rNewCell.type) 1806 { 1807 case sc::element_type_numeric: 1808 { 1809 sc::numeric_block::iterator itData = sc::numeric_block::begin(*rNewCell.data); 1810 sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*rNewCell.data); 1811 itDestPos = mrDestColumn.GetCellStore().set(itDestPos, nDestRow, itData, itDataEnd); 1812 } 1813 break; 1814 case sc::element_type_string: 1815 { 1816 sc::string_block::iterator itData = sc::string_block::begin(*rNewCell.data); 1817 sc::string_block::iterator itDataEnd = sc::string_block::end(*rNewCell.data); 1818 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd); 1819 } 1820 break; 1821 case sc::element_type_edittext: 1822 { 1823 sc::edittext_block::iterator itData = sc::edittext_block::begin(*rNewCell.data); 1824 sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*rNewCell.data); 1825 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd); 1826 } 1827 break; 1828 case sc::element_type_formula: 1829 { 1830 sc::formula_block::iterator itData = sc::formula_block::begin(*rNewCell.data); 1831 sc::formula_block::iterator itDataEnd = sc::formula_block::end(*rNewCell.data); 1832 1833 // Group new formula cells before inserting them. 1834 sc::SharedFormulaUtil::groupFormulaCells(itData, itDataEnd); 1835 1836 // Insert the formula cells to the column. 1837 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd); 1838 1839 // Merge with the previous formula group (if any). 1840 aPos = rDestCells.position(itDestPos, nDestRow); 1841 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); 1842 1843 // Merge with the next formula group (if any). 1844 size_t nNextRow = nDestRow + rNewCell.size; 1845 if (mrDestColumn.GetDoc()->ValidRow(nNextRow)) 1846 { 1847 aPos = rDestCells.position(aPos.first, nNextRow); 1848 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); 1849 } 1850 } 1851 break; 1852 case sc::element_type_empty: 1853 { 1854 itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+rNewCell.size-1); 1855 bHasContent = false; 1856 } 1857 break; 1858 default: 1859 ; 1860 } 1861 1862 sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore(); 1863 if (bHasContent) 1864 { 1865 std::vector<sc::CellTextAttr> aAttrs(rNewCell.size, sc::CellTextAttr()); 1866 itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end()); 1867 } 1868 else 1869 itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+rNewCell.size-1); 1870 } 1871 1872 maNewCells.release(); 1873 } 1874 }; 1875 1876 } 1877 1878 void ScColumn::MixData( 1879 sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction, 1880 bool bSkipEmpty, const ScColumn& rSrcCol ) 1881 { 1882 // destination (this column) block position. 1883 1884 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol); 1885 if (!p) 1886 return; 1887 1888 MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty); 1889 sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc); 1890 1891 aFunc.commit(); 1892 CellStorageModified(); 1893 } 1894 1895 std::unique_ptr<ScAttrIterator> ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const 1896 { 1897 return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, nEndRow, GetDoc()->GetDefPattern() ); 1898 } 1899 1900 namespace { 1901 1902 class StartListenersHandler 1903 { 1904 sc::StartListeningContext* mpCxt; 1905 bool mbAllListeners; 1906 1907 public: 1908 StartListenersHandler( sc::StartListeningContext& rCxt, bool bAllListeners ) : 1909 mpCxt(&rCxt), mbAllListeners(bAllListeners) {} 1910 1911 void operator() ( sc::CellStoreType::value_type& aBlk ) 1912 { 1913 if (aBlk.type != sc::element_type_formula) 1914 return; 1915 1916 ScFormulaCell** pp = &sc::formula_block::at(*aBlk.data, 0); 1917 ScFormulaCell** ppEnd = pp + aBlk.size; 1918 1919 for (; pp != ppEnd; ++pp) 1920 { 1921 ScFormulaCell& rFC = **pp; 1922 if (!mbAllListeners && !rFC.NeedsListening()) 1923 continue; 1924 1925 if (rFC.IsSharedTop()) 1926 { 1927 sc::SharedFormulaUtil::startListeningAsGroup(*mpCxt, pp); 1928 pp += rFC.GetSharedLength() - 1; // Move to the last cell in the group. 1929 } 1930 else 1931 rFC.StartListeningTo(*mpCxt); 1932 } 1933 } 1934 }; 1935 1936 } 1937 1938 void ScColumn::StartListeners( sc::StartListeningContext& rCxt, bool bAll ) 1939 { 1940 std::for_each(maCells.begin(), maCells.end(), StartListenersHandler(rCxt, bAll)); 1941 } 1942 1943 namespace { 1944 1945 void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter ) 1946 { 1947 sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TEXT); 1948 ScPatternAttr aNewAttrs(rCol.GetDoc()->GetPool()); 1949 SfxItemSet& rSet = aNewAttrs.GetItemSet(); 1950 rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat)); 1951 rCol.ApplyPattern(nRow, aNewAttrs); 1952 } 1953 1954 } 1955 1956 bool ScColumn::ParseString( 1957 ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const OUString& rString, 1958 formula::FormulaGrammar::AddressConvention eConv, 1959 const ScSetStringParam* pParam ) 1960 { 1961 if (rString.isEmpty()) 1962 return false; 1963 1964 bool bNumFmtSet = false; 1965 1966 ScSetStringParam aParam; 1967 1968 if (pParam) 1969 aParam = *pParam; 1970 1971 sal_uInt32 nIndex = 0; 1972 sal_uInt32 nOldIndex = 0; 1973 SvNumFormatType eNumFormatType = SvNumFormatType::ALL; 1974 if (!aParam.mpNumFormatter) 1975 aParam.mpNumFormatter = GetDoc()->GetFormatTable(); 1976 1977 sal_Unicode cFirstChar = 0; // Text 1978 nIndex = nOldIndex = GetNumberFormat( GetDoc()->GetNonThreadedContext(), nRow ); 1979 if ( rString.getLength() > 1 ) 1980 { 1981 eNumFormatType = aParam.mpNumFormatter->GetType(nIndex); 1982 if ( eNumFormatType != SvNumFormatType::TEXT ) 1983 cFirstChar = rString[0]; 1984 } 1985 1986 svl::SharedStringPool& rPool = GetDoc()->GetSharedStringPool(); 1987 1988 if ( cFirstChar == '=' ) 1989 { 1990 if ( rString.getLength() == 1 ) // = Text 1991 { 1992 rCell.set(rPool.intern(rString)); 1993 } 1994 else if (aParam.meSetTextNumFormat == ScSetStringParam::Always) 1995 { 1996 // Set the cell format type to Text. 1997 applyTextNumFormat(*this, nRow, aParam.mpNumFormatter); 1998 rCell.set(rPool.intern(rString)); 1999 } 2000 else // = Formula 2001 { 2002 ScFormulaCell* pFormulaCell = new ScFormulaCell( 2003 GetDoc(), ScAddress(nCol, nRow, nTabP), rString, 2004 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv), 2005 ScMatrixMode::NONE); 2006 if (aParam.mbCheckLinkFormula) 2007 GetDoc()->CheckLinkFormulaNeedingCheck( *pFormulaCell->GetCode()); 2008 rCell.set( pFormulaCell); 2009 } 2010 } 2011 else if ( cFirstChar == '\'') // 'Text 2012 { 2013 bool bNumeric = false; 2014 if (aParam.mbHandleApostrophe) 2015 { 2016 // Cell format is not 'Text', and the first char 2017 // is an apostrophe. Check if the input is considered a number. 2018 OUString aTest = rString.copy(1); 2019 double fTest; 2020 bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest); 2021 if (bNumeric) 2022 // This is a number. Strip out the first char. 2023 rCell.set(rPool.intern(aTest)); 2024 } 2025 if (!bNumeric) 2026 // This is normal text. Take it as-is. 2027 rCell.set(rPool.intern(rString)); 2028 } 2029 else 2030 { 2031 double nVal; 2032 2033 do 2034 { 2035 if (aParam.mbDetectNumberFormat) 2036 { 2037 // Editing a date prefers the format's locale's edit date 2038 // format's date acceptance patterns and YMD order. 2039 /* TODO: this could be determined already far above when 2040 * starting to edit a date "cell" and passed down. A problem 2041 * could also be if a new date was typed over or written by a 2042 * macro assuming the current locale if that conflicts somehow. 2043 * You can't have everything. See tdf#116579 and tdf#125109. */ 2044 if (eNumFormatType == SvNumFormatType::ALL) 2045 eNumFormatType = aParam.mpNumFormatter->GetType(nIndex); 2046 bool bForceFormatDate = (eNumFormatType == SvNumFormatType::DATE 2047 || eNumFormatType == SvNumFormatType::DATETIME); 2048 const SvNumberformat* pOldFormat = nullptr; 2049 NfEvalDateFormat eEvalDateFormat = NF_EVALDATEFORMAT_INTL_FORMAT; 2050 if (bForceFormatDate) 2051 { 2052 ScRefCellValue aCell = GetCellValue(nRow); 2053 if (aCell.meType == CELLTYPE_VALUE) 2054 { 2055 // Only for an actual date (serial number), not an 2056 // arbitrary string or formula or empty cell. 2057 // Also ensure the edit date format's pattern is used, 2058 // not the display format's. 2059 pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex); 2060 if (!pOldFormat) 2061 bForceFormatDate = false; 2062 else 2063 { 2064 nIndex = aParam.mpNumFormatter->GetEditFormat( aCell.getValue(), nOldIndex, eNumFormatType, 2065 pOldFormat->GetLanguage(), pOldFormat); 2066 eEvalDateFormat = aParam.mpNumFormatter->GetEvalDateFormat(); 2067 aParam.mpNumFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL); 2068 } 2069 } 2070 else 2071 { 2072 bForceFormatDate = false; 2073 } 2074 } 2075 2076 const bool bIsNumberFormat = aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal); 2077 2078 if (bForceFormatDate) 2079 aParam.mpNumFormatter->SetEvalDateFormat( eEvalDateFormat); 2080 2081 if (!bIsNumberFormat) 2082 break; 2083 2084 // If we have bForceFormatDate, the pOldFormat was/is of 2085 // nOldIndex date(+time) type already, if detected type is 2086 // compatible keep the original format. 2087 if (bForceFormatDate && SvNumberFormatter::IsCompatible( 2088 eNumFormatType, aParam.mpNumFormatter->GetType( nIndex))) 2089 { 2090 nIndex = nOldIndex; 2091 } 2092 else 2093 { 2094 // convert back to the original language if a built-in format was detected 2095 if (!pOldFormat) 2096 pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex ); 2097 if (pOldFormat) 2098 nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( 2099 nIndex, pOldFormat->GetLanguage()); 2100 } 2101 2102 rCell.set(nVal); 2103 if ( nIndex != nOldIndex) 2104 { 2105 // #i22345# New behavior: Apply the detected number format only if 2106 // the old one was the default number, date, time or boolean format. 2107 // Exception: If the new format is boolean, always apply it. 2108 2109 bool bOverwrite = false; 2110 if ( pOldFormat ) 2111 { 2112 SvNumFormatType nOldType = pOldFormat->GetMaskedType(); 2113 if ( nOldType == SvNumFormatType::NUMBER || nOldType == SvNumFormatType::DATE || 2114 nOldType == SvNumFormatType::TIME || nOldType == SvNumFormatType::LOGICAL ) 2115 { 2116 if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat( 2117 nOldType, pOldFormat->GetLanguage() ) ) 2118 { 2119 bOverwrite = true; // default of these types can be overwritten 2120 } 2121 } 2122 } 2123 if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == SvNumFormatType::LOGICAL ) 2124 { 2125 bOverwrite = true; // overwrite anything if boolean was detected 2126 } 2127 2128 if ( bOverwrite ) 2129 { 2130 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, 2131 nIndex) ); 2132 bNumFmtSet = true; 2133 } 2134 } 2135 } 2136 else if (aParam.meSetTextNumFormat == ScSetStringParam::Never || 2137 aParam.meSetTextNumFormat == ScSetStringParam::SpecialNumberOnly) 2138 { 2139 // Only check if the string is a regular number. 2140 const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData(); 2141 if (!pLocale) 2142 break; 2143 2144 const LocaleDataItem2& aLocaleItem = pLocale->getLocaleItem(); 2145 const OUString& rDecSep = aLocaleItem.decimalSeparator; 2146 const OUString& rGroupSep = aLocaleItem.thousandSeparator; 2147 const OUString& rDecSepAlt = aLocaleItem.decimalSeparatorAlternative; 2148 if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1 || rDecSepAlt.getLength() > 1) 2149 break; 2150 2151 sal_Unicode dsep = rDecSep[0]; 2152 sal_Unicode gsep = rGroupSep[0]; 2153 sal_Unicode dsepa = rDecSepAlt.toChar(); 2154 2155 if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, dsepa, nVal)) 2156 break; 2157 2158 rCell.set(nVal); 2159 } 2160 } 2161 while (false); 2162 2163 if (rCell.meType == CELLTYPE_NONE) 2164 { 2165 // If we reach here with ScSetStringParam::SpecialNumberOnly it 2166 // means a simple number was not detected above, so test for 2167 // special numbers. In any case ScSetStringParam::Always does not 2168 // mean always, but only always for content that could be any 2169 // numeric. 2170 if ((aParam.meSetTextNumFormat == ScSetStringParam::Always || 2171 aParam.meSetTextNumFormat == ScSetStringParam::SpecialNumberOnly) && 2172 aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal)) 2173 { 2174 // Set the cell format type to Text. 2175 applyTextNumFormat(*this, nRow, aParam.mpNumFormatter); 2176 } 2177 2178 rCell.set(rPool.intern(rString)); 2179 } 2180 } 2181 2182 return bNumFmtSet; 2183 } 2184 2185 /** 2186 * Returns true if the cell format was set as well 2187 */ 2188 bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString, 2189 formula::FormulaGrammar::AddressConvention eConv, 2190 const ScSetStringParam* pParam ) 2191 { 2192 if (!GetDoc()->ValidRow(nRow)) 2193 return false; 2194 2195 ScCellValue aNewCell; 2196 bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam); 2197 if (pParam) 2198 aNewCell.release(*this, nRow, pParam->meStartListening); 2199 else 2200 aNewCell.release(*this, nRow); 2201 2202 // Do not set Formats and Formulas here anymore! 2203 // These are queried during output 2204 2205 return bNumFmtSet; 2206 } 2207 2208 void ScColumn::SetEditText( SCROW nRow, std::unique_ptr<EditTextObject> pEditText ) 2209 { 2210 pEditText->NormalizeString(GetDoc()->GetSharedStringPool()); 2211 std::vector<SCROW> aNewSharedRows; 2212 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false); 2213 maCells.set(it, nRow, pEditText.release()); 2214 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2215 CellStorageModified(); 2216 2217 StartListeningUnshared( aNewSharedRows); 2218 2219 BroadcastNewCell(nRow); 2220 } 2221 2222 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, std::unique_ptr<EditTextObject> pEditText ) 2223 { 2224 pEditText->NormalizeString(GetDoc()->GetSharedStringPool()); 2225 std::vector<SCROW> aNewSharedRows; 2226 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false); 2227 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText.release()); 2228 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( 2229 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); 2230 2231 CellStorageModified(); 2232 2233 StartListeningUnshared( aNewSharedRows); 2234 2235 BroadcastNewCell(nRow); 2236 } 2237 2238 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText ) 2239 { 2240 if (GetDoc()->GetEditPool() == rEditText.GetPool()) 2241 { 2242 SetEditText(rBlockPos, nRow, rEditText.Clone()); 2243 return; 2244 } 2245 2246 // rats, yet another "spool" 2247 // Sadly there is no other way to change the Pool than to 2248 // "spool" the Object through a corresponding Engine 2249 EditEngine& rEngine = GetDoc()->GetEditEngine(); 2250 rEngine.SetText(rEditText); 2251 SetEditText(rBlockPos, nRow, rEngine.CreateTextObject()); 2252 } 2253 2254 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool ) 2255 { 2256 if (pEditPool && GetDoc()->GetEditPool() == pEditPool) 2257 { 2258 SetEditText(nRow, rEditText.Clone()); 2259 return; 2260 } 2261 2262 // rats, yet another "spool" 2263 // Sadly there is no other way to change the Pool than to 2264 // "spool" the Object through a corresponding Engine 2265 EditEngine& rEngine = GetDoc()->GetEditEngine(); 2266 rEngine.SetText(rEditText); 2267 SetEditText(nRow, rEngine.CreateTextObject()); 2268 } 2269 2270 void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram ) 2271 { 2272 ScAddress aPos(nCol, nRow, nTab); 2273 2274 std::vector<SCROW> aNewSharedRows; 2275 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true); 2276 ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rArray, eGram); 2277 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); 2278 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) 2279 pCell->SetNeedNumberFormat(true); 2280 it = maCells.set(it, nRow, pCell); 2281 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2282 2283 CellStorageModified(); 2284 2285 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows); 2286 } 2287 2288 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram ) 2289 { 2290 ScAddress aPos(nCol, nRow, nTab); 2291 2292 std::vector<SCROW> aNewSharedRows; 2293 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true); 2294 ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rFormula, eGram); 2295 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); 2296 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) 2297 pCell->SetNeedNumberFormat(true); 2298 it = maCells.set(it, nRow, pCell); 2299 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2300 2301 CellStorageModified(); 2302 2303 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows); 2304 } 2305 2306 ScFormulaCell* ScColumn::SetFormulaCell( 2307 SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType, 2308 bool bInheritNumFormatIfNeeded ) 2309 { 2310 std::vector<SCROW> aNewSharedRows; 2311 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true); 2312 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); 2313 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded ) 2314 pCell->SetNeedNumberFormat(true); 2315 it = maCells.set(it, nRow, pCell); 2316 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2317 2318 CellStorageModified(); 2319 2320 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows, true, eListenType); 2321 2322 return pCell; 2323 } 2324 2325 void ScColumn::SetFormulaCell( 2326 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell, 2327 sc::StartListeningType eListenType, 2328 bool bInheritNumFormatIfNeeded ) 2329 { 2330 std::vector<SCROW> aNewSharedRows; 2331 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, true); 2332 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); 2333 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded ) 2334 pCell->SetNeedNumberFormat(true); 2335 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell); 2336 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( 2337 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); 2338 2339 CellStorageModified(); 2340 2341 AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, aNewSharedRows, true, eListenType); 2342 } 2343 2344 bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells ) 2345 { 2346 if (!GetDoc()->ValidRow(nRow)) 2347 return false; 2348 2349 SCROW nEndRow = nRow + rCells.size() - 1; 2350 if (!GetDoc()->ValidRow(nEndRow)) 2351 return false; 2352 2353 sc::CellStoreType::position_type aPos = maCells.position(nRow); 2354 2355 // Detach all formula cells that will be overwritten. 2356 std::vector<SCROW> aNewSharedRows; 2357 DetachFormulaCells(aPos, rCells.size(), &aNewSharedRows); 2358 2359 if (!GetDoc()->IsClipOrUndo()) 2360 { 2361 for (size_t i = 0, n = rCells.size(); i < n; ++i) 2362 { 2363 SCROW nThisRow = nRow + i; 2364 sal_uInt32 nFmt = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nThisRow); 2365 if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0) 2366 rCells[i]->SetNeedNumberFormat(true); 2367 } 2368 } 2369 2370 std::vector<sc::CellTextAttr> aDefaults(rCells.size(), sc::CellTextAttr()); 2371 maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end()); 2372 2373 maCells.set(aPos.first, nRow, rCells.begin(), rCells.end()); 2374 2375 CellStorageModified(); 2376 2377 // Reget position_type as the type may have changed to formula, block and 2378 // block size changed, ... 2379 aPos = maCells.position(nRow); 2380 AttachNewFormulaCells(aPos, rCells.size(), aNewSharedRows); 2381 2382 return true; 2383 } 2384 2385 svl::SharedString ScColumn::GetSharedString( SCROW nRow ) const 2386 { 2387 sc::CellStoreType::const_position_type aPos = maCells.position(nRow); 2388 switch (aPos.first->type) 2389 { 2390 case sc::element_type_string: 2391 return sc::string_block::at(*aPos.first->data, aPos.second); 2392 case sc::element_type_edittext: 2393 { 2394 const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second); 2395 std::vector<svl::SharedString> aSSs = pObj->GetSharedStrings(); 2396 if (aSSs.size() != 1) 2397 // We don't handle multiline content for now. 2398 return svl::SharedString(); 2399 2400 return aSSs[0]; 2401 } 2402 break; 2403 default: 2404 ; 2405 } 2406 return svl::SharedString(); 2407 } 2408 2409 namespace { 2410 2411 class FilterEntriesHandler 2412 { 2413 ScColumn& mrColumn; 2414 ScFilterEntries& mrFilterEntries; 2415 2416 void processCell(SCROW nRow, ScRefCellValue& rCell) 2417 { 2418 SvNumberFormatter* pFormatter = mrColumn.GetDoc()->GetFormatTable(); 2419 OUString aStr; 2420 sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc()->GetNonThreadedContext(), nRow); 2421 ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, mrColumn.GetDoc()); 2422 2423 if (rCell.hasString()) 2424 { 2425 mrFilterEntries.push_back(ScTypedStrData(aStr)); 2426 return; 2427 } 2428 2429 double fVal = 0.0; 2430 2431 switch (rCell.meType) 2432 { 2433 case CELLTYPE_VALUE: 2434 fVal = rCell.mfValue; 2435 break; 2436 2437 case CELLTYPE_FORMULA: 2438 { 2439 ScFormulaCell* pFC = rCell.mpFormula; 2440 FormulaError nErr = pFC->GetErrCode(); 2441 if (nErr != FormulaError::NONE) 2442 { 2443 // Error cell is evaluated as string (for now). 2444 OUString aErr = ScGlobal::GetErrorString(nErr); 2445 if (!aErr.isEmpty()) 2446 { 2447 mrFilterEntries.push_back(ScTypedStrData(aErr)); 2448 return; 2449 } 2450 } 2451 else 2452 fVal = pFC->GetValue(); 2453 } 2454 break; 2455 default: 2456 ; 2457 } 2458 2459 SvNumFormatType nType = pFormatter->GetType(nFormat); 2460 bool bDate = false; 2461 if ((nType & SvNumFormatType::DATE) && !(nType & SvNumFormatType::TIME)) 2462 { 2463 // special case for date values. Disregard the time 2464 // element if the number format is of date type. 2465 fVal = rtl::math::approxFloor(fVal); 2466 mrFilterEntries.mbHasDates = true; 2467 bDate = true; 2468 // Convert string representation to ISO 8601 date to eliminate 2469 // locale dependent behaviour later when filtering for dates. 2470 sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_YYYYMMDD); 2471 pFormatter->GetInputLineString( fVal, nIndex, aStr); 2472 } 2473 // maybe extend ScTypedStrData enum is also an option here 2474 mrFilterEntries.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value,bDate)); 2475 } 2476 2477 public: 2478 FilterEntriesHandler(ScColumn& rColumn, ScFilterEntries& rFilterEntries) : 2479 mrColumn(rColumn), mrFilterEntries(rFilterEntries) {} 2480 2481 void operator() (size_t nRow, double fVal) 2482 { 2483 ScRefCellValue aCell(fVal); 2484 processCell(nRow, aCell); 2485 } 2486 2487 void operator() (size_t nRow, const svl::SharedString& rStr) 2488 { 2489 ScRefCellValue aCell(&rStr); 2490 processCell(nRow, aCell); 2491 } 2492 2493 void operator() (size_t nRow, const EditTextObject* p) 2494 { 2495 ScRefCellValue aCell(p); 2496 processCell(nRow, aCell); 2497 } 2498 2499 void operator() (size_t nRow, const ScFormulaCell* p) 2500 { 2501 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p)); 2502 processCell(nRow, aCell); 2503 } 2504 2505 void operator() (const int nElemType, size_t nRow, size_t /* nDataSize */) 2506 { 2507 if ( nElemType == sc::element_type_empty ) 2508 { 2509 if (!mrFilterEntries.mbHasEmpties) 2510 { 2511 mrFilterEntries.push_back(ScTypedStrData(OUString())); 2512 mrFilterEntries.mbHasEmpties = true; 2513 } 2514 return; 2515 } 2516 ScRefCellValue aCell = mrColumn.GetCellValue(nRow); 2517 processCell(nRow, aCell); 2518 } 2519 }; 2520 2521 } 2522 2523 void ScColumn::GetFilterEntries( 2524 sc::ColumnBlockConstPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow, 2525 ScFilterEntries& rFilterEntries ) 2526 { 2527 FilterEntriesHandler aFunc(*this, rFilterEntries); 2528 rBlockPos.miCellPos = 2529 sc::ParseAll(rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc, aFunc); 2530 } 2531 2532 namespace { 2533 2534 /** 2535 * Iterate over only string and edit-text cells. 2536 */ 2537 class StrCellIterator 2538 { 2539 typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType; 2540 PosType maPos; 2541 sc::CellStoreType::const_iterator miBeg; 2542 sc::CellStoreType::const_iterator miEnd; 2543 const ScDocument* mpDoc; 2544 public: 2545 StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart, const ScDocument* pDoc) : 2546 miBeg(rCells.begin()), miEnd(rCells.end()), mpDoc(pDoc) 2547 { 2548 if (pDoc->ValidRow(nStart)) 2549 maPos = rCells.position(nStart); 2550 else 2551 // Make this iterator invalid. 2552 maPos.first = miEnd; 2553 } 2554 2555 bool valid() const { return (maPos.first != miEnd); } 2556 2557 bool has() const 2558 { 2559 return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext); 2560 } 2561 2562 bool prev() 2563 { 2564 if (!has()) 2565 { 2566 // Not in a string block. Move back until we hit a string block. 2567 while (!has()) 2568 { 2569 if (maPos.first == miBeg) 2570 return false; 2571 2572 --maPos.first; // move to the preceding block. 2573 maPos.second = maPos.first->size - 1; // last cell in the block. 2574 } 2575 return true; 2576 } 2577 2578 // We are in a string block. 2579 if (maPos.second > 0) 2580 { 2581 // Move back one cell in the same block. 2582 --maPos.second; 2583 } 2584 else 2585 { 2586 // Move back to the preceding string block. 2587 while (true) 2588 { 2589 if (maPos.first == miBeg) 2590 return false; 2591 2592 // Move to the last cell of the previous block. 2593 --maPos.first; 2594 maPos.second = maPos.first->size - 1; 2595 if (has()) 2596 break; 2597 } 2598 } 2599 return true; 2600 } 2601 2602 bool next() 2603 { 2604 if (!has()) 2605 { 2606 // Not in a string block. Move forward until we hit a string block. 2607 while (!has()) 2608 { 2609 ++maPos.first; 2610 if (maPos.first == miEnd) 2611 return false; 2612 2613 maPos.second = 0; // First cell in this block. 2614 } 2615 return true; 2616 } 2617 2618 // We are in a string block. 2619 ++maPos.second; 2620 if (maPos.second >= maPos.first->size) 2621 { 2622 // Move to the next string block. 2623 while (true) 2624 { 2625 ++maPos.first; 2626 if (maPos.first == miEnd) 2627 return false; 2628 2629 maPos.second = 0; 2630 if (has()) 2631 break; 2632 } 2633 } 2634 return true; 2635 } 2636 2637 OUString get() const 2638 { 2639 switch (maPos.first->type) 2640 { 2641 case sc::element_type_string: 2642 return sc::string_block::at(*maPos.first->data, maPos.second).getString(); 2643 case sc::element_type_edittext: 2644 { 2645 const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second); 2646 return ScEditUtil::GetString(*p, mpDoc); 2647 } 2648 default: 2649 ; 2650 } 2651 return OUString(); 2652 } 2653 }; 2654 2655 } 2656 2657 // GetDataEntries - Strings from continuous Section around nRow 2658 2659 // DATENT_MAX - max. number of entries in list for auto entry 2660 // DATENT_SEARCH - max. number of cells that get transparent - new: only count Strings 2661 #define DATENT_MAX 200 2662 #define DATENT_SEARCH 2000 2663 2664 bool ScColumn::GetDataEntries( 2665 SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit ) const 2666 { 2667 // Start at the specified row position, and collect all string values 2668 // going upward and downward directions in parallel. The start position 2669 // cell must be skipped. 2670 2671 StrCellIterator aItrUp(maCells, nStartRow, GetDoc()); 2672 StrCellIterator aItrDown(maCells, nStartRow+1, GetDoc()); 2673 2674 bool bMoveUp = aItrUp.valid(); 2675 if (!bMoveUp) 2676 // Current cell is invalid. 2677 return false; 2678 2679 // Skip the start position cell. 2680 bMoveUp = aItrUp.prev(); // Find the previous string cell position. 2681 2682 bool bMoveDown = aItrDown.valid(); 2683 if (bMoveDown && !aItrDown.has()) 2684 bMoveDown = aItrDown.next(); // Find the next string cell position. 2685 2686 bool bFound = false; 2687 size_t nCellsSearched = 0; 2688 while (bMoveUp || bMoveDown) 2689 { 2690 if (bMoveUp) 2691 { 2692 // Get the current string and move up. 2693 OUString aStr = aItrUp.get(); 2694 if (!aStr.isEmpty()) 2695 { 2696 bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second; 2697 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX) 2698 return true; // Maximum reached 2699 bFound = true; 2700 } 2701 2702 if (bLimit && ++nCellsSearched >= DATENT_SEARCH) 2703 return bFound; // max search cell count reached. 2704 2705 bMoveUp = aItrUp.prev(); 2706 } 2707 2708 if (bMoveDown) 2709 { 2710 // Get the current string and move down. 2711 OUString aStr = aItrDown.get(); 2712 if (!aStr.isEmpty()) 2713 { 2714 bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second; 2715 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX) 2716 return true; // Maximum reached 2717 bFound = true; 2718 } 2719 2720 if (bLimit && ++nCellsSearched >= DATENT_SEARCH) 2721 return bFound; // max search cell count reached. 2722 2723 bMoveDown = aItrDown.next(); 2724 } 2725 } 2726 2727 return bFound; 2728 } 2729 2730 namespace { 2731 2732 class FormulaToValueHandler 2733 { 2734 struct Entry 2735 { 2736 SCROW mnRow; 2737 ScCellValue maValue; 2738 2739 Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {} 2740 Entry(SCROW nRow, const svl::SharedString& rStr) : mnRow(nRow), maValue(rStr) {} 2741 }; 2742 2743 typedef std::vector<Entry> EntriesType; 2744 EntriesType maEntries; 2745 2746 public: 2747 2748 void operator() (size_t nRow, const ScFormulaCell* p) 2749 { 2750 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p); 2751 if (p2->IsValue()) 2752 maEntries.emplace_back(nRow, p2->GetValue()); 2753 else 2754 maEntries.emplace_back(nRow, p2->GetString()); 2755 } 2756 2757 void commitCells(ScColumn& rColumn) 2758 { 2759 sc::ColumnBlockPosition aBlockPos; 2760 rColumn.InitBlockPosition(aBlockPos); 2761 2762 for (const Entry& r : maEntries) 2763 { 2764 switch (r.maValue.meType) 2765 { 2766 case CELLTYPE_VALUE: 2767 rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false); 2768 break; 2769 case CELLTYPE_STRING: 2770 rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false); 2771 break; 2772 default: 2773 ; 2774 } 2775 } 2776 } 2777 }; 2778 2779 } 2780 2781 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow ) 2782 { 2783 FormulaToValueHandler aFunc; 2784 sc::CellStoreType::const_iterator itPos = maCells.begin(); 2785 2786 ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc()->GetDefPattern() ); 2787 SCROW nTop = -1; 2788 SCROW nBottom = -1; 2789 const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom ); 2790 while (pPattern) 2791 { 2792 const ScProtectionAttr* pAttr = &pPattern->GetItem(ATTR_PROTECTION); 2793 if ( pAttr->GetHideCell() ) 2794 DeleteArea( nTop, nBottom, InsertDeleteFlags::CONTENTS ); 2795 else if ( pAttr->GetHideFormula() ) 2796 { 2797 // Replace all formula cells between nTop and nBottom with raw value cells. 2798 itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc); 2799 } 2800 2801 pPattern = aAttrIter.Next( nTop, nBottom ); 2802 } 2803 2804 aFunc.commitCells(*this); 2805 } 2806 2807 void ScColumn::SetError( SCROW nRow, const FormulaError nError) 2808 { 2809 if (!GetDoc()->ValidRow(nRow)) 2810 return; 2811 2812 ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), ScAddress(nCol, nRow, nTab)); 2813 pCell->SetErrCode(nError); 2814 2815 std::vector<SCROW> aNewSharedRows; 2816 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true); 2817 it = maCells.set(it, nRow, pCell); 2818 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2819 2820 CellStorageModified(); 2821 2822 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows); 2823 } 2824 2825 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr ) 2826 { 2827 if (!GetDoc()->ValidRow(nRow)) 2828 return; 2829 2830 svl::SharedString aSS = GetDoc()->GetSharedStringPool().intern(rStr); 2831 if (!aSS.getData()) 2832 return; 2833 2834 SetRawString(nRow, aSS); 2835 } 2836 2837 void ScColumn::SetRawString( SCROW nRow, const svl::SharedString& rStr ) 2838 { 2839 if (!GetDoc()->ValidRow(nRow)) 2840 return; 2841 2842 std::vector<SCROW> aNewSharedRows; 2843 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false); 2844 maCells.set(it, nRow, rStr); 2845 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2846 2847 CellStorageModified(); 2848 2849 StartListeningUnshared( aNewSharedRows); 2850 2851 BroadcastNewCell(nRow); 2852 } 2853 2854 void ScColumn::SetRawString( 2855 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const svl::SharedString& rStr, bool bBroadcast ) 2856 { 2857 if (!GetDoc()->ValidRow(nRow)) 2858 return; 2859 2860 std::vector<SCROW> aNewSharedRows; 2861 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false); 2862 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr); 2863 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( 2864 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); 2865 2866 CellStorageModified(); 2867 2868 StartListeningUnshared( aNewSharedRows); 2869 2870 if (bBroadcast) 2871 BroadcastNewCell(nRow); 2872 } 2873 2874 void ScColumn::SetValue( SCROW nRow, double fVal ) 2875 { 2876 if (!GetDoc()->ValidRow(nRow)) 2877 return; 2878 2879 std::vector<SCROW> aNewSharedRows; 2880 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false); 2881 maCells.set(it, nRow, fVal); 2882 maCellTextAttrs.set(nRow, sc::CellTextAttr()); 2883 2884 CellStorageModified(); 2885 2886 StartListeningUnshared( aNewSharedRows); 2887 2888 BroadcastNewCell(nRow); 2889 } 2890 2891 void ScColumn::SetValue( 2892 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast ) 2893 { 2894 if (!GetDoc()->ValidRow(nRow)) 2895 return; 2896 2897 std::vector<SCROW> aNewSharedRows; 2898 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false); 2899 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal); 2900 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( 2901 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); 2902 2903 CellStorageModified(); 2904 2905 StartListeningUnshared( aNewSharedRows); 2906 2907 if (bBroadcast) 2908 BroadcastNewCell(nRow); 2909 } 2910 2911 void ScColumn::GetString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString, const ScInterpreterContext* pContext ) const 2912 { 2913 // ugly hack for ordering problem with GetNumberFormat and missing inherited formats 2914 if (aCell.meType == CELLTYPE_FORMULA) 2915 aCell.mpFormula->MaybeInterpret(); 2916 2917 sal_uInt32 nFormat = GetNumberFormat( pContext ? *pContext : GetDoc()->GetNonThreadedContext(), nRow); 2918 Color* pColor = nullptr; 2919 ScCellFormat::GetString(aCell, nFormat, rString, &pColor, 2920 pContext ? *(pContext->GetFormatTable()) : *(GetDoc()->GetFormatTable()), GetDoc()); 2921 } 2922 2923 double* ScColumn::GetValueCell( SCROW nRow ) 2924 { 2925 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow); 2926 sc::CellStoreType::iterator it = aPos.first; 2927 if (it == maCells.end()) 2928 return nullptr; 2929 2930 if (it->type != sc::element_type_numeric) 2931 return nullptr; 2932 2933 return &sc::numeric_block::at(*it->data, aPos.second); 2934 } 2935 2936 void ScColumn::GetInputString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString ) const 2937 { 2938 sal_uLong nFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); 2939 ScCellFormat::GetInputString(aCell, nFormat, rString, *(GetDoc()->GetFormatTable()), GetDoc()); 2940 } 2941 2942 double ScColumn::GetValue( SCROW nRow ) const 2943 { 2944 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow); 2945 sc::CellStoreType::const_iterator it = aPos.first; 2946 switch (it->type) 2947 { 2948 case sc::element_type_numeric: 2949 return sc::numeric_block::at(*it->data, aPos.second); 2950 case sc::element_type_formula: 2951 { 2952 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second); 2953 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p); 2954 return p2->IsValue() ? p2->GetValue() : 0.0; 2955 } 2956 default: 2957 ; 2958 } 2959 2960 return 0.0; 2961 } 2962 2963 const EditTextObject* ScColumn::GetEditText( SCROW nRow ) const 2964 { 2965 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow); 2966 sc::CellStoreType::const_iterator it = aPos.first; 2967 if (it == maCells.end()) 2968 return nullptr; 2969 2970 if (it->type != sc::element_type_edittext) 2971 return nullptr; 2972 2973 return sc::edittext_block::at(*it->data, aPos.second); 2974 } 2975 2976 void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr ) 2977 { 2978 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow); 2979 sc::CellStoreType::iterator it = aPos.first; 2980 if (it == maCells.end()) 2981 return; 2982 2983 if (it->type != sc::element_type_edittext) 2984 return; 2985 2986 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second); 2987 ScEditUtil::RemoveCharAttribs(*p, rAttr); 2988 } 2989 2990 void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const 2991 { 2992 const ScFormulaCell* p = FetchFormulaCell(nRow); 2993 if (p) 2994 p->GetFormula(rFormula); 2995 else 2996 rFormula = EMPTY_OUSTRING; 2997 } 2998 2999 const ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) const 3000 { 3001 return FetchFormulaCell(nRow); 3002 } 3003 3004 ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) 3005 { 3006 return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow)); 3007 } 3008 3009 CellType ScColumn::GetCellType( SCROW nRow ) const 3010 { 3011 switch (maCells.get_type(nRow)) 3012 { 3013 case sc::element_type_numeric: 3014 return CELLTYPE_VALUE; 3015 case sc::element_type_string: 3016 return CELLTYPE_STRING; 3017 case sc::element_type_edittext: 3018 return CELLTYPE_EDIT; 3019 case sc::element_type_formula: 3020 return CELLTYPE_FORMULA; 3021 default: 3022 ; 3023 } 3024 return CELLTYPE_NONE; 3025 } 3026 3027 namespace { 3028 3029 /** 3030 * Count the number of all non-empty cells. 3031 */ 3032 class CellCounter 3033 { 3034 size_t mnCount; 3035 public: 3036 CellCounter() : mnCount(0) {} 3037 3038 void operator() (const sc::CellStoreType::value_type& node) 3039 { 3040 if (node.type == sc::element_type_empty) 3041 return; 3042 3043 mnCount += node.size; 3044 } 3045 3046 size_t getCount() const { return mnCount; } 3047 }; 3048 3049 } 3050 3051 SCSIZE ScColumn::GetCellCount() const 3052 { 3053 CellCounter aFunc; 3054 aFunc = std::for_each(maCells.begin(), maCells.end(), aFunc); 3055 return aFunc.getCount(); 3056 } 3057 3058 FormulaError ScColumn::GetErrCode( SCROW nRow ) const 3059 { 3060 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow); 3061 sc::CellStoreType::const_iterator it = aPos.first; 3062 if (it == maCells.end()) 3063 return FormulaError::NONE; 3064 3065 if (it->type != sc::element_type_formula) 3066 return FormulaError::NONE; 3067 3068 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second); 3069 return const_cast<ScFormulaCell*>(p)->GetErrCode(); 3070 } 3071 3072 bool ScColumn::HasStringData( SCROW nRow ) const 3073 { 3074 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow); 3075 switch (aPos.first->type) 3076 { 3077 case sc::element_type_string: 3078 case sc::element_type_edittext: 3079 return true; 3080 case sc::element_type_formula: 3081 { 3082 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second); 3083 return !const_cast<ScFormulaCell*>(p)->IsValue(); 3084 } 3085 default: 3086 ; 3087 } 3088 3089 return false; 3090 } 3091 3092 bool ScColumn::HasValueData( SCROW nRow ) const 3093 { 3094 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow); 3095 switch (aPos.first->type) 3096 { 3097 case sc::element_type_numeric: 3098 return true; 3099 case sc::element_type_formula: 3100 { 3101 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second); 3102 return const_cast<ScFormulaCell*>(p)->IsValue(); 3103 } 3104 default: 3105 ; 3106 } 3107 3108 return false; 3109 } 3110 3111 /** 3112 * Return true if there is a string or editcell in the range 3113 */ 3114 bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const 3115 { 3116 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow); 3117 sc::CellStoreType::const_iterator it = aPos.first; 3118 size_t nOffset = aPos.second; 3119 SCROW nRow = nStartRow; 3120 for (; it != maCells.end() && nRow <= nEndRow; ++it) 3121 { 3122 if (it->type == sc::element_type_string || it->type == sc::element_type_edittext) 3123 return true; 3124 3125 nRow += it->size - nOffset; 3126 nOffset = 0; 3127 } 3128 3129 return false; 3130 } 3131 3132 namespace { 3133 3134 class MaxStringLenHandler 3135 { 3136 sal_Int32 mnMaxLen; 3137 const ScColumn& mrColumn; 3138 SvNumberFormatter* mpFormatter; 3139 rtl_TextEncoding meCharSet; 3140 bool mbOctetEncoding; 3141 3142 void processCell(size_t nRow, const ScRefCellValue& rCell) 3143 { 3144 Color* pColor; 3145 OUString aString; 3146 sal_uInt32 nFormat = mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue(); 3147 ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter, mrColumn.GetDoc()); 3148 sal_Int32 nLen = 0; 3149 if (mbOctetEncoding) 3150 { 3151 OString aOString; 3152 if (!aString.convertToString(&aOString, meCharSet, 3153 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | 3154 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) 3155 { 3156 // TODO: anything? this is used by the dBase export filter 3157 // that throws an error anyway, but in case of another 3158 // context we might want to indicate a conversion error 3159 // early. 3160 } 3161 nLen = aOString.getLength(); 3162 } 3163 else 3164 nLen = aString.getLength() * sizeof(sal_Unicode); 3165 3166 if (mnMaxLen < nLen) 3167 mnMaxLen = nLen; 3168 } 3169 3170 public: 3171 MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) : 3172 mnMaxLen(0), 3173 mrColumn(rColumn), 3174 mpFormatter(rColumn.GetDoc()->GetFormatTable()), 3175 meCharSet(eCharSet), 3176 mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet)) 3177 { 3178 } 3179 3180 void operator() (size_t nRow, double fVal) 3181 { 3182 ScRefCellValue aCell(fVal); 3183 processCell(nRow, aCell); 3184 } 3185 3186 void operator() (size_t nRow, const svl::SharedString& rStr) 3187 { 3188 ScRefCellValue aCell(&rStr); 3189 processCell(nRow, aCell); 3190 } 3191 3192 void operator() (size_t nRow, const EditTextObject* p) 3193 { 3194 ScRefCellValue aCell(p); 3195 processCell(nRow, aCell); 3196 } 3197 3198 void operator() (size_t nRow, const ScFormulaCell* p) 3199 { 3200 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p)); 3201 processCell(nRow, aCell); 3202 } 3203 3204 sal_Int32 getMaxLen() const { return mnMaxLen; } 3205 }; 3206 3207 } 3208 3209 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const 3210 { 3211 MaxStringLenHandler aFunc(*this, eCharSet); 3212 sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc); 3213 return aFunc.getMaxLen(); 3214 } 3215 3216 namespace { 3217 3218 class MaxNumStringLenHandler 3219 { 3220 const ScColumn& mrColumn; 3221 SvNumberFormatter* mpFormatter; 3222 sal_Int32 mnMaxLen; 3223 sal_uInt16 mnPrecision; 3224 sal_uInt16 mnMaxGeneralPrecision; 3225 bool mbHaveSigned; 3226 3227 void processCell(size_t nRow, ScRefCellValue& rCell) 3228 { 3229 sal_uInt16 nCellPrecision = mnMaxGeneralPrecision; 3230 if (rCell.meType == CELLTYPE_FORMULA) 3231 { 3232 if (!rCell.mpFormula->IsValue()) 3233 return; 3234 3235 // Limit unformatted formula cell precision to precision 3236 // encountered so far, if any, otherwise we'd end up with 15 just 3237 // because of =1/3 ... If no precision yet then arbitrarily limit 3238 // to a maximum of 4 unless a maximum general precision is set. 3239 if (mnPrecision) 3240 nCellPrecision = mnPrecision; 3241 else 3242 nCellPrecision = (mnMaxGeneralPrecision >= 15) ? 4 : mnMaxGeneralPrecision; 3243 } 3244 3245 double fVal = rCell.getValue(); 3246 if (!mbHaveSigned && fVal < 0.0) 3247 mbHaveSigned = true; 3248 3249 OUString aString; 3250 OUString aSep; 3251 sal_uInt16 nPrec; 3252 sal_uInt32 nFormat = 3253 mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue(); 3254 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) 3255 { 3256 aSep = mpFormatter->GetFormatDecimalSep(nFormat); 3257 ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter, mrColumn.GetDoc()); 3258 const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat); 3259 if (pEntry) 3260 { 3261 bool bThousand, bNegRed; 3262 sal_uInt16 nLeading; 3263 pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading); 3264 } 3265 else 3266 nPrec = mpFormatter->GetFormatPrecision(nFormat); 3267 } 3268 else 3269 { 3270 if (mnPrecision >= mnMaxGeneralPrecision) 3271 return; // early bail out for nothing changes here 3272 3273 if (!fVal) 3274 { 3275 // 0 doesn't change precision, but set a maximum length if none yet. 3276 if (!mnMaxLen) 3277 mnMaxLen = 1; 3278 return; 3279 } 3280 3281 // Simple number string with at most 15 decimals and trailing 3282 // decimal zeros eliminated. 3283 aSep = "."; 3284 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true); 3285 nPrec = SvNumberFormatter::UNLIMITED_PRECISION; 3286 } 3287 3288 sal_Int32 nLen = aString.getLength(); 3289 if (nLen <= 0) 3290 // Ignore empty string. 3291 return; 3292 3293 if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && mnPrecision < mnMaxGeneralPrecision) 3294 { 3295 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) 3296 { 3297 // For some reason we couldn't obtain a precision from the 3298 // format, retry with simple number string. 3299 aSep = "."; 3300 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true); 3301 nLen = aString.getLength(); 3302 } 3303 sal_Int32 nSep = aString.indexOf( aSep); 3304 if (nSep != -1) 3305 nPrec = aString.getLength() - nSep - 1; 3306 3307 } 3308 3309 if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision) 3310 mnPrecision = nPrec; 3311 3312 if (mnPrecision) 3313 { // less than mnPrecision in string => widen it 3314 // more => shorten it 3315 sal_Int32 nTmp = aString.indexOf(aSep); 3316 if ( nTmp == -1 ) 3317 nLen += mnPrecision + aSep.getLength(); 3318 else 3319 { 3320 nTmp = aString.getLength() - (nTmp + aSep.getLength()); 3321 if (nTmp != mnPrecision) 3322 nLen += mnPrecision - nTmp; 3323 // nPrecision > nTmp : nLen + Diff 3324 // nPrecision < nTmp : nLen - Diff 3325 } 3326 } 3327 3328 // Enlarge for sign if necessary. Bear in mind that 3329 // GetMaxNumberStringLen() is for determining dBase decimal field width 3330 // and precision where the overall field width must include the sign. 3331 // Fitting -1 into "#.##" (width 4, 2 decimals) does not work. 3332 if (mbHaveSigned && fVal >= 0.0) 3333 ++nLen; 3334 3335 if (mnMaxLen < nLen) 3336 mnMaxLen = nLen; 3337 } 3338 3339 public: 3340 MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nMaxGeneralPrecision) : 3341 mrColumn(rColumn), mpFormatter(rColumn.GetDoc()->GetFormatTable()), 3342 mnMaxLen(0), mnPrecision(0), mnMaxGeneralPrecision(nMaxGeneralPrecision), 3343 mbHaveSigned(false) 3344 { 3345 // Limit the decimals passed to doubleToUString(). 3346 // Also, the dBaseIII maximum precision is 15. 3347 if (mnMaxGeneralPrecision > 15) 3348 mnMaxGeneralPrecision = 15; 3349 } 3350 3351 void operator() (size_t nRow, double fVal) 3352 { 3353 ScRefCellValue aCell(fVal); 3354 processCell(nRow, aCell); 3355 } 3356 3357 void operator() (size_t nRow, const ScFormulaCell* p) 3358 { 3359 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p)); 3360 processCell(nRow, aCell); 3361 } 3362 3363 sal_Int32 getMaxLen() const { return mnMaxLen; } 3364 3365 sal_uInt16 getPrecision() const { return mnPrecision; } 3366 }; 3367 3368 } 3369 3370 sal_Int32 ScColumn::GetMaxNumberStringLen( 3371 sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const 3372 { 3373 sal_uInt16 nMaxGeneralPrecision = GetDoc()->GetDocOptions().GetStdPrecision(); 3374 MaxNumStringLenHandler aFunc(*this, nMaxGeneralPrecision); 3375 sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc); 3376 nPrecision = aFunc.getPrecision(); 3377 return aFunc.getMaxLen(); 3378 } 3379 3380 namespace { 3381 3382 class GroupFormulaCells 3383 { 3384 std::vector<ScAddress>* mpGroupPos; 3385 3386 public: 3387 explicit GroupFormulaCells(std::vector<ScAddress>* pGroupPos) 3388 : mpGroupPos(pGroupPos) {} 3389 3390 void operator() (sc::CellStoreType::value_type& node) 3391 { 3392 if (node.type != sc::element_type_formula) 3393 // We are only interested in formula cells. 3394 return; 3395 3396 size_t nRow = node.position; // start row position. 3397 3398 sc::formula_block::iterator it = sc::formula_block::begin(*node.data); 3399 sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data); 3400 3401 // This block should never be empty. 3402 3403 ScFormulaCell* pPrev = *it; 3404 ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup(); 3405 if (xPrevGrp) 3406 { 3407 // Move to the cell after the last cell of the current group. 3408 std::advance(it, xPrevGrp->mnLength); 3409 nRow += xPrevGrp->mnLength; 3410 } 3411 else 3412 { 3413 ++it; 3414 ++nRow; 3415 } 3416 3417 ScFormulaCell* pCur = nullptr; 3418 ScFormulaCellGroupRef xCurGrp; 3419 for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp) 3420 { 3421 pCur = *it; 3422 xCurGrp = pCur->GetCellGroup(); 3423 3424 ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur); 3425 if (eCompState == ScFormulaCell::NotEqual) 3426 { 3427 // different formula tokens. 3428 if (xCurGrp) 3429 { 3430 // Move to the cell after the last cell of the current group. 3431 if (xCurGrp->mnLength > std::distance(it, itEnd)) 3432 throw css::lang::IllegalArgumentException(); 3433 std::advance(it, xCurGrp->mnLength); 3434 nRow += xCurGrp->mnLength; 3435 } 3436 else 3437 { 3438 ++it; 3439 ++nRow; 3440 } 3441 3442 continue; 3443 } 3444 3445 // Formula tokens equal those of the previous formula cell or cell group. 3446 if (xPrevGrp) 3447 { 3448 // Previous cell is a group. 3449 if (xCurGrp) 3450 { 3451 // The current cell is a group. Merge these two groups. 3452 xPrevGrp->mnLength += xCurGrp->mnLength; 3453 pCur->SetCellGroup(xPrevGrp); 3454 sc::formula_block::iterator itGrpEnd = it; 3455 if (xCurGrp->mnLength > std::distance(itGrpEnd, itEnd)) 3456 throw css::lang::IllegalArgumentException(); 3457 std::advance(itGrpEnd, xCurGrp->mnLength); 3458 for (++it; it != itGrpEnd; ++it) 3459 { 3460 ScFormulaCell* pCell = *it; 3461 pCell->SetCellGroup(xPrevGrp); 3462 } 3463 nRow += xCurGrp->mnLength; 3464 } 3465 else 3466 { 3467 // Add this cell to the previous group. 3468 pCur->SetCellGroup(xPrevGrp); 3469 ++xPrevGrp->mnLength; 3470 ++nRow; 3471 ++it; 3472 } 3473 3474 } 3475 else if (xCurGrp) 3476 { 3477 // Previous cell is a regular cell and current cell is a group. 3478 nRow += xCurGrp->mnLength; 3479 if (xCurGrp->mnLength > std::distance(it, itEnd)) 3480 throw css::lang::IllegalArgumentException(); 3481 std::advance(it, xCurGrp->mnLength); 3482 pPrev->SetCellGroup(xCurGrp); 3483 xCurGrp->mpTopCell = pPrev; 3484 ++xCurGrp->mnLength; 3485 xPrevGrp = xCurGrp; 3486 } 3487 else 3488 { 3489 // Both previous and current cells are regular cells. 3490 assert(pPrev->aPos.Row() == static_cast<SCROW>(nRow - 1)); 3491 xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant); 3492 pCur->SetCellGroup(xPrevGrp); 3493 ++nRow; 3494 ++it; 3495 } 3496 3497 if (mpGroupPos) 3498 mpGroupPos->push_back(pCur->aPos); 3499 3500 pCur = pPrev; 3501 xCurGrp = xPrevGrp; 3502 } 3503 } 3504 }; 3505 3506 } 3507 3508 void ScColumn::RegroupFormulaCells( std::vector<ScAddress>* pGroupPos ) 3509 { 3510 // re-build formula groups. 3511 std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells(pGroupPos)); 3512 } 3513 3514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 3515
