LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/data - column3.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 406 902 45.0 %
Date: 2012-12-27 Functions: 28 42 66.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10