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