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