/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Ensure sane ranges for the slots, specifically don't attempt to listen // to more sheets than the document has. The slot machine handles it but // with memory waste. Binary import filters can set out-of-bounds ranges // in formula expressions' references, so all middle layers would have to // check it, rather have this central point here.
ScRange aLimitedRange( ScAddress::UNINITIALIZED ); bool bEntirelyOut; if (!LimitRangeToAvailableSheets( rRange, aLimitedRange, bEntirelyOut))
{
pBASM->StartListeningArea(rRange, bGroupListening, pListener); return;
}
// If both sheets are out-of-bounds in the same direction then just bail out. if (bEntirelyOut) return;
// End listening has to limit the range exactly the same as in // StartListeningArea(), otherwise the range would not be found.
ScRange aLimitedRange( ScAddress::UNINITIALIZED ); bool bEntirelyOut; if (!LimitRangeToAvailableSheets( rRange, aLimitedRange, bEntirelyOut))
{
pBASM->EndListeningArea(rRange, bGroupListening, pListener); return;
}
// If both sheets are out-of-bounds in the same direction then just bail out. if (bEntirelyOut) return;
// Originally BCA_LISTEN_ALWAYS uses an implicit tab 0 and should had been // valid already, but in case that would change... if (rRange == BCA_LISTEN_ALWAYS) returnfalse;
void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
{
ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
assert(pCell && "RemoveFromFormulaTree: pCell Null");
ScFormulaCell* pPrev = pCell->GetPrevious();
assert(pPrev != pCell); // pointing to itself?!? // if the cell is first or somewhere in chain if ( pPrev || pFormulaTree == pCell )
{
ScFormulaCell* pNext = pCell->GetNext();
assert(pNext != pCell); // pointing to itself?!? if ( pPrev )
{
assert(pFormulaTree != pCell); // if this cell is also head something's wrong
pPrev->SetNext( pNext ); // predecessor exists, set successor
} else
{
pFormulaTree = pNext; // this cell was first cell
} if ( pNext )
{
assert(pEOFormulaTree != pCell); // if this cell is also tail something's wrong
pNext->SetPrevious( pPrev ); // successor exists, set predecessor
} else
{
pEOFormulaTree = pPrev; // this cell was last cell
}
pCell->SetPrevious( nullptr );
pCell->SetNext( nullptr );
sal_uInt16 nRPN = pCell->GetCode()->GetCodeLen(); if ( nFormulaCodeInTree >= nRPN )
nFormulaCodeInTree -= nRPN; else
{
OSL_FAIL( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
nFormulaCodeInTree = 0;
}
} elseif ( !pFormulaTree && nFormulaCodeInTree )
{
OSL_FAIL( "!pFormulaTree && nFormulaCodeInTree != 0" );
nFormulaCodeInTree = 0;
}
}
void ScDocument::CalcFormulaTree( bool bOnlyForced, bool bProgressBar, bool bSetAllDirty )
{
OSL_ENSURE( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" ); // never ever recurse into this, might end up lost in infinity if ( IsCalculatingFormulaTree() ) return ;
SetForcedFormulaPending( false ); bool bOldIdleEnabled = IsIdleEnabled();
EnableIdle(false); bool bOldAutoCalc = GetAutoCalc(); //ATTENTION: _not_ SetAutoCalc( true ) because this might call CalcFormulaTree( true ) //ATTENTION: if it was disabled before and bHasForcedFormulas is set
bAutoCalc = true; if (eHardRecalcState == HardRecalcState::ETERNAL)
CalcAll(); else
{
::std::vector<ScFormulaCell*> vAlwaysDirty;
ScFormulaCell* pCell = pFormulaTree; while ( pCell )
{ if ( pCell->GetDirty() )
; // nothing to do elseif ( pCell->GetCode()->IsRecalcModeAlways() )
{ // pCell and dependents are to be set dirty again, collect // them first and broadcast afterwards to not break the // FormulaTree chain here.
vAlwaysDirty.push_back( pCell);
} elseif ( bSetAllDirty )
{ // Force calculating all in tree, without broadcasting.
pCell->SetDirtyVar();
}
pCell = pCell->GetNext();
} for (constauto& rpCell : vAlwaysDirty)
{
pCell = rpCell; if (!pCell->GetDirty())
pCell->SetDirty();
}
bool bProgress = !bOnlyForced && nFormulaCodeInTree && bProgressBar; if ( bProgress )
ScProgress::CreateInterpretProgress( this );
pCell = pFormulaTree;
ScFormulaCell* pLastNoGood = nullptr; while ( pCell )
{ // Interpret resets bDirty and calls Remove, also the referenced! // the Cell remains when ScRecalcMode::ALWAYS. if ( bOnlyForced )
{ if ( pCell->GetCode()->IsRecalcModeForced() )
pCell->Interpret();
} else
{
pCell->Interpret();
} if ( pCell->GetPrevious() || pCell == pFormulaTree )
{ // (IsInFormulaTree(pCell)) no Remove was called => next
pLastNoGood = pCell;
pCell = pCell->GetNext();
} else
{ if ( pFormulaTree )
{ if ( pFormulaTree->GetDirty() && !bOnlyForced )
{
pCell = pFormulaTree;
pLastNoGood = nullptr;
} else
{ // IsInFormulaTree(pLastNoGood) if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
pLastNoGood == pFormulaTree) )
pCell = pLastNoGood->GetNext(); else
{
pCell = pFormulaTree; while ( pCell && !pCell->GetDirty() )
pCell = pCell->GetNext(); if ( pCell )
pLastNoGood = pCell->GetPrevious();
}
}
} else
pCell = nullptr;
}
} if ( bProgress )
ScProgress::DeleteInterpretProgress();
}
bAutoCalc = bOldAutoCalc;
EnableIdle(bOldIdleEnabled);
bCalculatingFormulaTree = false;
void ScDocument::AppendToFormulaTrack( ScFormulaCell* pCell )
{
OSL_ENSURE( pCell, "AppendToFormulaTrack: pCell Null" ); // The cell can not be in both lists at the same time
RemoveFromFormulaTrack( pCell );
RemoveFromFormulaTree( pCell ); if ( pEOFormulaTrack )
pEOFormulaTrack->SetNextTrack( pCell ); else
pFormulaTrack = pCell; // No end, no beginning...
pCell->SetPreviousTrack( pEOFormulaTrack );
pCell->SetNextTrack( nullptr );
pEOFormulaTrack = pCell;
++nFormulaTrackCount;
}
void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
{
assert(pCell && "RemoveFromFormulaTrack: pCell Null");
ScFormulaCell* pPrev = pCell->GetPreviousTrack();
assert(pPrev != pCell); // pointing to itself?!? // if the cell is first or somewhere in chain if ( !(pPrev || pFormulaTrack == pCell) ) return;
ScFormulaCell* pNext = pCell->GetNextTrack();
assert(pNext != pCell); // pointing to itself?!? if ( pPrev )
{
assert(pFormulaTrack != pCell); // if this cell is also head something's wrong
pPrev->SetNextTrack( pNext ); // predecessor exists, set successor
} else
{
pFormulaTrack = pNext; // this cell was first cell
} if ( pNext )
{
assert(pEOFormulaTrack != pCell); // if this cell is also tail something's wrong
pNext->SetPreviousTrack( pPrev ); // successor exists, set predecessor
} else
{
pEOFormulaTrack = pPrev; // this cell was last cell
}
pCell->SetPreviousTrack( nullptr );
pCell->SetNextTrack( nullptr );
--nFormulaTrackCount;
}
void ScDocument::FinalTrackFormulas( SfxHintId nHintId )
{
mbTrackFormulasPending = false;
mbFinalTrackFormulas = true;
{
ScBulkBroadcast aBulk( GetBASM(), nHintId); // Collect all pending formula cells in bulk.
TrackFormulas( nHintId );
} // A final round not in bulk to track all remaining formula cells and their // dependents that were collected during ScBulkBroadcast dtor.
TrackFormulas( nHintId );
mbFinalTrackFormulas = false;
}
/* The first is broadcasted, the ones that are created through this are appended to the Track by Notify. The next is broadcasted again, and so on. View initiates Interpret.
*/ void ScDocument::TrackFormulas( SfxHintId nHintId )
{ if (!pBASM) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.