1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 // INCLUDE --------------------------------------------------------------- 27 28 29 30 #include <sfx2/objsh.hxx> 31 #include <svl/zforlist.hxx> 32 #include <svl/zformat.hxx> 33 34 #include "boost/tuple/tuple.hpp" 35 #include <boost/function.hpp> 36 #include "boost/lambda/bind.hpp" 37 #include "boost/bind.hpp" 38 #include "boost/lambda/lambda.hpp" 39 #include "scitems.hxx" 40 #include "column.hxx" 41 #include "cell.hxx" 42 #include "document.hxx" 43 #include "attarray.hxx" 44 #include "patattr.hxx" 45 #include "cellform.hxx" 46 #include "collect.hxx" 47 #include "formula/errorcodes.hxx" 48 #include "formula/token.hxx" 49 #include "brdcst.hxx" 50 #include "docoptio.hxx" // GetStdPrecision fuer GetMaxNumberStringLen 51 #include "subtotal.hxx" 52 #include "markdata.hxx" 53 #include "detfunc.hxx" // fuer Notizen bei DeleteRange 54 #include "postit.hxx" 55 #include "stringutil.hxx" 56 #include "dpglobal.hxx" 57 #include <dptablecache.hxx> 58 #include <com/sun/star/i18n/LocaleDataItem.hpp> 59 using ::com::sun::star::i18n::LocaleDataItem; 60 using ::rtl::OUString; 61 using ::rtl::OUStringBuffer; 62 63 // Err527 Workaround 64 extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx 65 using namespace formula; 66 // STATIC DATA ----------------------------------------------------------- 67 68 sal_Bool ScColumn::bDoubleAlloc = sal_False; // fuer Import: Groesse beim Allozieren verdoppeln 69 70 71 void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell ) 72 { 73 sal_Bool bIsAppended = sal_False; 74 if (pItems && nCount>0) 75 { 76 if (pItems[nCount-1].nRow < nRow) 77 { 78 Append(nRow, pNewCell ); 79 bIsAppended = sal_True; 80 } 81 } 82 if ( !bIsAppended ) 83 { 84 SCSIZE nIndex; 85 if (Search(nRow, nIndex)) 86 { 87 ScBaseCell* pOldCell = pItems[nIndex].pCell; 88 89 // move broadcaster and note to new cell, if not existing in new cell 90 if (pOldCell->HasBroadcaster() && !pNewCell->HasBroadcaster()) 91 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() ); 92 if (pOldCell->HasNote() && !pNewCell->HasNote()) 93 pNewCell->TakeNote( pOldCell->ReleaseNote() ); 94 95 if ( pOldCell->GetCellType() == CELLTYPE_FORMULA && !pDocument->IsClipOrUndo() ) 96 { 97 pOldCell->EndListeningTo( pDocument ); 98 // falls in EndListening NoteCell in gleicher Col zerstoert 99 if ( nIndex >= nCount || pItems[nIndex].nRow != nRow ) 100 Search(nRow, nIndex); 101 } 102 pOldCell->Delete(); 103 pItems[nIndex].pCell = pNewCell; 104 } 105 else 106 { 107 if (nCount + 1 > nLimit) 108 { 109 if (bDoubleAlloc) 110 { 111 if (nLimit < COLUMN_DELTA) 112 nLimit = COLUMN_DELTA; 113 else 114 { 115 nLimit *= 2; 116 if ( nLimit > sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) 117 nLimit = MAXROWCOUNT; 118 } 119 } 120 else 121 nLimit += COLUMN_DELTA; 122 123 ColEntry* pNewItems = new ColEntry[nLimit]; 124 if (pItems) 125 { 126 memmove( pNewItems, pItems, nCount * sizeof(ColEntry) ); 127 delete[] pItems; 128 } 129 pItems = pNewItems; 130 } 131 memmove( &pItems[nIndex + 1], &pItems[nIndex], (nCount - nIndex) * sizeof(ColEntry) ); 132 pItems[nIndex].pCell = pNewCell; 133 pItems[nIndex].nRow = nRow; 134 ++nCount; 135 } 136 } 137 // Bei aus Clipboard sind hier noch falsche (alte) Referenzen! 138 // Werden in CopyBlockFromClip per UpdateReference umgesetzt, 139 // danach StartListeningFromClip und BroadcastFromClip gerufen. 140 // Wird ins Clipboard/UndoDoc gestellt, wird kein Broadcast gebraucht. 141 // Nach Import wird CalcAfterLoad gerufen, dort Listening. 142 if ( !(pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) ) 143 { 144 pNewCell->StartListeningTo( pDocument ); 145 CellType eCellType = pNewCell->GetCellType(); 146 // Notizzelle entsteht beim Laden nur durch StartListeningCell, 147 // ausloesende Formelzelle muss sowieso dirty sein. 148 if ( !(pDocument->IsCalcingAfterLoad() && eCellType == CELLTYPE_NOTE) ) 149 { 150 if ( eCellType == CELLTYPE_FORMULA ) 151 ((ScFormulaCell*)pNewCell)->SetDirty(); 152 else 153 pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, 154 ScAddress( nCol, nRow, nTab ), pNewCell ) ); 155 } 156 } 157 } 158 159 160 void ScColumn::Insert( SCROW nRow, sal_uLong nNumberFormat, ScBaseCell* pCell ) 161 { 162 Insert(nRow, pCell); 163 short eOldType = pDocument->GetFormatTable()-> 164 GetType( (sal_uLong) 165 ((SfxUInt32Item*)GetAttr( nRow, ATTR_VALUE_FORMAT ))-> 166 GetValue() ); 167 short eNewType = pDocument->GetFormatTable()->GetType(nNumberFormat); 168 if (!pDocument->GetFormatTable()->IsCompatible(eOldType, eNewType)) 169 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, (sal_uInt32) nNumberFormat) ); 170 } 171 172 173 void ScColumn::Append( SCROW nRow, ScBaseCell* pCell ) 174 { 175 if (nCount + 1 > nLimit) 176 { 177 if (bDoubleAlloc) 178 { 179 if (nLimit < COLUMN_DELTA) 180 nLimit = COLUMN_DELTA; 181 else 182 { 183 nLimit *= 2; 184 if ( nLimit > sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) 185 nLimit = MAXROWCOUNT; 186 } 187 } 188 else 189 nLimit += COLUMN_DELTA; 190 191 ColEntry* pNewItems = new ColEntry[nLimit]; 192 if (pItems) 193 { 194 memmove( pNewItems, pItems, nCount * sizeof(ColEntry) ); 195 delete[] pItems; 196 } 197 pItems = pNewItems; 198 } 199 pItems[nCount].pCell = pCell; 200 pItems[nCount].nRow = nRow; 201 ++nCount; 202 } 203 204 205 void ScColumn::Delete( SCROW nRow ) 206 { 207 SCSIZE nIndex; 208 209 if (Search(nRow, nIndex)) 210 { 211 ScBaseCell* pCell = pItems[nIndex].pCell; 212 ScNoteCell* pNoteCell = new ScNoteCell; 213 pItems[nIndex].pCell = pNoteCell; // Dummy fuer Interpret 214 pDocument->Broadcast( ScHint( SC_HINT_DYING, 215 ScAddress( nCol, nRow, nTab ), pCell ) ); 216 if ( SvtBroadcaster* pBC = pCell->ReleaseBroadcaster() ) 217 { 218 pNoteCell->TakeBroadcaster( pBC ); 219 } 220 else 221 { 222 delete pNoteCell; 223 --nCount; 224 memmove( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ColEntry) ); 225 pItems[nCount].nRow = 0; 226 pItems[nCount].pCell = NULL; 227 // Soll man hier den Speicher freigeben (delta)? Wird dann langsamer! 228 } 229 pCell->EndListeningTo( pDocument ); 230 pCell->Delete(); 231 } 232 } 233 234 235 void ScColumn::DeleteAtIndex( SCSIZE nIndex ) 236 { 237 ScBaseCell* pCell = pItems[nIndex].pCell; 238 ScNoteCell* pNoteCell = new ScNoteCell; 239 pItems[nIndex].pCell = pNoteCell; // Dummy fuer Interpret 240 pDocument->Broadcast( ScHint( SC_HINT_DYING, 241 ScAddress( nCol, pItems[nIndex].nRow, nTab ), pCell ) ); 242 delete pNoteCell; 243 --nCount; 244 memmove( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ColEntry) ); 245 pItems[nCount].nRow = 0; 246 pItems[nCount].pCell = NULL; 247 pCell->EndListeningTo( pDocument ); 248 pCell->Delete(); 249 } 250 251 252 void ScColumn::FreeAll() 253 { 254 if (pItems) 255 { 256 for (SCSIZE i = 0; i < nCount; i++) 257 pItems[i].pCell->Delete(); 258 delete[] pItems; 259 pItems = NULL; 260 } 261 nCount = 0; 262 nLimit = 0; 263 } 264 265 266 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize ) 267 { 268 pAttrArray->DeleteRow( nStartRow, nSize ); 269 270 if ( !pItems || !nCount ) 271 return ; 272 273 SCSIZE nFirstIndex; 274 Search( nStartRow, nFirstIndex ); 275 if ( nFirstIndex >= nCount ) 276 return ; 277 278 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 279 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden 280 281 sal_Bool bFound=sal_False; 282 SCROW nEndRow = nStartRow + nSize - 1; 283 SCSIZE nStartIndex = 0; 284 SCSIZE nEndIndex = 0; 285 SCSIZE i; 286 287 for ( i = nFirstIndex; i < nCount && pItems[i].nRow <= nEndRow; i++ ) 288 { 289 if (!bFound) 290 { 291 nStartIndex = i; 292 bFound = sal_True; 293 } 294 nEndIndex = i; 295 296 ScBaseCell* pCell = pItems[i].pCell; 297 SvtBroadcaster* pBC = pCell->GetBroadcaster(); 298 if (pBC) 299 { 300 // gibt jetzt invalid reference, kein Aufruecken der direkten Referenzen 301 // MoveListeners( *pBC, nRow+nSize ); 302 pCell->DeleteBroadcaster(); 303 // in DeleteRange werden leere Broadcaster geloescht 304 } 305 } 306 if (bFound) 307 { 308 DeleteRange( nStartIndex, nEndIndex, IDF_CONTENTS ); 309 Search( nStartRow, i ); 310 if ( i >= nCount ) 311 { 312 pDocument->SetAutoCalc( bOldAutoCalc ); 313 return ; 314 } 315 } 316 else 317 i = nFirstIndex; 318 319 ScAddress aAdr( nCol, 0, nTab ); 320 ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL ); // only areas (ScBaseCell* == NULL) 321 ScAddress& rAddress = aHint.GetAddress(); 322 // for sparse occupation use single broadcasts, not ranges 323 sal_Bool bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) / 324 (nCount - i)) > 1); 325 if ( bSingleBroadcasts ) 326 { 327 SCROW nLastBroadcast = MAXROW+1; 328 for ( ; i < nCount; i++ ) 329 { 330 SCROW nOldRow = pItems[i].nRow; 331 // #43940# Aenderung Quelle broadcasten 332 rAddress.SetRow( nOldRow ); 333 pDocument->AreaBroadcast( aHint ); 334 SCROW nNewRow = (pItems[i].nRow -= nSize); 335 // #43940# Aenderung Ziel broadcasten 336 if ( nLastBroadcast != nNewRow ) 337 { // direkt aufeinanderfolgende nicht doppelt broadcasten 338 rAddress.SetRow( nNewRow ); 339 pDocument->AreaBroadcast( aHint ); 340 } 341 nLastBroadcast = nOldRow; 342 ScBaseCell* pCell = pItems[i].pCell; 343 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 344 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow ); 345 } 346 } 347 else 348 { 349 rAddress.SetRow( pItems[i].nRow ); 350 ScRange aRange( rAddress ); 351 aRange.aEnd.SetRow( pItems[nCount-1].nRow ); 352 for ( ; i < nCount; i++ ) 353 { 354 SCROW nNewRow = (pItems[i].nRow -= nSize); 355 ScBaseCell* pCell = pItems[i].pCell; 356 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 357 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow ); 358 } 359 pDocument->AreaBroadcastInRange( aRange, aHint ); 360 } 361 362 pDocument->SetAutoCalc( bOldAutoCalc ); 363 } 364 365 366 void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDelFlag ) 367 { 368 /* If caller specifies to not remove the note caption objects, all cells 369 have to forget the pointers to them. This is used e.g. while undoing a 370 "paste cells" operation, which removes the caption objects later in 371 drawing undo. */ 372 bool bDeleteNote = (nDelFlag & IDF_NOTE) != 0; 373 bool bNoCaptions = (nDelFlag & IDF_NOCAPTIONS) != 0; 374 if (bDeleteNote && bNoCaptions) 375 for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx ) 376 if ( ScPostIt* pNote = pItems[ nIdx ].pCell->GetNote() ) 377 pNote->ForgetCaption(); 378 379 // special simple mode if all contents are deleted and cells do not contain broadcasters 380 bool bSimple = ((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS); 381 if (bSimple) 382 for ( SCSIZE nIdx = nStartIndex; bSimple && (nIdx <= nEndIndex); ++nIdx ) 383 if (pItems[ nIdx ].pCell->GetBroadcaster()) 384 bSimple = false; 385 386 ScHint aHint( SC_HINT_DYING, ScAddress( nCol, 0, nTab ), 0 ); 387 388 // cache all formula cells, they will be deleted at end of this function 389 typedef ::std::vector< ScFormulaCell* > FormulaCellVector; 390 FormulaCellVector aDelCells; 391 aDelCells.reserve( nEndIndex - nStartIndex + 1 ); 392 393 // simple deletion of the cell objects 394 if (bSimple) 395 { 396 // pNoteCell: dummy replacement for old cells, to prevent that interpreter uses old cell 397 ScNoteCell* pNoteCell = new ScNoteCell; 398 for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx ) 399 { 400 ScBaseCell* pOldCell = pItems[ nIdx ].pCell; 401 if (pOldCell->GetCellType() == CELLTYPE_FORMULA) 402 { 403 // cache formula cell, will be deleted below 404 aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) ); 405 } 406 else 407 { 408 // interpret in broadcast must not use the old cell 409 pItems[ nIdx ].pCell = pNoteCell; 410 aHint.GetAddress().SetRow( pItems[ nIdx ].nRow ); 411 aHint.SetCell( pOldCell ); 412 pDocument->Broadcast( aHint ); 413 pOldCell->Delete(); 414 } 415 } 416 delete pNoteCell; 417 memmove( &pItems[nStartIndex], &pItems[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ColEntry) ); 418 nCount -= nEndIndex-nStartIndex+1; 419 } 420 421 // else: delete some contents of the cells 422 else 423 { 424 SCSIZE j = nStartIndex; 425 for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx ) 426 { 427 // decide whether to delete the cell object according to passed flags 428 bool bDelete = false; 429 ScBaseCell* pOldCell = pItems[j].pCell; 430 CellType eCellType = pOldCell->GetCellType(); 431 switch ( eCellType ) 432 { 433 case CELLTYPE_VALUE: 434 { 435 sal_uInt16 nValFlags = nDelFlag & (IDF_DATETIME|IDF_VALUE); 436 // delete values and dates? 437 bDelete = nValFlags == (IDF_DATETIME|IDF_VALUE); 438 // if not, decide according to cell number format 439 if( !bDelete && (nValFlags != 0) ) 440 { 441 sal_uLong nIndex = (sal_uLong)((SfxUInt32Item*)GetAttr( pItems[j].nRow, ATTR_VALUE_FORMAT ))->GetValue(); 442 short nType = pDocument->GetFormatTable()->GetType(nIndex); 443 bool bIsDate = (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME); 444 bDelete = nValFlags == (bIsDate ? IDF_DATETIME : IDF_VALUE); 445 } 446 } 447 break; 448 449 case CELLTYPE_STRING: 450 case CELLTYPE_EDIT: 451 bDelete = (nDelFlag & IDF_STRING) != 0; 452 break; 453 454 case CELLTYPE_FORMULA: 455 bDelete = (nDelFlag & IDF_FORMULA) != 0; 456 break; 457 458 case CELLTYPE_NOTE: 459 // do note delete note cell with broadcaster 460 bDelete = bDeleteNote && !pOldCell->GetBroadcaster(); 461 break; 462 463 default:; // added to avoid warnings 464 } 465 466 if (bDelete) 467 { 468 // try to create a replacement note cell, if note or broadcaster exists 469 ScNoteCell* pNoteCell = 0; 470 if (eCellType != CELLTYPE_NOTE) 471 { 472 // do not rescue note if it has to be deleted according to passed flags 473 ScPostIt* pNote = bDeleteNote ? 0 : pOldCell->ReleaseNote(); 474 // #i99844# do not release broadcaster from old cell, it still has to notify deleted content 475 SvtBroadcaster* pBC = pOldCell->GetBroadcaster(); 476 if( pNote || pBC ) 477 pNoteCell = new ScNoteCell( pNote, pBC ); 478 } 479 480 // remove cell entry in cell item list 481 SCROW nOldRow = pItems[j].nRow; 482 if (pNoteCell) 483 { 484 // replace old cell with the replacement note cell 485 pItems[j].pCell = pNoteCell; 486 ++j; 487 } 488 else 489 { 490 // remove the old cell from the cell item list 491 --nCount; 492 memmove( &pItems[j], &pItems[j + 1], (nCount - j) * sizeof(ColEntry) ); 493 pItems[nCount].nRow = 0; 494 pItems[nCount].pCell = 0; 495 } 496 497 // cache formula cells (will be deleted later), delete cell of other type 498 if (eCellType == CELLTYPE_FORMULA) 499 { 500 aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) ); 501 } 502 else 503 { 504 aHint.GetAddress().SetRow( nOldRow ); 505 aHint.SetCell( pOldCell ); 506 pDocument->Broadcast( aHint ); 507 // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by pNoteCell) 508 pOldCell->ReleaseBroadcaster(); 509 pOldCell->Delete(); 510 } 511 } 512 else 513 { 514 // delete cell note 515 if (bDeleteNote) 516 pItems[j].pCell->DeleteNote(); 517 // cell not deleted, move index to next cell 518 ++j; 519 } 520 } 521 } 522 523 // *** delete all formula cells *** 524 525 // first, all cells stop listening, may save unneeded recalcualtions 526 for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt ) 527 (*aIt)->EndListeningTo( pDocument ); 528 529 // #i101869# if the note cell with the broadcaster was deleted in EndListening, 530 // forget the pointer to the broadcaster 531 for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt ) 532 { 533 SCSIZE nIndex; 534 if ( !Search( (*aIt)->aPos.Row(), nIndex ) ) 535 (*aIt)->ReleaseBroadcaster(); 536 } 537 538 // broadcast SC_HINT_DYING for all cells and delete them 539 for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt ) 540 { 541 aHint.SetAddress( (*aIt)->aPos ); 542 aHint.SetCell( *aIt ); 543 pDocument->Broadcast( aHint ); 544 // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by replacement note cell) 545 (*aIt)->ReleaseBroadcaster(); 546 (*aIt)->Delete(); 547 } 548 } 549 550 551 void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag) 552 { 553 // FreeAll darf hier nicht gerufen werden wegen Broadcastern 554 555 // Attribute erst am Ende, damit vorher noch zwischen Zahlen und Datum 556 // unterschieden werden kann (#47901#) 557 558 sal_uInt16 nContMask = IDF_CONTENTS; 559 // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set 560 if( nDelFlag & IDF_NOTE ) 561 nContMask |= IDF_NOCAPTIONS; 562 sal_uInt16 nContFlag = nDelFlag & nContMask; 563 564 if (pItems && nCount>0 && nContFlag) 565 { 566 if (nStartRow==0 && nEndRow==MAXROW) 567 DeleteRange( 0, nCount-1, nContFlag ); 568 else 569 { 570 sal_Bool bFound=sal_False; 571 SCSIZE nStartIndex = 0; 572 SCSIZE nEndIndex = 0; 573 for (SCSIZE i = 0; i < nCount; i++) 574 if ((pItems[i].nRow >= nStartRow) && (pItems[i].nRow <= nEndRow)) 575 { 576 if (!bFound) 577 { 578 nStartIndex = i; 579 bFound = sal_True; 580 } 581 nEndIndex = i; 582 } 583 if (bFound) 584 DeleteRange( nStartIndex, nEndIndex, nContFlag ); 585 } 586 } 587 588 if ( nDelFlag & IDF_EDITATTR ) 589 { 590 DBG_ASSERT( nContFlag == 0, "DeleteArea: falsche Flags" ); 591 RemoveEditAttribs( nStartRow, nEndRow ); 592 } 593 594 // Attribute erst hier 595 if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow ); 596 else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow ); 597 } 598 599 600 ScFormulaCell* ScColumn::CreateRefCell( ScDocument* pDestDoc, const ScAddress& rDestPos, 601 SCSIZE nIndex, sal_uInt16 nFlags ) const 602 { 603 sal_uInt16 nContFlags = nFlags & IDF_CONTENTS; 604 if (!nContFlags) 605 return NULL; 606 607 // Testen, ob Zelle kopiert werden soll 608 // auch bei IDF_CONTENTS komplett, wegen Notes / Broadcastern 609 610 sal_Bool bMatch = sal_False; 611 ScBaseCell* pCell = pItems[nIndex].pCell; 612 CellType eCellType = pCell->GetCellType(); 613 switch ( eCellType ) 614 { 615 case CELLTYPE_VALUE: 616 { 617 sal_uInt16 nValFlags = nFlags & (IDF_DATETIME|IDF_VALUE); 618 619 if ( nValFlags == (IDF_DATETIME|IDF_VALUE) ) 620 bMatch = sal_True; 621 else if ( nValFlags ) 622 { 623 sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)GetAttr( 624 pItems[nIndex].nRow, ATTR_VALUE_FORMAT ))->GetValue(); 625 short nTyp = pDocument->GetFormatTable()->GetType(nNumIndex); 626 if ((nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME)) 627 bMatch = ((nFlags & IDF_DATETIME) != 0); 628 else 629 bMatch = ((nFlags & IDF_VALUE) != 0); 630 } 631 } 632 break; 633 case CELLTYPE_STRING: 634 case CELLTYPE_EDIT: bMatch = ((nFlags & IDF_STRING) != 0); break; 635 case CELLTYPE_FORMULA: bMatch = ((nFlags & IDF_FORMULA) != 0); break; 636 default: 637 { 638 // added to avoid warnings 639 } 640 } 641 if (!bMatch) 642 return NULL; 643 644 645 // Referenz einsetzen 646 ScSingleRefData aRef; 647 aRef.nCol = nCol; 648 aRef.nRow = pItems[nIndex].nRow; 649 aRef.nTab = nTab; 650 aRef.InitFlags(); // -> alles absolut 651 aRef.SetFlag3D(sal_True); 652 653 //! 3D(sal_False) und TabRel(sal_True), wenn die endgueltige Position auf der selben Tabelle ist? 654 //! (bei TransposeClip ist die Zielposition noch nicht bekannt) 655 656 aRef.CalcRelFromAbs( rDestPos ); 657 658 ScTokenArray aArr; 659 aArr.AddSingleReference( aRef ); 660 661 return new ScFormulaCell( pDestDoc, rDestPos, &aArr ); 662 } 663 664 665 // rColumn = Quelle 666 // nRow1, nRow2 = Zielposition 667 668 void ScColumn::CopyFromClip(SCROW nRow1, SCROW nRow2, long nDy, 669 sal_uInt16 nInsFlag, sal_Bool bAsLink, sal_Bool bSkipAttrForEmpty, 670 ScColumn& rColumn) 671 { 672 if ((nInsFlag & IDF_ATTRIB) != 0) 673 { 674 if ( bSkipAttrForEmpty ) 675 { 676 // copy only attributes for non-empty cells 677 // (notes are not counted as non-empty here, to match the content behavior) 678 679 SCSIZE nStartIndex; 680 rColumn.Search( nRow1-nDy, nStartIndex ); 681 while ( nStartIndex < rColumn.nCount && rColumn.pItems[nStartIndex].nRow <= nRow2-nDy ) 682 { 683 SCSIZE nEndIndex = nStartIndex; 684 if ( rColumn.pItems[nStartIndex].pCell->GetCellType() != CELLTYPE_NOTE ) 685 { 686 SCROW nStartRow = rColumn.pItems[nStartIndex].nRow; 687 SCROW nEndRow = nStartRow; 688 689 // find consecutive non-empty cells 690 691 while ( nEndRow < nRow2-nDy && 692 nEndIndex+1 < rColumn.nCount && 693 rColumn.pItems[nEndIndex+1].nRow == nEndRow+1 && 694 rColumn.pItems[nEndIndex+1].pCell->GetCellType() != CELLTYPE_NOTE ) 695 { 696 ++nEndIndex; 697 ++nEndRow; 698 } 699 700 rColumn.pAttrArray->CopyAreaSafe( nStartRow+nDy, nEndRow+nDy, nDy, *pAttrArray ); 701 } 702 nStartIndex = nEndIndex + 1; 703 } 704 } 705 else 706 rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray ); 707 } 708 if ((nInsFlag & IDF_CONTENTS) == 0) 709 return; 710 711 if ( bAsLink && nInsFlag == IDF_ALL ) 712 { 713 // bei "alles" werden auch leere Zellen referenziert 714 //! IDF_ALL muss immer mehr Flags enthalten, als bei "Inhalte Einfuegen" 715 //! einzeln ausgewaehlt werden koennen! 716 717 Resize( nCount + static_cast<SCSIZE>(nRow2-nRow1+1) ); 718 719 ScAddress aDestPos( nCol, 0, nTab ); // Row wird angepasst 720 721 // Referenz erzeugen (Quell-Position) 722 ScSingleRefData aRef; 723 aRef.nCol = rColumn.nCol; 724 // nRow wird angepasst 725 aRef.nTab = rColumn.nTab; 726 aRef.InitFlags(); // -> alles absolut 727 aRef.SetFlag3D(sal_True); 728 729 for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++) 730 { 731 aRef.nRow = nDestRow - nDy; // Quell-Zeile 732 aDestPos.SetRow( nDestRow ); 733 734 aRef.CalcRelFromAbs( aDestPos ); 735 ScTokenArray aArr; 736 aArr.AddSingleReference( aRef ); 737 Insert( nDestRow, new ScFormulaCell( pDocument, aDestPos, &aArr ) ); 738 } 739 740 return; 741 } 742 743 SCSIZE nColCount = rColumn.nCount; 744 745 // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells 746 if ((nInsFlag & ( IDF_CONTENTS & ~IDF_FORMULA )) == ( IDF_CONTENTS & ~IDF_FORMULA ) && nRow2-nRow1 >= 64) 747 { 748 //! Always do the Resize from the outside, where the number of repetitions is known 749 //! (then it can be removed here) 750 751 SCSIZE nNew = nCount + nColCount; 752 if ( nLimit < nNew ) 753 Resize( nNew ); 754 } 755 756 // IDF_ADDNOTES must be passed without other content flags than IDF_NOTE 757 bool bAddNotes = (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES); 758 759 sal_Bool bAtEnd = sal_False; 760 for (SCSIZE i = 0; i < nColCount && !bAtEnd; i++) 761 { 762 SCsROW nDestRow = rColumn.pItems[i].nRow + nDy; 763 if ( nDestRow > (SCsROW) nRow2 ) 764 bAtEnd = sal_True; 765 else if ( nDestRow >= (SCsROW) nRow1 ) 766 { 767 // rows at the beginning may be skipped if filtered rows are left out, 768 // nDestRow may be negative then 769 770 ScAddress aDestPos( nCol, (SCROW)nDestRow, nTab ); 771 772 /* #i102056# Paste from clipboard needs to paste the cell notes in 773 a second pass. This must not overwrite the existing cells 774 already copied to the destination position in the first pass. 775 To indicate this special case, the modifier IDF_ADDNOTES is 776 passed together with IDF_NOTE in nInsFlag. Of course, there is 777 still the need to create a new cell, if there is no cell at the 778 destination position at all. */ 779 ScBaseCell* pAddNoteCell = bAddNotes ? GetCell( aDestPos.Row() ) : 0; 780 if (pAddNoteCell) 781 { 782 // do nothing if source cell does not contain a note 783 const ScBaseCell* pSourceCell = rColumn.pItems[i].pCell; 784 const ScPostIt* pSourceNote = pSourceCell ? pSourceCell->GetNote() : 0; 785 if (pSourceNote) 786 { 787 DBG_ASSERT( !pAddNoteCell->HasNote(), "ScColumn::CopyFromClip - unexpected note at destination cell" ); 788 bool bCloneCaption = (nInsFlag & IDF_NOCAPTIONS) == 0; 789 // #i52342# if caption is cloned, the note must be constructed with the destination document 790 ScAddress aSourcePos( rColumn.nCol, rColumn.pItems[i].nRow, rColumn.nTab ); 791 ScPostIt* pNewNote = pSourceNote->Clone( aSourcePos, *pDocument, aDestPos, bCloneCaption ); 792 pAddNoteCell->TakeNote( pNewNote ); 793 } 794 } 795 else 796 { 797 ScBaseCell* pNewCell = bAsLink ? 798 rColumn.CreateRefCell( pDocument, aDestPos, i, nInsFlag ) : 799 rColumn.CloneCell( i, nInsFlag, *pDocument, aDestPos ); 800 if (pNewCell) 801 Insert( aDestPos.Row(), pNewCell ); 802 } 803 } 804 } 805 } 806 807 808 namespace { 809 810 /** Helper for ScColumn::CloneCell - decides whether to clone a value cell depending on clone flags and number format. */ 811 bool lclCanCloneValue( ScDocument& rDoc, const ScColumn& rCol, SCROW nRow, bool bCloneValue, bool bCloneDateTime ) 812 { 813 // values and dates, or nothing to be cloned -> not needed to check number format 814 if( bCloneValue == bCloneDateTime ) 815 return bCloneValue; 816 817 // check number format of value cell 818 sal_uLong nNumIndex = (sal_uLong)((SfxUInt32Item*)rCol.GetAttr( nRow, ATTR_VALUE_FORMAT ))->GetValue(); 819 short nTyp = rDoc.GetFormatTable()->GetType( nNumIndex ); 820 bool bIsDateTime = (nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME); 821 return bIsDateTime ? bCloneDateTime : bCloneValue; 822 } 823 824 } // namespace 825 826 827 ScBaseCell* ScColumn::CloneCell(SCSIZE nIndex, sal_uInt16 nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos) 828 { 829 bool bCloneValue = (nFlags & IDF_VALUE) != 0; 830 bool bCloneDateTime = (nFlags & IDF_DATETIME) != 0; 831 bool bCloneString = (nFlags & IDF_STRING) != 0; 832 bool bCloneFormula = (nFlags & IDF_FORMULA) != 0; 833 bool bCloneNote = (nFlags & IDF_NOTE) != 0; 834 835 ScBaseCell* pNew = 0; 836 ScBaseCell& rSource = *pItems[nIndex].pCell; 837 switch (rSource.GetCellType()) 838 { 839 case CELLTYPE_NOTE: 840 // note will be cloned below 841 break; 842 843 case CELLTYPE_STRING: 844 case CELLTYPE_EDIT: 845 // note will be cloned below 846 if (bCloneString) 847 pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos ); 848 break; 849 850 case CELLTYPE_VALUE: 851 // note will be cloned below 852 if (lclCanCloneValue( *pDocument, *this, pItems[nIndex].nRow, bCloneValue, bCloneDateTime )) 853 pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos ); 854 break; 855 856 case CELLTYPE_FORMULA: 857 if (bCloneFormula) 858 { 859 // note will be cloned below 860 pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos ); 861 } 862 else if ( (bCloneValue || bCloneDateTime || bCloneString) && !rDestDoc.IsUndo() ) 863 { 864 // #48491# ins Undo-Dokument immer nur die Original-Zelle kopieren, 865 // aus Formeln keine Value/String-Zellen erzeugen 866 ScFormulaCell& rForm = (ScFormulaCell&)rSource; 867 sal_uInt16 nErr = rForm.GetErrCode(); 868 if ( nErr ) 869 { 870 // error codes are cloned with values 871 if (bCloneValue) 872 { 873 ScFormulaCell* pErrCell = new ScFormulaCell( &rDestDoc, rDestPos ); 874 pErrCell->SetErrCode( nErr ); 875 pNew = pErrCell; 876 } 877 } 878 else if (rForm.IsValue()) 879 { 880 if (lclCanCloneValue( *pDocument, *this, pItems[nIndex].nRow, bCloneValue, bCloneDateTime )) 881 { 882 double nVal = rForm.GetValue(); 883 pNew = new ScValueCell(nVal); 884 } 885 } 886 else if (bCloneString) 887 { 888 String aString; 889 rForm.GetString( aString ); 890 // #33224# do not clone empty string 891 if (aString.Len() > 0) 892 { 893 if ( rForm.IsMultilineResult() ) 894 { 895 pNew = new ScEditCell( aString, &rDestDoc ); 896 } 897 else 898 { 899 pNew = new ScStringCell( aString ); 900 } 901 } 902 } 903 } 904 break; 905 906 default: DBG_ERRORFILE( "ScColumn::CloneCell - unknown cell type" ); 907 } 908 909 // clone the cell note 910 if (bCloneNote) 911 { 912 if (ScPostIt* pNote = rSource.GetNote()) 913 { 914 bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == 0; 915 // #i52342# if caption is cloned, the note must be constructed with the destination document 916 ScAddress aOwnPos( nCol, pItems[nIndex].nRow, nTab ); 917 ScPostIt* pNewNote = pNote->Clone( aOwnPos, rDestDoc, rDestPos, bCloneCaption ); 918 if (!pNew) 919 pNew = new ScNoteCell( pNewNote ); 920 else 921 pNew->TakeNote( pNewNote ); 922 } 923 } 924 925 return pNew; 926 } 927 928 929 void ScColumn::MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction, 930 sal_Bool bSkipEmpty, ScColumn& rSrcCol ) 931 { 932 SCROW nRow1, nRow2; 933 934 if (rMark.IsMultiMarked()) 935 { 936 ScMarkArrayIter aIter( rMark.GetArray()+nCol ); 937 while (aIter.Next( nRow1, nRow2 )) 938 MixData( nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol ); 939 } 940 } 941 942 943 // Ergebnis in rVal1 944 945 sal_Bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction ) 946 { 947 sal_Bool bOk = sal_False; 948 switch (nFunction) 949 { 950 case PASTE_ADD: 951 bOk = SubTotal::SafePlus( rVal1, nVal2 ); 952 break; 953 case PASTE_SUB: 954 nVal2 = -nVal2; //! geht das immer ohne Fehler? 955 bOk = SubTotal::SafePlus( rVal1, nVal2 ); 956 break; 957 case PASTE_MUL: 958 bOk = SubTotal::SafeMult( rVal1, nVal2 ); 959 break; 960 case PASTE_DIV: 961 bOk = SubTotal::SafeDiv( rVal1, nVal2 ); 962 break; 963 } 964 return bOk; 965 } 966 967 968 void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell ) 969 { 970 rArr.AddOpCode(ocOpen); 971 972 ScTokenArray* pCode = pCell->GetCode(); 973 if (pCode) 974 { 975 const formula::FormulaToken* pToken = pCode->First(); 976 while (pToken) 977 { 978 rArr.AddToken( *pToken ); 979 pToken = pCode->Next(); 980 } 981 } 982 983 rArr.AddOpCode(ocClose); 984 } 985 986 987 void ScColumn::MixData( SCROW nRow1, SCROW nRow2, 988 sal_uInt16 nFunction, sal_Bool bSkipEmpty, 989 ScColumn& rSrcCol ) 990 { 991 SCSIZE nSrcCount = rSrcCol.nCount; 992 993 SCSIZE nIndex; 994 Search( nRow1, nIndex ); 995 996 // SCSIZE nSrcIndex = 0; 997 SCSIZE nSrcIndex; 998 rSrcCol.Search( nRow1, nSrcIndex ); //! Testen, ob Daten ganz vorne 999 1000 SCROW nNextThis = MAXROW+1; 1001 if ( nIndex < nCount ) 1002 nNextThis = pItems[nIndex].nRow; 1003 SCROW nNextSrc = MAXROW+1; 1004 if ( nSrcIndex < nSrcCount ) 1005 nNextSrc = rSrcCol.pItems[nSrcIndex].nRow; 1006 1007 while ( nNextThis <= nRow2 || nNextSrc <= nRow2 ) 1008 { 1009 SCROW nRow = Min( nNextThis, nNextSrc ); 1010 1011 ScBaseCell* pSrc = NULL; 1012 ScBaseCell* pDest = NULL; 1013 ScBaseCell* pNew = NULL; 1014 sal_Bool bDelete = sal_False; 1015 1016 if ( nSrcIndex < nSrcCount && nNextSrc == nRow ) 1017 pSrc = rSrcCol.pItems[nSrcIndex].pCell; 1018 1019 if ( nIndex < nCount && nNextThis == nRow ) 1020 pDest = pItems[nIndex].pCell; 1021 1022 DBG_ASSERT( pSrc || pDest, "Nanu ?" ); 1023 1024 CellType eSrcType = pSrc ? pSrc->GetCellType() : CELLTYPE_NONE; 1025 CellType eDestType = pDest ? pDest->GetCellType() : CELLTYPE_NONE; 1026 1027 sal_Bool bSrcEmpty = ( eSrcType == CELLTYPE_NONE || eSrcType == CELLTYPE_NOTE ); 1028 sal_Bool bDestEmpty = ( eDestType == CELLTYPE_NONE || eDestType == CELLTYPE_NOTE ); 1029 1030 if ( bSkipEmpty && bDestEmpty ) // Originalzelle wiederherstellen 1031 { 1032 if ( pSrc ) // war da eine Zelle? 1033 { 1034 pNew = pSrc->CloneWithoutNote( *pDocument ); 1035 } 1036 } 1037 else if ( nFunction ) // wirklich Rechenfunktion angegeben 1038 { 1039 double nVal1; 1040 double nVal2; 1041 if ( eSrcType == CELLTYPE_VALUE ) 1042 nVal1 = ((ScValueCell*)pSrc)->GetValue(); 1043 else 1044 nVal1 = 0.0; 1045 if ( eDestType == CELLTYPE_VALUE ) 1046 nVal2 = ((ScValueCell*)pDest)->GetValue(); 1047 else 1048 nVal2 = 0.0; 1049 1050 // leere Zellen werden als Werte behandelt 1051 1052 sal_Bool bSrcVal = ( bSrcEmpty || eSrcType == CELLTYPE_VALUE ); 1053 sal_Bool bDestVal = ( bDestEmpty || eDestType == CELLTYPE_VALUE ); 1054 1055 sal_Bool bSrcText = ( eSrcType == CELLTYPE_STRING || 1056 eSrcType == CELLTYPE_EDIT ); 1057 sal_Bool bDestText = ( eDestType == CELLTYPE_STRING || 1058 eDestType == CELLTYPE_EDIT ); 1059 1060 // sonst bleibt nur Formel... 1061 1062 if ( bSrcEmpty && bDestEmpty ) 1063 { 1064 // beide leer -> nix 1065 } 1066 else if ( bSrcVal && bDestVal ) 1067 { 1068 // neuen Wert eintragen, oder Fehler bei Ueberlauf 1069 1070 sal_Bool bOk = lcl_DoFunction( nVal1, nVal2, nFunction ); 1071 1072 if (bOk) 1073 pNew = new ScValueCell( nVal1 ); 1074 else 1075 { 1076 ScFormulaCell* pFC = new ScFormulaCell( pDocument, 1077 ScAddress( nCol, nRow, nTab ) ); 1078 pFC->SetErrCode( errNoValue ); 1079 //! oder NOVALUE, dann auch in consoli, 1080 //! sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus 1081 //! (dann geht Stringzelle+Wertzelle nicht mehr) 1082 pNew = pFC; 1083 } 1084 } 1085 else if ( bSrcText || bDestText ) 1086 { 1087 // mit Texten wird nicht gerechnet - immer "alte" Zelle, also pSrc 1088 1089 if (pSrc) 1090 pNew = pSrc->CloneWithoutNote( *pDocument ); 1091 else if (pDest) 1092 bDelete = sal_True; 1093 } 1094 else 1095 { 1096 // Kombination aus Wert und mindestens einer Formel -> Formel erzeugen 1097 1098 ScTokenArray aArr; 1099 1100 // erste Zelle 1101 if ( eSrcType == CELLTYPE_FORMULA ) 1102 lcl_AddCode( aArr, (ScFormulaCell*)pSrc ); 1103 else 1104 aArr.AddDouble( nVal1 ); 1105 1106 // Operator 1107 OpCode eOp = ocAdd; 1108 switch ( nFunction ) 1109 { 1110 case PASTE_ADD: eOp = ocAdd; break; 1111 case PASTE_SUB: eOp = ocSub; break; 1112 case PASTE_MUL: eOp = ocMul; break; 1113 case PASTE_DIV: eOp = ocDiv; break; 1114 } 1115 aArr.AddOpCode(eOp); // Funktion 1116 1117 // zweite Zelle 1118 if ( eDestType == CELLTYPE_FORMULA ) 1119 lcl_AddCode( aArr, (ScFormulaCell*)pDest ); 1120 else 1121 aArr.AddDouble( nVal2 ); 1122 1123 pNew = new ScFormulaCell( pDocument, ScAddress( nCol, nRow, nTab ), &aArr ); 1124 } 1125 } 1126 1127 1128 if ( pNew || bDelete ) // neues Ergebnis ? 1129 { 1130 if (pDest && !pNew) // alte Zelle da ? 1131 { 1132 if ( pDest->GetBroadcaster() ) 1133 pNew = new ScNoteCell; // Broadcaster uebernehmen 1134 else 1135 Delete(nRow); // -> loeschen 1136 } 1137 if (pNew) 1138 Insert(nRow, pNew); // neue einfuegen 1139 1140 Search( nRow, nIndex ); // alles kann sich verschoben haben 1141 if (pNew) 1142 nNextThis = nRow; // nIndex zeigt jetzt genau auf nRow 1143 else 1144 nNextThis = ( nIndex < nCount ) ? pItems[nIndex].nRow : MAXROW+1; 1145 } 1146 1147 if ( nNextThis == nRow ) 1148 { 1149 ++nIndex; 1150 nNextThis = ( nIndex < nCount ) ? pItems[nIndex].nRow : MAXROW+1; 1151 } 1152 if ( nNextSrc == nRow ) 1153 { 1154 ++nSrcIndex; 1155 nNextSrc = ( nSrcIndex < nSrcCount ) ? 1156 rSrcCol.pItems[nSrcIndex].nRow : 1157 MAXROW+1; 1158 } 1159 } 1160 } 1161 1162 1163 ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const 1164 { 1165 return new ScAttrIterator( pAttrArray, nStartRow, nEndRow ); 1166 } 1167 1168 1169 void ScColumn::StartAllListeners() 1170 { 1171 if (pItems) 1172 for (SCSIZE i = 0; i < nCount; i++) 1173 { 1174 ScBaseCell* pCell = pItems[i].pCell; 1175 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1176 { 1177 SCROW nRow = pItems[i].nRow; 1178 ((ScFormulaCell*)pCell)->StartListeningTo( pDocument ); 1179 if ( nRow != pItems[i].nRow ) 1180 Search( nRow, i ); // Listener eingefuegt? 1181 } 1182 } 1183 } 1184 1185 1186 void ScColumn::StartNeededListeners() 1187 { 1188 if (pItems) 1189 { 1190 for (SCSIZE i = 0; i < nCount; i++) 1191 { 1192 ScBaseCell* pCell = pItems[i].pCell; 1193 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1194 { 1195 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); 1196 if (pFCell->NeedsListening()) 1197 { 1198 SCROW nRow = pItems[i].nRow; 1199 pFCell->StartListeningTo( pDocument ); 1200 if ( nRow != pItems[i].nRow ) 1201 Search( nRow, i ); // Listener eingefuegt? 1202 } 1203 } 1204 } 1205 } 1206 } 1207 1208 1209 void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 ) 1210 { 1211 if ( pItems ) 1212 { 1213 SCROW nRow; 1214 SCSIZE nIndex; 1215 Search( nRow1, nIndex ); 1216 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 ) 1217 { 1218 ScBaseCell* pCell = pItems[nIndex].pCell; 1219 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1220 ((ScFormulaCell*)pCell)->SetDirty(); 1221 else 1222 pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, 1223 ScAddress( nCol, nRow, nTab ), pCell ) ); 1224 nIndex++; 1225 } 1226 } 1227 } 1228 1229 1230 void ScColumn::StartListeningInArea( SCROW nRow1, SCROW nRow2 ) 1231 { 1232 if ( pItems ) 1233 { 1234 SCROW nRow; 1235 SCSIZE nIndex; 1236 Search( nRow1, nIndex ); 1237 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 ) 1238 { 1239 ScBaseCell* pCell = pItems[nIndex].pCell; 1240 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1241 ((ScFormulaCell*)pCell)->StartListeningTo( pDocument ); 1242 if ( nRow != pItems[nIndex].nRow ) 1243 Search( nRow, nIndex ); // durch Listening eingefuegt 1244 nIndex++; 1245 } 1246 } 1247 } 1248 1249 1250 // sal_True = Zahlformat gesetzt 1251 sal_Bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString, 1252 formula::FormulaGrammar::AddressConvention eConv, 1253 SvNumberFormatter* pLangFormatter, bool bDetectNumberFormat ) 1254 { 1255 sal_Bool bNumFmtSet = sal_False; 1256 if (VALIDROW(nRow)) 1257 { 1258 ScBaseCell* pNewCell = NULL; 1259 sal_Bool bIsLoading = sal_False; 1260 if (rString.Len() > 0) 1261 { 1262 double nVal; 1263 sal_uInt32 nIndex, nOldIndex = 0; 1264 sal_Unicode cFirstChar; 1265 // #i110979# If a different NumberFormatter is passed in (pLangFormatter), 1266 // its formats aren't valid in the document. 1267 // Only use the language / LocaleDataWrapper from pLangFormatter, 1268 // always the document's number formatter for IsNumberFormat. 1269 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 1270 SfxObjectShell* pDocSh = pDocument->GetDocumentShell(); 1271 if ( pDocSh ) 1272 bIsLoading = pDocSh->IsLoading(); 1273 // IsLoading bei ConvertFrom Import 1274 if ( !bIsLoading ) 1275 { 1276 nIndex = nOldIndex = GetNumberFormat( nRow ); 1277 if ( rString.Len() > 1 1278 && pFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT ) 1279 cFirstChar = rString.GetChar(0); 1280 else 1281 cFirstChar = 0; // Text 1282 } 1283 else 1284 { // waehrend ConvertFrom Import gibt es keine gesetzten Formate 1285 cFirstChar = rString.GetChar(0); 1286 } 1287 1288 if ( cFirstChar == '=' ) 1289 { 1290 if ( rString.Len() == 1 ) // = Text 1291 pNewCell = new ScStringCell( rString ); 1292 else // =Formel 1293 pNewCell = new ScFormulaCell( pDocument, 1294 ScAddress( nCol, nRow, nTabP ), rString, 1295 formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT, 1296 eConv), MM_NONE ); 1297 } 1298 else if ( cFirstChar == '\'') // 'Text 1299 pNewCell = new ScStringCell( rString.Copy(1) ); 1300 else 1301 { 1302 sal_Bool bIsText = sal_False; 1303 if ( bIsLoading ) 1304 { 1305 if ( pItems && nCount ) 1306 { 1307 String aStr; 1308 SCSIZE i = nCount; 1309 SCSIZE nStop = (i >= 3 ? i - 3 : 0); 1310 // die letzten Zellen vergleichen, ob gleicher String 1311 // und IsNumberFormat eingespart werden kann 1312 do 1313 { 1314 i--; 1315 ScBaseCell* pCell = pItems[i].pCell; 1316 switch ( pCell->GetCellType() ) 1317 { 1318 case CELLTYPE_STRING : 1319 ((ScStringCell*)pCell)->GetString( aStr ); 1320 if ( rString == aStr ) 1321 bIsText = sal_True; 1322 break; 1323 case CELLTYPE_NOTE : // durch =Formel referenziert 1324 break; 1325 default: 1326 if ( i == nCount - 1 ) 1327 i = 0; 1328 // wahrscheinlich ganze Spalte kein String 1329 } 1330 } while ( i && i > nStop && !bIsText ); 1331 } 1332 // nIndex fuer IsNumberFormat vorbelegen 1333 if ( !bIsText ) 1334 nIndex = nOldIndex = pFormatter->GetStandardIndex(); 1335 } 1336 1337 do 1338 { 1339 if (bIsText) 1340 break; 1341 1342 if (bDetectNumberFormat) 1343 { 1344 if ( pLangFormatter ) 1345 { 1346 // for number detection: valid format index for selected language 1347 nIndex = pFormatter->GetStandardIndex( pLangFormatter->GetLanguage() ); 1348 } 1349 1350 if (!pFormatter->IsNumberFormat(rString, nIndex, nVal)) 1351 break; 1352 1353 if ( pLangFormatter ) 1354 { 1355 // convert back to the original language if a built-in format was detected 1356 const SvNumberformat* pOldFormat = pFormatter->GetEntry( nOldIndex ); 1357 if ( pOldFormat ) 1358 nIndex = pFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() ); 1359 } 1360 1361 pNewCell = new ScValueCell( nVal ); 1362 if ( nIndex != nOldIndex) 1363 { 1364 // #i22345# New behavior: Apply the detected number format only if 1365 // the old one was the default number, date, time or boolean format. 1366 // Exception: If the new format is boolean, always apply it. 1367 1368 sal_Bool bOverwrite = sal_False; 1369 const SvNumberformat* pOldFormat = pFormatter->GetEntry( nOldIndex ); 1370 if ( pOldFormat ) 1371 { 1372 short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED; 1373 if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE || 1374 nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL ) 1375 { 1376 if ( nOldIndex == pFormatter->GetStandardFormat( 1377 nOldType, pOldFormat->GetLanguage() ) ) 1378 { 1379 bOverwrite = sal_True; // default of these types can be overwritten 1380 } 1381 } 1382 } 1383 if ( !bOverwrite && pFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL ) 1384 { 1385 bOverwrite = sal_True; // overwrite anything if boolean was detected 1386 } 1387 1388 if ( bOverwrite ) 1389 { 1390 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, 1391 (sal_uInt32) nIndex) ); 1392 bNumFmtSet = sal_True; 1393 } 1394 } 1395 } 1396 else 1397 { 1398 // Only check if the string is a regular number. 1399 SvNumberFormatter* pLocaleSource = pLangFormatter ? pLangFormatter : pFormatter; 1400 const LocaleDataWrapper* pLocale = pLocaleSource->GetLocaleData(); 1401 if (!pLocale) 1402 break; 1403 1404 LocaleDataItem aLocaleItem = pLocale->getLocaleItem(); 1405 const OUString& rDecSep = aLocaleItem.decimalSeparator; 1406 const OUString& rGroupSep = aLocaleItem.thousandSeparator; 1407 if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1) 1408 break; 1409 1410 sal_Unicode dsep = rDecSep.getStr()[0]; 1411 sal_Unicode gsep = rGroupSep.getStr()[0]; 1412 1413 if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal)) 1414 break; 1415 1416 pNewCell = new ScValueCell(nVal); 1417 } 1418 } 1419 while (false); 1420 1421 if (!pNewCell) 1422 pNewCell = new ScStringCell(rString); 1423 } 1424 } 1425 1426 if ( bIsLoading && (!nCount || nRow > pItems[nCount-1].nRow) ) 1427 { // Search einsparen und ohne Umweg ueber Insert, Listener aufbauen 1428 // und Broadcast kommt eh erst nach dem Laden 1429 if ( pNewCell ) 1430 Append( nRow, pNewCell ); 1431 } 1432 else 1433 { 1434 SCSIZE i; 1435 if (Search(nRow, i)) 1436 { 1437 ScBaseCell* pOldCell = pItems[i].pCell; 1438 ScPostIt* pNote = pOldCell->ReleaseNote(); 1439 SvtBroadcaster* pBC = pOldCell->ReleaseBroadcaster(); 1440 if (pNewCell || pNote || pBC) 1441 { 1442 if (pNewCell) 1443 pNewCell->TakeNote( pNote ); 1444 else 1445 pNewCell = new ScNoteCell( pNote ); 1446 if (pBC) 1447 { 1448 pNewCell->TakeBroadcaster(pBC); 1449 pLastFormulaTreeTop = 0; // Err527 Workaround 1450 } 1451 1452 if ( pOldCell->GetCellType() == CELLTYPE_FORMULA ) 1453 { 1454 pOldCell->EndListeningTo( pDocument ); 1455 // falls in EndListening NoteCell in gleicher Col zerstoert 1456 if ( i >= nCount || pItems[i].nRow != nRow ) 1457 Search(nRow, i); 1458 } 1459 pOldCell->Delete(); 1460 pItems[i].pCell = pNewCell; // ersetzen 1461 if ( pNewCell->GetCellType() == CELLTYPE_FORMULA ) 1462 { 1463 pNewCell->StartListeningTo( pDocument ); 1464 ((ScFormulaCell*)pNewCell)->SetDirty(); 1465 } 1466 else 1467 pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, 1468 ScAddress( nCol, nRow, nTabP ), pNewCell ) ); 1469 } 1470 else 1471 { 1472 DeleteAtIndex(i); // loeschen und Broadcast 1473 } 1474 } 1475 else if (pNewCell) 1476 { 1477 Insert(nRow, pNewCell); // neu eintragen und Broadcast 1478 } 1479 } 1480 1481 // hier keine Formate mehr fuer Formeln setzen! 1482 // (werden bei der Ausgabe abgefragt) 1483 1484 } 1485 return bNumFmtSet; 1486 } 1487 1488 1489 void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, TypedScStrCollection& rStrings, bool& rHasDates) 1490 { 1491 bool bHasDates = false; 1492 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 1493 String aString; 1494 SCROW nRow = 0; 1495 SCSIZE nIndex; 1496 1497 Search( nStartRow, nIndex ); 1498 1499 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False ) 1500 { 1501 ScBaseCell* pCell = pItems[nIndex].pCell; 1502 TypedStrData* pData; 1503 sal_uLong nFormat = GetNumberFormat( nRow ); 1504 1505 ScCellFormat::GetInputString( pCell, nFormat, aString, *pFormatter ); 1506 1507 if ( pDocument->HasStringData( nCol, nRow, nTab ) ) 1508 pData = new TypedStrData( aString ); 1509 else 1510 { 1511 double nValue; 1512 1513 switch ( pCell->GetCellType() ) 1514 { 1515 case CELLTYPE_VALUE: 1516 nValue = ((ScValueCell*)pCell)->GetValue(); 1517 break; 1518 1519 case CELLTYPE_FORMULA: 1520 nValue = ((ScFormulaCell*)pCell)->GetValue(); 1521 break; 1522 1523 default: 1524 nValue = 0.0; 1525 } 1526 1527 if (pFormatter) 1528 { 1529 short nType = pFormatter->GetType(nFormat); 1530 if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME)) 1531 { 1532 // special case for date values. Disregard the time 1533 // element if the number format is of date type. 1534 nValue = ::rtl::math::approxFloor(nValue); 1535 bHasDates = true; 1536 } 1537 } 1538 1539 pData = new TypedStrData( aString, nValue, SC_STRTYPE_VALUE ); 1540 } 1541 #if 0 // DR 1542 ScPostIt aCellNote( ScPostIt::UNINITIALIZED ); 1543 // Hide visible notes during Filtering. 1544 if(pCell->GetNote(aCellNote) && aCellNote.IsCaptionShown()) 1545 { 1546 ScDetectiveFunc( pDocument, nTab ).HideComment( nCol, nRow ); 1547 aCellNote.SetShown( false ); 1548 pCell->SetNote(aCellNote); 1549 } 1550 #endif 1551 1552 if ( !rStrings.Insert( pData ) ) 1553 delete pData; // doppelt 1554 1555 ++nIndex; 1556 } 1557 1558 rHasDates = bHasDates; 1559 } 1560 1561 // 1562 // GetDataEntries - Strings aus zusammenhaengendem Bereich um nRow 1563 // 1564 1565 // DATENT_MAX - max. Anzahl Eintrage in Liste fuer Auto-Eingabe 1566 // DATENT_SEARCH - max. Anzahl Zellen, die durchsucht werden - neu: nur Strings zaehlen 1567 #define DATENT_MAX 200 1568 #define DATENT_SEARCH 2000 1569 1570 1571 sal_Bool ScColumn::GetDataEntries(SCROW nStartRow, TypedScStrCollection& rStrings, sal_Bool bLimit) 1572 { 1573 sal_Bool bFound = sal_False; 1574 SCSIZE nThisIndex; 1575 sal_Bool bThisUsed = Search( nStartRow, nThisIndex ); 1576 String aString; 1577 sal_uInt16 nCells = 0; 1578 1579 // Die Beschraenkung auf angrenzende Zellen (ohne Luecken) ist nicht mehr gewollt 1580 // (Featurekommission zur 5.1), stattdessen abwechselnd nach oben und unten suchen, 1581 // damit naheliegende Zellen wenigstens zuerst gefunden werden. 1582 //! Abstaende der Zeilennummern vergleichen? (Performance??) 1583 1584 SCSIZE nUpIndex = nThisIndex; // zeigt hinter die Zelle 1585 SCSIZE nDownIndex = nThisIndex; // zeigt auf die Zelle 1586 if (bThisUsed) 1587 ++nDownIndex; // Startzelle ueberspringen 1588 1589 while ( nUpIndex || nDownIndex < nCount ) 1590 { 1591 if ( nUpIndex ) // nach oben 1592 { 1593 ScBaseCell* pCell = pItems[nUpIndex-1].pCell; 1594 CellType eType = pCell->GetCellType(); 1595 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // nur Strings interessieren 1596 { 1597 if (eType == CELLTYPE_STRING) 1598 ((ScStringCell*)pCell)->GetString(aString); 1599 else 1600 ((ScEditCell*)pCell)->GetString(aString); 1601 1602 TypedStrData* pData = new TypedStrData(aString); 1603 if ( !rStrings.Insert( pData ) ) 1604 delete pData; // doppelt 1605 else if ( bLimit && rStrings.GetCount() >= DATENT_MAX ) 1606 break; // Maximum erreicht 1607 bFound = sal_True; 1608 1609 if ( bLimit ) 1610 if (++nCells >= DATENT_SEARCH) 1611 break; // genug gesucht 1612 } 1613 --nUpIndex; 1614 } 1615 1616 if ( nDownIndex < nCount ) // nach unten 1617 { 1618 ScBaseCell* pCell = pItems[nDownIndex].pCell; 1619 CellType eType = pCell->GetCellType(); 1620 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // nur Strings interessieren 1621 { 1622 if (eType == CELLTYPE_STRING) 1623 ((ScStringCell*)pCell)->GetString(aString); 1624 else 1625 ((ScEditCell*)pCell)->GetString(aString); 1626 1627 TypedStrData* pData = new TypedStrData(aString); 1628 if ( !rStrings.Insert( pData ) ) 1629 delete pData; // doppelt 1630 else if ( bLimit && rStrings.GetCount() >= DATENT_MAX ) 1631 break; // Maximum erreicht 1632 bFound = sal_True; 1633 1634 if ( bLimit ) 1635 if (++nCells >= DATENT_SEARCH) 1636 break; // genug gesucht 1637 } 1638 ++nDownIndex; 1639 } 1640 } 1641 1642 return bFound; 1643 } 1644 1645 #undef DATENT_MAX 1646 #undef DATENT_SEARCH 1647 1648 1649 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow ) 1650 { 1651 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow ); 1652 SCROW nTop = -1; 1653 SCROW nBottom = -1; 1654 SCSIZE nIndex; 1655 const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom ); 1656 while (pPattern) 1657 { 1658 const ScProtectionAttr* pAttr = (const ScProtectionAttr*)&pPattern->GetItem(ATTR_PROTECTION); 1659 if ( pAttr->GetHideCell() ) 1660 DeleteArea( nTop, nBottom, IDF_CONTENTS ); 1661 else if ( pAttr->GetHideFormula() ) 1662 { 1663 Search( nTop, nIndex ); 1664 while ( nIndex<nCount && pItems[nIndex].nRow<=nBottom ) 1665 { 1666 if ( pItems[nIndex].pCell->GetCellType() == CELLTYPE_FORMULA ) 1667 { 1668 ScFormulaCell* pFormula = (ScFormulaCell*)pItems[nIndex].pCell; 1669 if (pFormula->IsValue()) 1670 { 1671 double nVal = pFormula->GetValue(); 1672 pItems[nIndex].pCell = new ScValueCell( nVal ); 1673 } 1674 else 1675 { 1676 String aString; 1677 pFormula->GetString(aString); 1678 pItems[nIndex].pCell = new ScStringCell( aString ); 1679 } 1680 delete pFormula; 1681 } 1682 ++nIndex; 1683 } 1684 } 1685 1686 pPattern = aAttrIter.Next( nTop, nBottom ); 1687 } 1688 } 1689 1690 1691 void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError) 1692 { 1693 if (VALIDROW(nRow)) 1694 { 1695 ScFormulaCell* pCell = new ScFormulaCell 1696 ( pDocument, ScAddress( nCol, nRow, nTab ) ); 1697 pCell->SetErrCode( nError ); 1698 Insert( nRow, pCell ); 1699 } 1700 } 1701 1702 1703 void ScColumn::SetValue( SCROW nRow, const double& rVal) 1704 { 1705 if (VALIDROW(nRow)) 1706 { 1707 ScBaseCell* pCell = new ScValueCell(rVal); 1708 Insert( nRow, pCell ); 1709 } 1710 } 1711 1712 1713 void ScColumn::GetString( SCROW nRow, String& rString ) const 1714 { 1715 SCSIZE nIndex; 1716 Color* pColor; 1717 if (Search(nRow, nIndex)) 1718 { 1719 ScBaseCell* pCell = pItems[nIndex].pCell; 1720 if (pCell->GetCellType() != CELLTYPE_NOTE) 1721 { 1722 sal_uLong nFormat = GetNumberFormat( nRow ); 1723 ScCellFormat::GetString( pCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()) ); 1724 } 1725 else 1726 rString.Erase(); 1727 } 1728 else 1729 rString.Erase(); 1730 } 1731 1732 template<> 1733 void ScColumn::FillDPCacheT( long nDim, SCROW nStartRow, SCROW nEndRow, const boost::function<void(ScDPItemData*)> & rAddLabel, const boost::function<sal_Bool(long,ScDPItemData*)> & rAddData ) 1734 { 1735 SCROW nPattenRowStart = -1, nPatternRowEnd = -1; 1736 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 1737 sal_uLong nNumberFormat = 0; 1738 sal_uLong nNumberFormatType = NUMBERFORMAT_NUMBER; 1739 SCROW nCurRow = nStartRow; 1740 ScDPItemData * pDPItemData = NULL; 1741 1742 if ( pItems ) 1743 { 1744 SCSIZE nIndex; 1745 1746 for ( Search( nStartRow, nIndex ) ? void( ) : void(nIndex = nCount); nIndex < nCount && pItems[nIndex].nRow <= nEndRow; ++nIndex, ++nCurRow ) 1747 { 1748 for( ; nCurRow < pItems[nIndex].nRow; nCurRow++ ) 1749 if( nCurRow == nStartRow ) 1750 rAddLabel( new ScDPItemData() ); 1751 else 1752 rAddData( nDim, new ScDPItemData() ); 1753 1754 if( nCurRow > nPatternRowEnd ) 1755 if( const ScPatternAttr* pPattern = pAttrArray ? pAttrArray->GetPatternRange( nPattenRowStart, nPatternRowEnd, nCurRow ) : NULL ) 1756 nNumberFormatType = pFormatter->GetType( nNumberFormat = pPattern->GetNumberFormat( pFormatter ) ); 1757 else 1758 nNumberFormatType = NUMBERFORMAT_NUMBER, nNumberFormat = 0; 1759 1760 if( ScBaseCell* pCell = pItems[nIndex].pCell ) 1761 if( pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->GetErrCode() ) 1762 { 1763 String str( GetStringFromCell( pCell, nNumberFormat, pFormatter ) ); 1764 sal_uInt8 bFlag = ScDPItemData::MK_ERR; 1765 pDPItemData = new ScDPItemData( 0, str, 0.0, bFlag ); 1766 } 1767 else if( pCell->HasValueData() ) 1768 { 1769 double fVal = GetValueFromCell( pCell ); 1770 String str( GetStringFromCell( pCell, nNumberFormat, pFormatter ) ); 1771 sal_uInt8 bFlag = ScDPItemData::MK_VAL|ScDPItemData::MK_DATA|(ScDPItemData::MK_DATE * isDateFormat( nNumberFormatType )); 1772 pDPItemData = new ScDPItemData( nNumberFormat, str, fVal, bFlag ); 1773 } 1774 else if( !pCell->IsBlank() ) 1775 pDPItemData = new ScDPItemData( GetStringFromCell( pCell, nNumberFormat, pFormatter ) ); 1776 else 1777 pDPItemData = new ScDPItemData(); 1778 else 1779 pDPItemData = new ScDPItemData(); 1780 1781 if( nCurRow == nStartRow ) 1782 rAddLabel( pDPItemData ); 1783 else 1784 rAddData( nDim, pDPItemData ); 1785 } 1786 } 1787 1788 for( ; nCurRow <= nEndRow; nCurRow++ ) 1789 if( nCurRow == nStartRow ) 1790 rAddLabel( new ScDPItemData() ); 1791 else 1792 rAddData( nDim, new ScDPItemData() ); 1793 } 1794 void ScColumn::FillDPCache( ScDPTableDataCache * pCache, long nDim, SCROW nStartRow, SCROW nEndRow ) 1795 { 1796 typedef sal_Bool(ScDPTableDataCache::*PFNAddData)( long, ScDPItemData* ); 1797 FillDPCacheT<boost::function<void(ScDPItemData*)>, boost::function<sal_Bool(long,ScDPItemData*)> >( nDim, nStartRow, nEndRow, boost::bind( &ScDPTableDataCache::AddLabel, pCache, _1 ), boost::bind( (PFNAddData)&ScDPTableDataCache::AddData<false>, pCache, _1, _2 ) ); 1798 } 1799 1800 void ScColumn::GetInputString( SCROW nRow, String& rString ) const 1801 { 1802 SCSIZE nIndex; 1803 if (Search(nRow, nIndex)) 1804 { 1805 ScBaseCell* pCell = pItems[nIndex].pCell; 1806 if (pCell->GetCellType() != CELLTYPE_NOTE) 1807 { 1808 sal_uLong nFormat = GetNumberFormat( nRow ); 1809 ScCellFormat::GetInputString( pCell, nFormat, rString, *(pDocument->GetFormatTable()) ); 1810 } 1811 else 1812 rString.Erase(); 1813 } 1814 else 1815 rString.Erase(); 1816 } 1817 1818 1819 double ScColumn::GetValue( SCROW nRow ) const 1820 { 1821 SCSIZE nIndex; 1822 if (Search(nRow, nIndex)) 1823 { 1824 ScBaseCell* pCell = pItems[nIndex].pCell; 1825 switch (pCell->GetCellType()) 1826 { 1827 case CELLTYPE_VALUE: 1828 return ((ScValueCell*)pCell)->GetValue(); 1829 // break; 1830 case CELLTYPE_FORMULA: 1831 { 1832 if (((ScFormulaCell*)pCell)->IsValue()) 1833 return ((ScFormulaCell*)pCell)->GetValue(); 1834 else 1835 return 0.0; 1836 } 1837 // break; 1838 default: 1839 return 0.0; 1840 // break; 1841 } 1842 } 1843 return 0.0; 1844 } 1845 1846 1847 void ScColumn::GetFormula( SCROW nRow, String& rFormula, sal_Bool ) const 1848 { 1849 SCSIZE nIndex; 1850 if (Search(nRow, nIndex)) 1851 { 1852 ScBaseCell* pCell = pItems[nIndex].pCell; 1853 if (pCell->GetCellType() == CELLTYPE_FORMULA) 1854 ((ScFormulaCell*)pCell)->GetFormula( rFormula ); 1855 else 1856 rFormula.Erase(); 1857 } 1858 else 1859 rFormula.Erase(); 1860 } 1861 1862 1863 CellType ScColumn::GetCellType( SCROW nRow ) const 1864 { 1865 SCSIZE nIndex; 1866 if (Search(nRow, nIndex)) 1867 return pItems[nIndex].pCell->GetCellType(); 1868 return CELLTYPE_NONE; 1869 } 1870 1871 1872 sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const 1873 { 1874 SCSIZE nIndex; 1875 if (Search(nRow, nIndex)) 1876 { 1877 ScBaseCell* pCell = pItems[nIndex].pCell; 1878 if (pCell->GetCellType() == CELLTYPE_FORMULA) 1879 return ((ScFormulaCell*)pCell)->GetErrCode(); 1880 } 1881 return 0; 1882 } 1883 1884 1885 sal_Bool ScColumn::HasStringData( SCROW nRow ) const 1886 { 1887 SCSIZE nIndex; 1888 if (Search(nRow, nIndex)) 1889 return (pItems[nIndex].pCell)->HasStringData(); 1890 return sal_False; 1891 } 1892 1893 1894 sal_Bool ScColumn::HasValueData( SCROW nRow ) const 1895 { 1896 SCSIZE nIndex; 1897 if (Search(nRow, nIndex)) 1898 return (pItems[nIndex].pCell)->HasValueData(); 1899 return sal_False; 1900 } 1901 1902 sal_Bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const 1903 { 1904 // sal_True, wenn String- oder Editzellen im Bereich 1905 1906 if ( pItems ) 1907 { 1908 SCSIZE nIndex; 1909 Search( nStartRow, nIndex ); 1910 while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow ) 1911 { 1912 CellType eType = pItems[nIndex].pCell->GetCellType(); 1913 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT ) 1914 return sal_True; 1915 ++nIndex; 1916 } 1917 } 1918 return sal_False; 1919 } 1920 1921 1922 ScPostIt* ScColumn::GetNote( SCROW nRow ) 1923 { 1924 SCSIZE nIndex; 1925 return Search( nRow, nIndex ) ? pItems[ nIndex ].pCell->GetNote() : 0; 1926 } 1927 1928 1929 void ScColumn::TakeNote( SCROW nRow, ScPostIt* pNote ) 1930 { 1931 SCSIZE nIndex; 1932 if( Search( nRow, nIndex ) ) 1933 pItems[ nIndex ].pCell->TakeNote( pNote ); 1934 else 1935 Insert( nRow, new ScNoteCell( pNote ) ); 1936 } 1937 1938 1939 ScPostIt* ScColumn::ReleaseNote( SCROW nRow ) 1940 { 1941 ScPostIt* pNote = 0; 1942 SCSIZE nIndex; 1943 if( Search( nRow, nIndex ) ) 1944 { 1945 ScBaseCell* pCell = pItems[ nIndex ].pCell; 1946 pNote = pCell->ReleaseNote(); 1947 if( (pCell->GetCellType() == CELLTYPE_NOTE) && !pCell->GetBroadcaster() ) 1948 DeleteAtIndex( nIndex ); 1949 } 1950 return pNote; 1951 } 1952 1953 1954 void ScColumn::DeleteNote( SCROW nRow ) 1955 { 1956 delete ReleaseNote( nRow ); 1957 } 1958 1959 1960 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const 1961 { 1962 sal_Int32 nStringLen = 0; 1963 if ( pItems ) 1964 { 1965 String aString; 1966 rtl::OString aOString; 1967 bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet); 1968 SvNumberFormatter* pNumFmt = pDocument->GetFormatTable(); 1969 SCSIZE nIndex; 1970 SCROW nRow; 1971 Search( nRowStart, nIndex ); 1972 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRowEnd ) 1973 { 1974 ScBaseCell* pCell = pItems[nIndex].pCell; 1975 if ( pCell->GetCellType() != CELLTYPE_NOTE ) 1976 { 1977 Color* pColor; 1978 sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr( 1979 nRow, ATTR_VALUE_FORMAT ))->GetValue(); 1980 ScCellFormat::GetString( pCell, nFormat, aString, &pColor, 1981 *pNumFmt ); 1982 sal_Int32 nLen; 1983 if (bIsOctetTextEncoding) 1984 { 1985 rtl::OUString aOUString( aString); 1986 if (!aOUString.convertToString( &aOString, eCharSet, 1987 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | 1988 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) 1989 { 1990 // TODO: anything? this is used by the dBase export filter 1991 // that throws an error anyway, but in case of another 1992 // context we might want to indicate a conversion error 1993 // early. 1994 } 1995 nLen = aOString.getLength(); 1996 } 1997 else 1998 nLen = aString.Len() * sizeof(sal_Unicode); 1999 if ( nStringLen < nLen) 2000 nStringLen = nLen; 2001 } 2002 nIndex++; 2003 } 2004 } 2005 return nStringLen; 2006 } 2007 2008 2009 xub_StrLen ScColumn::GetMaxNumberStringLen( 2010 sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const 2011 { 2012 xub_StrLen nStringLen = 0; 2013 nPrecision = pDocument->GetDocOptions().GetStdPrecision(); 2014 if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION ) 2015 // In case of unlimited precision, use 2 instead. 2016 nPrecision = 2; 2017 2018 if ( pItems ) 2019 { 2020 String aString; 2021 SvNumberFormatter* pNumFmt = pDocument->GetFormatTable(); 2022 SCSIZE nIndex; 2023 SCROW nRow; 2024 Search( nRowStart, nIndex ); 2025 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRowEnd ) 2026 { 2027 ScBaseCell* pCell = pItems[nIndex].pCell; 2028 CellType eType = pCell->GetCellType(); 2029 if ( eType == CELLTYPE_VALUE || (eType == CELLTYPE_FORMULA 2030 && ((ScFormulaCell*)pCell)->IsValue()) ) 2031 { 2032 sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr( 2033 nRow, ATTR_VALUE_FORMAT ))->GetValue(); 2034 ScCellFormat::GetInputString( pCell, nFormat, aString, *pNumFmt ); 2035 xub_StrLen nLen = aString.Len(); 2036 if ( nLen ) 2037 { 2038 if ( nFormat ) 2039 { // more decimals than standard? 2040 sal_uInt16 nPrec = pNumFmt->GetFormatPrecision( nFormat ); 2041 if ( nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > nPrecision ) 2042 nPrecision = nPrec; 2043 } 2044 if ( nPrecision ) 2045 { // less than nPrecision in string => widen it 2046 // more => shorten it 2047 String aSep = pNumFmt->GetFormatDecimalSep( nFormat ); 2048 xub_StrLen nTmp = aString.Search( aSep ); 2049 if ( nTmp == STRING_NOTFOUND ) 2050 nLen += nPrecision + aSep.Len(); 2051 else 2052 { 2053 nTmp = aString.Len() - (nTmp + aSep.Len()); 2054 if ( nTmp != nPrecision ) 2055 nLen += nPrecision - nTmp; 2056 // nPrecision > nTmp : nLen + Diff 2057 // nPrecision < nTmp : nLen - Diff 2058 } 2059 } 2060 if ( nStringLen < nLen ) 2061 nStringLen = nLen; 2062 } 2063 } 2064 nIndex++; 2065 } 2066 } 2067 return nStringLen; 2068 } 2069 2070