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