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