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