Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <svl/zforlist.hxx>
30 : :
31 : : #include "scitems.hxx"
32 : : #include "attrib.hxx"
33 : : #include "cell.hxx"
34 : : #include "compiler.hxx"
35 : : #include "interpre.hxx"
36 : : #include "document.hxx"
37 : : #include "scmatrix.hxx"
38 : : #include "dociter.hxx"
39 : : #include "docoptio.hxx"
40 : : #include "rechead.hxx"
41 : : #include "rangenam.hxx"
42 : : #include "brdcst.hxx"
43 : : #include "ddelink.hxx"
44 : : #include "validat.hxx"
45 : : #include "progress.hxx"
46 : : #include "editutil.hxx"
47 : : #include "recursionhelper.hxx"
48 : : #include "postit.hxx"
49 : : #include "externalrefmgr.hxx"
50 : : #include "macromgr.hxx"
51 : : #include "dbdata.hxx"
52 : :
53 : : #include <editeng/editobj.hxx>
54 : : #include <svl/intitem.hxx>
55 : : #include <editeng/flditem.hxx>
56 : : #include <svl/broadcast.hxx>
57 : :
58 : : using namespace formula;
59 : : // More or less arbitrary, of course all recursions must fit into available
60 : : // stack space (which is what on all systems we don't know yet?). Choosing a
61 : : // lower value may be better than trying a much higher value that also isn't
62 : : // sufficient but temporarily leads to high memory consumption. On the other
63 : : // hand, if the value fits all recursions, execution is quicker as no resumes
64 : : // are necessary. Could be made a configurable option.
65 : : // Allow for a year's calendar (366).
66 : : const sal_uInt16 MAXRECURSION = 400;
67 : :
68 : : // STATIC DATA -----------------------------------------------------------
69 : :
70 : : #ifdef USE_MEMPOOL
71 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell )
72 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
73 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell )
74 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell )
75 : : #endif
76 : :
77 : : // ============================================================================
78 : :
79 : 51923 : ScBaseCell::ScBaseCell( CellType eNewType ) :
80 : : mpBroadcaster( 0 ),
81 : : nTextWidth( TEXTWIDTH_DIRTY ),
82 : 51923 : eCellType( sal::static_int_cast<sal_uInt8>(eNewType) ),
83 : 103846 : nScriptType( SC_SCRIPTTYPE_UNKNOWN )
84 : : {
85 : 51923 : }
86 : :
87 : 6595 : ScBaseCell::ScBaseCell( const ScBaseCell& rCell ) :
88 : : mpBroadcaster( 0 ),
89 : : nTextWidth( rCell.nTextWidth ),
90 : : eCellType( rCell.eCellType ),
91 : 6595 : nScriptType( SC_SCRIPTTYPE_UNKNOWN )
92 : : {
93 : 6595 : }
94 : :
95 : 56727 : ScBaseCell::~ScBaseCell()
96 : : {
97 [ + + ]: 56727 : delete mpBroadcaster;
98 : : OSL_ENSURE( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" );
99 : 56727 : }
100 : :
101 : : namespace {
102 : :
103 : 6593 : ScBaseCell* lclCloneCell( const ScBaseCell& rSrcCell, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags )
104 : : {
105 [ + + + + : 6593 : switch( rSrcCell.GetCellType() )
+ - ]
106 : : {
107 : : case CELLTYPE_VALUE:
108 [ + - ]: 3544 : return new ScValueCell( static_cast< const ScValueCell& >( rSrcCell ) );
109 : : case CELLTYPE_STRING:
110 [ + - ]: 2328 : return new ScStringCell( static_cast< const ScStringCell& >( rSrcCell ) );
111 : : case CELLTYPE_EDIT:
112 [ + - ]: 389 : return new ScEditCell(static_cast<const ScEditCell&>(rSrcCell), rDestDoc, rDestPos);
113 : : case CELLTYPE_FORMULA:
114 [ + - ][ + - ]: 331 : return new ScFormulaCell( static_cast< const ScFormulaCell& >( rSrcCell ), rDestDoc, rDestPos, nCloneFlags );
115 : : case CELLTYPE_NOTE:
116 [ + - ]: 1 : return new ScNoteCell;
117 : : default:;
118 : : }
119 : : OSL_FAIL( "lclCloneCell - unknown cell type" );
120 : 6593 : return 0;
121 : : }
122 : :
123 : 34 : void adjustRangeName(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& aNewPos, const ScAddress& aOldPos)
124 : : {
125 [ + - ]: 34 : bool bOldGlobal = pToken->IsGlobal();
126 : 34 : SCTAB aOldTab = aOldPos.Tab();
127 : 34 : rtl::OUString aRangeName;
128 [ + - ]: 34 : int nOldIndex = pToken->GetIndex();
129 : 34 : ScRangeData* pOldRangeData = NULL;
130 : :
131 : : //search the name of the RangeName
132 [ + + ]: 34 : if (!bOldGlobal)
133 : : {
134 [ + - ][ + - ]: 9 : pOldRangeData = pOldDoc->GetRangeName(aOldTab)->findByIndex(nOldIndex);
135 [ - + ]: 9 : if (!pOldRangeData)
136 : : return; //might be an error in the formula array
137 : 9 : aRangeName = pOldRangeData->GetUpperName();
138 : : }
139 : : else
140 : : {
141 [ + - ][ + - ]: 25 : pOldRangeData = pOldDoc->GetRangeName()->findByIndex(nOldIndex);
142 [ - + ]: 25 : if (!pOldRangeData)
143 : : return; //might be an error in the formula array
144 : 25 : aRangeName = pOldRangeData->GetUpperName();
145 : : }
146 : :
147 : : //find corresponding range name in new document
148 : : //first search for local range name then global range names
149 : 34 : SCTAB aNewTab = aNewPos.Tab();
150 [ + - ]: 34 : ScRangeName* pRangeName = rNewDoc.GetRangeName(aNewTab);
151 : 34 : ScRangeData* pRangeData = NULL;
152 : 34 : bool bNewGlobal = false;
153 : : //search local range names
154 [ + - ]: 34 : if (pRangeName)
155 : : {
156 [ + - ]: 34 : pRangeData = pRangeName->findByUpperName(aRangeName);
157 : : }
158 : : //search global range names
159 [ + + ]: 34 : if (!pRangeData)
160 : : {
161 : 31 : bNewGlobal = true;
162 [ + - ]: 31 : pRangeName = rNewDoc.GetRangeName();
163 [ + - ]: 31 : if (pRangeName)
164 [ + - ]: 31 : pRangeData = pRangeName->findByUpperName(aRangeName);
165 : : }
166 : : //if no range name was found copy it
167 [ + + ]: 34 : if (!pRangeData)
168 : : {
169 : 13 : bNewGlobal = bOldGlobal;
170 [ + - ][ + - ]: 13 : pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
171 : 13 : ScTokenArray* pRangeNameToken = pRangeData->GetCode();
172 [ + - ][ + + ]: 13 : if (rNewDoc.GetPool() != const_cast<ScDocument*>(pOldDoc)->GetPool())
[ + - ]
173 : : {
174 [ + - ]: 4 : pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true);
175 [ + - ]: 4 : pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, aOldPos, aNewPos, false, true);
176 : : }
177 : :
178 : : bool bInserted;
179 [ + + ]: 13 : if (bNewGlobal)
180 [ + - ][ + - ]: 7 : bInserted = rNewDoc.GetRangeName()->insert(pRangeData);
181 : : else
182 [ + - ][ + - ]: 6 : bInserted = rNewDoc.GetRangeName(aNewTab)->insert(pRangeData);
183 [ - + ]: 13 : if (!bInserted)
184 : : {
185 : : //if this happened we have a real problem
186 : 0 : pRangeData = NULL;
187 [ # # ]: 0 : pToken->SetIndex(0);
188 : : OSL_FAIL("inserting the range name should not fail");
189 : : return;
190 : : }
191 : : }
192 : 34 : sal_Int32 nIndex = pRangeData->GetIndex();
193 [ + - ]: 34 : pToken->SetIndex(nIndex);
194 [ + - ][ + - ]: 34 : pToken->SetGlobal(bNewGlobal);
195 : : }
196 : :
197 : 0 : void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc)
198 : : {
199 [ # # ]: 0 : ScDBCollection* pOldDBCollection = pOldDoc->GetDBCollection();
200 [ # # ]: 0 : if (!pOldDBCollection)
201 : : return;//strange error case, don't do anything
202 [ # # ]: 0 : ScDBCollection::NamedDBs& aOldNamedDBs = pOldDBCollection->getNamedDBs();
203 [ # # ][ # # ]: 0 : ScDBData* pDBData = aOldNamedDBs.findByIndex(pToken->GetIndex());
204 [ # # ]: 0 : if (!pDBData)
205 : : return; //invalid index
206 : 0 : rtl::OUString aDBName = pDBData->GetName();
207 : :
208 : : //search in new document
209 [ # # ]: 0 : ScDBCollection* pNewDBCollection = rNewDoc.GetDBCollection();
210 [ # # ]: 0 : if (!pNewDBCollection)
211 : : {
212 [ # # ][ # # ]: 0 : pNewDBCollection = new ScDBCollection(&rNewDoc);
213 : : }
214 [ # # ]: 0 : ScDBCollection::NamedDBs& aNewNamedDBs = pNewDBCollection->getNamedDBs();
215 [ # # ]: 0 : ScDBData* pNewDBData = aNewNamedDBs.findByName(aDBName);
216 [ # # ]: 0 : if (!pNewDBData)
217 : : {
218 [ # # ][ # # ]: 0 : pNewDBData = new ScDBData(*pDBData);
219 [ # # ]: 0 : aNewNamedDBs.insert(pNewDBData);
220 : : }
221 [ # # ]: 0 : pToken->SetIndex(pNewDBData->GetIndex());
222 : : }
223 : :
224 : : } // namespace
225 : :
226 : 51 : ScBaseCell* ScBaseCell::Clone( ScDocument& rDestDoc, int nCloneFlags ) const
227 : : {
228 : : // notes will not be cloned -> cell address only needed for formula cells
229 : 51 : ScAddress aDestPos;
230 [ + + ]: 51 : if( eCellType == CELLTYPE_FORMULA )
231 : 10 : aDestPos = static_cast< const ScFormulaCell* >( this )->aPos;
232 [ + - ]: 51 : return lclCloneCell( *this, rDestDoc, aDestPos, nCloneFlags );
233 : : }
234 : :
235 : 6542 : ScBaseCell* ScBaseCell::Clone( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
236 : : {
237 : 6542 : return lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
238 : : }
239 : :
240 : 56064 : void ScBaseCell::Delete()
241 : : {
242 [ + + + + : 56064 : switch (eCellType)
+ - ]
243 : : {
244 : : case CELLTYPE_VALUE:
245 [ + - ]: 39815 : delete (ScValueCell*) this;
246 : 39815 : break;
247 : : case CELLTYPE_STRING:
248 [ + - ]: 11349 : delete (ScStringCell*) this;
249 : 11349 : break;
250 : : case CELLTYPE_EDIT:
251 [ + - ]: 845 : delete (ScEditCell*) this;
252 : 845 : break;
253 : : case CELLTYPE_FORMULA:
254 [ + - ]: 3818 : delete (ScFormulaCell*) this;
255 : 3818 : break;
256 : : case CELLTYPE_NOTE:
257 [ + - ]: 237 : delete (ScNoteCell*) this;
258 : 237 : break;
259 : : default:
260 : : OSL_FAIL("Attempt to Delete() an unknown CELLTYPE");
261 : 0 : break;
262 : : }
263 : 56064 : }
264 : :
265 : 1776 : bool ScBaseCell::IsBlank() const
266 : : {
267 : 1776 : return false;
268 : : }
269 : :
270 : 3713 : void ScBaseCell::TakeBroadcaster( SvtBroadcaster* pBroadcaster )
271 : : {
272 [ - + ]: 3713 : delete mpBroadcaster;
273 : 3713 : mpBroadcaster = pBroadcaster;
274 : 3713 : }
275 : :
276 : 1251 : SvtBroadcaster* ScBaseCell::ReleaseBroadcaster()
277 : : {
278 : 1251 : SvtBroadcaster* pBroadcaster = mpBroadcaster;
279 : 1251 : mpBroadcaster = 0;
280 : 1251 : return pBroadcaster;
281 : : }
282 : :
283 : 311 : void ScBaseCell::DeleteBroadcaster()
284 : : {
285 [ + - ]: 311 : DELETEZ( mpBroadcaster );
286 : 311 : }
287 : :
288 : 6874 : ScBaseCell* ScBaseCell::CreateTextCell( const rtl::OUString& rString, ScDocument* pDoc )
289 : : {
290 [ + + ][ - + ]: 6874 : if ( rString.indexOf('\n') != -1 || rString.indexOf(CHAR_CR) != -1 )
[ + + ]
291 [ + - ]: 5 : return new ScEditCell( rString, pDoc );
292 : : else
293 [ + - ]: 6874 : return new ScStringCell( rString );
294 : : }
295 : :
296 : 31913 : void ScBaseCell::StartListeningTo( ScDocument* pDoc )
297 : : {
298 [ + + ][ + - : 39708 : if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
+ + + - ]
[ + + ]
299 : 3909 : && !pDoc->GetNoListening()
300 : 3886 : && !((ScFormulaCell*)this)->IsInChangeTrack()
301 : : )
302 : : {
303 : 3886 : pDoc->SetDetectiveDirty(true); // es hat sich was geaendert...
304 : :
305 : 3886 : ScFormulaCell* pFormCell = (ScFormulaCell*)this;
306 : 3886 : ScTokenArray* pArr = pFormCell->GetCode();
307 [ + + ]: 3886 : if( pArr->IsRecalcModeAlways() )
308 [ + - ]: 66 : pDoc->StartListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
309 : : else
310 : : {
311 : 3820 : pArr->Reset();
312 : : ScToken* t;
313 [ + + ]: 14531 : while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
314 : : {
315 : 10711 : StackVar eType = t->GetType();
316 : 10711 : ScSingleRefData& rRef1 = t->GetSingleRef();
317 : : ScSingleRefData& rRef2 = (eType == svDoubleRef ?
318 [ + + ]: 10711 : t->GetDoubleRef().Ref2 : rRef1);
319 [ + + + ]: 10711 : switch( eType )
320 : : {
321 : : case svSingleRef:
322 : 5110 : rRef1.CalcAbsIfRel( pFormCell->aPos );
323 [ + + ]: 5110 : if ( rRef1.Valid() )
324 : : {
325 : : pDoc->StartListeningCell(
326 : : ScAddress( rRef1.nCol,
327 : : rRef1.nRow,
328 [ + - ]: 5107 : rRef1.nTab ), pFormCell );
329 : : }
330 : 5110 : break;
331 : : case svDoubleRef:
332 : 5503 : t->CalcAbsIfRel( pFormCell->aPos );
333 [ + - ][ + - ]: 5503 : if ( rRef1.Valid() && rRef2.Valid() )
[ + - ]
334 : : {
335 [ - + ]: 5503 : if ( t->GetOpCode() == ocColRowNameAuto )
336 : : { // automagically
337 [ # # ]: 0 : if ( rRef1.IsColRel() )
338 : : { // ColName
339 : : pDoc->StartListeningArea( ScRange (
340 : : rRef1.nCol,
341 : : rRef1.nRow,
342 : : rRef1.nTab,
343 : : rRef2.nCol,
344 : : MAXROW,
345 [ # # ]: 0 : rRef2.nTab ), pFormCell );
346 : : }
347 : : else
348 : : { // RowName
349 : : pDoc->StartListeningArea( ScRange (
350 : : rRef1.nCol,
351 : : rRef1.nRow,
352 : : rRef1.nTab,
353 : : MAXCOL,
354 : : rRef2.nRow,
355 [ # # ]: 0 : rRef2.nTab ), pFormCell );
356 : : }
357 : : }
358 : : else
359 : : {
360 : : pDoc->StartListeningArea( ScRange (
361 : : rRef1.nCol,
362 : : rRef1.nRow,
363 : : rRef1.nTab,
364 : : rRef2.nCol,
365 : : rRef2.nRow,
366 [ + - ]: 5503 : rRef2.nTab ), pFormCell );
367 : : }
368 : : }
369 : 5503 : break;
370 : : default:
371 : : ; // nothing
372 : : }
373 : : }
374 : : }
375 : 3886 : pFormCell->SetNeedsListening( false);
376 : : }
377 : 31913 : }
378 : :
379 : : // pArr gesetzt -> Referenzen von anderer Zelle nehmen
380 : : // dann muss auch aPos uebergeben werden!
381 : :
382 : 535 : void ScBaseCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
383 : : ScAddress aPos )
384 : : {
385 [ + + ]: 1046 : if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
[ + - + - ]
[ + + ]
386 : 511 : && !((ScFormulaCell*)this)->IsInChangeTrack()
387 : : )
388 : : {
389 : 511 : pDoc->SetDetectiveDirty(true); // es hat sich was geaendert...
390 : :
391 : 511 : ScFormulaCell* pFormCell = (ScFormulaCell*)this;
392 [ - + ]: 511 : if( pFormCell->GetCode()->IsRecalcModeAlways() )
393 [ # # ]: 0 : pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
394 : : else
395 : : {
396 [ + - ]: 511 : if (!pArr)
397 : : {
398 : 511 : pArr = pFormCell->GetCode();
399 : 511 : aPos = pFormCell->aPos;
400 : : }
401 : 511 : pArr->Reset();
402 : : ScToken* t;
403 [ + + ]: 1234 : while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
404 : : {
405 : 723 : StackVar eType = t->GetType();
406 : 723 : ScSingleRefData& rRef1 = t->GetSingleRef();
407 : : ScSingleRefData& rRef2 = (eType == svDoubleRef ?
408 [ + + ]: 723 : t->GetDoubleRef().Ref2 : rRef1);
409 [ + + + ]: 723 : switch( eType )
410 : : {
411 : : case svSingleRef:
412 : 477 : rRef1.CalcAbsIfRel( aPos );
413 [ + + ]: 477 : if ( rRef1.Valid() )
414 : : {
415 : : pDoc->EndListeningCell(
416 : : ScAddress( rRef1.nCol,
417 : : rRef1.nRow,
418 [ + - ]: 474 : rRef1.nTab ), pFormCell );
419 : : }
420 : 477 : break;
421 : : case svDoubleRef:
422 : 226 : t->CalcAbsIfRel( aPos );
423 [ + - ][ + - ]: 226 : if ( rRef1.Valid() && rRef2.Valid() )
[ + - ]
424 : : {
425 [ - + ]: 226 : if ( t->GetOpCode() == ocColRowNameAuto )
426 : : { // automagically
427 [ # # ]: 0 : if ( rRef1.IsColRel() )
428 : : { // ColName
429 : : pDoc->EndListeningArea( ScRange (
430 : : rRef1.nCol,
431 : : rRef1.nRow,
432 : : rRef1.nTab,
433 : : rRef2.nCol,
434 : : MAXROW,
435 [ # # ]: 0 : rRef2.nTab ), pFormCell );
436 : : }
437 : : else
438 : : { // RowName
439 : : pDoc->EndListeningArea( ScRange (
440 : : rRef1.nCol,
441 : : rRef1.nRow,
442 : : rRef1.nTab,
443 : : MAXCOL,
444 : : rRef2.nRow,
445 [ # # ]: 0 : rRef2.nTab ), pFormCell );
446 : : }
447 : : }
448 : : else
449 : : {
450 : : pDoc->EndListeningArea( ScRange (
451 : : rRef1.nCol,
452 : : rRef1.nRow,
453 : : rRef1.nTab,
454 : : rRef2.nCol,
455 : : rRef2.nRow,
456 [ + - ]: 226 : rRef2.nTab ), pFormCell );
457 : : }
458 : : }
459 : 226 : break;
460 : : default:
461 : : ; // nothing
462 : : }
463 : : }
464 : : }
465 : : }
466 : 535 : }
467 : :
468 : :
469 : 1306 : sal_uInt16 ScBaseCell::GetErrorCode() const
470 : : {
471 [ + + ]: 1306 : switch ( eCellType )
472 : : {
473 : : case CELLTYPE_FORMULA :
474 : 186 : return ((ScFormulaCell*)this)->GetErrCode();
475 : : default:
476 : 1306 : return 0;
477 : : }
478 : : }
479 : :
480 : :
481 : 752 : bool ScBaseCell::HasEmptyData() const
482 : : {
483 [ + + + ]: 752 : switch ( eCellType )
484 : : {
485 : : case CELLTYPE_NOTE :
486 : 30 : return true;
487 : : case CELLTYPE_FORMULA :
488 : 31 : return ((ScFormulaCell*)this)->IsEmpty();
489 : : default:
490 : 752 : return false;
491 : : }
492 : : }
493 : :
494 : :
495 : 26074 : bool ScBaseCell::HasValueData() const
496 : : {
497 [ + + + ]: 26074 : switch ( eCellType )
498 : : {
499 : : case CELLTYPE_VALUE :
500 : 17936 : return true;
501 : : case CELLTYPE_FORMULA :
502 : 604 : return ((ScFormulaCell*)this)->IsValue();
503 : : default:
504 : 26074 : return false;
505 : : }
506 : : }
507 : :
508 : :
509 : 10870 : bool ScBaseCell::HasStringData() const
510 : : {
511 [ + + + ]: 10870 : switch ( eCellType )
512 : : {
513 : : case CELLTYPE_STRING :
514 : : case CELLTYPE_EDIT :
515 : 6054 : return true;
516 : : case CELLTYPE_FORMULA :
517 : 1079 : return !((ScFormulaCell*)this)->IsValue();
518 : : default:
519 : 10870 : return false;
520 : : }
521 : : }
522 : :
523 : 5375 : rtl::OUString ScBaseCell::GetStringData() const
524 : : {
525 : 5375 : rtl::OUString aStr;
526 [ + + - - ]: 5375 : switch ( eCellType )
527 : : {
528 : : case CELLTYPE_STRING:
529 : 5374 : aStr = ((const ScStringCell*)this)->GetString();
530 : 5374 : break;
531 : : case CELLTYPE_EDIT:
532 [ + - ]: 1 : aStr = ((const ScEditCell*)this)->GetString();
533 : 1 : break;
534 : : case CELLTYPE_FORMULA:
535 [ # # ]: 0 : aStr = ((ScFormulaCell*)this)->GetString(); // an der Formelzelle nicht-const
536 : 0 : break;
537 : : }
538 : 5375 : return aStr;
539 : : }
540 : :
541 : 68 : bool ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 )
542 : : {
543 : 68 : CellType eType1 = CELLTYPE_NONE;
544 : 68 : CellType eType2 = CELLTYPE_NONE;
545 [ + - ]: 68 : if ( pCell1 )
546 : : {
547 : 68 : eType1 = pCell1->GetCellType();
548 [ - + ]: 68 : if (eType1 == CELLTYPE_EDIT)
549 : 0 : eType1 = CELLTYPE_STRING;
550 [ - + ]: 68 : else if (eType1 == CELLTYPE_NOTE)
551 : 0 : eType1 = CELLTYPE_NONE;
552 : : }
553 [ + - ]: 68 : if ( pCell2 )
554 : : {
555 : 68 : eType2 = pCell2->GetCellType();
556 [ - + ]: 68 : if (eType2 == CELLTYPE_EDIT)
557 : 0 : eType2 = CELLTYPE_STRING;
558 [ - + ]: 68 : else if (eType2 == CELLTYPE_NOTE)
559 : 0 : eType2 = CELLTYPE_NONE;
560 : : }
561 [ + + ]: 68 : if ( eType1 != eType2 )
562 : 10 : return false;
563 : :
564 [ - + + + : 58 : switch ( eType1 ) // beide Typen gleich
- ]
565 : : {
566 : : case CELLTYPE_NONE: // beide leer
567 : 0 : return true;
568 : : case CELLTYPE_VALUE: // wirklich Value-Zellen
569 : 14 : return ( ((const ScValueCell*)pCell1)->GetValue() ==
570 : 14 : ((const ScValueCell*)pCell2)->GetValue() );
571 : : case CELLTYPE_STRING: // String oder Edit
572 : : {
573 : 40 : rtl::OUString aText1;
574 [ + - ]: 40 : if ( pCell1->GetCellType() == CELLTYPE_STRING )
575 : 40 : aText1 = ((const ScStringCell*)pCell1)->GetString();
576 : : else
577 [ # # ]: 0 : aText1 = ((const ScEditCell*)pCell1)->GetString();
578 : 40 : rtl::OUString aText2;
579 [ + - ]: 40 : if ( pCell2->GetCellType() == CELLTYPE_STRING )
580 : 40 : aText2 = ((const ScStringCell*)pCell2)->GetString();
581 : : else
582 [ # # ]: 0 : aText2 = ((const ScEditCell*)pCell2)->GetString();
583 : 40 : return ( aText1 == aText2 );
584 : : }
585 : : case CELLTYPE_FORMULA:
586 : : {
587 : : //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!!
588 : : //! Vergleichsfunktion an der Formelzelle ???
589 : : //! Abfrage mit ScColumn::SwapRow zusammenfassen!
590 : :
591 [ + - ]: 4 : ScTokenArray* pCode1 = ((ScFormulaCell*)pCell1)->GetCode();
592 [ + - ]: 4 : ScTokenArray* pCode2 = ((ScFormulaCell*)pCell2)->GetCode();
593 : :
594 [ + - ]: 4 : if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN
595 : : {
596 : 4 : bool bEqual = true;
597 : 4 : sal_uInt16 nLen = pCode1->GetLen();
598 : 4 : FormulaToken** ppToken1 = pCode1->GetArray();
599 : 4 : FormulaToken** ppToken2 = pCode2->GetArray();
600 [ + + ]: 16 : for (sal_uInt16 i=0; i<nLen; i++)
601 [ - + ]: 12 : if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) )
602 : : {
603 : 0 : bEqual = false;
604 : 0 : break;
605 : : }
606 : :
607 [ + - ]: 4 : if (bEqual)
608 : 4 : return true;
609 : : }
610 : :
611 : 0 : return false; // unterschiedlich lang oder unterschiedliche Tokens
612 : : }
613 : : default:
614 : : OSL_FAIL("huch, was fuer Zellen???");
615 : : }
616 : 68 : return false;
617 : : }
618 : :
619 : : // ============================================================================
620 : :
621 : 928 : ScNoteCell::ScNoteCell( SvtBroadcaster* pBC ) :
622 : 928 : ScBaseCell( CELLTYPE_NOTE )
623 : : {
624 [ + - ]: 928 : TakeBroadcaster( pBC );
625 : 928 : }
626 : :
627 : : #if OSL_DEBUG_LEVEL > 0
628 : : ScNoteCell::~ScNoteCell()
629 : : {
630 : : eCellType = CELLTYPE_DESTROYED;
631 : : }
632 : : #endif
633 : :
634 : : // ============================================================================
635 : :
636 : 37150 : ScValueCell::ScValueCell( double fValue ) :
637 : : ScBaseCell( CELLTYPE_VALUE ),
638 : 37150 : mfValue( fValue )
639 : : {
640 : 37150 : }
641 : :
642 : : #if OSL_DEBUG_LEVEL > 0
643 : : ScValueCell::~ScValueCell()
644 : : {
645 : : eCellType = CELLTYPE_DESTROYED;
646 : : }
647 : : #endif
648 : :
649 : : // ============================================================================
650 : :
651 : 9620 : ScStringCell::ScStringCell( const rtl::OUString& rString ) :
652 : : ScBaseCell( CELLTYPE_STRING ),
653 [ + - ]: 9620 : maString( rString.intern() )
654 : : {
655 : 9620 : }
656 : :
657 : : #if OSL_DEBUG_LEVEL > 0
658 : : ScStringCell::~ScStringCell()
659 : : {
660 : : eCellType = CELLTYPE_DESTROYED;
661 : : }
662 : : #endif
663 : :
664 : : // ============================================================================
665 : :
666 : : //
667 : : // ScFormulaCell
668 : : //
669 : :
670 : 519 : ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
671 : : const rtl::OUString& rFormula,
672 : : const FormulaGrammar::Grammar eGrammar,
673 : : sal_uInt8 cMatInd ) :
674 : : ScBaseCell( CELLTYPE_FORMULA ),
675 : : eTempGrammar( eGrammar),
676 : : pCode( NULL ),
677 : : pDocument( pDoc ),
678 : : pPrevious(0),
679 : : pNext(0),
680 : : pPreviousTrack(0),
681 : : pNextTrack(0),
682 : : nFormatIndex(0),
683 : : nFormatType( NUMBERFORMAT_NUMBER ),
684 : : nSeenInIteration(0),
685 : : cMatrixFlag ( cMatInd ),
686 : : bDirty( true ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0
687 : : bChanged( false ),
688 : : bRunning( false ),
689 : : bCompile( false ),
690 : : bSubTotal( false ),
691 : : bIsIterCell( false ),
692 : : bInChangeTrack( false ),
693 : : bTableOpDirty( false ),
694 : : bNeedListening( false ),
695 [ + - ][ + - ]: 519 : aPos( rPos )
696 : : {
697 [ + - ]: 519 : Compile( rFormula, true, eGrammar ); // bNoListening, Insert does that
698 [ - + ]: 519 : if (!pCode)
699 : : // We need to have a non-NULL token array instance at all times.
700 [ # # ][ # # ]: 0 : pCode = new ScTokenArray;
701 : 519 : }
702 : :
703 : : // Wird von den Importfiltern verwendet
704 : :
705 : 3250 : ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
706 : : const ScTokenArray* pArr,
707 : : const FormulaGrammar::Grammar eGrammar, sal_uInt8 cInd ) :
708 : : ScBaseCell( CELLTYPE_FORMULA ),
709 : : eTempGrammar( eGrammar),
710 [ + - ][ + - ]: 3250 : pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ),
711 : : pDocument( pDoc ),
712 : : pPrevious(0),
713 : : pNext(0),
714 : : pPreviousTrack(0),
715 : : pNextTrack(0),
716 : : nFormatIndex(0),
717 : : nFormatType( NUMBERFORMAT_NUMBER ),
718 : : nSeenInIteration(0),
719 : : cMatrixFlag ( cInd ),
720 : : bDirty( NULL != pArr ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cInd != 0
721 : : bChanged( false ),
722 : : bRunning( false ),
723 : : bCompile( false ),
724 : : bSubTotal( false ),
725 : : bIsIterCell( false ),
726 : : bInChangeTrack( false ),
727 : : bTableOpDirty( false ),
728 : : bNeedListening( false ),
729 [ + - ][ + - ]: 6500 : aPos( rPos )
[ + + ][ + - ]
[ + - ]
730 : : {
731 : : // UPN-Array erzeugen
732 [ + - ][ + - ]: 3250 : if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() )
[ + + ][ + + ]
733 : : {
734 [ + - ]: 3213 : ScCompiler aComp( pDocument, aPos, *pCode);
735 [ + - ]: 3213 : aComp.SetGrammar(eTempGrammar);
736 [ + - ]: 3213 : bSubTotal = aComp.CompileTokenArray();
737 [ + - ]: 3213 : nFormatType = aComp.GetNumFormatType();
738 : : }
739 : : else
740 : : {
741 : 37 : pCode->Reset();
742 [ - + ][ + - ]: 37 : if ( pCode->GetNextOpCodeRPN( ocSubTotal ) )
743 : 0 : bSubTotal = true;
744 : : }
745 : :
746 [ + + ]: 3250 : if (bSubTotal)
747 [ + - ]: 5 : pDocument->AddSubTotalCell(this);
748 : 3250 : }
749 : :
750 : 334 : ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
751 : : ScBaseCell( rCell ),
752 : : SvtListener(),
753 : : aResult( rCell.aResult ),
754 : : eTempGrammar( rCell.eTempGrammar),
755 : : pDocument( &rDoc ),
756 : : pPrevious(0),
757 : : pNext(0),
758 : : pPreviousTrack(0),
759 : : pNextTrack(0),
760 : : nFormatIndex( &rDoc == rCell.pDocument ? rCell.nFormatIndex : 0 ),
761 : : nFormatType( rCell.nFormatType ),
762 : : nSeenInIteration(0),
763 : : cMatrixFlag ( rCell.cMatrixFlag ),
764 : : bDirty( rCell.bDirty ),
765 : : bChanged( rCell.bChanged ),
766 : : bRunning( false ),
767 : : bCompile( rCell.bCompile ),
768 : : bSubTotal( rCell.bSubTotal ),
769 : : bIsIterCell( false ),
770 : : bInChangeTrack( false ),
771 : : bTableOpDirty( false ),
772 : : bNeedListening( false ),
773 [ + - ][ + - ]: 334 : aPos( rPos )
[ + + ]
774 : : {
775 [ + - ]: 334 : pCode = rCell.pCode->Clone();
776 : :
777 : : // evtl. Fehler zuruecksetzen und neu kompilieren
778 : : // nicht im Clipboard - da muss das Fehlerflag erhalten bleiben
779 : : // Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten
780 [ + + ][ + - ]: 334 : if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
[ - + ][ - + ]
781 : : {
782 : 0 : pCode->SetCodeError( 0 );
783 : 0 : bCompile = true;
784 : : }
785 : : //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
786 : 334 : bool bCompileLater = false;
787 : 334 : bool bClipMode = rCell.pDocument->IsClipboard();
788 : :
789 : : //update ScNameTokens
790 [ + + ][ + + ]: 334 : if (!pDocument->IsClipOrUndo() || rDoc.IsUndo())
[ + + ]
791 : : {
792 [ + - ][ - + ]: 298 : if (!pDocument->IsClipboardSource() || aPos.Tab() != rCell.aPos.Tab())
[ # # ][ + - ]
793 : : {
794 : 298 : ScToken* pToken = NULL;
795 [ + - ][ + + ]: 332 : while((pToken = static_cast<ScToken*>(pCode->GetNextName()))!= NULL)
796 : : {
797 : 34 : OpCode eOpCode = pToken->GetOpCode();
798 [ + - ]: 34 : if (eOpCode == ocName)
799 [ + - ]: 34 : adjustRangeName(pToken, rDoc, rCell.pDocument, aPos, rCell.aPos);
800 [ # # ]: 0 : else if (eOpCode == ocDBArea)
801 [ # # ]: 0 : adjustDBRange(pToken, rDoc, rCell.pDocument);
802 : : }
803 : : }
804 : :
805 [ + - ][ + - ]: 298 : bool bCopyBetweenDocs = pDocument->GetPool() != rCell.pDocument->GetPool();
806 [ + + ][ + - ]: 298 : if (bCopyBetweenDocs && !(nCloneFlags & SC_CLONECELL_NOMAKEABS_EXTERNAL))
807 : : {
808 [ + - ]: 28 : pCode->ReadjustAbsolute3DReferences( rCell.pDocument, &rDoc, rCell.aPos);
809 : : }
810 : :
811 [ + - ]: 298 : pCode->AdjustAbsoluteRefs( rCell.pDocument, rCell.aPos, aPos, false, bCopyBetweenDocs );
812 : : }
813 : :
814 [ - + ]: 334 : if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
815 [ # # ]: 0 : pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
816 : :
817 [ + + ]: 334 : if( !bCompile )
818 : : { // Name references with references and ColRowNames
819 : 328 : pCode->Reset();
820 : : ScToken* t;
821 [ + - ][ + + ]: 851 : while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
[ + + ][ + + ]
822 : : {
823 [ + - ][ + + ]: 523 : if ( t->IsExternalRef() )
824 : : {
825 : : // External name, cell, and area references.
826 : 9 : bCompile = true;
827 : : }
828 [ + + ]: 514 : else if ( t->GetType() == svIndex )
829 : : {
830 [ + - ][ + - ]: 22 : ScRangeData* pRangeData = rDoc.GetRangeName()->findByIndex( t->GetIndex() );
[ + - ]
831 [ + - ]: 22 : if( pRangeData )
832 : : {
833 [ + - ][ + - ]: 22 : if( pRangeData->HasReferences() )
834 : 22 : bCompile = true;
835 : : }
836 : : else
837 : 0 : bCompile = true; // invalid reference!
838 : : }
839 [ - + ]: 492 : else if ( t->GetOpCode() == ocColRowName )
840 : : {
841 : 0 : bCompile = true; // new lookup needed
842 : 0 : bCompileLater = bClipMode;
843 : : }
844 : : }
845 : : }
846 [ + + ]: 334 : if( bCompile )
847 : : {
848 [ + - ][ + + ]: 37 : if ( !bCompileLater && bClipMode )
849 : : {
850 : : // Merging ranges needs the actual positions after UpdateReference.
851 : : // ColRowNames need new lookup after positions are adjusted.
852 [ + - ][ + - ]: 12 : bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
[ + - ][ - + ]
853 : : }
854 [ + - ]: 37 : if ( !bCompileLater )
855 : : {
856 : : // bNoListening, not at all if in Clipboard/Undo,
857 : : // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
858 [ + - ]: 37 : CompileTokenArray( true );
859 : : }
860 : : }
861 : :
862 [ + + ]: 334 : if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
863 [ + - ]: 55 : StartListeningTo( &rDoc );
864 : :
865 [ + + ]: 334 : if (bSubTotal)
866 [ + - ]: 8 : pDocument->AddSubTotalCell(this);
867 : 334 : }
868 : :
869 [ + - ][ + - ]: 3847 : ScFormulaCell::~ScFormulaCell()
870 : : {
871 [ + - ]: 3847 : pDocument->RemoveFromFormulaTree( this );
872 [ + - ]: 3847 : pDocument->RemoveSubTotalCell(this);
873 [ + - ][ + + ]: 3847 : if (pCode->HasOpCode(ocMacro))
874 [ + - ][ + - ]: 3 : pDocument->GetMacroManager()->RemoveDependentCell(this);
875 : :
876 [ + + ]: 3847 : if (pDocument->HasExternalRefManager())
877 [ + - ][ + - ]: 229 : pDocument->GetExternalRefManager()->removeRefCell(this);
878 : :
879 [ + - ][ + - ]: 3847 : delete pCode;
880 : : #if OSL_DEBUG_LEVEL > 0
881 : : eCellType = CELLTYPE_DESTROYED;
882 : : #endif
883 [ - + ]: 7688 : }
884 : :
885 : 98 : void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
886 : : const FormulaGrammar::Grammar eGrammar ) const
887 : : {
888 [ - + ][ # # ]: 98 : if( pCode->GetCodeError() && !pCode->GetLen() )
[ - + ]
889 : : {
890 [ # # ][ # # ]: 0 : rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
[ # # ][ # # ]
[ # # ]
891 : : return;
892 : : }
893 [ - + ]: 98 : else if( cMatrixFlag == MM_REFERENCE )
894 : : {
895 : : // Reference to another cell that contains a matrix formula.
896 : 0 : pCode->Reset();
897 [ # # ]: 0 : ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
898 [ # # ]: 0 : if( p )
899 : : {
900 : : /* FIXME: original GetFormula() code obtained
901 : : * pCell only if (!this->IsInChangeTrack()),
902 : : * GetEnglishFormula() omitted that test.
903 : : * Can we live without in all cases? */
904 : : ScBaseCell* pCell;
905 [ # # ]: 0 : ScSingleRefData& rRef = p->GetSingleRef();
906 [ # # ]: 0 : rRef.CalcAbsIfRel( aPos );
907 [ # # ]: 0 : if ( rRef.Valid() )
908 : : pCell = pDocument->GetCell( ScAddress( rRef.nCol,
909 [ # # ]: 0 : rRef.nRow, rRef.nTab ) );
910 : : else
911 : 0 : pCell = NULL;
912 [ # # ][ # # ]: 0 : if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
[ # # ]
913 : : {
914 [ # # ][ # # ]: 0 : ((ScFormulaCell*)pCell)->GetFormula( rBuffer, eGrammar);
915 : : return;
916 : : }
917 : : else
918 : : {
919 [ # # ]: 0 : ScCompiler aComp( pDocument, aPos, *pCode);
920 [ # # ]: 0 : aComp.SetGrammar(eGrammar);
921 [ # # ][ # # ]: 0 : aComp.CreateStringFromTokenArray( rBuffer );
922 : : }
923 : : }
924 : : else
925 : : {
926 : : OSL_FAIL("ScFormulaCell::GetFormula: not a matrix");
927 : : }
928 : : }
929 : : else
930 : : {
931 [ + - ]: 98 : ScCompiler aComp( pDocument, aPos, *pCode);
932 [ + - ]: 98 : aComp.SetGrammar(eGrammar);
933 [ + - ][ + - ]: 98 : aComp.CreateStringFromTokenArray( rBuffer );
934 : : }
935 : :
936 : 98 : sal_Unicode ch('=');
937 [ + - ]: 98 : rBuffer.insert( 0, &ch, 1 );
938 [ + + ]: 98 : if( cMatrixFlag )
939 : : {
940 : 2 : sal_Unicode ch2('{');
941 [ + - ]: 2 : rBuffer.insert( 0, &ch2, 1);
942 [ + - ]: 98 : rBuffer.append( sal_Unicode('}'));
943 : : }
944 : : }
945 : :
946 : 98 : void ScFormulaCell::GetFormula( rtl::OUString& rFormula, const FormulaGrammar::Grammar eGrammar ) const
947 : : {
948 [ + - ]: 98 : rtl::OUStringBuffer rBuffer( rFormula );
949 [ + - ]: 98 : GetFormula( rBuffer, eGrammar );
950 [ + - ]: 98 : rFormula = rBuffer.makeStringAndClear();
951 : 98 : }
952 : :
953 : 0 : void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
954 : : {
955 : 0 : MaybeInterpret();
956 : :
957 : 0 : const ScMatrix* pMat = NULL;
958 [ # # ]: 0 : if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell &&
[ # # # # ]
[ # # ][ # # ]
[ # # ]
959 [ # # ][ # # ]: 0 : ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0))
[ # # ]
960 : 0 : pMat->GetDimensions( rCols, rRows );
961 : : else
962 : : {
963 : 0 : rCols = 0;
964 : 0 : rRows = 0;
965 : : }
966 : 0 : }
967 : :
968 : 519 : void ScFormulaCell::Compile( const rtl::OUString& rFormula, bool bNoListening,
969 : : const FormulaGrammar::Grammar eGrammar )
970 : : {
971 [ + - ]: 519 : if ( pDocument->IsClipOrUndo() )
972 : 519 : return;
973 [ + - ]: 519 : bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
974 [ - + ]: 519 : if ( bWasInFormulaTree )
975 [ # # ]: 0 : pDocument->RemoveFromFormulaTree( this );
976 : : // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
977 [ - + ]: 519 : if ( pCode )
978 [ # # ]: 0 : pCode->Clear();
979 : 519 : ScTokenArray* pCodeOld = pCode;
980 [ + - ]: 519 : ScCompiler aComp( pDocument, aPos);
981 [ + - ]: 519 : aComp.SetGrammar(eGrammar);
982 [ + - ][ + - ]: 519 : pCode = aComp.CompileString( rFormula );
[ + - ]
983 [ - + ]: 519 : if ( pCodeOld )
984 [ # # ][ # # ]: 0 : delete pCodeOld;
985 [ + - ]: 519 : if( !pCode->GetCodeError() )
986 : : {
987 [ - + ][ # # ]: 519 : if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() && rFormula == rtl::OUString(aResult.GetHybridFormula()) )
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ]
[ - + # # ]
988 : : { // nicht rekursiv CompileTokenArray/Compile/CompileTokenArray
989 [ # # ]: 0 : if ( rFormula[0] == '=' )
990 [ # # ][ # # ]: 0 : pCode->AddBad( rFormula.copy(1) );
[ # # ]
991 : : else
992 [ # # ][ # # ]: 0 : pCode->AddBad( rFormula );
[ # # ]
993 : : }
994 : 519 : bCompile = true;
995 [ + - ]: 519 : CompileTokenArray( bNoListening );
996 : : }
997 : : else
998 : : {
999 : 0 : bChanged = true;
1000 : 0 : SetTextWidth( TEXTWIDTH_DIRTY );
1001 : 0 : SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
1002 : : }
1003 [ - + ]: 519 : if ( bWasInFormulaTree )
1004 [ # # ][ + - ]: 519 : pDocument->PutInFormulaTree( this );
1005 : : }
1006 : :
1007 : :
1008 : 642 : void ScFormulaCell::CompileTokenArray( bool bNoListening )
1009 : : {
1010 : : // Not already compiled?
1011 [ - + ][ # # ]: 642 : if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
[ - + ]
1012 [ # # ]: 0 : Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar);
1013 [ + + ][ + + ]: 642 : else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() )
[ + - ][ + + ]
1014 : : {
1015 : : // RPN length may get changed
1016 [ + - ]: 563 : bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
1017 [ + + ]: 563 : if ( bWasInFormulaTree )
1018 [ + - ]: 10 : pDocument->RemoveFromFormulaTree( this );
1019 : :
1020 : : // Loading from within filter? No listening yet!
1021 [ + + ]: 563 : if( pDocument->IsInsertingFromOtherDoc() )
1022 : 15 : bNoListening = true;
1023 : :
1024 [ + + ][ + - ]: 563 : if( !bNoListening && pCode->GetCodeLen() )
[ + + ]
1025 [ + - ]: 13 : EndListeningTo( pDocument );
1026 [ + - ]: 563 : ScCompiler aComp(pDocument, aPos, *pCode);
1027 [ + - ][ + - ]: 563 : aComp.SetGrammar(pDocument->GetGrammar());
1028 [ + - ]: 563 : bSubTotal = aComp.CompileTokenArray();
1029 [ + - ]: 563 : if( !pCode->GetCodeError() )
1030 : : {
1031 : 563 : nFormatType = aComp.GetNumFormatType();
1032 : 563 : nFormatIndex = 0;
1033 : 563 : bChanged = true;
1034 [ + - ]: 563 : aResult.SetToken( NULL);
1035 : 563 : bCompile = false;
1036 [ + + ]: 563 : if ( !bNoListening )
1037 [ + - ]: 13 : StartListeningTo( pDocument );
1038 : : }
1039 [ + + ]: 563 : if ( bWasInFormulaTree )
1040 [ + - ]: 10 : pDocument->PutInFormulaTree( this );
1041 : :
1042 [ - + ]: 563 : if (bSubTotal)
1043 [ # # ][ + - ]: 563 : pDocument->AddSubTotalCell(this);
1044 : : }
1045 : 642 : }
1046 : :
1047 : :
1048 : 1202 : void ScFormulaCell::CompileXML( ScProgress& rProgress )
1049 : : {
1050 [ + + ]: 1202 : if ( cMatrixFlag == MM_REFERENCE )
1051 : : { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
1052 : : // just establish listeners
1053 [ + - ]: 135 : StartListeningTo( pDocument );
1054 : 1202 : return ;
1055 : : }
1056 : :
1057 [ + - ]: 1067 : ScCompiler aComp( pDocument, aPos, *pCode);
1058 [ + - ]: 1067 : aComp.SetGrammar(eTempGrammar);
1059 : 1067 : rtl::OUString aFormula, aFormulaNmsp;
1060 [ + - ]: 1067 : aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
1061 : 1067 : pDocument->DecXMLImportedFormulaCount( aFormula.getLength() );
1062 [ + - ]: 1067 : rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() );
1063 : : // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
1064 [ + - ]: 1067 : if ( pCode )
1065 [ + - ]: 1067 : pCode->Clear();
1066 : 1067 : ScTokenArray* pCodeOld = pCode;
1067 [ + - ][ + - ]: 1067 : pCode = aComp.CompileString( aFormula, aFormulaNmsp );
[ + - ][ + - ]
[ + - ]
1068 [ + - ][ + - ]: 1067 : delete pCodeOld;
1069 [ + - ]: 1067 : if( !pCode->GetCodeError() )
1070 : : {
1071 [ - + ]: 1067 : if ( !pCode->GetLen() )
1072 : : {
1073 [ # # ]: 0 : if ( aFormula[0] == '=' )
1074 [ # # ][ # # ]: 0 : pCode->AddBad( aFormula.copy( 1 ) );
[ # # ]
1075 : : else
1076 [ # # ][ # # ]: 0 : pCode->AddBad( aFormula );
[ # # ]
1077 : : }
1078 [ + - ]: 1067 : bSubTotal = aComp.CompileTokenArray();
1079 [ + - ]: 1067 : if( !pCode->GetCodeError() )
1080 : : {
1081 : 1067 : nFormatType = aComp.GetNumFormatType();
1082 : 1067 : nFormatIndex = 0;
1083 : 1067 : bChanged = true;
1084 : 1067 : bCompile = false;
1085 [ + - ]: 1067 : StartListeningTo( pDocument );
1086 : : }
1087 : :
1088 [ - + ]: 1067 : if (bSubTotal)
1089 [ # # ]: 0 : pDocument->AddSubTotalCell(this);
1090 : : }
1091 : : else
1092 : : {
1093 : 0 : bChanged = true;
1094 : 0 : SetTextWidth( TEXTWIDTH_DIRTY );
1095 : 0 : SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
1096 : : }
1097 : :
1098 : : // Same as in Load: after loading, it must be known if ocMacro is in any formula
1099 : : // (for macro warning, CompileXML is called at the end of loading XML file)
1100 [ + - ][ + - ]: 1067 : if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
[ - + ][ - + ]
1101 : 0 : pDocument->SetHasMacroFunc( true );
1102 : :
1103 : : //volatile cells must be added here for import
1104 [ + + ][ + - : 3099 : if( pCode->IsRecalcModeAlways() || pCode->IsRecalcModeForced() ||
+ - - + ]
[ + + ]
1105 : 2032 : pCode->IsRecalcModeOnLoad() || pCode->IsRecalcModeOnLoadOnce() )
1106 [ + - ][ + - ]: 1202 : pDocument->PutInFormulaTree(this);
1107 : : }
1108 : :
1109 : :
1110 : 1773 : void ScFormulaCell::CalcAfterLoad()
1111 : : {
1112 : 1773 : bool bNewCompiled = false;
1113 : : // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis,
1114 : : // aber kein TokenArray
1115 [ - + ][ # # ]: 1773 : if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
[ - + ]
1116 : : {
1117 [ # # ]: 0 : Compile( aResult.GetHybridFormula(), true, eTempGrammar);
1118 : 0 : aResult.SetToken( NULL);
1119 : 0 : bDirty = true;
1120 : 0 : bNewCompiled = true;
1121 : : }
1122 : : // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen
1123 : : // wurde, da die RangeNames erst jetzt existieren.
1124 [ + - ][ - + ]: 1773 : if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() )
[ # # ][ - + ]
1125 : : {
1126 [ # # ]: 0 : ScCompiler aComp(pDocument, aPos, *pCode);
1127 [ # # ][ # # ]: 0 : aComp.SetGrammar(pDocument->GetGrammar());
1128 [ # # ]: 0 : bSubTotal = aComp.CompileTokenArray();
1129 : 0 : nFormatType = aComp.GetNumFormatType();
1130 : 0 : nFormatIndex = 0;
1131 : 0 : bDirty = true;
1132 : 0 : bCompile = false;
1133 : 0 : bNewCompiled = true;
1134 : :
1135 [ # # ]: 0 : if (bSubTotal)
1136 [ # # ][ # # ]: 0 : pDocument->AddSubTotalCell(this);
1137 : : }
1138 : : // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503
1139 : : // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib
1140 : : // bei einem fabs(-NAN) abstuerzt (#32739#)
1141 : : // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht
1142 [ + + ][ - + ]: 1773 : if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
[ - + ]
1143 : : {
1144 : : OSL_FAIL("Formelzelle INFINITY !!! Woher kommt das Dokument?");
1145 : 0 : aResult.SetResultError( errIllegalFPOperation );
1146 : 0 : bDirty = true;
1147 : : }
1148 : : // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix,
1149 : : // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge
1150 [ - + # # : 1773 : if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF &&
# # ][ - + ]
1151 : 0 : GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() )
1152 : : {
1153 : 0 : cMatrixFlag = MM_FORMULA;
1154 : 0 : SetMatColsRows( 1, 1);
1155 : : }
1156 : : // Muss die Zelle berechnet werden?
1157 : : // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann
1158 : : // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL
1159 [ - + ][ # # ]: 1773 : if( !bNewCompiled || !pCode->GetCodeError() )
[ + - ]
1160 : : {
1161 : 1773 : StartListeningTo( pDocument );
1162 [ - + ]: 1773 : if( !pCode->IsRecalcModeNormal() )
1163 : 0 : bDirty = true;
1164 : : }
1165 [ - + ]: 1773 : if ( pCode->IsRecalcModeAlways() )
1166 : : { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie
1167 : : // auch bei jedem F9 berechnet werden.
1168 : 0 : bDirty = true;
1169 : : }
1170 : : // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in
1171 : : // SetDirtyAfterLoad.
1172 : 1773 : }
1173 : :
1174 : :
1175 : 0 : bool ScFormulaCell::MarkUsedExternalReferences()
1176 : : {
1177 [ # # ][ # # ]: 0 : return pCode && pDocument->MarkUsedExternalReferences( *pCode);
1178 : : }
1179 : :
1180 : :
1181 : 2702 : void ScFormulaCell::Interpret()
1182 : : {
1183 [ + + ][ - + ]: 2702 : if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
[ + + ]
1184 : 34 : return; // no double/triple processing
1185 : :
1186 : : //! HACK:
1187 : : // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen
1188 : : // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!!
1189 : :
1190 [ - + ]: 2668 : if ( pDocument->IsInDdeLinkUpdate() )
1191 : 0 : return;
1192 : :
1193 [ + + ]: 2668 : if (bRunning)
1194 : : {
1195 [ + - ]: 9 : if (!pDocument->GetDocOptions().IsIter())
1196 : : {
1197 : 9 : aResult.SetResultError( errCircularReference );
1198 : 9 : return;
1199 : : }
1200 : :
1201 [ # # ]: 0 : if (aResult.GetResultError() == errCircularReference)
1202 : 0 : aResult.SetResultError( 0 );
1203 : :
1204 : : // Start or add to iteration list.
1205 [ # # # # ]: 0 : if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
[ # # ]
1206 : 0 : !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell)
1207 : 0 : pDocument->GetRecursionHelper().SetInIterationReturn( true);
1208 : :
1209 : 0 : return;
1210 : : }
1211 : : // no multiple interprets for GetErrCode, IsValue, GetValue and
1212 : : // different entry point recursions. Would also lead to premature
1213 : : // convergence in iterations.
1214 [ - + # # ]: 2659 : if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration ==
[ - + ]
1215 : 0 : pDocument->GetRecursionHelper().GetIteration())
1216 : 0 : return ;
1217 : :
1218 : 2659 : ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
1219 : 2659 : bool bOldRunning = bRunning;
1220 [ - + ]: 2659 : if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
1221 : : {
1222 : 0 : bRunning = true;
1223 : 0 : rRecursionHelper.SetInRecursionReturn( true);
1224 : : }
1225 : : else
1226 : : {
1227 : 2659 : InterpretTail( SCITP_NORMAL);
1228 : : }
1229 : :
1230 : : // While leaving a recursion or iteration stack, insert its cells to the
1231 : : // recursion list in reverse order.
1232 [ - + ]: 2659 : if (rRecursionHelper.IsInReturn())
1233 : : {
1234 [ # # # # ]: 0 : if (rRecursionHelper.GetRecursionCount() > 0 ||
[ # # ]
1235 : 0 : !rRecursionHelper.IsDoingRecursion())
1236 : 0 : rRecursionHelper.Insert( this, bOldRunning, aResult);
1237 : 0 : bool bIterationFromRecursion = false;
1238 : 0 : bool bResumeIteration = false;
1239 [ # # ][ # # ]: 2702 : do
[ # # ]
1240 : : {
1241 [ # # # # : 0 : if ((rRecursionHelper.IsInIterationReturn() &&
# # ][ # # ]
[ # # ][ # # ]
1242 : 0 : rRecursionHelper.GetRecursionCount() == 0 &&
1243 : 0 : !rRecursionHelper.IsDoingIteration()) ||
1244 : : bIterationFromRecursion || bResumeIteration)
1245 : : {
1246 : 0 : ScFormulaCell* pIterCell = this; // scope for debug convenience
1247 : 0 : bool & rDone = rRecursionHelper.GetConvergingReference();
1248 : 0 : rDone = false;
1249 [ # # ][ # # ]: 0 : if (!bIterationFromRecursion && bResumeIteration)
1250 : : {
1251 : 0 : bResumeIteration = false;
1252 : : // Resuming iteration expands the range.
1253 : : ScFormulaRecursionList::const_iterator aOldStart(
1254 : 0 : rRecursionHelper.GetLastIterationStart());
1255 [ # # ]: 0 : rRecursionHelper.ResumeIteration();
1256 : : // Mark new cells being in iteration.
1257 [ # # ]: 0 : for (ScFormulaRecursionList::const_iterator aIter(
1258 [ # # ]: 0 : rRecursionHelper.GetIterationStart()); aIter !=
1259 : : aOldStart; ++aIter)
1260 : : {
1261 : 0 : pIterCell = (*aIter).pCell;
1262 : 0 : pIterCell->bIsIterCell = true;
1263 : : }
1264 : : // Mark older cells dirty again, in case they converted
1265 : : // without accounting for all remaining cells in the circle
1266 : : // that weren't touched so far, e.g. conditional. Restore
1267 : : // backuped result.
1268 : 0 : sal_uInt16 nIteration = rRecursionHelper.GetIteration();
1269 [ # # ]: 0 : for (ScFormulaRecursionList::const_iterator aIter(
1270 : 0 : aOldStart); aIter !=
1271 [ # # ]: 0 : rRecursionHelper.GetIterationEnd(); ++aIter)
1272 : : {
1273 : 0 : pIterCell = (*aIter).pCell;
1274 [ # # ]: 0 : if (pIterCell->nSeenInIteration == nIteration)
1275 : : {
1276 [ # # ][ # # ]: 0 : if (!pIterCell->bDirty || aIter == aOldStart)
[ # # ]
1277 : : {
1278 [ # # ]: 0 : pIterCell->aResult = (*aIter).aPreviousResult;
1279 : : }
1280 : 0 : --pIterCell->nSeenInIteration;
1281 : : }
1282 : 0 : pIterCell->bDirty = true;
1283 : 0 : }
1284 : : }
1285 : : else
1286 : : {
1287 : 0 : bResumeIteration = false;
1288 : : // Close circle once.
1289 : 0 : rRecursionHelper.GetList().back().pCell->InterpretTail(
1290 : 0 : SCITP_CLOSE_ITERATION_CIRCLE);
1291 : : // Start at 1, init things.
1292 : 0 : rRecursionHelper.StartIteration();
1293 : : // Mark all cells being in iteration.
1294 [ # # ]: 0 : for (ScFormulaRecursionList::const_iterator aIter(
1295 [ # # ]: 0 : rRecursionHelper.GetIterationStart()); aIter !=
1296 [ # # ]: 0 : rRecursionHelper.GetIterationEnd(); ++aIter)
1297 : : {
1298 : 0 : pIterCell = (*aIter).pCell;
1299 : 0 : pIterCell->bIsIterCell = true;
1300 : : }
1301 : : }
1302 : 0 : bIterationFromRecursion = false;
1303 : 0 : sal_uInt16 nIterMax = pDocument->GetDocOptions().GetIterCount();
1304 [ # # ][ # # ]: 0 : for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone;
[ # # ]
1305 : 0 : rRecursionHelper.IncIteration())
1306 : : {
1307 : 0 : rDone = true;
1308 [ # # # # ]: 0 : for ( ScFormulaRecursionList::iterator aIter(
[ # # ]
1309 [ # # ]: 0 : rRecursionHelper.GetIterationStart()); aIter !=
1310 [ # # ][ # # ]: 0 : rRecursionHelper.GetIterationEnd() &&
[ # # ]
1311 : 0 : !rRecursionHelper.IsInReturn(); ++aIter)
1312 : : {
1313 : 0 : pIterCell = (*aIter).pCell;
1314 [ # # # # ]: 0 : if (pIterCell->IsDirtyOrInTableOpDirty() &&
[ # # ][ # # ]
1315 : 0 : rRecursionHelper.GetIteration() !=
1316 : 0 : pIterCell->GetSeenInIteration())
1317 : : {
1318 [ # # ]: 0 : (*aIter).aPreviousResult = pIterCell->aResult;
1319 [ # # ]: 0 : pIterCell->InterpretTail( SCITP_FROM_ITERATION);
1320 : : }
1321 [ # # ][ # # ]: 0 : rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
[ # # ]
1322 : : }
1323 [ # # ]: 0 : if (rRecursionHelper.IsInReturn())
1324 : : {
1325 : 0 : bResumeIteration = true;
1326 : 0 : break; // for
1327 : : // Don't increment iteration.
1328 : : }
1329 : : }
1330 [ # # ]: 0 : if (!bResumeIteration)
1331 : : {
1332 [ # # ]: 0 : if (rDone)
1333 : : {
1334 [ # # ]: 0 : for (ScFormulaRecursionList::const_iterator aIter(
1335 [ # # ]: 0 : rRecursionHelper.GetIterationStart());
1336 [ # # ]: 0 : aIter != rRecursionHelper.GetIterationEnd();
1337 : : ++aIter)
1338 : : {
1339 : 0 : pIterCell = (*aIter).pCell;
1340 : 0 : pIterCell->bIsIterCell = false;
1341 : 0 : pIterCell->nSeenInIteration = 0;
1342 : 0 : pIterCell->bRunning = (*aIter).bOldRunning;
1343 : : }
1344 : : }
1345 : : else
1346 : : {
1347 [ # # ]: 0 : for (ScFormulaRecursionList::const_iterator aIter(
1348 [ # # ]: 0 : rRecursionHelper.GetIterationStart());
1349 [ # # ]: 0 : aIter != rRecursionHelper.GetIterationEnd();
1350 : : ++aIter)
1351 : : {
1352 : 0 : pIterCell = (*aIter).pCell;
1353 : 0 : pIterCell->bIsIterCell = false;
1354 : 0 : pIterCell->nSeenInIteration = 0;
1355 : 0 : pIterCell->bRunning = (*aIter).bOldRunning;
1356 : : // If one cell didn't converge, all cells of this
1357 : : // circular dependency don't, no matter whether
1358 : : // single cells did.
1359 : 0 : pIterCell->bDirty = false;
1360 : 0 : pIterCell->bTableOpDirty = false;
1361 [ # # ]: 0 : pIterCell->aResult.SetResultError( errNoConvergence);
1362 : 0 : pIterCell->bChanged = true;
1363 : 0 : pIterCell->SetTextWidth( TEXTWIDTH_DIRTY);
1364 : 0 : pIterCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN);
1365 : : }
1366 : : }
1367 : : // End this iteration and remove entries.
1368 : 0 : rRecursionHelper.EndIteration();
1369 : 0 : bResumeIteration = rRecursionHelper.IsDoingIteration();
1370 : : }
1371 : : }
1372 [ # # # # : 0 : if (rRecursionHelper.IsInRecursionReturn() &&
# # ][ # # ]
1373 : 0 : rRecursionHelper.GetRecursionCount() == 0 &&
1374 : 0 : !rRecursionHelper.IsDoingRecursion())
1375 : : {
1376 : 0 : bIterationFromRecursion = false;
1377 : : // Iterate over cells known so far, start with the last cell
1378 : : // encountered, inserting new cells if another recursion limit
1379 : : // is reached. Repeat until solved.
1380 : 0 : rRecursionHelper.SetDoingRecursion( true);
1381 [ # # ]: 0 : do
1382 : : {
1383 : 0 : rRecursionHelper.SetInRecursionReturn( false);
1384 [ # # # # ]: 0 : for (ScFormulaRecursionList::const_iterator aIter(
[ # # ]
1385 [ # # ]: 0 : rRecursionHelper.GetIterationStart());
1386 : 0 : !rRecursionHelper.IsInReturn() && aIter !=
1387 [ # # ][ # # ]: 0 : rRecursionHelper.GetIterationEnd(); ++aIter)
[ # # ]
[ # # # # ]
1388 : : {
1389 : 0 : ScFormulaCell* pCell = (*aIter).pCell;
1390 [ # # ][ # # ]: 0 : if (pCell->IsDirtyOrInTableOpDirty())
1391 : : {
1392 [ # # ]: 0 : pCell->InterpretTail( SCITP_NORMAL);
1393 [ # # ][ # # ]: 0 : if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
[ # # ][ # # ]
1394 : 0 : pCell->bRunning = (*aIter).bOldRunning;
1395 : : }
1396 : : }
1397 : : } while (rRecursionHelper.IsInRecursionReturn());
1398 : 0 : rRecursionHelper.SetDoingRecursion( false);
1399 [ # # ]: 0 : if (rRecursionHelper.IsInIterationReturn())
1400 : : {
1401 [ # # ]: 0 : if (!bResumeIteration)
1402 : 0 : bIterationFromRecursion = true;
1403 : : }
1404 [ # # # # ]: 0 : else if (bResumeIteration ||
[ # # ]
1405 : 0 : rRecursionHelper.IsDoingIteration())
1406 : 0 : rRecursionHelper.GetList().erase(
1407 : : rRecursionHelper.GetIterationStart(),
1408 : 0 : rRecursionHelper.GetLastIterationStart());
1409 : : else
1410 : 0 : rRecursionHelper.Clear();
1411 : : }
1412 : : } while (bIterationFromRecursion || bResumeIteration);
1413 : : }
1414 : : }
1415 : :
1416 : 2659 : void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
1417 : : {
1418 : : class RecursionCounter
1419 : : {
1420 : : ScRecursionHelper& rRec;
1421 : : bool bStackedInIteration;
1422 : : public:
1423 : 2659 : RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r)
1424 : : {
1425 : 2659 : bStackedInIteration = rRec.IsDoingIteration();
1426 [ - + ]: 2659 : if (bStackedInIteration)
1427 : 0 : rRec.GetRecursionInIterationStack().push( p);
1428 : 2659 : rRec.IncRecursionCount();
1429 : 2659 : }
1430 : 2659 : ~RecursionCounter()
1431 : : {
1432 : 2659 : rRec.DecRecursionCount();
1433 [ - + ]: 2659 : if (bStackedInIteration)
1434 : 0 : rRec.GetRecursionInIterationStack().pop();
1435 : 2659 : }
1436 [ + - ][ + - ]: 2659 : } aRecursionCounter( pDocument->GetRecursionHelper(), this);
1437 [ + - ]: 2659 : nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
1438 [ - + ][ - + ]: 2659 : if( !pCode->GetCodeLen() && !pCode->GetCodeError() )
[ + + ]
1439 : : {
1440 : : // #i11719# no UPN and no error and no token code but result string present
1441 : : // => interpretation of this cell during name-compilation and unknown names
1442 : : // => can't exchange underlying code array in CompileTokenArray() /
1443 : : // Compile() because interpreter's token iterator would crash or pCode
1444 : : // would be deleted twice if this cell was interpreted during
1445 : : // compilation.
1446 : : // This should only be a temporary condition and, since we set an
1447 : : // error, if ran into it again we'd bump into the dirty-clearing
1448 : : // condition further down.
1449 [ # # ][ # # ]: 0 : if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
[ # # ][ # # ]
1450 : : {
1451 : 0 : pCode->SetCodeError( errNoCode );
1452 : : // This is worth an assertion; if encountered in daily work
1453 : : // documents we might need another solution. Or just confirm correctness.
1454 : : OSL_FAIL( "ScFormulaCell::Interpret: no UPN, no error, no token, but hybrid formula string" );
1455 : : return;
1456 : : }
1457 [ # # ]: 0 : CompileTokenArray();
1458 : : }
1459 : :
1460 [ + + ][ + - ]: 2659 : if( pCode->GetCodeLen() && pDocument )
[ + + ]
1461 : : {
1462 : : class StackCleaner
1463 : : {
1464 : : ScDocument* pDoc;
1465 : : ScInterpreter* pInt;
1466 : : public:
1467 : 2619 : StackCleaner( ScDocument* pD, ScInterpreter* pI )
1468 : 2619 : : pDoc(pD), pInt(pI)
1469 : 2619 : {}
1470 : 2619 : ~StackCleaner()
1471 : : {
1472 [ + - ]: 2619 : delete pInt;
1473 : 2619 : pDoc->DecInterpretLevel();
1474 : 2619 : }
1475 : : };
1476 : 2619 : pDocument->IncInterpretLevel();
1477 [ + - ][ + - ]: 2619 : ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode );
1478 : 2619 : StackCleaner aStackCleaner( pDocument, p);
1479 [ + - ]: 2619 : sal_uInt16 nOldErrCode = aResult.GetResultError();
1480 [ + - ]: 2619 : if ( nSeenInIteration == 0 )
1481 : : { // Only the first time
1482 : : // With bChanged=false, if a newly compiled cell has a result of
1483 : : // 0.0, no change is detected and the cell will not be repainted.
1484 : : // bChanged = false;
1485 [ + - ]: 2619 : aResult.SetResultError( 0 );
1486 : : }
1487 : :
1488 [ + - ][ - + ]: 2619 : switch ( aResult.GetResultError() )
1489 : : {
1490 : : case errCircularReference : // will be determined again if so
1491 [ # # ]: 0 : aResult.SetResultError( 0 );
1492 : 0 : break;
1493 : : }
1494 : :
1495 : 2619 : bool bOldRunning = bRunning;
1496 : 2619 : bRunning = true;
1497 [ + - ]: 2619 : p->Interpret();
1498 [ + - ][ - + ]: 2619 : if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
[ # # ][ - + ]
1499 : : {
1500 [ # # ]: 0 : if (nSeenInIteration > 0)
1501 : 0 : --nSeenInIteration; // retry when iteration is resumed
1502 : : return;
1503 : : }
1504 : 2619 : bRunning = bOldRunning;
1505 : :
1506 : : // #i102616# For single-sheet saving consider only content changes, not format type,
1507 : : // because format type isn't set on loading (might be changed later)
1508 : 2619 : bool bContentChanged = false;
1509 : :
1510 : : // Do not create a HyperLink() cell if the formula results in an error.
1511 [ + + ][ - + ]: 2619 : if( p->GetError() && pCode->IsHyperLink())
[ - + ]
1512 : 0 : pCode->SetHyperLink(false);
1513 : :
1514 [ + + ][ + + ]: 2619 : if( p->GetError() && p->GetError() != errCircularReference)
[ + + ]
1515 : : {
1516 : 309 : bDirty = false;
1517 : 309 : bTableOpDirty = false;
1518 : 309 : bChanged = true;
1519 : : }
1520 [ - + ][ # # ]: 2619 : if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
[ # # ][ - + ]
1521 : : {
1522 [ # # ]: 0 : bool bIsValue = aResult.IsValue(); // the previous type
1523 : : // Did it converge?
1524 [ # # ][ # # ]: 0 : if ((bIsValue && p->GetResultType() == svDouble && fabs(
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1525 [ # # ][ # # ]: 0 : p->GetNumResult() - aResult.GetDouble()) <=
1526 [ # # ]: 0 : pDocument->GetDocOptions().GetIterEps()) ||
1527 [ # # ]: 0 : (!bIsValue && p->GetResultType() == svString &&
1528 [ # # ][ # # ]: 0 : p->GetStringResult() == aResult.GetString()))
[ # # ]
1529 : : {
1530 : : // A convergence in the first iteration doesn't necessarily
1531 : : // mean that it's done, it may be because not all related cells
1532 : : // of a circle changed their values yet. If the set really
1533 : : // converges it will do so also during the next iteration. This
1534 : : // fixes situations like of #i44115#. If this wasn't wanted an
1535 : : // initial "uncalculated" value would be needed for all cells
1536 : : // of a circular dependency => graph needed before calculation.
1537 [ # # # # ]: 0 : if (nSeenInIteration > 1 ||
[ # # ]
1538 [ # # ]: 0 : pDocument->GetDocOptions().GetIterCount() == 1)
1539 : : {
1540 : 0 : bDirty = false;
1541 : 0 : bTableOpDirty = false;
1542 : : }
1543 : : }
1544 : : }
1545 : :
1546 : : // New error code?
1547 [ + + ]: 2619 : if( p->GetError() != nOldErrCode )
1548 : : {
1549 : 173 : bChanged = true;
1550 : : // bContentChanged only has to be set if the file content would be changed
1551 [ + - ][ + + ]: 173 : if ( aResult.GetCellResultType() != svUnknown )
1552 : 138 : bContentChanged = true;
1553 : : }
1554 : : // Different number format?
1555 [ + + ]: 2619 : if( nFormatType != p->GetRetFormatType() )
1556 : : {
1557 : 187 : nFormatType = p->GetRetFormatType();
1558 : 187 : bChanged = true;
1559 : : }
1560 [ - + ]: 2619 : if( nFormatIndex != p->GetRetFormatIndex() )
1561 : : {
1562 : 0 : nFormatIndex = p->GetRetFormatIndex();
1563 : 0 : bChanged = true;
1564 : : }
1565 : :
1566 : : // In case of changes just obtain the result, no temporary and
1567 : : // comparison needed anymore.
1568 [ + + ]: 2619 : if (bChanged)
1569 : : {
1570 : : // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
1571 : : // Also handle special cases of initial results after loading.
1572 : :
1573 [ + + ][ + - ]: 2149 : if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
[ + + ][ + + ]
1574 : : {
1575 [ + - ][ + - ]: 216 : ScFormulaResult aNewResult( p->GetResultToken().get());
[ + - ]
1576 [ + - ]: 216 : StackVar eOld = aResult.GetCellResultType();
1577 [ + - ]: 216 : StackVar eNew = aNewResult.GetCellResultType();
1578 [ - + ][ # # ]: 216 : if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
[ # # ][ # # ]
[ # # ][ + - ]
1579 : : {
1580 : : // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
1581 : : // -> no change
1582 : : }
1583 : : else
1584 : : {
1585 [ + + ]: 216 : if ( eOld == svHybridCell ) // string result from SetFormulaResultString?
1586 : 18 : eOld = svString; // ScHybridCellToken has a valid GetString method
1587 : :
1588 : : // #i106045# use approxEqual to compare with stored value
1589 : : bContentChanged = (eOld != eNew ||
1590 [ + - ][ + - ]: 180 : (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) ||
1591 [ + - ]: 396 : (eNew == svString && aResult.GetString() != aNewResult.GetString()));
[ + + + + ]
[ + + ][ + - ]
[ + - ][ + - ]
[ - + ]
1592 [ + - ]: 216 : }
1593 : : }
1594 : :
1595 [ + - ][ + - ]: 2149 : aResult.SetToken( p->GetResultToken().get() );
[ + - ]
1596 : : }
1597 : : else
1598 : : {
1599 [ + - ][ + - ]: 470 : ScFormulaResult aNewResult( p->GetResultToken().get());
[ + - ]
1600 [ + - ]: 470 : StackVar eOld = aResult.GetCellResultType();
1601 [ + - ]: 470 : StackVar eNew = aNewResult.GetCellResultType();
1602 : : bChanged = (eOld != eNew ||
1603 [ + - ][ + - ]: 314 : (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
1604 [ + + ][ + + ]: 784 : (eNew == svString && aResult.GetString() != aNewResult.GetString()));
[ + + ][ + + ]
[ + - ][ + - ]
[ + - ][ - + ]
1605 : :
1606 : : // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
1607 [ + + ][ + - ]: 470 : if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
[ + - ][ - + ]
[ - + ]
1608 : : {
1609 [ # # ][ # # ]: 0 : if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
[ # # ]
1610 [ # # ][ # # ]: 0 : ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) ||
[ # # ]
1611 [ # # ][ # # ]: 0 : ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) )
1612 : : {
1613 : : // no change, see above
1614 : : }
1615 : : else
1616 : 0 : bContentChanged = true;
1617 : : }
1618 : :
1619 [ + - ][ + - ]: 470 : aResult.Assign( aNewResult);
1620 : : }
1621 : :
1622 : : // Precision as shown?
1623 [ + - ][ + + ]: 4707 : if ( aResult.IsValue() && !p->GetError()
[ + + + + ]
[ + - ][ + - ]
[ + - ][ + + ]
1624 [ + - ]: 2088 : && pDocument->GetDocOptions().IsCalcAsShown()
1625 : : && nFormatType != NUMBERFORMAT_DATE
1626 : : && nFormatType != NUMBERFORMAT_TIME
1627 : : && nFormatType != NUMBERFORMAT_DATETIME )
1628 : : {
1629 [ + - ]: 14 : sal_uLong nFormat = pDocument->GetNumberFormat( aPos );
1630 [ - + ][ # # ]: 14 : if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1631 : 0 : nFormat = nFormatIndex;
1632 [ + - ]: 14 : if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1633 : : nFormat = ScGlobal::GetStandardFormat(
1634 [ + - ][ + - ]: 14 : *pDocument->GetFormatTable(), nFormat, nFormatType );
1635 : : aResult.SetDouble( pDocument->RoundValueAsShown(
1636 [ + - ][ + - ]: 14 : aResult.GetDouble(), nFormat));
[ + - ]
1637 : : }
1638 [ + - ]: 2619 : if (eTailParam == SCITP_NORMAL)
1639 : : {
1640 : 2619 : bDirty = false;
1641 : 2619 : bTableOpDirty = false;
1642 : : }
1643 [ + - ][ + - ]: 2619 : if( aResult.GetMatrix() )
[ + + ]
1644 : : {
1645 : : // If the formula wasn't entered as a matrix formula, live on with
1646 : : // the upper left corner and let reference counting delete the matrix.
1647 [ + + ][ + - ]: 81 : if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
[ + + ]
1648 [ + - ][ + - ]: 23 : aResult.SetToken( aResult.GetCellResultToken().get());
[ + - ]
1649 : : }
1650 [ + - ][ + + ]: 2619 : if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
[ + - ][ - + ]
[ - + ]
1651 : : {
1652 : : // Coded double error may occur via filter import.
1653 [ # # ]: 0 : sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble());
1654 [ # # ]: 0 : aResult.SetResultError( nErr);
1655 : 0 : bChanged = bContentChanged = true;
1656 : : }
1657 [ + + ]: 2619 : if( bChanged )
1658 : : {
1659 : 2325 : SetTextWidth( TEXTWIDTH_DIRTY );
1660 : 2325 : SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
1661 : : }
1662 [ + + ][ + - ]: 2619 : if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
[ + + ][ + + ]
1663 : : {
1664 : : // pass bIgnoreLock=true, because even if called from pending row height update,
1665 : : // a changed result must still reset the stream flag
1666 [ + - ]: 12 : pDocument->SetStreamValid(aPos.Tab(), false, true);
1667 : : }
1668 [ + + ]: 2619 : if ( !pCode->IsRecalcModeAlways() )
1669 [ + - ]: 2487 : pDocument->RemoveFromFormulaTree( this );
1670 : :
1671 : : // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten)
1672 : :
1673 [ - + ]: 2619 : if ( pCode->IsRecalcModeForced() )
1674 : : {
1675 : : sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
1676 [ # # ]: 0 : aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
1677 [ # # ]: 0 : if ( nValidation )
1678 : : {
1679 [ # # ]: 0 : const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
1680 [ # # ][ # # ]: 0 : if ( pData && !pData->IsDataValid( this, aPos ) )
[ # # ][ # # ]
1681 [ # # ]: 0 : pData->DoCalcError( this );
1682 : : }
1683 : : }
1684 : :
1685 : : // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren
1686 : : ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
1687 [ + - ]: 2619 : pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
1688 : :
1689 [ + - ]: 2619 : switch (p->GetVolatileType())
[ + - + - ]
1690 : : {
1691 : : case ScInterpreter::VOLATILE:
1692 : : // Volatile via built-in volatile functions. No actions needed.
1693 : 132 : break;
1694 : : case ScInterpreter::VOLATILE_MACRO:
1695 : : // The formula contains a volatile macro.
1696 : 0 : pCode->SetRecalcModeAlways();
1697 [ # # ]: 0 : pDocument->PutInFormulaTree(this);
1698 [ # # ]: 0 : StartListeningTo(pDocument);
1699 : 0 : break;
1700 : : case ScInterpreter::NOT_VOLATILE:
1701 [ - + ]: 2487 : if (pCode->IsRecalcModeAlways())
1702 : : {
1703 : : // The formula was previously volatile, but no more.
1704 [ # # ]: 0 : EndListeningTo(pDocument);
1705 : 0 : pCode->SetRecalcModeNormal();
1706 : : }
1707 : : else
1708 : : {
1709 : : // non-volatile formula. End listening to the area in case
1710 : : // it's listening due to macro module change.
1711 [ + - ]: 2487 : pDocument->EndListeningArea(BCA_LISTEN_ALWAYS, this);
1712 : : }
1713 [ + - ]: 2487 : pDocument->RemoveFromFormulaTree(this);
1714 : 2619 : break;
1715 : : default:
1716 : : ;
1717 [ + - ][ + - ]: 2619 : }
1718 : : }
1719 : : else
1720 : : {
1721 : : // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen
1722 : : OSL_ENSURE( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" );
1723 : 40 : bDirty = false;
1724 : 2659 : bTableOpDirty = false;
1725 [ + - ][ + - ]: 2659 : }
1726 : : }
1727 : :
1728 : :
1729 : 84 : void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows )
1730 : : {
1731 : 84 : ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
1732 [ - + ]: 84 : if (pMat)
1733 : 0 : pMat->SetMatColsRows( nCols, nRows);
1734 [ - + ][ # # ]: 84 : else if (nCols || nRows)
1735 : : {
1736 [ + - ]: 84 : aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
1737 : : // Setting the new token actually forces an empty result at this top
1738 : : // left cell, so have that recalculated.
1739 : 84 : SetDirty();
1740 : : }
1741 : 84 : }
1742 : :
1743 : :
1744 : 28 : void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
1745 : : {
1746 : 28 : const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
1747 [ + - ]: 28 : if (pMat)
1748 : 28 : pMat->GetMatColsRows( nCols, nRows);
1749 : : else
1750 : : {
1751 : 0 : nCols = 0;
1752 : 0 : nRows = 0;
1753 : : }
1754 : 28 : }
1755 : :
1756 : :
1757 : 1755 : sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const
1758 : : {
1759 [ - + ][ # # ]: 1755 : if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1760 : 0 : return nFormatIndex;
1761 : : //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
1762 [ + + ]: 1755 : if ( aResult.IsValue() )
1763 : 1512 : return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType );
1764 : : else
1765 : 1755 : return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType );
1766 : : }
1767 : :
1768 : :
1769 : 10237 : void ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
1770 : : {
1771 [ + + ][ + - ]: 10237 : if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
[ + + ]
1772 : : {
1773 [ + - ][ + + ]: 3025 : const ScHint* p = PTR_CAST( ScHint, &rHint );
1774 [ + + ]: 3025 : sal_uLong nHint = (p ? p->GetId() : 0);
1775 [ + + ]: 3025 : if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
1776 : : {
1777 : 3018 : bool bForceTrack = false;
1778 [ + + ]: 3018 : if ( nHint & SC_HINT_TABLEOPDIRTY )
1779 : : {
1780 : 1414 : bForceTrack = !bTableOpDirty;
1781 [ + + ]: 1414 : if ( !bTableOpDirty )
1782 : : {
1783 : 795 : pDocument->AddTableOpFormulaCell( this );
1784 : 795 : bTableOpDirty = true;
1785 : : }
1786 : : }
1787 : : else
1788 : : {
1789 : 1604 : bForceTrack = !bDirty;
1790 : 1604 : SetDirtyVar();
1791 : : }
1792 : : // Don't remove from FormulaTree to put in FormulaTrack to
1793 : : // put in FormulaTree again and again, only if necessary.
1794 : : // Any other means except RECALCMODE_ALWAYS by which a cell could
1795 : : // be in FormulaTree if it would notify other cells through
1796 : : // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
1797 : : // Yes. The new TableOpDirty made it necessary to have a
1798 : : // forced mode where formulas may still be in FormulaTree from
1799 : : // TableOpDirty but have to notify dependents for normal dirty.
1800 [ + + ][ + + : 6036 : if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
- + + + ]
[ + + ]
1801 : 1392 : || pCode->IsRecalcModeAlways())
1802 : 1626 : && !pDocument->IsInFormulaTrack( this ) )
1803 : 1403 : pDocument->AppendToFormulaTrack( this );
1804 : : }
1805 : : }
1806 : 10237 : }
1807 : :
1808 : 962 : void ScFormulaCell::SetDirty()
1809 : : {
1810 [ + - ]: 962 : if ( !IsInChangeTrack() )
1811 : : {
1812 [ - + ]: 962 : if ( pDocument->GetHardRecalcState() )
1813 : 0 : SetDirtyVar();
1814 : : else
1815 : : {
1816 : : // Mehrfach-FormulaTracking in Load und in CompileAll
1817 : : // nach CopyScenario und CopyBlockFromClip vermeiden.
1818 : : // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=false
1819 : : // setzen, z.B. in CompileTokenArray
1820 [ + + ][ + + ]: 962 : if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
[ + + ]
1821 : : {
1822 : 907 : SetDirtyVar();
1823 : 907 : pDocument->AppendToFormulaTrack( this );
1824 : 907 : pDocument->TrackFormulas();
1825 : : }
1826 : : }
1827 : :
1828 [ + + ]: 962 : if (pDocument->IsStreamValid(aPos.Tab()))
1829 : 15 : pDocument->SetStreamValid(aPos.Tab(), false);
1830 : : }
1831 : 962 : }
1832 : :
1833 : 4421 : void ScFormulaCell::SetDirtyVar()
1834 : : {
1835 : 4421 : bDirty = true;
1836 : : // mark the sheet of this cell to be calculated
1837 : : //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
1838 : 4421 : }
1839 : :
1840 : 1773 : void ScFormulaCell::SetDirtyAfterLoad()
1841 : : {
1842 : 1773 : bDirty = true;
1843 [ + - ]: 1773 : if ( !pDocument->GetHardRecalcState() )
1844 : 1773 : pDocument->PutInFormulaTree( this );
1845 : 1773 : }
1846 : :
1847 : 1205 : void ScFormulaCell::SetTableOpDirty()
1848 : : {
1849 [ + - ]: 1205 : if ( !IsInChangeTrack() )
1850 : : {
1851 [ - + ]: 1205 : if ( pDocument->GetHardRecalcState() )
1852 : 0 : bTableOpDirty = true;
1853 : : else
1854 : : {
1855 [ + + ][ - + ]: 1205 : if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
[ + + ]
1856 : : {
1857 [ + - ]: 134 : if ( !bTableOpDirty )
1858 : : {
1859 : 134 : pDocument->AddTableOpFormulaCell( this );
1860 : 134 : bTableOpDirty = true;
1861 : : }
1862 : 134 : pDocument->AppendToFormulaTrack( this );
1863 : 134 : pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
1864 : : }
1865 : : }
1866 : : }
1867 : 1205 : }
1868 : :
1869 : :
1870 : 19480 : bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
1871 : : {
1872 [ + + ][ - + ]: 19480 : return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
[ # # ]
1873 : : }
1874 : :
1875 : :
1876 : 40 : void ScFormulaCell::SetErrCode( sal_uInt16 n )
1877 : : {
1878 : : /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
1879 : : * used whether it is solely for transport of a simple result error and get
1880 : : * rid of that abuse. */
1881 : 40 : pCode->SetCodeError( n );
1882 : : // Hard set errors are transported as result type value per convention,
1883 : : // e.g. via clipboard. ScFormulaResult::IsValue() and
1884 : : // ScFormulaResult::GetDouble() handle that.
1885 : 40 : aResult.SetResultError( n );
1886 : 40 : }
1887 : :
1888 : 48 : void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
1889 : : {
1890 [ + - ]: 48 : if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
1891 : 48 : bDirty = true;
1892 [ + - ]: 48 : if ( nBits & RECALCMODE_ONLOAD_ONCE )
1893 : : { // OnLoadOnce nur zum Dirty setzen nach Filter-Import
1894 : 48 : nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
1895 : : }
1896 : 48 : pCode->AddRecalcMode( nBits );
1897 : 48 : }
1898 : :
1899 : : // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
1900 : 0 : void ScFormulaCell::GetURLResult( rtl::OUString& rURL, rtl::OUString& rCellText )
1901 : : {
1902 : 0 : rtl::OUString aCellString;
1903 : :
1904 : : Color* pColor;
1905 : :
1906 : : // Cell Text uses the Cell format while the URL uses
1907 : : // the default format for the type.
1908 [ # # ]: 0 : sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos );
1909 [ # # ]: 0 : SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
1910 : :
1911 [ # # ]: 0 : if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1912 [ # # ]: 0 : nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
1913 : :
1914 [ # # ]: 0 : sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER);
1915 : :
1916 [ # # ][ # # ]: 0 : if ( IsValue() )
1917 : : {
1918 [ # # ]: 0 : double fValue = GetValue();
1919 [ # # ]: 0 : pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
1920 : : }
1921 : : else
1922 : : {
1923 [ # # ]: 0 : aCellString = GetString();
1924 [ # # ]: 0 : pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
1925 : : }
1926 [ # # ]: 0 : ScConstMatrixRef xMat( aResult.GetMatrix());
1927 [ # # ]: 0 : if (xMat)
1928 : : {
1929 : : // determine if the matrix result is a string or value.
1930 [ # # ][ # # ]: 0 : if (!xMat->IsValue(0, 1))
1931 [ # # ]: 0 : rURL = xMat->GetString(0, 1);
1932 : : else
1933 : : pFormatter->GetOutputString(
1934 [ # # ][ # # ]: 0 : xMat->GetDouble(0, 1), nURLFormat, rURL, &pColor);
1935 : : }
1936 : :
1937 [ # # ]: 0 : if(rURL.isEmpty())
1938 : : {
1939 [ # # ][ # # ]: 0 : if(IsValue())
1940 [ # # ][ # # ]: 0 : pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
1941 : : else
1942 [ # # ]: 0 : pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
1943 [ # # ]: 0 : }
1944 : 0 : }
1945 : :
1946 : 334 : bool ScFormulaCell::IsMultilineResult()
1947 : : {
1948 [ + + ]: 334 : if (!IsValue())
1949 : 40 : return aResult.IsMultiline();
1950 : 334 : return false;
1951 : : }
1952 : :
1953 : 16624 : void ScFormulaCell::MaybeInterpret()
1954 : : {
1955 [ + + ]: 16624 : if (!IsDirtyOrInTableOpDirty())
1956 : 16624 : return;
1957 : :
1958 [ + + ][ - + ]: 630 : if (pDocument->GetAutoCalc() || (cMatrixFlag != MM_NONE))
[ + + ]
1959 : 624 : Interpret();
1960 : : }
1961 : :
1962 : 0 : EditTextObject* ScFormulaCell::CreateURLObject()
1963 : : {
1964 : 0 : rtl::OUString aCellText;
1965 : 0 : rtl::OUString aURL;
1966 [ # # ]: 0 : GetURLResult( aURL, aCellText );
1967 : :
1968 [ # # ]: 0 : SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT);
1969 [ # # ]: 0 : EditEngine& rEE = pDocument->GetEditEngine();
1970 [ # # ][ # # ]: 0 : rEE.SetText( EMPTY_STRING );
1971 [ # # ][ # # ]: 0 : rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) );
[ # # ]
1972 : :
1973 [ # # ][ # # ]: 0 : return rEE.CreateTextObject();
1974 : : }
1975 : :
1976 : : // ============================================================================
1977 : :
1978 : 32 : ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell )
1979 : : {
1980 : 32 : pCode = pCell->GetCode();
1981 : 32 : pCode->Reset();
1982 : 32 : aPos = pCell->aPos;
1983 : 32 : }
1984 : :
1985 : 44 : bool lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
1986 : : {
1987 : 44 : ScSingleRefData& rRef1 = p->GetSingleRef();
1988 [ + - ]: 88 : if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
[ + - - + ]
[ - + ][ + - ]
1989 : 44 : || !rRef1.Valid() )
1990 : 0 : return true;
1991 [ + + ][ - + ]: 44 : if ( p->GetType() == svDoubleRef || p->GetType() == svExternalDoubleRef )
[ + + ]
1992 : : {
1993 : 5 : ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
1994 [ + - ]: 10 : if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
[ + - - + ]
[ - + ][ + - ]
1995 : 5 : || !rRef2.Valid() )
1996 : 0 : return true;
1997 : : }
1998 : 44 : return false;
1999 : : }
2000 : :
2001 : 40 : bool ScDetectiveRefIter::GetNextRef( ScRange& rRange )
2002 : : {
2003 : 40 : bool bRet = false;
2004 : 40 : ScToken* p = GetNextRefToken();
2005 [ + + ]: 40 : if( p )
2006 : : {
2007 [ + - ]: 20 : SingleDoubleRefProvider aProv( *p );
2008 : 20 : rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
2009 : 20 : rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
2010 : 20 : bRet = true;
2011 : : }
2012 : :
2013 : 40 : return bRet;
2014 : : }
2015 : :
2016 : 76 : ScToken* ScDetectiveRefIter::GetNextRefToken()
2017 : : {
2018 : 76 : ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
2019 [ + + ]: 76 : if (p)
2020 : 44 : p->CalcAbsIfRel( aPos );
2021 : :
2022 [ + + ][ - + ]: 76 : while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) )
[ - + ]
2023 : : {
2024 : 0 : p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
2025 [ # # ]: 0 : if (p)
2026 : 0 : p->CalcAbsIfRel( aPos );
2027 : : }
2028 : 76 : return p;
2029 [ + - ][ + - ]: 153 : }
2030 : :
2031 : : // ============================================================================
2032 : :
2033 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|