xref: /aoo41x/main/sc/source/core/data/cell2.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 #include <algorithm>
35 #include <deque>
36 
37 #include <boost/bind.hpp>
38 
39 #include <vcl/mapmod.hxx>
40 #include <editeng/editobj.hxx>
41 #include <editeng/editstat.hxx>
42 
43 #include "cell.hxx"
44 #include "compiler.hxx"
45 #include "formula/errorcodes.hxx"
46 #include "document.hxx"
47 #include "rangenam.hxx"
48 #include "rechead.hxx"
49 #include "refupdat.hxx"
50 #include "scmatrix.hxx"
51 #include "editutil.hxx"
52 #include "chgtrack.hxx"
53 #include "externalrefmgr.hxx"
54 
55 using namespace formula;
56 
57 // STATIC DATA -----------------------------------------------------------
58 
59 #ifdef USE_MEMPOOL
60 const sal_uInt16 nMemPoolEditCell = (0x1000 - 64) / sizeof(ScNoteCell);
61 IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell, nMemPoolEditCell, nMemPoolEditCell )
62 #endif
63 
64 // ============================================================================
65 
66 ScEditCell::ScEditCell( const EditTextObject* pObject, ScDocument* pDocP,
67             const SfxItemPool* pFromPool )  :
68         ScBaseCell( CELLTYPE_EDIT ),
69         pString( NULL ),
70         pDoc( pDocP )
71 {
72     SetTextObject( pObject, pFromPool );
73 }
74 
75 ScEditCell::ScEditCell( const ScEditCell& rCell, ScDocument& rDoc )  :
76         ScBaseCell( rCell ),
77         pString( NULL ),
78         pDoc( &rDoc )
79 {
80     SetTextObject( rCell.pData, rCell.pDoc->GetEditPool() );
81 }
82 
83 ScEditCell::ScEditCell( const String& rString, ScDocument* pDocP )  :
84         ScBaseCell( CELLTYPE_EDIT ),
85         pString( NULL ),
86         pDoc( pDocP )
87 {
88     DBG_ASSERT( rString.Search('\n') != STRING_NOTFOUND ||
89                 rString.Search(CHAR_CR) != STRING_NOTFOUND,
90                 "EditCell mit einfachem Text !?!?" );
91 
92     EditEngine& rEngine = pDoc->GetEditEngine();
93     rEngine.SetText( rString );
94     pData = rEngine.CreateTextObject();
95 }
96 
97 ScEditCell::~ScEditCell()
98 {
99     delete pData;
100     delete pString;
101 
102 #ifdef DBG_UTIL
103     eCellType = CELLTYPE_DESTROYED;
104 #endif
105 }
106 
107 void ScEditCell::SetData( const EditTextObject* pObject,
108             const SfxItemPool* pFromPool )
109 {
110     if ( pString )
111     {
112         delete pString;
113         pString = NULL;
114     }
115     delete pData;
116     SetTextObject( pObject, pFromPool );
117 }
118 
119 void ScEditCell::GetData( const EditTextObject*& rpObject ) const
120 {
121     rpObject = pData;
122 }
123 
124 void ScEditCell::GetString( String& rString ) const
125 {
126     if ( pString )
127         rString = *pString;
128     else if ( pData )
129     {
130         // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
131         EditEngine& rEngine = pDoc->GetEditEngine();
132         rEngine.SetText( *pData );
133         rString = ScEditUtil::GetMultilineString(rEngine); // string with line separators between paragraphs
134         // cache short strings for formulas
135         if ( rString.Len() < 256 )
136             ((ScEditCell*)this)->pString = new String( rString );   //! non-const
137     }
138     else
139         rString.Erase();
140 }
141 
142 void ScEditCell::SetTextObject( const EditTextObject* pObject,
143             const SfxItemPool* pFromPool )
144 {
145     if ( pObject )
146     {
147         if ( pFromPool && pDoc->GetEditPool() == pFromPool )
148             pData = pObject->Clone();
149         else
150         {   //! anderer Pool
151             // Leider gibt es keinen anderen Weg, um den Pool umzuhaengen,
152             // als das Object durch eine entsprechende Engine zu schleusen..
153             EditEngine& rEngine = pDoc->GetEditEngine();
154             if ( pObject->HasOnlineSpellErrors() )
155             {
156                 sal_uLong nControl = rEngine.GetControlWord();
157                 const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
158                 sal_Bool bNewControl = ( (nControl & nSpellControl) != nSpellControl );
159                 if ( bNewControl )
160                     rEngine.SetControlWord( nControl | nSpellControl );
161                 rEngine.SetText( *pObject );
162                 pData = rEngine.CreateTextObject();
163                 if ( bNewControl )
164                     rEngine.SetControlWord( nControl );
165             }
166             else
167             {
168                 rEngine.SetText( *pObject );
169                 pData = rEngine.CreateTextObject();
170             }
171         }
172     }
173     else
174         pData = NULL;
175 }
176 
177 // ============================================================================
178 
179 namespace
180 {
181 
182 using std::deque;
183 
184 typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&);
185 
186 
187 static SCCOLROW lcl_GetCol(const ScSingleRefData& rData)
188 {
189     return rData.nCol;
190 }
191 
192 
193 static SCCOLROW lcl_GetRow(const ScSingleRefData& rData)
194 {
195     return rData.nRow;
196 }
197 
198 
199 static SCCOLROW lcl_GetTab(const ScSingleRefData& rData)
200 {
201     return rData.nTab;
202 }
203 
204 
205 /** Check if both references span the same range in selected dimension.
206  */
207 static bool
208 lcl_checkRangeDimension(
209         const SingleDoubleRefProvider& rRef1,
210         const SingleDoubleRefProvider& rRef2,
211         const DimensionSelector aWhich)
212 {
213     return
214         aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1)
215         && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2);
216 }
217 
218 
219 static bool
220 lcl_checkRangeDimensions(
221         const SingleDoubleRefProvider& rRef1,
222         const SingleDoubleRefProvider& rRef2,
223         bool& bCol, bool& bRow, bool& bTab)
224 {
225     const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol));
226     const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow));
227     const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab));
228 
229     // Test if exactly two dimensions are equal
230     if (!(bSameCols ^ bSameRows ^ bSameTabs)
231             && (bSameCols || bSameRows || bSameTabs))
232     {
233         bCol = !bSameCols;
234         bRow = !bSameRows;
235         bTab = !bSameTabs;
236         return true;
237     }
238     return false;
239 }
240 
241 
242 /** Check if references in given reference list can possibly
243     form a range. To do that, two of their dimensions must be the same.
244  */
245 static bool
246 lcl_checkRangeDimensions(
247         const deque<ScToken*>::const_iterator aBegin,
248         const deque<ScToken*>::const_iterator aEnd,
249         bool& bCol, bool& bRow, bool& bTab)
250 {
251     deque<ScToken*>::const_iterator aCur(aBegin);
252     ++aCur;
253     const SingleDoubleRefProvider aRef(**aBegin);
254     bool bOk(false);
255     {
256         const SingleDoubleRefProvider aRefCur(**aCur);
257         bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab);
258     }
259     while (bOk && aCur != aEnd)
260     {
261         const SingleDoubleRefProvider aRefCur(**aCur);
262         bool bColTmp(false);
263         bool bRowTmp(false);
264         bool bTabTmp(false);
265         bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp);
266         bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp);
267         ++aCur;
268     }
269 
270     if (bOk && aCur == aEnd)
271     {
272         bCol = bCol;
273         bRow = bRow;
274         bTab = bTab;
275         return true;
276     }
277     return false;
278 }
279 
280 
281 bool
282 lcl_lessReferenceBy(
283         const ScToken* const pRef1, const ScToken* const pRef2,
284         const DimensionSelector aWhich)
285 {
286     const SingleDoubleRefProvider rRef1(*pRef1);
287     const SingleDoubleRefProvider rRef2(*pRef2);
288     return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1);
289 }
290 
291 
292 /** Returns true if range denoted by token pRef2 starts immediately after
293     range denoted by token pRef1. Dimension, in which the comparison takes
294     place, is given by aWhich.
295  */
296 bool
297 lcl_isImmediatelyFollowing(
298         const ScToken* const pRef1, const ScToken* const pRef2,
299         const DimensionSelector aWhich)
300 {
301     const SingleDoubleRefProvider rRef1(*pRef1);
302     const SingleDoubleRefProvider rRef2(*pRef2);
303     return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1;
304 }
305 
306 
307 static bool
308 lcl_checkIfAdjacent(
309         const deque<ScToken*>& rReferences,
310         const DimensionSelector aWhich)
311 {
312     typedef deque<ScToken*>::const_iterator Iter;
313     Iter aBegin(rReferences.begin());
314     Iter aEnd(rReferences.end());
315     Iter aBegin1(aBegin);
316     ++aBegin1, --aEnd;
317     return std::equal(
318             aBegin, aEnd, aBegin1,
319             boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich));
320 }
321 
322 
323 static void
324 lcl_fillRangeFromRefList(
325         const deque<ScToken*>& rReferences, ScRange& rRange)
326 {
327     const ScSingleRefData aStart(
328             SingleDoubleRefProvider(*rReferences.front()).Ref1);
329     rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab);
330     const ScSingleRefData aEnd(
331             SingleDoubleRefProvider(*rReferences.back()).Ref2);
332     rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab);
333 }
334 
335 
336 static bool
337 lcl_refListFormsOneRange(
338         const ScAddress& aPos, deque<ScToken*>& rReferences,
339         ScRange& rRange)
340 {
341     std::for_each(
342             rReferences.begin(), rReferences.end(),
343             bind(&ScToken::CalcAbsIfRel, _1, aPos))
344         ;
345     if (rReferences.size() == 1) {
346         lcl_fillRangeFromRefList(rReferences, rRange);
347         return true;
348     }
349 
350     bool bCell(false);
351     bool bRow(false);
352     bool bTab(false);
353     if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(),
354             bCell, bRow, bTab))
355     {
356         DimensionSelector aWhich;
357         if (bCell)
358         {
359             aWhich = lcl_GetCol;
360         }
361         else if (bRow)
362         {
363             aWhich = lcl_GetRow;
364         }
365         else if (bTab)
366         {
367             aWhich = lcl_GetTab;
368         }
369         else
370         {
371             OSL_ENSURE(false, "lcl_checkRangeDimensions shouldn't allow that!");
372             aWhich = lcl_GetRow;    // initialize to avoid warning
373         }
374         // Sort the references by start of range
375         std::sort(rReferences.begin(), rReferences.end(),
376                 boost::bind(lcl_lessReferenceBy, _1, _2, aWhich));
377         if (lcl_checkIfAdjacent(rReferences, aWhich))
378         {
379             lcl_fillRangeFromRefList(rReferences, rRange);
380             return true;
381         }
382     }
383     return false;
384 }
385 
386 
387 bool lcl_isReference(const FormulaToken& rToken)
388 {
389     return
390         rToken.GetType() == svSingleRef ||
391         rToken.GetType() == svDoubleRef;
392 }
393 
394 }
395 
396 sal_Bool ScFormulaCell::IsEmpty()
397 {
398     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
399         Interpret();
400     return aResult.GetCellResultType() == formula::svEmptyCell;
401 }
402 
403 sal_Bool ScFormulaCell::IsEmptyDisplayedAsString()
404 {
405     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
406         Interpret();
407     return aResult.IsEmptyDisplayedAsString();
408 }
409 
410 sal_Bool ScFormulaCell::IsValue()
411 {
412     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
413         Interpret();
414     return aResult.IsValue();
415 }
416 
417 double ScFormulaCell::GetValue()
418 {
419     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
420         Interpret();
421     if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
422             !aResult.GetResultError())
423         return aResult.GetDouble();
424     return 0.0;
425 }
426 
427 double ScFormulaCell::GetValueAlways()
428 {
429     // for goal seek: return result value even if error code is set
430 
431     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
432         Interpret();
433     return aResult.GetDouble();
434 }
435 
436 void ScFormulaCell::GetString( String& rString )
437 {
438     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
439         Interpret();
440     if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
441             !aResult.GetResultError())
442         rString = aResult.GetString();
443     else
444         rString.Erase();
445 }
446 
447 const ScMatrix* ScFormulaCell::GetMatrix()
448 {
449     if ( pDocument->GetAutoCalc() )
450     {
451         // Was stored !bDirty but an accompanying matrix cell was bDirty?
452         // => we need to get the matrix.
453         if (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix().Is())
454             bDirty = sal_True;
455         if ( IsDirtyOrInTableOpDirty() )
456             Interpret();
457     }
458     return aResult.GetMatrix();
459 }
460 
461 sal_Bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
462 {
463     switch ( cMatrixFlag )
464     {
465         case MM_FORMULA :
466             rPos = aPos;
467             return sal_True;
468 //        break;
469         case MM_REFERENCE :
470         {
471             pCode->Reset();
472             ScToken* t = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
473             if( t )
474             {
475                 ScSingleRefData& rRef = t->GetSingleRef();
476                 rRef.CalcAbsIfRel( aPos );
477                 if ( rRef.Valid() )
478                 {
479                     rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab );
480                     return sal_True;
481                 }
482             }
483         }
484         break;
485     }
486     return sal_False;
487 }
488 
489 
490 /*
491  Edge-Values:
492 
493    8
494  4   16
495    2
496 
497  innerhalb: 1
498  ausserhalb: 0
499  (reserviert: offen: 32)
500  */
501 
502 sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
503 {
504     switch ( cMatrixFlag )
505     {
506         case MM_FORMULA :
507         case MM_REFERENCE :
508         {
509             static SCCOL nC;
510             static SCROW nR;
511             ScAddress aOrg;
512             if ( !GetMatrixOrigin( aOrg ) )
513                 return 0;               // dumm gelaufen..
514             if ( aOrg != rOrgPos )
515             {   // erstes Mal oder andere Matrix als letztes Mal
516                 rOrgPos = aOrg;
517                 ScFormulaCell* pFCell;
518                 if ( cMatrixFlag == MM_REFERENCE )
519                     pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
520                 else
521                     pFCell = this;      // this MM_FORMULA
522                 // this gibt's nur einmal, kein Vergleich auf pFCell==this
523                 if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA
524                   && pFCell->cMatrixFlag == MM_FORMULA )
525                 {
526                     pFCell->GetMatColsRows( nC, nR );
527                     if ( nC == 0 || nR == 0 )
528                     {   // aus altem Dokument geladen, neu erzeugen
529                         nC = 1;
530                         nR = 1;
531                         ScAddress aTmpOrg;
532                         ScBaseCell* pCell;
533                         ScAddress aAdr( aOrg );
534                         aAdr.IncCol();
535                         sal_Bool bCont = sal_True;
536                         do
537                         {
538                             pCell = pDocument->GetCell( aAdr );
539                             if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
540                               && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
541                               && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
542                             {
543                                 nC++;
544                                 aAdr.IncCol();
545                             }
546                             else
547                                 bCont = sal_False;
548                         } while ( bCont );
549                         aAdr = aOrg;
550                         aAdr.IncRow();
551                         bCont = sal_True;
552                         do
553                         {
554                             pCell = pDocument->GetCell( aAdr );
555                             if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
556                               && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
557                               && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
558                             {
559                                 nR++;
560                                 aAdr.IncRow();
561                             }
562                             else
563                                 bCont = sal_False;
564                         } while ( bCont );
565                         pFCell->SetMatColsRows( nC, nR );
566                     }
567                 }
568                 else
569                 {
570 #ifdef DBG_UTIL
571                     String aTmp;
572                     ByteString aMsg( "broken Matrix, no MatFormula at origin, Pos: " );
573                     aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
574                     aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
575                     aMsg += ", MatOrg: ";
576                     aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
577                     aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
578                     DBG_ERRORFILE( aMsg.GetBuffer() );
579 #endif
580                     return 0;           // bad luck ...
581                 }
582             }
583             // here we are, healthy and clean, somewhere in between
584             SCsCOL dC = aPos.Col() - aOrg.Col();
585             SCsROW dR = aPos.Row() - aOrg.Row();
586             sal_uInt16 nEdges = 0;
587             if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
588             {
589                 if ( dC == 0 )
590                     nEdges |= 4;            // linke Kante
591                 if ( dC+1 == nC )
592                     nEdges |= 16;           // rechte Kante
593                 if ( dR == 0 )
594                     nEdges |= 8;            // obere Kante
595                 if ( dR+1 == nR )
596                     nEdges |= 2;            // untere Kante
597                 if ( !nEdges )
598                     nEdges = 1;             // mittendrin
599             }
600 #ifdef DBG_UTIL
601             else
602             {
603                 String aTmp;
604                 ByteString aMsg( "broken Matrix, Pos: " );
605                 aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
606                 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
607                 aMsg += ", MatOrg: ";
608                 aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
609                 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
610                 aMsg += ", MatCols: ";
611                 aMsg += ByteString::CreateFromInt32( nC );
612                 aMsg += ", MatRows: ";
613                 aMsg += ByteString::CreateFromInt32( nR );
614                 aMsg += ", DiffCols: ";
615                 aMsg += ByteString::CreateFromInt32( dC );
616                 aMsg += ", DiffRows: ";
617                 aMsg += ByteString::CreateFromInt32( dR );
618                 DBG_ERRORFILE( aMsg.GetBuffer() );
619             }
620 #endif
621             return nEdges;
622 //            break;
623         }
624         default:
625             return 0;
626     }
627 }
628 
629 sal_uInt16 ScFormulaCell::GetErrCode()
630 {
631     if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
632         Interpret();
633     /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
634      * and not also abused for signaling other error conditions we could bail
635      * out even before attempting to interpret broken code. */
636     sal_uInt16 nErr =  pCode->GetCodeError();
637     if (nErr)
638         return nErr;
639     return aResult.GetResultError();
640 }
641 
642 sal_uInt16 ScFormulaCell::GetRawError()
643 {
644     sal_uInt16 nErr =  pCode->GetCodeError();
645     if (nErr)
646         return nErr;
647     return aResult.GetResultError();
648 }
649 
650 sal_Bool ScFormulaCell::HasOneReference( ScRange& r ) const
651 {
652     pCode->Reset();
653     ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
654     if( p && !pCode->GetNextReferenceRPN() )        // nur eine!
655     {
656         p->CalcAbsIfRel( aPos );
657         SingleDoubleRefProvider aProv( *p );
658         r.aStart.Set( aProv.Ref1.nCol,
659                       aProv.Ref1.nRow,
660                       aProv.Ref1.nTab );
661         r.aEnd.Set( aProv.Ref2.nCol,
662                     aProv.Ref2.nRow,
663                     aProv.Ref2.nTab );
664         return sal_True;
665     }
666     else
667         return sal_False;
668 }
669 
670 bool
671 ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const
672 {
673     /* If there appears just one reference in the formula, it's the same
674        as HasOneReference(). If there are more of them, they can denote
675        one range if they are (sole) arguments of one function.
676        Union of these references must form one range and their
677        intersection must be empty set.
678     */
679 
680     // Detect the simple case of exactly one reference in advance without all
681     // overhead.
682     // #i107741# Doing so actually makes outlines using SUBTOTAL(x;reference)
683     // work again, where the function does not have only references.
684     if (HasOneReference( rRange))
685         return true;
686 
687     pCode->Reset();
688     // Get first reference, if any
689     ScToken* const pFirstReference(
690             dynamic_cast<ScToken*>(pCode->GetNextReferenceRPN()));
691     if (pFirstReference)
692     {
693         // Collect all consecutive references, starting by the one
694         // already found
695         std::deque<ScToken*> aReferences;
696         aReferences.push_back(pFirstReference);
697         FormulaToken* pToken(pCode->NextRPN());
698         FormulaToken* pFunction(0);
699         while (pToken)
700         {
701             if (lcl_isReference(*pToken))
702             {
703                 aReferences.push_back(dynamic_cast<ScToken*>(pToken));
704                 pToken = pCode->NextRPN();
705             }
706             else
707             {
708                 if (pToken->IsFunction())
709                 {
710                     pFunction = pToken;
711                 }
712                 break;
713             }
714         }
715         if (pFunction && !pCode->GetNextReferenceRPN()
716                 && (pFunction->GetParamCount() == aReferences.size()))
717         {
718             return lcl_refListFormsOneRange(aPos, aReferences, rRange);
719         }
720     }
721     return false;
722 }
723 
724 sal_Bool ScFormulaCell::HasRelNameReference() const
725 {
726     pCode->Reset();
727     ScToken* t;
728     while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
729     {
730         if ( t->GetSingleRef().IsRelName() ||
731                 (t->GetType() == formula::svDoubleRef &&
732                 t->GetDoubleRef().Ref2.IsRelName()) )
733             return sal_True;
734     }
735     return sal_False;
736 }
737 
738 sal_Bool ScFormulaCell::HasColRowName() const
739 {
740     pCode->Reset();
741     return (pCode->GetNextColRowName() != NULL);
742 }
743 
744 void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
745                                     const ScRange& r,
746                                     SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
747                                     ScDocument* pUndoDoc, const ScAddress* pUndoCellPos )
748 {
749     SCCOL nCol1 = r.aStart.Col();
750     SCROW nRow1 = r.aStart.Row();
751     SCTAB nTab1 = r.aStart.Tab();
752     SCCOL nCol2 = r.aEnd.Col();
753     SCROW nRow2 = r.aEnd.Row();
754     SCTAB nTab2 = r.aEnd.Tab();
755     SCCOL nCol = aPos.Col();
756     SCROW nRow = aPos.Row();
757     SCTAB nTab = aPos.Tab();
758     ScAddress aUndoPos( aPos );         // position for undo cell in pUndoDoc
759     if ( pUndoCellPos )
760         aUndoPos = *pUndoCellPos;
761     ScAddress aOldPos( aPos );
762 //  sal_Bool bPosChanged = sal_False;           // ob diese Zelle bewegt wurde
763     sal_Bool bIsInsert = sal_False;
764     if (eUpdateRefMode == URM_INSDEL)
765     {
766         bIsInsert = (nDx >= 0 && nDy >= 0 && nDz >= 0);
767         if ( nDx && nRow >= nRow1 && nRow <= nRow2 &&
768             nTab >= nTab1 && nTab <= nTab2 )
769         {
770             if (nCol >= nCol1)
771             {
772                 nCol = sal::static_int_cast<SCCOL>( nCol + nDx );
773                 if ((SCsCOL) nCol < 0)
774                     nCol = 0;
775                 else if ( nCol > MAXCOL )
776                     nCol = MAXCOL;
777                 aPos.SetCol( nCol );
778 //              bPosChanged = sal_True;
779             }
780         }
781         if ( nDy && nCol >= nCol1 && nCol <= nCol2 &&
782             nTab >= nTab1 && nTab <= nTab2 )
783         {
784             if (nRow >= nRow1)
785             {
786                 nRow = sal::static_int_cast<SCROW>( nRow + nDy );
787                 if ((SCsROW) nRow < 0)
788                     nRow = 0;
789                 else if ( nRow > MAXROW )
790                     nRow = MAXROW;
791                 aPos.SetRow( nRow );
792 //              bPosChanged = sal_True;
793             }
794         }
795         if ( nDz && nCol >= nCol1 && nCol <= nCol2 &&
796             nRow >= nRow1 && nRow <= nRow2 )
797         {
798             if (nTab >= nTab1)
799             {
800                 SCTAB nMaxTab = pDocument->GetTableCount() - 1;
801                 nTab = sal::static_int_cast<SCTAB>( nTab + nDz );
802                 if ((SCsTAB) nTab < 0)
803                     nTab = 0;
804                 else if ( nTab > nMaxTab )
805                     nTab = nMaxTab;
806                 aPos.SetTab( nTab );
807 //              bPosChanged = sal_True;
808             }
809         }
810     }
811     else if ( r.In( aPos ) )
812     {
813         aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
814 //      bPosChanged = sal_True;
815     }
816 
817     sal_Bool bHasRefs = sal_False;
818     sal_Bool bHasColRowNames = sal_False;
819     sal_Bool bOnRefMove = sal_False;
820     if ( !pDocument->IsClipOrUndo() )
821     {
822         pCode->Reset();
823         bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
824         if ( !bHasRefs || eUpdateRefMode == URM_COPY )
825         {
826             pCode->Reset();
827             bHasColRowNames = (pCode->GetNextColRowName() != NULL);
828             bHasRefs = bHasRefs || bHasColRowNames;
829         }
830         bOnRefMove = pCode->IsRecalcModeOnRefMove();
831     }
832     if( bHasRefs || bOnRefMove )
833     {
834         ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
835         sal_Bool bValChanged;
836         ScRangeData* pRangeData;
837         sal_Bool bRangeModified;            // any range, not only shared formula
838         sal_Bool bRefSizeChanged;
839         if ( bHasRefs )
840         {
841             ScCompiler aComp(pDocument, aPos, *pCode);
842             aComp.SetGrammar(pDocument->GetGrammar());
843             pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r,
844                                              nDx, nDy, nDz,
845                                              bValChanged, bRefSizeChanged);
846             bRangeModified = aComp.HasModifiedRange();
847         }
848         else
849         {
850             bValChanged = sal_False;
851             pRangeData = NULL;
852             bRangeModified = sal_False;
853             bRefSizeChanged = sal_False;
854         }
855         if ( bOnRefMove )
856             bOnRefMove = (bValChanged || (aPos != aOldPos));
857             // Cell may reference itself, e.g. ocColumn, ocRow without parameter
858 
859         sal_Bool bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo;
860         if ( bHasRefs )
861         {
862             // Upon Insert ColRowNames have to be recompiled in case the
863             // insertion occurs right in front of the range.
864             bColRowNameCompile =
865                 (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
866             if ( bColRowNameCompile )
867             {
868                 bColRowNameCompile = sal_False;
869                 ScToken* t;
870                 ScRangePairList* pColList = pDocument->GetColNameRanges();
871                 ScRangePairList* pRowList = pDocument->GetRowNameRanges();
872                 pCode->Reset();
873                 while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
874                 {
875                     ScSingleRefData& rRef = t->GetSingleRef();
876                     if ( nDy > 0 && rRef.IsColRel() )
877                     {   // ColName
878                         rRef.CalcAbsIfRel( aPos );
879                         ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
880                         ScRangePair* pR = pColList->Find( aAdr );
881                         if ( pR )
882                         {   // definiert
883                             if ( pR->GetRange(1).aStart.Row() == nRow1 )
884                                 bColRowNameCompile = sal_True;
885                         }
886                         else
887                         {   // on the fly
888                             if ( rRef.nRow + 1 == nRow1 )
889                                 bColRowNameCompile = sal_True;
890                         }
891                     }
892                     if ( nDx > 0 && rRef.IsRowRel() )
893                     {   // RowName
894                         rRef.CalcAbsIfRel( aPos );
895                         ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
896                         ScRangePair* pR = pRowList->Find( aAdr );
897                         if ( pR )
898                         {   // definiert
899                             if ( pR->GetRange(1).aStart.Col() == nCol1 )
900                                 bColRowNameCompile = sal_True;
901                         }
902                         else
903                         {   // on the fly
904                             if ( rRef.nCol + 1 == nCol1 )
905                                 bColRowNameCompile = sal_True;
906                         }
907                     }
908                 }
909             }
910             else if ( eUpdateRefMode == URM_MOVE )
911             {   // bei Move/D&D neu kompilieren wenn ColRowName verschoben wurde
912                 // oder diese Zelle auf einen zeigt und verschoben wurde
913                 bColRowNameCompile = bCompile;      // evtl. aus Copy-ctor
914                 if ( !bColRowNameCompile )
915                 {
916                     sal_Bool bMoved = (aPos != aOldPos);
917                     pCode->Reset();
918                     ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
919                     if ( t && bMoved )
920                         bColRowNameCompile = sal_True;
921                     while ( t && !bColRowNameCompile )
922                     {
923                         ScSingleRefData& rRef = t->GetSingleRef();
924                         rRef.CalcAbsIfRel( aPos );
925                         if ( rRef.Valid() )
926                         {
927                             ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
928                             if ( r.In( aAdr ) )
929                                 bColRowNameCompile = sal_True;
930                         }
931                         t = static_cast<ScToken*>(pCode->GetNextColRowName());
932                     }
933                 }
934             }
935             else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
936             {
937                 bColRowNameCompile = sal_True;
938             }
939             ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
940             if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
941                 bInDeleteUndo = sal_True;
942             else
943                 bInDeleteUndo = sal_False;
944             // RelNameRefs are always moved
945             bHasRelName = HasRelNameReference();
946             // Reference changed and new listening needed?
947             // Except in Insert/Delete without specialties.
948             bNewListening = (bRangeModified || pRangeData || bColRowNameCompile
949                     || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
950                             bInDeleteUndo || bRefSizeChanged)) ||
951                     (bHasRelName && eUpdateRefMode != URM_COPY))
952                 // #i36299# Don't duplicate action during cut&paste / drag&drop
953                 // on a cell in the range moved, start/end listeners is done
954                 // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
955                 && !(eUpdateRefMode == URM_MOVE &&
956                         pDocument->IsInsertingFromOtherDoc() && r.In(aPos));
957             if ( bNewListening )
958                 EndListeningTo( pDocument, pOld, aOldPos );
959         }
960         else
961         {
962             bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo =
963                 sal_False;
964         }
965 
966         sal_Bool bNeedDirty;
967         // NeedDirty bei Aenderungen ausser Copy und Move/Insert ohne RelNames
968         if ( bRangeModified || pRangeData || bColRowNameCompile ||
969                 (bValChanged && eUpdateRefMode != URM_COPY &&
970                  (eUpdateRefMode != URM_MOVE || bHasRelName) &&
971                  (!bIsInsert || bHasRelName || bInDeleteUndo ||
972                   bRefSizeChanged)) || bOnRefMove)
973             bNeedDirty = sal_True;
974         else
975             bNeedDirty = sal_False;
976         if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove))
977         {
978             //  Copy the cell to aUndoPos, which is its current position in the document,
979             //  so this works when UpdateReference is called before moving the cells
980             //  (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
981             //  is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
982 
983             // If there is already a formula cell in the undo document, don't overwrite it,
984             // the first (oldest) is the important cell.
985             if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA )
986             {
987                 ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
988                         pOld, eTempGrammar, cMatrixFlag );
989                 pFCell->aResult.SetToken( NULL);  // to recognize it as changed later (Cut/Paste!)
990                 pUndoDoc->PutCell( aUndoPos, pFCell );
991             }
992         }
993         // #i116833# If the formula is changed, always invalidate the stream (even if the result is the same).
994         // If the formula is moved, the change is recognized separately.
995         if (bValChanged && pDocument->IsStreamValid(aPos.Tab()))
996             pDocument->SetStreamValid(aPos.Tab(), sal_False);
997         bValChanged = sal_False;
998         if ( pRangeData )
999         {   // Replace shared formula with own formula
1000             pDocument->RemoveFromFormulaTree( this );   // update formula count
1001             delete pCode;
1002             pCode = pRangeData->GetCode()->Clone();
1003             // #i18937# #i110008# call MoveRelWrap, but with the old position
1004             ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1005             ScCompiler aComp2(pDocument, aPos, *pCode);
1006             aComp2.SetGrammar(pDocument->GetGrammar());
1007             aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r,
1008                 nDx, nDy, nDz );
1009             bValChanged = sal_True;
1010             bNeedDirty = sal_True;
1011         }
1012         if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
1013         {
1014             CompileTokenArray( bNewListening ); // kein Listening
1015             bNeedDirty = sal_True;
1016         }
1017         if ( !bInDeleteUndo )
1018         {   // In ChangeTrack Delete-Reject listeners are established in
1019             // InsertCol/InsertRow
1020             if ( bNewListening )
1021             {
1022                 if ( eUpdateRefMode == URM_INSDEL )
1023                 {
1024                     // Inserts/Deletes re-establish listeners after all
1025                     // UpdateReference calls.
1026                     // All replaced shared formula listeners have to be
1027                     // established after an Insert or Delete. Do nothing here.
1028                     SetNeedsListening( sal_True);
1029                 }
1030                 else
1031                     StartListeningTo( pDocument );
1032             }
1033         }
1034         if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) )
1035         {   // Referenzen abgeschnitten, ungueltig o.ae.?
1036             sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1037             // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
1038             pDocument->SetAutoCalc( sal_False );
1039             SetDirty();
1040             pDocument->SetAutoCalc( bOldAutoCalc );
1041         }
1042 
1043         delete pOld;
1044     }
1045 }
1046 
1047 void ScFormulaCell::UpdateInsertTab(SCTAB nTable)
1048 {
1049     sal_Bool bPosChanged = ( aPos.Tab() >= nTable ? sal_True : sal_False );
1050     pCode->Reset();
1051     if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
1052     {
1053         EndListeningTo( pDocument );
1054         // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
1055         if ( bPosChanged )
1056             aPos.IncTab();
1057         ScRangeData* pRangeData;
1058         ScCompiler aComp(pDocument, aPos, *pCode);
1059         aComp.SetGrammar(pDocument->GetGrammar());
1060         pRangeData = aComp.UpdateInsertTab( nTable, sal_False );
1061         if (pRangeData)                     // Shared Formula gegen echte Formel
1062         {                                   // austauschen
1063             sal_Bool bRefChanged;
1064             pDocument->RemoveFromFormulaTree( this );   // update formula count
1065             delete pCode;
1066             pCode = new ScTokenArray( *pRangeData->GetCode() );
1067             ScCompiler aComp2(pDocument, aPos, *pCode);
1068             aComp2.SetGrammar(pDocument->GetGrammar());
1069             aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1070             aComp2.UpdateInsertTab( nTable, sal_False );
1071             // If the shared formula contained a named range/formula containing
1072             // an absolute reference to a sheet, those have to be readjusted.
1073             aComp2.UpdateDeleteTab( nTable, sal_False, sal_True, bRefChanged );
1074             bCompile = sal_True;
1075         }
1076         // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
1077     }
1078     else if ( bPosChanged )
1079         aPos.IncTab();
1080 }
1081 
1082 sal_Bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, sal_Bool bIsMove)
1083 {
1084     sal_Bool bRefChanged = sal_False;
1085     sal_Bool bPosChanged = ( aPos.Tab() > nTable ? sal_True : sal_False );
1086     pCode->Reset();
1087     if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
1088     {
1089         EndListeningTo( pDocument );
1090         // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
1091         if ( bPosChanged )
1092             aPos.IncTab(-1);
1093         ScRangeData* pRangeData;
1094         ScCompiler aComp(pDocument, aPos, *pCode);
1095         aComp.SetGrammar(pDocument->GetGrammar());
1096         pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, sal_False, bRefChanged);
1097         if (pRangeData)                     // Shared Formula gegen echte Formel
1098         {                                   // austauschen
1099             pDocument->RemoveFromFormulaTree( this );   // update formula count
1100             delete pCode;
1101             pCode = pRangeData->GetCode()->Clone();
1102             ScCompiler aComp2(pDocument, aPos, *pCode);
1103             aComp2.SetGrammar(pDocument->GetGrammar());
1104             aComp2.CompileTokenArray();
1105             aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1106             aComp2.UpdateDeleteTab( nTable, sal_False, sal_False, bRefChanged );
1107             // If the shared formula contained a named range/formula containing
1108             // an absolute reference to a sheet, those have to be readjusted.
1109             aComp2.UpdateInsertTab( nTable,sal_True );
1110             // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
1111             bRefChanged = sal_True;
1112             bCompile = sal_True;
1113         }
1114         // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1115     }
1116     else if ( bPosChanged )
1117         aPos.IncTab(-1);
1118 
1119     return bRefChanged;
1120 }
1121 
1122 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
1123 {
1124     pCode->Reset();
1125     if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
1126     {
1127         EndListeningTo( pDocument );
1128         // SetTab _nach_ EndListeningTo und _vor_ Compiler UpdateMoveTab !
1129         aPos.SetTab( nTabNo );
1130         ScRangeData* pRangeData;
1131         ScCompiler aComp(pDocument, aPos, *pCode);
1132         aComp.SetGrammar(pDocument->GetGrammar());
1133         pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, sal_False );
1134         if (pRangeData)                     // Shared Formula gegen echte Formel
1135         {                                   // austauschen
1136             pDocument->RemoveFromFormulaTree( this );   // update formula count
1137             delete pCode;
1138             pCode = pRangeData->GetCode()->Clone();
1139             ScCompiler aComp2(pDocument, aPos, *pCode);
1140             aComp2.SetGrammar(pDocument->GetGrammar());
1141             aComp2.CompileTokenArray();
1142             aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1143             aComp2.UpdateMoveTab( nOldPos, nNewPos, sal_True );
1144             bCompile = sal_True;
1145         }
1146         // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1147     }
1148     else
1149         aPos.SetTab( nTabNo );
1150 }
1151 
1152 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
1153 {
1154     if( !pDocument->IsClipOrUndo() )
1155     {
1156         pCode->Reset();
1157         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1158         while( p )
1159         {
1160             ScSingleRefData& rRef1 = p->GetSingleRef();
1161             if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab )
1162                 rRef1.nTab++;
1163             if( p->GetType() == formula::svDoubleRef )
1164             {
1165                 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
1166                 if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab )
1167                     rRef2.nTab++;
1168             }
1169             p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1170         }
1171     }
1172 }
1173 
1174 sal_Bool ScFormulaCell::TestTabRefAbs(SCTAB nTable)
1175 {
1176     sal_Bool bRet = sal_False;
1177     if( !pDocument->IsClipOrUndo() )
1178     {
1179         pCode->Reset();
1180         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1181         while( p )
1182         {
1183             ScSingleRefData& rRef1 = p->GetSingleRef();
1184             if( !rRef1.IsTabRel() )
1185             {
1186                 if( (SCsTAB) nTable != rRef1.nTab )
1187                     bRet = sal_True;
1188                 else if (nTable != aPos.Tab())
1189                     rRef1.nTab = aPos.Tab();
1190             }
1191             if( p->GetType() == formula::svDoubleRef )
1192             {
1193                 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
1194                 if( !rRef2.IsTabRel() )
1195                 {
1196                     if( (SCsTAB) nTable != rRef2.nTab )
1197                         bRet = sal_True;
1198                     else if (nTable != aPos.Tab())
1199                         rRef2.nTab = aPos.Tab();
1200                 }
1201             }
1202             p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1203         }
1204     }
1205     return bRet;
1206 }
1207 
1208 void ScFormulaCell::UpdateCompile( sal_Bool bForceIfNameInUse )
1209 {
1210     if ( bForceIfNameInUse && !bCompile )
1211         bCompile = pCode->HasNameOrColRowName();
1212     if ( bCompile )
1213         pCode->SetCodeError( 0 );   // make sure it will really be compiled
1214     CompileTokenArray();
1215 }
1216 
1217 //  Referenzen transponieren - wird nur in Clipboard-Dokumenten aufgerufen
1218 
1219 void ScFormulaCell::TransposeReference()
1220 {
1221     sal_Bool bFound = sal_False;
1222     pCode->Reset();
1223     ScToken* t;
1224     while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
1225     {
1226         ScSingleRefData& rRef1 = t->GetSingleRef();
1227         if ( rRef1.IsColRel() && rRef1.IsRowRel() )
1228         {
1229             sal_Bool bDouble = (t->GetType() == formula::svDoubleRef);
1230             ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1);
1231             if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) )
1232             {
1233                 sal_Int16 nTemp;
1234 
1235                 nTemp = rRef1.nRelCol;
1236                 rRef1.nRelCol = static_cast<SCCOL>(rRef1.nRelRow);
1237                 rRef1.nRelRow = static_cast<SCROW>(nTemp);
1238 
1239                 if ( bDouble )
1240                 {
1241                     nTemp = rRef2.nRelCol;
1242                     rRef2.nRelCol = static_cast<SCCOL>(rRef2.nRelRow);
1243                     rRef2.nRelRow = static_cast<SCROW>(nTemp);
1244                 }
1245 
1246                 bFound = sal_True;
1247             }
1248         }
1249     }
1250 
1251     if (bFound)
1252         bCompile = sal_True;
1253 }
1254 
1255 void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1256                                         ScDocument* pUndoDoc )
1257 {
1258     EndListeningTo( pDocument );
1259 
1260     ScAddress aOldPos = aPos;
1261     sal_Bool bPosChanged = sal_False;           // ob diese Zelle bewegt wurde
1262 
1263     ScRange aDestRange( rDest, ScAddress(
1264                 static_cast<SCCOL>(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()),
1265                 static_cast<SCROW>(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()),
1266                 rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) );
1267     if ( aDestRange.In( aOldPos ) )
1268     {
1269         //  Position zurueckrechnen
1270         SCsCOL nRelPosX = aOldPos.Col();
1271         SCsROW nRelPosY = aOldPos.Row();
1272         SCsTAB nRelPosZ = aOldPos.Tab();
1273         ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart );
1274         aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ );
1275         bPosChanged = sal_True;
1276     }
1277 
1278     ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
1279     sal_Bool bRefChanged = sal_False;
1280     ScToken* t;
1281 
1282     ScRangeData* pShared = NULL;
1283     pCode->Reset();
1284     while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
1285     {
1286         if( t->GetOpCode() == ocName )
1287         {
1288             ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
1289             if (pName)
1290             {
1291                 if (pName->IsModified())
1292                     bRefChanged = sal_True;
1293                 if (pName->HasType(RT_SHAREDMOD))
1294                     pShared = pName;
1295             }
1296         }
1297         else if( t->GetType() != svIndex )
1298         {
1299             t->CalcAbsIfRel( aOldPos );
1300             sal_Bool bMod;
1301             {   // own scope for SingleDoubleRefModifier dtor if SingleRef
1302                 SingleDoubleRefModifier aMod( *t );
1303                 ScComplexRefData& rRef = aMod.Ref();
1304                 bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
1305                     rDest, rRef ) != UR_NOTHING || bPosChanged);
1306             }
1307             if ( bMod )
1308             {
1309                 t->CalcRelFromAbs( aPos );
1310                 bRefChanged = sal_True;
1311             }
1312         }
1313     }
1314 
1315     if (pShared)            // Shared Formula gegen echte Formel austauschen
1316     {
1317         pDocument->RemoveFromFormulaTree( this );   // update formula count
1318         delete pCode;
1319         pCode = new ScTokenArray( *pShared->GetCode() );
1320         bRefChanged = sal_True;
1321         pCode->Reset();
1322         while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
1323         {
1324             if( t->GetType() != svIndex )
1325             {
1326                 t->CalcAbsIfRel( aOldPos );
1327                 sal_Bool bMod;
1328                 {   // own scope for SingleDoubleRefModifier dtor if SingleRef
1329                     SingleDoubleRefModifier aMod( *t );
1330                     ScComplexRefData& rRef = aMod.Ref();
1331                     bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
1332                         rDest, rRef ) != UR_NOTHING || bPosChanged);
1333                 }
1334                 if ( bMod )
1335                     t->CalcRelFromAbs( aPos );
1336             }
1337         }
1338     }
1339 
1340     if (bRefChanged)
1341     {
1342         if (pUndoDoc)
1343         {
1344             ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld,
1345                     eTempGrammar, cMatrixFlag);
1346             pFCell->aResult.SetToken( NULL);  // to recognize it as changed later (Cut/Paste!)
1347             pUndoDoc->PutCell( aPos.Col(), aPos.Row(), aPos.Tab(), pFCell );
1348         }
1349 
1350         bCompile = sal_True;
1351         CompileTokenArray();                // ruft auch StartListeningTo
1352         SetDirty();
1353     }
1354     else
1355         StartListeningTo( pDocument );      // Listener wie vorher
1356 
1357     delete pOld;
1358 }
1359 
1360 void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1361 {
1362     EndListeningTo( pDocument );
1363 
1364     sal_Bool bRefChanged = sal_False;
1365     ScToken* t;
1366     ScRangeData* pShared = NULL;
1367 
1368     pCode->Reset();
1369     while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
1370     {
1371         if( t->GetOpCode() == ocName )
1372         {
1373             ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
1374             if (pName)
1375             {
1376                 if (pName->IsModified())
1377                     bRefChanged = sal_True;
1378                 if (pName->HasType(RT_SHAREDMOD))
1379                     pShared = pName;
1380             }
1381         }
1382         else if( t->GetType() != svIndex )
1383         {
1384             t->CalcAbsIfRel( aPos );
1385             sal_Bool bMod;
1386             {   // own scope for SingleDoubleRefModifier dtor if SingleRef
1387                 SingleDoubleRefModifier aMod( *t );
1388                 ScComplexRefData& rRef = aMod.Ref();
1389                 bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
1390                     rRef ) != UR_NOTHING);
1391             }
1392             if ( bMod )
1393             {
1394                 t->CalcRelFromAbs( aPos );
1395                 bRefChanged = sal_True;
1396             }
1397         }
1398     }
1399 
1400     if (pShared)            // Shared Formula gegen echte Formel austauschen
1401     {
1402         pDocument->RemoveFromFormulaTree( this );   // update formula count
1403         delete pCode;
1404         pCode = new ScTokenArray( *pShared->GetCode() );
1405         bRefChanged = sal_True;
1406         pCode->Reset();
1407         while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
1408         {
1409             if( t->GetType() != svIndex )
1410             {
1411                 t->CalcAbsIfRel( aPos );
1412                 sal_Bool bMod;
1413                 {   // own scope for SingleDoubleRefModifier dtor if SingleRef
1414                     SingleDoubleRefModifier aMod( *t );
1415                     ScComplexRefData& rRef = aMod.Ref();
1416                     bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
1417                         rRef ) != UR_NOTHING);
1418                 }
1419                 if ( bMod )
1420                     t->CalcRelFromAbs( aPos );
1421             }
1422         }
1423     }
1424 
1425     if (bRefChanged)
1426     {
1427         bCompile = sal_True;
1428         CompileTokenArray();                // ruft auch StartListeningTo
1429         SetDirty();
1430     }
1431     else
1432         StartListeningTo( pDocument );      // Listener wie vorher
1433 }
1434 
1435 sal_Bool lcl_IsRangeNameInUse(sal_uInt16 nIndex, ScTokenArray* pCode, ScRangeName* pNames)
1436 {
1437     for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
1438     {
1439         if (p->GetOpCode() == ocName)
1440         {
1441             if (p->GetIndex() == nIndex)
1442                 return sal_True;
1443             else
1444             {
1445                 //  RangeData kann Null sein in bestimmten Excel-Dateien (#31168#)
1446                 ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
1447                 if (pSubName && lcl_IsRangeNameInUse(nIndex,
1448                                     pSubName->GetCode(), pNames))
1449                     return sal_True;
1450             }
1451         }
1452     }
1453     return sal_False;
1454 }
1455 
1456 sal_Bool ScFormulaCell::IsRangeNameInUse(sal_uInt16 nIndex) const
1457 {
1458     return lcl_IsRangeNameInUse( nIndex, pCode, pDocument->GetRangeName() );
1459 }
1460 
1461 void lcl_FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes, ScTokenArray* pCode, ScRangeName* pNames)
1462 {
1463     for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
1464     {
1465         if (p->GetOpCode() == ocName)
1466         {
1467             sal_uInt16 nTokenIndex = p->GetIndex();
1468             rIndexes.insert( nTokenIndex );
1469 
1470             ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
1471             if (pSubName)
1472                 lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames);
1473         }
1474     }
1475 }
1476 
1477 void ScFormulaCell::FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes) const
1478 {
1479     lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() );
1480 }
1481 
1482 void ScFormulaCell::ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap )
1483 {
1484     for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1485     {
1486         if( p->GetOpCode() == ocName )
1487         {
1488             sal_uInt16 nIndex = p->GetIndex();
1489             ScRangeData::IndexMap::const_iterator itr = rMap.find(nIndex);
1490             sal_uInt16 nNewIndex = itr == rMap.end() ? nIndex : itr->second;
1491             if ( nIndex != nNewIndex )
1492             {
1493                 p->SetIndex( nNewIndex );
1494                 bCompile = sal_True;
1495             }
1496         }
1497     }
1498     if( bCompile )
1499         CompileTokenArray();
1500 }
1501 
1502 void ScFormulaCell::CompileDBFormula()
1503 {
1504     for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1505     {
1506         if ( p->GetOpCode() == ocDBArea
1507             || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) )
1508         {
1509             bCompile = sal_True;
1510             CompileTokenArray();
1511             SetDirty();
1512             break;
1513         }
1514     }
1515 }
1516 
1517 void ScFormulaCell::CompileDBFormula( sal_Bool bCreateFormulaString )
1518 {
1519     // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1520     // 1. FormelString mit alten Namen erzeugen
1521     // 2. FormelString mit neuen Namen kompilieren
1522     if ( bCreateFormulaString )
1523     {
1524         sal_Bool bRecompile = sal_False;
1525         pCode->Reset();
1526         for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
1527         {
1528             switch ( p->GetOpCode() )
1529             {
1530                 case ocBad:             // DB-Bereich evtl. zugefuegt
1531                 case ocColRowName:      // #36762# falls Namensgleichheit
1532                 case ocDBArea:          // DB-Bereich
1533                     bRecompile = sal_True;
1534                 break;
1535                 case ocName:
1536                     if ( p->GetIndex() >= SC_START_INDEX_DB_COLL )
1537                         bRecompile = sal_True;  // DB-Bereich
1538                 break;
1539                 default:
1540                     ; // nothing
1541             }
1542         }
1543         if ( bRecompile )
1544         {
1545             String aFormula;
1546             GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1547             if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
1548             {
1549                 if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
1550                     aFormula.Erase( aFormula.Len()-1 , 1 );
1551                 if ( aFormula.GetChar(0) == '{' )
1552                     aFormula.Erase( 0, 1 );
1553             }
1554             EndListeningTo( pDocument );
1555             pDocument->RemoveFromFormulaTree( this );
1556             pCode->Clear();
1557             SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1558         }
1559     }
1560     else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1561     {
1562         Compile( aResult.GetHybridFormula(), sal_False, eTempGrammar );
1563         aResult.SetToken( NULL);
1564         SetDirty();
1565     }
1566 }
1567 
1568 void ScFormulaCell::CompileNameFormula( sal_Bool bCreateFormulaString )
1569 {
1570     // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1571     // 1. FormelString mit alten RangeNames erzeugen
1572     // 2. FormelString mit neuen RangeNames kompilieren
1573     if ( bCreateFormulaString )
1574     {
1575         sal_Bool bRecompile = sal_False;
1576         pCode->Reset();
1577         for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
1578         {
1579             switch ( p->GetOpCode() )
1580             {
1581                 case ocBad:             // RangeName evtl. zugefuegt
1582                 case ocColRowName:      // #36762# falls Namensgleichheit
1583                     bRecompile = sal_True;
1584                 break;
1585                 default:
1586                     if ( p->GetType() == svIndex )
1587                         bRecompile = sal_True;  // RangeName
1588             }
1589         }
1590         if ( bRecompile )
1591         {
1592             String aFormula;
1593             GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1594             if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
1595             {
1596                 if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
1597                     aFormula.Erase( aFormula.Len()-1 , 1 );
1598                 if ( aFormula.GetChar(0) == '{' )
1599                     aFormula.Erase( 0, 1 );
1600             }
1601             EndListeningTo( pDocument );
1602             pDocument->RemoveFromFormulaTree( this );
1603             pCode->Clear();
1604             SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1605         }
1606     }
1607     else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1608     {
1609         Compile( aResult.GetHybridFormula(), sal_False, eTempGrammar );
1610         aResult.SetToken( NULL);
1611         SetDirty();
1612     }
1613 }
1614 
1615 void ScFormulaCell::CompileColRowNameFormula()
1616 {
1617     pCode->Reset();
1618     for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1619     {
1620         if ( p->GetOpCode() == ocColRowName )
1621         {
1622             bCompile = sal_True;
1623             CompileTokenArray();
1624             SetDirty();
1625             break;
1626         }
1627     }
1628 }
1629 
1630 // ============================================================================
1631 
1632