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: */
|