diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-04-07 14:13:20 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-04-07 14:43:16 -0400 |
commit | 355baf573425165cbc1c789a6271eb29940e1f76 (patch) | |
tree | 42050f8ac0a293b75e3745d511fe2e086e88cd42 /sc/source/core/data/column4.cxx | |
parent | 137c288978fb8f4aee259fabfdcb9252b1b011d3 (diff) |
fdo#75741: Re-implement CompileNameFormula for formula groups.
Change-Id: I57e1e464ac5f7abc10ce5ea5752e036ddb6cf6d7
Diffstat (limited to 'sc/source/core/data/column4.cxx')
-rw-r--r-- | sc/source/core/data/column4.cxx | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index 2f216233e800..7a360d09a673 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -16,18 +16,23 @@ #include <cellvalues.hxx> #include <columnspanset.hxx> #include <listenercontext.hxx> +#include <tokenstringcontext.hxx> #include <mtvcellfunc.hxx> #include <clipcontext.hxx> #include <attrib.hxx> #include <patattr.hxx> #include <docpool.hxx> #include <conditio.hxx> +#include <formulagroup.hxx> +#include <tokenarray.hxx> #include <svl/sharedstringpool.hxx> #include <vector> #include <cassert> +#include <boost/shared_ptr.hpp> + bool ScColumn::IsMerged( SCROW nRow ) const { return pAttrArray->IsMerged(nRow); @@ -544,4 +549,150 @@ void ScColumn::GetNotesInRange(SCROW nStartRow, SCROW nEndRow, std::for_each(it, itEnd, NoteEntryCollector(rNotes, nTab, nCol, nStartRow, nEndRow)); } +namespace { + +class PreRangeNameUpdateHandler +{ + ScDocument* mpDoc; + boost::shared_ptr<sc::EndListeningContext> mpEndListenCxt; + boost::shared_ptr<sc::CompileFormulaContext> mpCompileFormulaCxt; + +public: + PreRangeNameUpdateHandler( ScDocument* pDoc ) : + mpDoc(pDoc), + mpEndListenCxt(new sc::EndListeningContext(*pDoc)), + mpCompileFormulaCxt(new sc::CompileFormulaContext(pDoc)) {} + + void operator() ( sc::FormulaGroupEntry& rEntry ) + { + // Perform end listening, remove from formula tree, and set them up + // for re-compilation. + + ScFormulaCell* pTop = NULL; + + if (rEntry.mbShared) + { + // Only inspect the code from the top cell. + pTop = *rEntry.mpCells; + } + else + pTop = rEntry.mpCell; + + ScTokenArray* pCode = pTop->GetCode(); + + boost::unordered_set<OpCode> aOps; + aOps.insert(ocBad); + aOps.insert(ocColRowName); + aOps.insert(ocName); + bool bRecompile = pCode->HasOpCodes(aOps); + + if (bRecompile) + { + // Get the formula string. + OUString aFormula = pTop->GetFormula(*mpCompileFormulaCxt); + sal_Int32 n = aFormula.getLength(); + if (pTop->GetMatrixFlag() != MM_NONE && n > 0) + { + if (aFormula[0] == '{' && aFormula[n-1] == '}') + aFormula = aFormula.copy(1, n-2); + } + + if (rEntry.mbShared) + { + ScFormulaCell** pp = rEntry.mpCells; + ScFormulaCell** ppEnd = pp + rEntry.mnLength; + for (; pp != ppEnd; ++pp) + { + ScFormulaCell* p = *pp; + p->EndListeningTo(*mpEndListenCxt); + mpDoc->RemoveFromFormulaTree(p); + } + } + else + { + rEntry.mpCell->EndListeningTo(*mpEndListenCxt); + mpDoc->RemoveFromFormulaTree(rEntry.mpCell); + } + + pCode->Clear(); + pTop->SetHybridFormula(aFormula, mpDoc->GetGrammar()); + } + } +}; + +class PostRangeNameUpdateHandler +{ + ScDocument* mpDoc; + boost::shared_ptr<sc::CompileFormulaContext> mpCompileFormulaCxt; + +public: + PostRangeNameUpdateHandler( ScDocument* pDoc ) : + mpDoc(pDoc), + mpCompileFormulaCxt(new sc::CompileFormulaContext(pDoc)) {} + + void operator() ( sc::FormulaGroupEntry& rEntry ) + { + if (rEntry.mbShared) + { + ScFormulaCell* pTop = *rEntry.mpCells; + OUString aFormula = pTop->GetHybridFormula(); + + // Create a new token array from the hybrid formula string, and + // set it to the group. + ScCompiler aComp(*mpCompileFormulaCxt, pTop->aPos); + ScTokenArray* pNewCode = aComp.CompileString(aFormula); + ScFormulaCellGroupRef xGroup = pTop->GetCellGroup(); + assert(xGroup); + xGroup->setCode(pNewCode); + xGroup->compileCode(*mpDoc, pTop->aPos, mpDoc->GetGrammar()); + + // Propagate the new token array to all formula cells in the group. + ScFormulaCell** pp = rEntry.mpCells; + ScFormulaCell** ppEnd = pp + rEntry.mnLength; + for (; pp != ppEnd; ++pp) + { + ScFormulaCell* p = *pp; + p->SyncSharedCode(); + p->SetDirty(); + } + } + else + { + ScFormulaCell* pCell = rEntry.mpCell; + OUString aFormula = pCell->GetHybridFormula(); + + // Create token array from formula string. + ScCompiler aComp(*mpCompileFormulaCxt, pCell->aPos); + ScTokenArray* pNewCode = aComp.CompileString(aFormula); + + // Generate RPN tokens. + ScCompiler aComp2(mpDoc, pCell->aPos, *pNewCode); + aComp2.CompileTokenArray(); + + pCell->SetCode(pNewCode); + pCell->SetDirty(); + } + } +}; + +} + +void ScColumn::PreprocessRangeNameUpdate() +{ + // Collect all formula groups. + std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries(); + + PreRangeNameUpdateHandler aFunc(pDocument); + std::for_each(aGroups.begin(), aGroups.end(), aFunc); +} + +void ScColumn::PostprocessRangeNameUpdate() +{ + // Collect all formula groups. + std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries(); + + PostRangeNameUpdateHandler aFunc(pDocument); + std::for_each(aGroups.begin(), aGroups.end(), aFunc); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |