1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cell2.cxx,v $
10 * $Revision: 1.34.102.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
37 #include <vcl/mapmod.hxx>
38 #include <svx/editobj.hxx>
39 #include <svx/editstat.hxx>
42 #include "compiler.hxx"
43 #include "formula/errorcodes.hxx"
44 #include "document.hxx"
45 #include "rangenam.hxx"
46 #include "rechead.hxx"
47 #include "refupdat.hxx"
48 #include "scmatrix.hxx"
49 #include "editutil.hxx"
50 #include "chgtrack.hxx"
51 #include "indexmap.hxx"
52 #include "externalrefmgr.hxx"
53 #include "scitems.hxx"
54 #include "patattr.hxx"
56 using namespace formula
;
58 // STATIC DATA -----------------------------------------------------------
61 const USHORT nMemPoolEditCell
= (0x1000 - 64) / sizeof(ScNoteCell
);
62 IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell
, nMemPoolEditCell
, nMemPoolEditCell
)
65 // ============================================================================
67 ScEditCell::ScEditCell( const EditTextObject
* pObject
, ScDocument
* pDocP
,
68 const SfxItemPool
* pFromPool
) :
69 ScBaseCell( CELLTYPE_EDIT
),
73 SetTextObject( pObject
, pFromPool
);
76 ScEditCell::ScEditCell( const ScEditCell
& rCell
, ScDocument
& rDoc
) :
81 SetTextObject( rCell
.pData
, rCell
.pDoc
->GetEditPool() );
84 ScEditCell::ScEditCell( const String
& rString
, ScDocument
* pDocP
) :
85 ScBaseCell( CELLTYPE_EDIT
),
89 DBG_ASSERT( rString
.Search('\n') != STRING_NOTFOUND
||
90 rString
.Search(CHAR_CR
) != STRING_NOTFOUND
,
91 "EditCell mit einfachem Text !?!?" );
93 EditEngine
& rEngine
= pDoc
->GetEditEngine();
94 rEngine
.SetText( rString
);
95 pData
= rEngine
.CreateTextObject();
98 ScEditCell::~ScEditCell()
104 eCellType
= CELLTYPE_DESTROYED
;
108 void ScEditCell::SetData( const EditTextObject
* pObject
,
109 const SfxItemPool
* pFromPool
)
117 SetTextObject( pObject
, pFromPool
);
120 void ScEditCell::GetData( const EditTextObject
*& rpObject
) const
125 void ScEditCell::GetString( String
& rString
) const
131 // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
132 EditEngine
& rEngine
= pDoc
->GetEditEngine();
133 rEngine
.SetText( *pData
);
134 rString
= ScEditUtil::GetMultilineString(rEngine
); // string with line separators between paragraphs
135 // kurze Strings fuer Formeln merken
136 if ( rString
.Len() < MAXSTRLEN
)
137 ((ScEditCell
*)this)->pString
= new String( rString
); //! non-const
143 bool ScEditCell::HasPhonetic() const
148 void ScEditCell::RemoveCharAttribs( const ScPatternAttr
& rAttr
)
154 { ATTR_FONT
, EE_CHAR_FONTINFO
},
155 { ATTR_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT
},
156 { ATTR_FONT_WEIGHT
, EE_CHAR_WEIGHT
},
157 { ATTR_FONT_COLOR
, EE_CHAR_COLOR
}
159 USHORT nMapCount
= sizeof(AttrTypeMap
) / sizeof(AttrTypeMap
[0]);
161 const SfxItemSet
& rSet
= rAttr
.GetItemSet();
162 const SfxPoolItem
* pItem
;
163 for (USHORT i
= 0; i
< nMapCount
; ++i
)
165 if ( rSet
.GetItemState(AttrTypeMap
[i
].nAttrType
, false, &pItem
) == SFX_ITEM_SET
)
166 pData
->RemoveCharAttribs(AttrTypeMap
[i
].nCharType
);
170 void ScEditCell::SetTextObject( const EditTextObject
* pObject
,
171 const SfxItemPool
* pFromPool
)
175 if ( pFromPool
&& pDoc
->GetEditPool() == pFromPool
)
176 pData
= pObject
->Clone();
179 // Leider gibt es keinen anderen Weg, um den Pool umzuhaengen,
180 // als das Object durch eine entsprechende Engine zu schleusen..
181 EditEngine
& rEngine
= pDoc
->GetEditEngine();
182 if ( pObject
->HasOnlineSpellErrors() )
184 ULONG nControl
= rEngine
.GetControlWord();
185 const ULONG nSpellControl
= EE_CNTRL_ONLINESPELLING
| EE_CNTRL_ALLOWBIGOBJS
;
186 BOOL bNewControl
= ( (nControl
& nSpellControl
) != nSpellControl
);
188 rEngine
.SetControlWord( nControl
| nSpellControl
);
189 rEngine
.SetText( *pObject
);
190 pData
= rEngine
.CreateTextObject();
192 rEngine
.SetControlWord( nControl
);
196 rEngine
.SetText( *pObject
);
197 pData
= rEngine
.CreateTextObject();
205 ScEditDataArray::ScEditDataArray()
209 ScEditDataArray::~ScEditDataArray()
213 void ScEditDataArray::AddItem(SCTAB nTab
, SCCOL nCol
, SCROW nRow
,
214 EditTextObject
* pOldData
, EditTextObject
* pNewData
)
216 maArray
.push_back(Item(nTab
, nCol
, nRow
, pOldData
, pNewData
));
219 const ScEditDataArray::Item
* ScEditDataArray::First()
221 maIter
= maArray
.begin();
222 if (maIter
== maArray
.end())
227 const ScEditDataArray::Item
* ScEditDataArray::Next()
229 if (maIter
== maArray
.end())
234 // ============================================================================
236 ScEditDataArray::Item::Item(SCTAB nTab
, SCCOL nCol
, SCROW nRow
,
237 EditTextObject
* pOldData
, EditTextObject
* pNewData
) :
242 mpOldData
.reset(pOldData
);
243 mpNewData
.reset(pNewData
);
246 ScEditDataArray::Item::~Item()
250 const EditTextObject
* ScEditDataArray::Item::GetOldData() const
252 return mpOldData
.get();
255 const EditTextObject
* ScEditDataArray::Item::GetNewData() const
257 return mpNewData
.get();
260 SCTAB
ScEditDataArray::Item::GetTab() const
265 SCCOL
ScEditDataArray::Item::GetCol() const
270 SCROW
ScEditDataArray::Item::GetRow() const
275 // ============================================================================
277 BOOL
ScFormulaCell::IsEmpty()
279 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
281 return aResult
.GetCellResultType() == formula::svEmptyCell
;
284 BOOL
ScFormulaCell::IsEmptyDisplayedAsString()
286 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
288 return aResult
.IsEmptyDisplayedAsString();
291 BOOL
ScFormulaCell::IsValue()
293 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
295 return aResult
.IsValue();
298 double ScFormulaCell::GetValue()
300 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
302 if ((!pCode
->GetCodeError() || pCode
->GetCodeError() == errDoubleRef
) &&
303 !aResult
.GetResultError())
304 return aResult
.GetDouble();
308 double ScFormulaCell::GetValueAlways()
310 // for goal seek: return result value even if error code is set
312 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
314 return aResult
.GetDouble();
317 void ScFormulaCell::GetString( String
& rString
)
319 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
321 if ((!pCode
->GetCodeError() || pCode
->GetCodeError() == errDoubleRef
) &&
322 !aResult
.GetResultError())
323 rString
= aResult
.GetString();
328 const ScMatrix
* ScFormulaCell::GetMatrix()
330 if ( pDocument
->GetAutoCalc() )
332 // Was stored !bDirty but an accompanying matrix cell was bDirty?
333 // => we need to get the matrix.
334 if (!bDirty
&& cMatrixFlag
== MM_FORMULA
&& !aResult
.GetMatrix().Is())
336 if ( IsDirtyOrInTableOpDirty() )
339 return aResult
.GetMatrix();
342 BOOL
ScFormulaCell::GetMatrixOrigin( ScAddress
& rPos
) const
344 switch ( cMatrixFlag
)
353 ScToken
* t
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
356 ScSingleRefData
& rRef
= t
->GetSingleRef();
357 rRef
.CalcAbsIfRel( aPos
);
360 rPos
.Set( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
380 (reserviert: offen: 32)
383 USHORT
ScFormulaCell::GetMatrixEdge( ScAddress
& rOrgPos
)
385 switch ( cMatrixFlag
)
393 if ( !GetMatrixOrigin( aOrg
) )
394 return 0; // dumm gelaufen..
395 if ( aOrg
!= rOrgPos
)
396 { // erstes Mal oder andere Matrix als letztes Mal
398 ScFormulaCell
* pFCell
;
399 if ( cMatrixFlag
== MM_REFERENCE
)
400 pFCell
= (ScFormulaCell
*) pDocument
->GetCell( aOrg
);
402 pFCell
= this; // this MM_FORMULA
403 // this gibt's nur einmal, kein Vergleich auf pFCell==this
404 if ( pFCell
&& pFCell
->GetCellType() == CELLTYPE_FORMULA
405 && pFCell
->cMatrixFlag
== MM_FORMULA
)
407 pFCell
->GetMatColsRows( nC
, nR
);
408 if ( nC
== 0 || nR
== 0 )
409 { // aus altem Dokument geladen, neu erzeugen
414 ScAddress
aAdr( aOrg
);
419 pCell
= pDocument
->GetCell( aAdr
);
420 if ( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
421 && ((ScFormulaCell
*)pCell
)->cMatrixFlag
== MM_REFERENCE
422 && GetMatrixOrigin( aTmpOrg
) && aTmpOrg
== aOrg
)
435 pCell
= pDocument
->GetCell( aAdr
);
436 if ( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
437 && ((ScFormulaCell
*)pCell
)->cMatrixFlag
== MM_REFERENCE
438 && GetMatrixOrigin( aTmpOrg
) && aTmpOrg
== aOrg
)
446 pFCell
->SetMatColsRows( nC
, nR
);
453 ByteString
aMsg( "broken Matrix, no MatFormula at origin, Pos: " );
454 aPos
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
455 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
456 aMsg
+= ", MatOrg: ";
457 aOrg
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
458 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
459 DBG_ERRORFILE( aMsg
.GetBuffer() );
461 return 0; // bad luck ...
464 // here we are, healthy and clean, somewhere in between
465 SCsCOL dC
= aPos
.Col() - aOrg
.Col();
466 SCsROW dR
= aPos
.Row() - aOrg
.Row();
468 if ( dC
>= 0 && dR
>= 0 && dC
< nC
&& dR
< nR
)
471 nEdges
|= 4; // linke Kante
473 nEdges
|= 16; // rechte Kante
475 nEdges
|= 8; // obere Kante
477 nEdges
|= 2; // untere Kante
479 nEdges
= 1; // mittendrin
485 ByteString
aMsg( "broken Matrix, Pos: " );
486 aPos
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
487 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
488 aMsg
+= ", MatOrg: ";
489 aOrg
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
490 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
491 aMsg
+= ", MatCols: ";
492 aMsg
+= ByteString::CreateFromInt32( nC
);
493 aMsg
+= ", MatRows: ";
494 aMsg
+= ByteString::CreateFromInt32( nR
);
495 aMsg
+= ", DiffCols: ";
496 aMsg
+= ByteString::CreateFromInt32( dC
);
497 aMsg
+= ", DiffRows: ";
498 aMsg
+= ByteString::CreateFromInt32( dR
);
499 DBG_ERRORFILE( aMsg
.GetBuffer() );
510 USHORT
ScFormulaCell::GetErrCode()
512 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
514 /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
515 * and not also abused for signaling other error conditions we could bail
516 * out even before attempting to interpret broken code. */
517 USHORT nErr
= pCode
->GetCodeError();
520 return aResult
.GetResultError();
523 USHORT
ScFormulaCell::GetRawError()
525 USHORT nErr
= pCode
->GetCodeError();
528 return aResult
.GetResultError();
531 BOOL
ScFormulaCell::HasOneReference( ScRange
& r
) const
534 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
535 if( p
&& !pCode
->GetNextReferenceRPN() ) // nur eine!
537 p
->CalcAbsIfRel( aPos
);
538 SingleDoubleRefProvider
aProv( *p
);
539 r
.aStart
.Set( aProv
.Ref1
.nCol
,
542 r
.aEnd
.Set( aProv
.Ref2
.nCol
,
551 BOOL
ScFormulaCell::HasRelNameReference() const
555 while ( ( t
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN()) ) != NULL
)
557 if ( t
->GetSingleRef().IsRelName() ||
558 (t
->GetType() == formula::svDoubleRef
&&
559 t
->GetDoubleRef().Ref2
.IsRelName()) )
565 BOOL
ScFormulaCell::HasColRowName() const
568 return (pCode
->GetNextColRowName() != NULL
);
571 void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode
,
573 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
574 ScDocument
* pUndoDoc
)
576 SCCOL nCol1
= r
.aStart
.Col();
577 SCROW nRow1
= r
.aStart
.Row();
578 SCTAB nTab1
= r
.aStart
.Tab();
579 SCCOL nCol2
= r
.aEnd
.Col();
580 SCROW nRow2
= r
.aEnd
.Row();
581 SCTAB nTab2
= r
.aEnd
.Tab();
582 SCCOL nCol
= aPos
.Col();
583 SCROW nRow
= aPos
.Row();
584 SCTAB nTab
= aPos
.Tab();
585 ScAddress
aUndoPos( aPos
); // position for undo cell in pUndoDoc
586 ScAddress
aOldPos( aPos
);
587 // BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
588 BOOL bIsInsert
= FALSE
;
589 if (eUpdateRefMode
== URM_INSDEL
)
591 bIsInsert
= (nDx
>= 0 && nDy
>= 0 && nDz
>= 0);
592 if ( nDx
&& nRow
>= nRow1
&& nRow
<= nRow2
&&
593 nTab
>= nTab1
&& nTab
<= nTab2
)
597 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nDx
);
598 if ((SCsCOL
) nCol
< 0)
600 else if ( nCol
> MAXCOL
)
603 // bPosChanged = TRUE;
606 if ( nDy
&& nCol
>= nCol1
&& nCol
<= nCol2
&&
607 nTab
>= nTab1
&& nTab
<= nTab2
)
611 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nDy
);
612 if ((SCsROW
) nRow
< 0)
614 else if ( nRow
> MAXROW
)
617 // bPosChanged = TRUE;
620 if ( nDz
&& nCol
>= nCol1
&& nCol
<= nCol2
&&
621 nRow
>= nRow1
&& nRow
<= nRow2
)
625 SCTAB nMaxTab
= pDocument
->GetTableCount() - 1;
626 nTab
= sal::static_int_cast
<SCTAB
>( nTab
+ nDz
);
627 if ((SCsTAB
) nTab
< 0)
629 else if ( nTab
> nMaxTab
)
632 // bPosChanged = TRUE;
636 else if ( r
.In( aPos
) )
638 aOldPos
.Set( nCol
- nDx
, nRow
- nDy
, nTab
- nDz
);
639 // bPosChanged = TRUE;
642 BOOL bHasRefs
= FALSE
;
643 BOOL bHasColRowNames
= FALSE
;
644 BOOL bOnRefMove
= FALSE
;
645 if ( !pDocument
->IsClipOrUndo() )
648 bHasRefs
= (pCode
->GetNextReferenceRPN() != NULL
);
649 if ( !bHasRefs
|| eUpdateRefMode
== URM_COPY
)
652 bHasColRowNames
= (pCode
->GetNextColRowName() != NULL
);
653 bHasRefs
= bHasRefs
|| bHasColRowNames
;
655 bOnRefMove
= pCode
->IsRecalcModeOnRefMove();
657 if( bHasRefs
|| bOnRefMove
)
659 ScTokenArray
* pOld
= pUndoDoc
? pCode
->Clone() : NULL
;
661 ScRangeData
* pRangeData
;
662 BOOL bRangeModified
; // any range, not only shared formula
663 BOOL bRefSizeChanged
;
666 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
667 aComp
.SetGrammar(pDocument
->GetGrammar());
668 pRangeData
= aComp
.UpdateReference(eUpdateRefMode
, aOldPos
, r
,
670 bValChanged
, bRefSizeChanged
);
671 bRangeModified
= aComp
.HasModifiedRange();
677 bRangeModified
= FALSE
;
678 bRefSizeChanged
= FALSE
;
681 bOnRefMove
= (bValChanged
|| (aPos
!= aOldPos
));
682 // Cell may reference itself, e.g. ocColumn, ocRow without parameter
684 BOOL bColRowNameCompile
, bHasRelName
, bNewListening
, bInDeleteUndo
;
687 // Upon Insert ColRowNames have to be recompiled in case the
688 // insertion occurs right in front of the range.
690 (eUpdateRefMode
== URM_INSDEL
&& (nDx
> 0 || nDy
> 0));
691 if ( bColRowNameCompile
)
693 bColRowNameCompile
= FALSE
;
695 ScRangePairList
* pColList
= pDocument
->GetColNameRanges();
696 ScRangePairList
* pRowList
= pDocument
->GetRowNameRanges();
698 while ( !bColRowNameCompile
&& (t
= static_cast<ScToken
*>(pCode
->GetNextColRowName())) != NULL
)
700 ScSingleRefData
& rRef
= t
->GetSingleRef();
701 if ( nDy
> 0 && rRef
.IsColRel() )
703 rRef
.CalcAbsIfRel( aPos
);
704 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
705 ScRangePair
* pR
= pColList
->Find( aAdr
);
708 if ( pR
->GetRange(1).aStart
.Row() == nRow1
)
709 bColRowNameCompile
= TRUE
;
713 if ( rRef
.nRow
+ 1 == nRow1
)
714 bColRowNameCompile
= TRUE
;
717 if ( nDx
> 0 && rRef
.IsRowRel() )
719 rRef
.CalcAbsIfRel( aPos
);
720 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
721 ScRangePair
* pR
= pRowList
->Find( aAdr
);
724 if ( pR
->GetRange(1).aStart
.Col() == nCol1
)
725 bColRowNameCompile
= TRUE
;
729 if ( rRef
.nCol
+ 1 == nCol1
)
730 bColRowNameCompile
= TRUE
;
735 else if ( eUpdateRefMode
== URM_MOVE
)
736 { // bei Move/D&D neu kompilieren wenn ColRowName verschoben wurde
737 // oder diese Zelle auf einen zeigt und verschoben wurde
738 bColRowNameCompile
= bCompile
; // evtl. aus Copy-ctor
739 if ( !bColRowNameCompile
)
741 BOOL bMoved
= (aPos
!= aOldPos
);
743 ScToken
* t
= static_cast<ScToken
*>(pCode
->GetNextColRowName());
745 bColRowNameCompile
= TRUE
;
746 while ( t
&& !bColRowNameCompile
)
748 ScSingleRefData
& rRef
= t
->GetSingleRef();
749 rRef
.CalcAbsIfRel( aPos
);
752 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
754 bColRowNameCompile
= TRUE
;
756 t
= static_cast<ScToken
*>(pCode
->GetNextColRowName());
760 else if ( eUpdateRefMode
== URM_COPY
&& bHasColRowNames
&& bValChanged
)
762 bColRowNameCompile
= TRUE
;
764 ScChangeTrack
* pChangeTrack
= pDocument
->GetChangeTrack();
765 if ( pChangeTrack
&& pChangeTrack
->IsInDeleteUndo() )
766 bInDeleteUndo
= TRUE
;
768 bInDeleteUndo
= FALSE
;
769 // RelNameRefs are always moved
770 bHasRelName
= HasRelNameReference();
771 // Reference changed and new listening needed?
772 // Except in Insert/Delete without specialties.
773 bNewListening
= (bRangeModified
|| pRangeData
|| bColRowNameCompile
774 || (bValChanged
&& (eUpdateRefMode
!= URM_INSDEL
||
775 bInDeleteUndo
|| bRefSizeChanged
)) ||
776 (bHasRelName
&& eUpdateRefMode
!= URM_COPY
))
777 // #i36299# Don't duplicate action during cut&paste / drag&drop
778 // on a cell in the range moved, start/end listeners is done
779 // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
780 && !(eUpdateRefMode
== URM_MOVE
&&
781 pDocument
->IsInsertingFromOtherDoc() && r
.In(aPos
));
783 EndListeningTo( pDocument
, pOld
, aOldPos
);
787 bColRowNameCompile
= bHasRelName
= bNewListening
= bInDeleteUndo
=
792 // NeedDirty bei Aenderungen ausser Copy und Move/Insert ohne RelNames
793 if ( bRangeModified
|| pRangeData
|| bColRowNameCompile
||
794 (bValChanged
&& eUpdateRefMode
!= URM_COPY
&&
795 (eUpdateRefMode
!= URM_MOVE
|| bHasRelName
) &&
796 (!bIsInsert
|| bHasRelName
|| bInDeleteUndo
||
797 bRefSizeChanged
)) || bOnRefMove
)
801 if (pUndoDoc
&& (bValChanged
|| pRangeData
|| bOnRefMove
))
803 // Copy the cell to aUndoPos, which is its current position in the document,
804 // so this works when UpdateReference is called before moving the cells
805 // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
806 // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
808 ScFormulaCell
* pFCell
= new ScFormulaCell( pUndoDoc
, aUndoPos
,
809 pOld
, eTempGrammar
, cMatrixFlag
);
810 pFCell
->aResult
.SetToken( NULL
); // to recognize it as changed later (Cut/Paste!)
811 pUndoDoc
->PutCell( aUndoPos
, pFCell
);
815 { // Replace shared formula with own formula
816 pDocument
->RemoveFromFormulaTree( this ); // update formula count
818 pCode
= pRangeData
->GetCode()->Clone();
819 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
820 aComp2
.SetGrammar(pDocument
->GetGrammar());
821 aComp2
.UpdateSharedFormulaReference( eUpdateRefMode
, aOldPos
, r
,
826 if ( ( bCompile
= (bCompile
|| bValChanged
|| bRangeModified
|| bColRowNameCompile
) ) != 0 )
828 CompileTokenArray( bNewListening
); // kein Listening
831 if ( !bInDeleteUndo
)
832 { // In ChangeTrack Delete-Reject listeners are established in
833 // InsertCol/InsertRow
836 if ( eUpdateRefMode
== URM_INSDEL
)
838 // Inserts/Deletes re-establish listeners after all
839 // UpdateReference calls.
840 // All replaced shared formula listeners have to be
841 // established after an Insert or Delete. Do nothing here.
842 SetNeedsListening( TRUE
);
845 StartListeningTo( pDocument
);
848 if ( bNeedDirty
&& (!(eUpdateRefMode
== URM_INSDEL
&& bHasRelName
) || pRangeData
) )
849 { // Referenzen abgeschnitten, ungueltig o.ae.?
850 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
851 // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
852 pDocument
->SetAutoCalc( FALSE
);
854 pDocument
->SetAutoCalc( bOldAutoCalc
);
861 for ( formula::FormulaToken
* t
= pCode
->GetNextReferenceOrName(); t
; t
= pCode
->GetNextReferenceOrName() )
863 StackVar sv
= t
->GetType();
864 if (sv
== svExternalSingleRef
|| sv
== svExternalDoubleRef
|| sv
== svExternalName
)
866 pDocument
->GetExternalRefManager()->updateRefCell(aOldPos
, aPos
, eUpdateRefMode
== URM_COPY
);
872 void ScFormulaCell::UpdateInsertTab(SCTAB nTable
)
874 BOOL bPosChanged
= ( aPos
.Tab() >= nTable
? TRUE
: FALSE
);
876 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
878 EndListeningTo( pDocument
);
879 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
882 ScRangeData
* pRangeData
;
883 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
884 aComp
.SetGrammar(pDocument
->GetGrammar());
885 pRangeData
= aComp
.UpdateInsertTab( nTable
, FALSE
);
886 if (pRangeData
) // Shared Formula gegen echte Formel
889 pDocument
->RemoveFromFormulaTree( this ); // update formula count
891 pCode
= new ScTokenArray( *pRangeData
->GetCode() );
892 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
893 aComp2
.SetGrammar(pDocument
->GetGrammar());
894 aComp2
.MoveRelWrap();
895 aComp2
.UpdateInsertTab( nTable
, FALSE
);
896 // If the shared formula contained a named range/formula containing
897 // an absolute reference to a sheet, those have to be readjusted.
898 aComp2
.UpdateDeleteTab( nTable
, FALSE
, TRUE
, bRefChanged
);
901 // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
903 else if ( bPosChanged
)
907 BOOL
ScFormulaCell::UpdateDeleteTab(SCTAB nTable
, BOOL bIsMove
)
909 BOOL bRefChanged
= FALSE
;
910 BOOL bPosChanged
= ( aPos
.Tab() > nTable
? TRUE
: FALSE
);
912 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
914 EndListeningTo( pDocument
);
915 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
918 ScRangeData
* pRangeData
;
919 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
920 aComp
.SetGrammar(pDocument
->GetGrammar());
921 pRangeData
= aComp
.UpdateDeleteTab(nTable
, bIsMove
, FALSE
, bRefChanged
);
922 if (pRangeData
) // Shared Formula gegen echte Formel
924 pDocument
->RemoveFromFormulaTree( this ); // update formula count
926 pCode
= pRangeData
->GetCode()->Clone();
927 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
928 aComp2
.SetGrammar(pDocument
->GetGrammar());
929 aComp2
.CompileTokenArray();
930 aComp2
.MoveRelWrap();
931 aComp2
.UpdateDeleteTab( nTable
, FALSE
, FALSE
, bRefChanged
);
932 // If the shared formula contained a named range/formula containing
933 // an absolute reference to a sheet, those have to be readjusted.
934 aComp2
.UpdateInsertTab( nTable
,TRUE
);
935 // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
939 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
941 else if ( bPosChanged
)
947 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
, SCTAB nTabNo
)
950 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
952 EndListeningTo( pDocument
);
953 // SetTab _nach_ EndListeningTo und _vor_ Compiler UpdateMoveTab !
954 aPos
.SetTab( nTabNo
);
955 ScRangeData
* pRangeData
;
956 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
957 aComp
.SetGrammar(pDocument
->GetGrammar());
958 pRangeData
= aComp
.UpdateMoveTab( nOldPos
, nNewPos
, FALSE
);
959 if (pRangeData
) // Shared Formula gegen echte Formel
961 pDocument
->RemoveFromFormulaTree( this ); // update formula count
963 pCode
= pRangeData
->GetCode()->Clone();
964 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
965 aComp2
.SetGrammar(pDocument
->GetGrammar());
966 aComp2
.CompileTokenArray();
967 aComp2
.MoveRelWrap();
968 aComp2
.UpdateMoveTab( nOldPos
, nNewPos
, TRUE
);
971 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
974 aPos
.SetTab( nTabNo
);
977 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable
)
979 if( !pDocument
->IsClipOrUndo() )
982 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
985 ScSingleRefData
& rRef1
= p
->GetSingleRef();
986 if( !rRef1
.IsTabRel() && (SCsTAB
) nTable
<= rRef1
.nTab
)
988 if( p
->GetType() == formula::svDoubleRef
)
990 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
991 if( !rRef2
.IsTabRel() && (SCsTAB
) nTable
<= rRef2
.nTab
)
994 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
999 BOOL
ScFormulaCell::TestTabRefAbs(SCTAB nTable
)
1002 if( !pDocument
->IsClipOrUndo() )
1005 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1008 ScSingleRefData
& rRef1
= p
->GetSingleRef();
1009 if( !rRef1
.IsTabRel() )
1011 if( (SCsTAB
) nTable
!= rRef1
.nTab
)
1013 else if (nTable
!= aPos
.Tab())
1014 rRef1
.nTab
= aPos
.Tab();
1016 if( p
->GetType() == formula::svDoubleRef
)
1018 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
1019 if( !rRef2
.IsTabRel() )
1021 if( (SCsTAB
) nTable
!= rRef2
.nTab
)
1023 else if (nTable
!= aPos
.Tab())
1024 rRef2
.nTab
= aPos
.Tab();
1027 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1033 void ScFormulaCell::UpdateCompile( BOOL bForceIfNameInUse
)
1035 if ( bForceIfNameInUse
&& !bCompile
)
1036 bCompile
= pCode
->HasNameOrColRowName();
1038 pCode
->SetCodeError( 0 ); // make sure it will really be compiled
1039 CompileTokenArray();
1042 // Referenzen transponieren - wird nur in Clipboard-Dokumenten aufgerufen
1044 void ScFormulaCell::TransposeReference()
1046 BOOL bFound
= FALSE
;
1049 while ( ( t
= static_cast<ScToken
*>(pCode
->GetNextReference()) ) != NULL
)
1051 ScSingleRefData
& rRef1
= t
->GetSingleRef();
1052 if ( rRef1
.IsColRel() && rRef1
.IsRowRel() )
1054 BOOL bDouble
= (t
->GetType() == formula::svDoubleRef
);
1055 ScSingleRefData
& rRef2
= (bDouble
? t
->GetDoubleRef().Ref2
: rRef1
);
1056 if ( !bDouble
|| (rRef2
.IsColRel() && rRef2
.IsRowRel()) )
1060 nTemp
= rRef1
.nRelCol
;
1061 rRef1
.nRelCol
= static_cast<SCCOL
>(rRef1
.nRelRow
);
1062 rRef1
.nRelRow
= static_cast<SCROW
>(nTemp
);
1066 nTemp
= rRef2
.nRelCol
;
1067 rRef2
.nRelCol
= static_cast<SCCOL
>(rRef2
.nRelRow
);
1068 rRef2
.nRelRow
= static_cast<SCROW
>(nTemp
);
1080 void ScFormulaCell::UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
1081 ScDocument
* pUndoDoc
)
1083 EndListeningTo( pDocument
);
1085 ScAddress aOldPos
= aPos
;
1086 BOOL bPosChanged
= FALSE
; // ob diese Zelle bewegt wurde
1088 ScRange
aDestRange( rDest
, ScAddress(
1089 static_cast<SCCOL
>(rDest
.Col() + rSource
.aEnd
.Row() - rSource
.aStart
.Row()),
1090 static_cast<SCROW
>(rDest
.Row() + rSource
.aEnd
.Col() - rSource
.aStart
.Col()),
1091 rDest
.Tab() + rSource
.aEnd
.Tab() - rSource
.aStart
.Tab() ) );
1092 if ( aDestRange
.In( aOldPos
) )
1094 // Position zurueckrechnen
1095 SCsCOL nRelPosX
= aOldPos
.Col();
1096 SCsROW nRelPosY
= aOldPos
.Row();
1097 SCsTAB nRelPosZ
= aOldPos
.Tab();
1098 ScRefUpdate::DoTranspose( nRelPosX
, nRelPosY
, nRelPosZ
, pDocument
, aDestRange
, rSource
.aStart
);
1099 aOldPos
.Set( nRelPosX
, nRelPosY
, nRelPosZ
);
1103 ScTokenArray
* pOld
= pUndoDoc
? pCode
->Clone() : NULL
;
1104 BOOL bRefChanged
= FALSE
;
1107 ScRangeData
* pShared
= NULL
;
1109 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName())) != NULL
)
1111 if( t
->GetOpCode() == ocName
)
1113 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
1116 if (pName
->IsModified())
1118 if (pName
->HasType(RT_SHAREDMOD
))
1122 else if( t
->GetType() != svIndex
)
1124 t
->CalcAbsIfRel( aOldPos
);
1126 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1127 SingleDoubleRefModifier
aMod( *t
);
1128 ScComplexRefData
& rRef
= aMod
.Ref();
1129 bMod
= (ScRefUpdate::UpdateTranspose( pDocument
, rSource
,
1130 rDest
, rRef
) != UR_NOTHING
|| bPosChanged
);
1134 t
->CalcRelFromAbs( aPos
);
1140 if (pShared
) // Shared Formula gegen echte Formel austauschen
1142 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1144 pCode
= new ScTokenArray( *pShared
->GetCode() );
1147 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReference())) != NULL
)
1149 if( t
->GetType() != svIndex
)
1151 t
->CalcAbsIfRel( aOldPos
);
1153 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1154 SingleDoubleRefModifier
aMod( *t
);
1155 ScComplexRefData
& rRef
= aMod
.Ref();
1156 bMod
= (ScRefUpdate::UpdateTranspose( pDocument
, rSource
,
1157 rDest
, rRef
) != UR_NOTHING
|| bPosChanged
);
1160 t
->CalcRelFromAbs( aPos
);
1169 ScFormulaCell
* pFCell
= new ScFormulaCell( pUndoDoc
, aPos
, pOld
,
1170 eTempGrammar
, cMatrixFlag
);
1171 pFCell
->aResult
.SetToken( NULL
); // to recognize it as changed later (Cut/Paste!)
1172 pUndoDoc
->PutCell( aPos
.Col(), aPos
.Row(), aPos
.Tab(), pFCell
);
1176 CompileTokenArray(); // ruft auch StartListeningTo
1180 StartListeningTo( pDocument
); // Listener wie vorher
1185 void ScFormulaCell::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
1187 EndListeningTo( pDocument
);
1189 BOOL bRefChanged
= FALSE
;
1191 ScRangeData
* pShared
= NULL
;
1194 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName())) != NULL
)
1196 if( t
->GetOpCode() == ocName
)
1198 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
1201 if (pName
->IsModified())
1203 if (pName
->HasType(RT_SHAREDMOD
))
1207 else if( t
->GetType() != svIndex
)
1209 t
->CalcAbsIfRel( aPos
);
1211 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1212 SingleDoubleRefModifier
aMod( *t
);
1213 ScComplexRefData
& rRef
= aMod
.Ref();
1214 bMod
= (ScRefUpdate::UpdateGrow( rArea
,nGrowX
,nGrowY
,
1215 rRef
) != UR_NOTHING
);
1219 t
->CalcRelFromAbs( aPos
);
1225 if (pShared
) // Shared Formula gegen echte Formel austauschen
1227 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1229 pCode
= new ScTokenArray( *pShared
->GetCode() );
1232 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReference())) != NULL
)
1234 if( t
->GetType() != svIndex
)
1236 t
->CalcAbsIfRel( aPos
);
1238 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1239 SingleDoubleRefModifier
aMod( *t
);
1240 ScComplexRefData
& rRef
= aMod
.Ref();
1241 bMod
= (ScRefUpdate::UpdateGrow( rArea
,nGrowX
,nGrowY
,
1242 rRef
) != UR_NOTHING
);
1245 t
->CalcRelFromAbs( aPos
);
1253 CompileTokenArray(); // ruft auch StartListeningTo
1257 StartListeningTo( pDocument
); // Listener wie vorher
1260 BOOL
lcl_IsRangeNameInUse(USHORT nIndex
, ScTokenArray
* pCode
, ScRangeName
* pNames
)
1262 for (FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next())
1264 if (p
->GetOpCode() == ocName
)
1266 if (p
->GetIndex() == nIndex
)
1270 // RangeData kann Null sein in bestimmten Excel-Dateien (#31168#)
1271 ScRangeData
* pSubName
= pNames
->FindIndex(p
->GetIndex());
1272 if (pSubName
&& lcl_IsRangeNameInUse(nIndex
,
1273 pSubName
->GetCode(), pNames
))
1281 BOOL
ScFormulaCell::IsRangeNameInUse(USHORT nIndex
) const
1283 return lcl_IsRangeNameInUse( nIndex
, pCode
, pDocument
->GetRangeName() );
1286 void lcl_FindRangeNamesInUse(std::set
<USHORT
>& rIndexes
, ScTokenArray
* pCode
, ScRangeName
* pNames
)
1288 for (FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next())
1290 if (p
->GetOpCode() == ocName
)
1292 USHORT nTokenIndex
= p
->GetIndex();
1293 rIndexes
.insert( nTokenIndex
);
1295 ScRangeData
* pSubName
= pNames
->FindIndex(p
->GetIndex());
1297 lcl_FindRangeNamesInUse(rIndexes
, pSubName
->GetCode(), pNames
);
1302 void ScFormulaCell::FindRangeNamesInUse(std::set
<USHORT
>& rIndexes
) const
1304 lcl_FindRangeNamesInUse( rIndexes
, pCode
, pDocument
->GetRangeName() );
1307 void ScFormulaCell::ReplaceRangeNamesInUse( const ScIndexMap
& rMap
)
1309 for( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1311 if( p
->GetOpCode() == ocName
)
1313 USHORT nIndex
= p
->GetIndex();
1314 USHORT nNewIndex
= rMap
.Find( nIndex
);
1315 if ( nIndex
!= nNewIndex
)
1317 p
->SetIndex( nNewIndex
);
1323 CompileTokenArray();
1326 void ScFormulaCell::ReplaceRangeNamesInUse( const ScRangeData::IndexMap
& rMap
)
1328 for( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1330 if( p
->GetOpCode() == ocName
)
1332 sal_uInt16 nIndex
= p
->GetIndex();
1333 ScRangeData::IndexMap::const_iterator itr
= rMap
.find(nIndex
);
1334 sal_uInt16 nNewIndex
= itr
== rMap
.end() ? nIndex
: nNewIndex
;
1335 if ( nIndex
!= nNewIndex
)
1337 p
->SetIndex( nNewIndex
);
1343 CompileTokenArray();
1346 void ScFormulaCell::CompileDBFormula()
1348 for( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1350 if ( p
->GetOpCode() == ocDBArea
1351 || (p
->GetOpCode() == ocName
&& p
->GetIndex() >= SC_START_INDEX_DB_COLL
) )
1354 CompileTokenArray();
1361 void ScFormulaCell::CompileDBFormula( BOOL bCreateFormulaString
)
1363 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1364 // 1. FormelString mit alten Namen erzeugen
1365 // 2. FormelString mit neuen Namen kompilieren
1366 if ( bCreateFormulaString
)
1368 BOOL bRecompile
= FALSE
;
1370 for ( FormulaToken
* p
= pCode
->First(); p
&& !bRecompile
; p
= pCode
->Next() )
1372 switch ( p
->GetOpCode() )
1374 case ocBad
: // DB-Bereich evtl. zugefuegt
1375 case ocColRowName
: // #36762# falls Namensgleichheit
1376 case ocDBArea
: // DB-Bereich
1380 if ( p
->GetIndex() >= SC_START_INDEX_DB_COLL
)
1381 bRecompile
= TRUE
; // DB-Bereich
1390 GetFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1391 if ( GetMatrixFlag() != MM_NONE
&& aFormula
.Len() )
1393 if ( aFormula
.GetChar( aFormula
.Len()-1 ) == '}' )
1394 aFormula
.Erase( aFormula
.Len()-1 , 1 );
1395 if ( aFormula
.GetChar(0) == '{' )
1396 aFormula
.Erase( 0, 1 );
1398 EndListeningTo( pDocument
);
1399 pDocument
->RemoveFromFormulaTree( this );
1401 SetHybridFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1404 else if ( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
1406 Compile( aResult
.GetHybridFormula(), FALSE
, eTempGrammar
);
1407 aResult
.SetToken( NULL
);
1412 void ScFormulaCell::CompileNameFormula( BOOL bCreateFormulaString
)
1414 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1415 // 1. FormelString mit alten RangeNames erzeugen
1416 // 2. FormelString mit neuen RangeNames kompilieren
1417 if ( bCreateFormulaString
)
1419 BOOL bRecompile
= FALSE
;
1421 for ( FormulaToken
* p
= pCode
->First(); p
&& !bRecompile
; p
= pCode
->Next() )
1423 switch ( p
->GetOpCode() )
1425 case ocBad
: // RangeName evtl. zugefuegt
1426 case ocColRowName
: // #36762# falls Namensgleichheit
1430 if ( p
->GetType() == svIndex
)
1431 bRecompile
= TRUE
; // RangeName
1437 GetFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1438 if ( GetMatrixFlag() != MM_NONE
&& aFormula
.Len() )
1440 if ( aFormula
.GetChar( aFormula
.Len()-1 ) == '}' )
1441 aFormula
.Erase( aFormula
.Len()-1 , 1 );
1442 if ( aFormula
.GetChar(0) == '{' )
1443 aFormula
.Erase( 0, 1 );
1445 EndListeningTo( pDocument
);
1446 pDocument
->RemoveFromFormulaTree( this );
1448 SetHybridFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1451 else if ( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
1453 Compile( aResult
.GetHybridFormula(), FALSE
, eTempGrammar
);
1454 aResult
.SetToken( NULL
);
1459 void ScFormulaCell::CompileColRowNameFormula()
1462 for ( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1464 if ( p
->GetOpCode() == ocColRowName
)
1467 CompileTokenArray();
1474 // ============================================================================