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