diff options
author | Kohei Yoshida <kohei@libreoffice.org> | 2023-02-21 22:16:30 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei@libreoffice.org> | 2023-03-02 23:35:56 +0000 |
commit | 687b950702c49c90cff9a43655ea97a0343799a0 (patch) | |
tree | de60765d191b62c0e92374534d3f836b8c406cbc | |
parent | e34074feeb1b918ab9f26a18c5fdb0b1f2e35f94 (diff) |
Add a means to query the internal broadcaster state ...
... and use it in one unit test case. Also, remove the code inside
DEBUG_AREA_BROADCASTER macro since it no longer builds & has been
superceded by this new state query method.
Change-Id: I38691a76df5c63034ff488522936dd566bf8b4e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148079
Tested-by: Kohei Yoshida <kohei@libreoffice.org>
Reviewed-by: Kohei Yoshida <kohei@libreoffice.org>
-rw-r--r-- | sc/Library_sc.mk | 1 | ||||
-rw-r--r-- | sc/inc/broadcast.hxx | 86 | ||||
-rw-r--r-- | sc/inc/calcmacros.hxx | 4 | ||||
-rw-r--r-- | sc/inc/column.hxx | 3 | ||||
-rw-r--r-- | sc/inc/document.hxx | 7 | ||||
-rw-r--r-- | sc/inc/grouparealistener.hxx | 3 | ||||
-rw-r--r-- | sc/inc/table.hxx | 3 | ||||
-rw-r--r-- | sc/qa/unit/ucalc_formula.cxx | 85 | ||||
-rw-r--r-- | sc/source/core/data/bcaslot.cxx | 59 | ||||
-rw-r--r-- | sc/source/core/data/broadcast.cxx | 164 | ||||
-rw-r--r-- | sc/source/core/data/column4.cxx | 31 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 8 | ||||
-rw-r--r-- | sc/source/core/data/document10.cxx | 15 | ||||
-rw-r--r-- | sc/source/core/data/table7.cxx | 6 | ||||
-rw-r--r-- | sc/source/core/inc/bcaslot.hxx | 15 |
15 files changed, 400 insertions, 90 deletions
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 4d3c7398b43d..49c36cf27d3c 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -104,6 +104,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/attrib \ sc/source/core/data/autonamecache \ sc/source/core/data/bcaslot \ + sc/source/core/data/broadcast \ sc/source/core/data/bigrange \ sc/source/core/data/celltextattr \ sc/source/core/data/cellvalue \ diff --git a/sc/inc/broadcast.hxx b/sc/inc/broadcast.hxx new file mode 100644 index 000000000000..b095f819acb7 --- /dev/null +++ b/sc/inc/broadcast.hxx @@ -0,0 +1,86 @@ +/* -*- 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/. + */ + +#pragma once + +#include "address.hxx" + +#include <map> +#include <variant> +#include <ostream> + +class ScFormulaCell; +class SvtListener; + +namespace sc +{ +class FormulaGroupAreaListener; + +struct BroadcasterState +{ + enum class CellListenerType + { + FormulaCell, + Generic, + }; + + enum class AreaListenerType + { + FormulaCell, + FormulaGroup, + Generic, + }; + + struct CellListener + { + using DataType = std::variant<const ScFormulaCell*, const SvtListener*>; + + CellListenerType eType; + DataType pData; + + CellListener(const ScFormulaCell* p); + CellListener(const SvtListener* p); + }; + + struct AreaListener + { + using DataType = std::variant<const ScFormulaCell*, const sc::FormulaGroupAreaListener*, + const SvtListener*>; + + AreaListenerType eType; + DataType pData; + + AreaListener(const ScFormulaCell* p); + AreaListener(const sc::FormulaGroupAreaListener* p); + AreaListener(const SvtListener* p); + }; + + std::map<ScAddress, std::vector<CellListener>> aCellListenerStore; + std::map<ScRange, std::vector<AreaListener>> aAreaListenerStore; + + /** + * Check if a formula cell listens on a single cell. + */ + bool hasFormulaCellListener(const ScAddress& rBroadcasterPos, + const ScAddress& rFormulaPos) const; + + /** + * Check if a formula cell listens on a single range. + */ + bool hasFormulaCellListener(const ScRange& rBroadcasterRange, + const ScAddress& rFormulaPos) const; + + /** + * Dump all broadcaster state in YAML format. + */ + void dump(std::ostream& rStrm, const ScDocument* pDoc = nullptr) const; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/calcmacros.hxx b/sc/inc/calcmacros.hxx index c0c68d4487cf..ebe96654804a 100644 --- a/sc/inc/calcmacros.hxx +++ b/sc/inc/calcmacros.hxx @@ -12,7 +12,6 @@ #define DEBUG_COLUMN_STORAGE 0 #define DEBUG_PIVOT_TABLE 0 #define DEBUG_FORMULA_COMPILER 0 -#define DEBUG_AREA_BROADCASTER 0 #define DUMP_COLUMN_STORAGE 0 #define DUMP_PIVOT_TABLE 0 @@ -26,8 +25,7 @@ #if DUMP_PIVOT_TABLE || DEBUG_PIVOT_TABLE || \ DUMP_COLUMN_STORAGE || DEBUG_COLUMN_STORAGE || \ - DEBUG_FORMULA_COMPILER || \ - DEBUG_AREA_BROADCASTER + DEBUG_FORMULA_COMPILER #include <iostream> using std::cout; using std::cerr; diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 949ca30dd137..5c42f02794ab 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -42,6 +42,7 @@ namespace formula { struct VectorRefArray; } namespace sc { +struct BroadcasterState; struct FormulaGroupEntry; class StartListeningContext; class EndListeningContext; @@ -864,6 +865,8 @@ private: void EndListeningGroup( sc::EndListeningContext& rCxt, SCROW nRow ); void SetNeedsListeningGroup( SCROW nRow ); + + void CollectBroadcasterState(sc::BroadcasterState& rState) const; }; inline bool ScColumn::IsEmptyAttr() const diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 092d9ba0d9a9..09fcc126ed06 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -77,6 +77,7 @@ namespace tools { class Guid; } namespace sc { +struct BroadcasterState; struct FormulaGroupContext; class StartListeningContext; class EndListeningContext; @@ -2368,6 +2369,8 @@ public: void EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells ); + sc::BroadcasterState GetBroadcasterState() const; + void PutInFormulaTree( ScFormulaCell* pCell ); void RemoveFromFormulaTree( ScFormulaCell* pCell ); @@ -2611,10 +2614,6 @@ public: SC_DLLPUBLIC void DumpColumnStorage( SCTAB nTab, SCCOL nCol ) const; #endif -#if DEBUG_AREA_BROADCASTER - SC_DLLPUBLIC void DumpAreaBroadcasters() const; -#endif - SC_DLLPUBLIC void SetCalcConfig( const ScCalcConfig& rConfig ); const ScCalcConfig& GetCalcConfig() const { return maCalcConfig; } void ConvertFormulaToValue( const ScRange& rRange, sc::TableValues* pUndo ); diff --git a/sc/inc/grouparealistener.hxx b/sc/inc/grouparealistener.hxx index d823fc987627..a52dc2fb8a74 100644 --- a/sc/inc/grouparealistener.hxx +++ b/sc/inc/grouparealistener.hxx @@ -60,10 +60,11 @@ public: void collectFormulaCells( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, std::vector<ScFormulaCell*>& rCells ) const; void collectFormulaCells( SCROW nRow1, SCROW nRow2, std::vector<ScFormulaCell*>& rCells ) const; + const ScFormulaCell* getTopCell() const; + private: void notifyCellChange( const SfxHint& rHint, const ScAddress& rPos, SCROW nNumRows ); void notifyBulkChange( const BulkDataHint& rHint ); - const ScFormulaCell* getTopCell() const; }; } diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index f81e3925964e..b5fa4e9ec334 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -57,6 +57,7 @@ namespace com::sun::star { namespace formula { struct VectorRefArray; } namespace sc { +struct BroadcasterState; class StartListeningContext; class EndListeningContext; class CopyFromClipContext; @@ -1156,6 +1157,8 @@ public: void CheckIntegrity() const; + void CollectBroadcasterState(sc::BroadcasterState& rState) const; + private: void FillFormulaVertical( diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index 059be9bbef3d..d6453cf0815d 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -25,6 +25,7 @@ #include <externalrefmgr.hxx> #include <scmod.hxx> #include <undomanager.hxx> +#include <broadcast.hxx> #include <formula/vectortoken.hxx> #include <svl/broadcast.hxx> @@ -6235,66 +6236,98 @@ CPPUNIT_TEST_FIXTURE(TestFormula, testFormulaDepTracking) sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation. + const ScAddress aA5(0, 4, 0); + const ScAddress aB2(1, 1, 0); + const ScAddress aB5(1, 4, 0); + const ScAddress aC5(2, 4, 0); + const ScAddress aD2(3, 1, 0); + const ScAddress aD5(3, 4, 0); + const ScAddress aD6(3, 5, 0); + const ScAddress aE2(4, 1, 0); + const ScAddress aE3(4, 2, 0); + const ScAddress aE6(4, 5, 0); + // B2 listens on D2. - m_pDoc->SetString(1, 1, 0, "=D2"); - double val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetString(aB2, "=D2"); + double val = m_pDoc->GetValue(aB2); ASSERT_DOUBLES_EQUAL_MESSAGE("Referencing an empty cell should yield zero.", 0.0, val); + { + // Check the internal broadcaster state. + auto aState = m_pDoc->GetBroadcasterState(); + aState.dump(std::cout, m_pDoc); + CPPUNIT_ASSERT(aState.hasFormulaCellListener(aD2, aB2)); + } + // Changing the value of D2 should trigger recalculation of B2. - m_pDoc->SetValue(3, 1, 0, 1.1); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aD2, 1.1); + val = m_pDoc->GetValue(aB2); ASSERT_DOUBLES_EQUAL_MESSAGE("Failed to recalculate on value change.", 1.1, val); // And again. - m_pDoc->SetValue(3, 1, 0, 2.2); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aD2, 2.2); + val = m_pDoc->GetValue(aB2); ASSERT_DOUBLES_EQUAL_MESSAGE("Failed to recalculate on value change.", 2.2, val); clearRange(m_pDoc, ScRange(0, 0, 0, 10, 10, 0)); + { + // Make sure nobody is listening on anything. + auto aState = m_pDoc->GetBroadcasterState(); + aState.dump(std::cout, m_pDoc); + CPPUNIT_ASSERT(aState.aCellListenerStore.empty()); + } + // Now, let's test the range dependency tracking. // B2 listens on D2:E6. - m_pDoc->SetString(1, 1, 0, "=SUM(D2:E6)"); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetString(aB2, "=SUM(D2:E6)"); + val = m_pDoc->GetValue(aB2); ASSERT_DOUBLES_EQUAL_MESSAGE("Summing an empty range should yield zero.", 0.0, val); + { + // Check the internal state to make sure it matches. + auto aState = m_pDoc->GetBroadcasterState(); + aState.dump(std::cout, m_pDoc); + CPPUNIT_ASSERT(aState.hasFormulaCellListener({aD2, aE6}, aB2)); + } + // Set value to E3. This should trigger recalc on B2. - m_pDoc->SetValue(4, 2, 0, 2.4); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aE3, 2.4); + val = m_pDoc->GetValue(aB2); ASSERT_DOUBLES_EQUAL_MESSAGE("Failed to recalculate on single value change.", 2.4, val); // Set value to D5 to trigger recalc again. Note that this causes an // addition of 1.2 + 2.4 which is subject to binary floating point // rounding error. We need to use approxEqual to assess its value. - m_pDoc->SetValue(3, 4, 0, 1.2); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aD5, 1.2); + val = m_pDoc->GetValue(aB2); CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 3.6)); // Change the value of D2 (boundary case). - m_pDoc->SetValue(3, 1, 0, 1.0); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aD2, 1.0); + val = m_pDoc->GetValue(aB2); CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 4.6)); // Change the value of E6 (another boundary case). - m_pDoc->SetValue(4, 5, 0, 2.0); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aE6, 2.0); + val = m_pDoc->GetValue(aB2); CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 6.6)); // Change the value of D6 (another boundary case). - m_pDoc->SetValue(3, 5, 0, 3.0); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aD6, 3.0); + val = m_pDoc->GetValue(aB2); CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 9.6)); // Change the value of E2 (another boundary case). - m_pDoc->SetValue(4, 1, 0, 0.4); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aE2, 0.4); + val = m_pDoc->GetValue(aB2); CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 10.0)); // Change the existing non-empty value cell (E2). - m_pDoc->SetValue(4, 1, 0, 2.4); - val = m_pDoc->GetValue(1, 1, 0); + m_pDoc->SetValue(aE2, 2.4); + val = m_pDoc->GetValue(aB2); CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 12.0)); clearRange(m_pDoc, ScRange(0, 0, 0, 10, 10, 0)); @@ -6328,10 +6361,10 @@ CPPUNIT_TEST_FIXTURE(TestFormula, testFormulaDepTracking) // Intentionally insert a formula in column 1. This will break column 1's // uniformity of consisting only of static value cells. - m_pDoc->SetString(0, 4, 0, "=R2C3"); - ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected formula value.", 2.0, m_pDoc->GetValue(0, 4, 0)); - ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected formula value.", 2.0, m_pDoc->GetValue(1, 4, 0)); - ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected formula value.", 4.0, m_pDoc->GetValue(2, 4, 0)); + m_pDoc->SetString(aA5, "=R2C3"); + ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected formula value.", 2.0, m_pDoc->GetValue(aA5)); + ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected formula value.", 2.0, m_pDoc->GetValue(aB5)); + ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected formula value.", 4.0, m_pDoc->GetValue(aC5)); m_pDoc->DeleteTab(0); } diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx index a39d5b4812b4..910eb46082e6 100644 --- a/sc/source/core/data/bcaslot.cxx +++ b/sc/source/core/data/bcaslot.cxx @@ -29,11 +29,9 @@ #include <refupdat.hxx> #include <bulkdatahint.hxx> #include <columnspanset.hxx> - -#if DEBUG_AREA_BROADCASTER #include <formulacell.hxx> #include <grouparealistener.hxx> -#endif +#include <broadcast.hxx> ScBroadcastArea::ScBroadcastArea( const ScRange& rRange ) : pUpdateChainNext(nullptr), @@ -500,46 +498,32 @@ void ScBroadcastAreaSlot::GetAllListeners( } } -#if DEBUG_AREA_BROADCASTER -void ScBroadcastAreaSlot::Dump() const +void ScBroadcastAreaSlot::CollectBroadcasterState(sc::BroadcasterState& rState) const { for (const ScBroadcastAreaEntry& rEntry : aBroadcastAreaTbl) { - const ScBroadcastArea* pArea = rEntry.mpArea; - const SvtBroadcaster& rBC = pArea->GetBroadcaster(); - const SvtBroadcaster::ListenersType& rListeners = rBC.GetAllListeners(); - size_t n = rListeners.size(); + const ScRange& rRange = rEntry.mpArea->GetRange(); + auto aRes = rState.aAreaListenerStore.try_emplace(rRange); + auto& rLisStore = aRes.first->second; - cout << " * range: " << OUStringToOString(pArea->GetRange().Format(ScRefFlags::VALID|ScRefFlags::TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr() - << ", group: " << pArea->IsGroupListening() - << ", listener count: " << n << endl; - - for (size_t i = 0; i < n; ++i) + for (const SvtListener* pLis : rEntry.mpArea->GetBroadcaster().GetAllListeners()) { - const ScFormulaCell* pFC = dynamic_cast<const ScFormulaCell*>(rListeners[i]); - if (pFC) + if (auto pFC = dynamic_cast<const ScFormulaCell*>(pLis); pFC) { - cout << " * listener: formula cell: " - << OUStringToOString(pFC->aPos.Format(ScRefFlags::VALID|ScRefFlags::TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr() - << endl; + rLisStore.emplace_back(pFC); continue; } - const sc::FormulaGroupAreaListener* pFGListener = dynamic_cast<const sc::FormulaGroupAreaListener*>(rListeners[i]); - if (pFGListener) + if (auto pFGL = dynamic_cast<const sc::FormulaGroupAreaListener*>(pLis); pFGL) { - cout << " * listener: formula group: (pos: " - << OUStringToOString(pFGListener->getTopCellPos().Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr() - << ", length: " << pFGListener->getGroupLength() - << ")" << endl; + rLisStore.emplace_back(pFGL); continue; } - cout << " * listener: unknown" << endl; + rLisStore.emplace_back(pLis); } } } -#endif void ScBroadcastAreaSlot::FinallyEraseAreas() { @@ -1283,27 +1267,20 @@ std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners( return aRet; } -#if DEBUG_AREA_BROADCASTER -void ScBroadcastAreaSlotMachine::Dump() const +void ScBroadcastAreaSlotMachine::CollectBroadcasterState(sc::BroadcasterState& rState) const { - cout << "slot distribution count: " << nBcaSlots << endl; - for (const auto& [rIndex, pTabSlots] : aTableSlotsMap) + for (const auto& [rTab, rTabSlots] : aTableSlotsMap) { - cout << "-- sheet (index: " << rIndex << ")" << endl; + (void)rTab; - assert(pTabSlots); - ScBroadcastAreaSlot** ppSlots = pTabSlots->getSlots(); - for (SCSIZE i = 0; i < nBcaSlots; ++i) + ScBroadcastAreaSlot** pp = rTabSlots.getSlots(); + for (SCSIZE i = 0; i < mnBcaSlots; ++i) { - const ScBroadcastAreaSlot* pSlot = ppSlots[i]; + const ScBroadcastAreaSlot* pSlot = pp[i]; if (pSlot) - { - cout << "* slot " << i << endl; - pSlot->Dump(); - } + pSlot->CollectBroadcasterState(rState); } } } -#endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/broadcast.cxx b/sc/source/core/data/broadcast.cxx new file mode 100644 index 000000000000..c0cd0c29edca --- /dev/null +++ b/sc/source/core/data/broadcast.cxx @@ -0,0 +1,164 @@ +/* -*- 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/. + */ + +#include <broadcast.hxx> +#include <address.hxx> +#include <formulacell.hxx> + +namespace sc +{ +BroadcasterState::CellListener::CellListener(const ScFormulaCell* p) + : eType(CellListenerType::FormulaCell) + , pData(p) +{ +} + +BroadcasterState::CellListener::CellListener(const SvtListener* p) + : eType(CellListenerType::Generic) + , pData(p) +{ +} + +BroadcasterState::AreaListener::AreaListener(const ScFormulaCell* p) + : eType(AreaListenerType::FormulaCell) + , pData(p) +{ +} + +BroadcasterState::AreaListener::AreaListener(const sc::FormulaGroupAreaListener* p) + : eType(AreaListenerType::FormulaGroup) + , pData(p) +{ +} + +BroadcasterState::AreaListener::AreaListener(const SvtListener* p) + : eType(AreaListenerType::Generic) + , pData(p) +{ +} + +bool BroadcasterState::hasFormulaCellListener(const ScAddress& rBroadcasterPos, + const ScAddress& rFormulaPos) const +{ + auto it = aCellListenerStore.find(rBroadcasterPos); + if (it == aCellListenerStore.end()) + return false; + + for (const auto& rLis : it->second) + { + if (rLis.eType == CellListenerType::FormulaCell) + { + auto pFC = std::get<const ScFormulaCell*>(rLis.pData); + if (pFC->aPos == rFormulaPos) + return true; + } + } + + return false; +} + +bool BroadcasterState::hasFormulaCellListener(const ScRange& rBroadcasterRange, + const ScAddress& rFormulaPos) const +{ + auto it = aAreaListenerStore.find(rBroadcasterRange); + if (it == aAreaListenerStore.end()) + return false; + + for (const auto& rLis : it->second) + { + if (rLis.eType == AreaListenerType::FormulaCell) + { + auto pFC = std::get<const ScFormulaCell*>(rLis.pData); + if (pFC->aPos == rFormulaPos) + return true; + } + } + + return false; +} + +void BroadcasterState::dump(std::ostream& rStrm, const ScDocument* pDoc) const +{ + constexpr ScRefFlags nPosFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D; + + rStrm << "---" << std::endl; + + for (const auto & [ rPos, rListeners ] : aCellListenerStore) + { + rStrm << "- type: cell-broadcaster\n"; + rStrm << " position: " << rPos.Format(nPosFlags, pDoc) << std::endl; + + if (!rListeners.empty()) + rStrm << " listeners:\n"; + + for (const auto& rLis : rListeners) + { + switch (rLis.eType) + { + case BroadcasterState::CellListenerType::FormulaCell: + { + auto* pFC = std::get<const ScFormulaCell*>(rLis.pData); + rStrm << " - type: formula-cell\n"; + rStrm << " position: " << pFC->aPos.Format(nPosFlags, pDoc) << std::endl; + break; + } + case BroadcasterState::CellListenerType::Generic: + { + rStrm << " - type: unknown" << std::endl; + break; + } + } + } + } + + for (const auto & [ rRange, rListeners ] : aAreaListenerStore) + { + rStrm << "- type: area-broadcaster\n"; + rStrm << " range: " << rRange.Format(*pDoc, nPosFlags) << std::endl; + + if (!rListeners.empty()) + rStrm << " listeners:\n"; + + for (const auto& rLis : rListeners) + { + switch (rLis.eType) + { + case BroadcasterState::AreaListenerType::FormulaCell: + { + auto* pFC = std::get<const ScFormulaCell*>(rLis.pData); + rStrm << " - type: formula-cell\n"; + rStrm << " position: " << pFC->aPos.Format(nPosFlags, pDoc) << std::endl; + break; + } + case BroadcasterState::AreaListenerType::FormulaGroup: + { + auto* pFGL = std::get<const sc::FormulaGroupAreaListener*>(rLis.pData); + + auto pTopCell = pFGL->getTopCell(); + if (auto xFG = pTopCell->GetCellGroup(); xFG) + { + ScRange aGR(pTopCell->aPos); + aGR.aEnd.IncRow(xFG->mnLength - 1); + rStrm << " - type: formula-group\n"; + rStrm << " range: " << aGR.Format(*pDoc, nPosFlags) << std::endl; + } + break; + } + case BroadcasterState::AreaListenerType::Generic: + { + rStrm << " - type: unknown" << std::endl; + break; + } + } + } + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index 49420642bf5f..a9b1b91857f8 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -31,6 +31,7 @@ #include <recursionhelper.hxx> #include <docsh.hxx> #include <editutil.hxx> +#include <broadcast.hxx> #include <SparklineGroup.hxx> @@ -2233,4 +2234,34 @@ void ScColumn::CheckIntegrity() const } } +void ScColumn::CollectBroadcasterState(sc::BroadcasterState& rState) const +{ + for (const auto& block : maBroadcasters) + { + if (block.type != sc::element_type_broadcaster) + continue; + + auto itBeg = sc::broadcaster_block::begin(*block.data); + auto itEnd = sc::broadcaster_block::end(*block.data); + + for (auto it = itBeg; it != itEnd; ++it) + { + ScAddress aBCPos(nCol, block.position + std::distance(itBeg, it), nTab); + + auto aRes = rState.aCellListenerStore.try_emplace(aBCPos); + auto& rLisStore = aRes.first->second; + + const SvtBroadcaster& rBC = **it; + for (const SvtListener* pLis : rBC.GetAllListeners()) + { + const auto* pFC = dynamic_cast<const ScFormulaCell*>(pLis); + if (pFC) + rLisStore.emplace_back(pFC); + else + rLisStore.emplace_back(pLis); + } + } + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index e204acd3cd24..b53de471e776 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2529,14 +2529,6 @@ void ScDocument::DumpColumnStorage( SCTAB nTab, SCCOL nCol ) const } #endif -#if DEBUG_AREA_BROADCASTER -void ScDocument::DumpAreaBroadcasters() const -{ - if (pBASM) - pBASM->Dump(); -} -#endif - bool ScDocument::TableExists( SCTAB nTab ) const { return ValidTab(nTab) && o3tl::make_unsigned(nTab) < maTabs.size() && maTabs[nTab]; diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index e0eb8d46bd28..baee3603fd1f 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -26,6 +26,8 @@ #include <scitems.hxx> #include <datamapper.hxx> #include <docsh.hxx> +#include <bcaslot.hxx> +#include <broadcast.hxx> // Add totally brand-new methods to this source file. @@ -1101,4 +1103,17 @@ void ScDocument::CheckIntegrity( SCTAB nTab ) const pTab->CheckIntegrity(); } +sc::BroadcasterState ScDocument::GetBroadcasterState() const +{ + sc::BroadcasterState aState; + + for (const auto& xTab : maTabs) + xTab->CollectBroadcasterState(aState); + + if (pBASM) + pBASM->CollectBroadcasterState(aState); + + return aState; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index 9af01cba748e..7755bc6176de 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -649,4 +649,10 @@ void ScTable::CheckIntegrity() const pCol->CheckIntegrity(); } +void ScTable::CollectBroadcasterState(sc::BroadcasterState& rState) const +{ + for (const auto& pCol : aCol) + pCol->CollectBroadcasterState(rState); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx index 4e1173596840..6e891e8aab5a 100644 --- a/sc/source/core/inc/bcaslot.hxx +++ b/sc/source/core/inc/bcaslot.hxx @@ -30,7 +30,12 @@ #include <document.hxx> #include <global.hxx> -namespace sc { class ColumnSpanSet; } +namespace sc { + +struct BroadcasterState; +class ColumnSpanSet; + +} class ScHint; namespace sc { @@ -233,9 +238,7 @@ public: const ScRange& rRange, std::vector<sc::AreaListener>& rListeners, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup ); -#if DEBUG_AREA_BROADCASTER - void Dump() const; -#endif + void CollectBroadcasterState(sc::BroadcasterState& rState) const; }; /** @@ -364,9 +367,7 @@ public: const ScRange& rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup = sc::ListenerGroupType::Both ); -#if DEBUG_AREA_BROADCASTER - void Dump() const; -#endif + void CollectBroadcasterState(sc::BroadcasterState& rState) const; }; class ScBulkBroadcast |