diff --git a/src/gui/interact/presentation-state-manager.hpp b/src/gui/interact/presentation-state-manager.hpp index 84da18322..c8fe47b68 100644 --- a/src/gui/interact/presentation-state-manager.hpp +++ b/src/gui/interact/presentation-state-manager.hpp @@ -39,9 +39,12 @@ ** remembers those messages, always retaining the latest state information observed for any ** property of any [tangible interface element](\ref tangible.hpp) encountered thus far. ** - ** @todo as of 2/2016 this is complete WIP-WIP-WIP + ** @todo as of 2/2016 this is still preliminary. + ** In the end, we want to capture and restore presentation state + ** in dependency to the current perspective and work site ** - ** @see ////TODO_test usage example + ** @see BusTerm_test::captureStateMark() usage example + ** @see BusTerm_test::replayStateMark() usage example ** */ @@ -50,12 +53,8 @@ #define GUI_INTERACT_PRESENTATION_STATE_MANAGER_H -#include "lib/error.hpp" -//#include "gui/ctrl/bus-term.hpp" -//#include "lib/idi/entry-id.hpp" +#include "lib/idi/entry-id.hpp" #include "lib/diff/gen-node.hpp" -//#include "lib/symbol.hpp" -//#include "lib/util.hpp" #include #include @@ -64,20 +63,24 @@ namespace gui { namespace interact { -// using lib::HashVal; -// using util::isnil; using std::string; /** * Interface: handling of persistent interface state. - * @todo write type comment... + * Operations to retrieve previously captured state and + * to re-play this state towards the originating UI-elements. + * It is assumed that the actual implementation is connected + * to the UI-Bus and captures *state mark notifications*. + * State is first grouped by ID of the originating interface + * element, and recorded per distinct property within each + * element. */ class PresentationStateManager : boost::noncopyable { protected: - virtual ~PresentationStateManager(); ///< this is an interface + virtual ~PresentationStateManager(); ///< this is an interface using ID = lib::idi::BareEntryID const&; using StateMark = lib::diff::GenNode const&; diff --git a/src/gui/interact/state-map-grouping-storage.hpp b/src/gui/interact/state-map-grouping-storage.hpp index 46854c8ff..23e5c04d6 100644 --- a/src/gui/interact/state-map-grouping-storage.hpp +++ b/src/gui/interact/state-map-grouping-storage.hpp @@ -74,9 +74,11 @@ namespace interact { struct StateMapGroupingStorage : boost::noncopyable { - using Record = std::set; + using StateData = std::set; - using Storage = std::unordered_map; + using Storage = std::unordered_map; + + using Record = Storage::value_type; Storage elmTable_; @@ -116,19 +118,19 @@ namespace interact { } static BareEntryID const& - getID (iterator entry) + getID (Record entry) { - return entry->first; + return entry.first; } - static Record const& - getState (iterator entry) + static StateData const& + getState (Record entry) { - return entry->second; + return entry.second; } static GenNode const& - getState (iterator entry, string propertyKey) + getState (Record entry, string propertyKey) { UNIMPLEMENTED ("fetch property data from given element record"); } diff --git a/src/gui/interact/state-recorder.hpp b/src/gui/interact/state-recorder.hpp index c85e3a9b2..e4d9208bf 100644 --- a/src/gui/interact/state-recorder.hpp +++ b/src/gui/interact/state-recorder.hpp @@ -27,9 +27,23 @@ ** groups recorded message by elementID and simply overwrites ** previous state info for a given attribute with later one. ** - ** @todo as of 2/2016 this is complete WIP-WIP-WIP + ** \par performance + ** The storage layout was chosen under the assumption that we'll get + ** many elements with only few properties per element. The implementing + ** hash table relies on the hash function for BareEntryID, which uses + ** the embedded hash, which in turn is based on hashing the symbolicID + ** plus a hashed type string. ** - ** @see ////TODO_test usage example + ** @todo as of 2/2016 noting but a simple data retrieval happens here. + ** Actually, on the long run, we want "intelligent" handling of + ** presentation state, we want to capture and restore state + ** with sensitivity to perspective and work site. Probably + ** this means to layer a second level of aggregation on top. + ** @warning state mark entries are added, never discarded. + ** Once we start actually persisting this state, + ** this might get us into trouble. + ** + ** @see BusTerm_test::captureStateMark usage example ** */ @@ -39,24 +53,18 @@ #include "lib/error.hpp" -//#include "gui/ctrl/bus-term.hpp" #include "lib/idi/entry-id.hpp" #include "lib/diff/gen-node.hpp" +#include "gui/ctrl/bus-term.hpp" #include "gui/interact/presentation-state-manager.hpp" #include "gui/interact/state-map-grouping-storage.hpp" -#include "gui/ctrl/bus-term.hpp" -//#include "lib/symbol.hpp" -//#include "lib/util.hpp" -#include #include namespace gui { namespace interact { -// using lib::HashVal; -// using util::isnil; using gui::ctrl::BusTerm; using lib::diff::GenNode; using lib::diff::Ref; @@ -68,14 +76,22 @@ namespace interact { /** * Simple map based implementation of the * PresentationStateManager interface. + * Requires a permanent connection to the UI-Bus, + * which is given as reference at construction. + * The intention is to use such an implementation + * embedded within the gui::ctrl::CoreService, + * which in turn then manages the lifecycle of + * this UI-Bus connection. Besides, a derived + * mock implementation is available through + * the test::Nexus * - * @todo write type comment... + * @see StateMapGroupingStorage storage implementation */ class StateRecorder : public PresentationStateManager { using Storage = StateMapGroupingStorage; - using Iter = Storage::iterator; + using Record = Storage::Record const&; BusTerm& uiBus_; Storage storage_; @@ -103,15 +119,18 @@ namespace interact { virtual void replayAllState() override { - for (Iter entry = storage_.begin(); entry!=storage_.end(); ++entry) + for (Record entry : storage_) replayPropertiesOf (entry); } + /** replay all captured state from any element, + * but captured especially for the given property + */ virtual void replayAllState (string propertyKey) override { - for (Iter entry = storage_.begin(); entry!=storage_.end(); ++entry) + for (Record entry : storage_) { StateMark state = Storage::getState (entry, propertyKey); if (state != Ref::NO) @@ -120,36 +139,43 @@ namespace interact { } + /** replay all captured state from the given element. */ virtual void replayAllProperties (ID uiElm) override { - Iter entry = storage_.find (uiElm); + auto entry = storage_.find (uiElm); if (entry != storage_.end()) - replayPropertiesOf (entry); + replayPropertiesOf (*entry); } + virtual void clearState() override { storage_.clear(); } + public: StateRecorder (BusTerm& busConnection) : uiBus_(busConnection) , storage_() { } - + /** Interface for the operating facility (CoreService) + * to feed state mark messages to be remembered. + * @param uiElm originator of the state notification + * @param stateMark state information to record + */ void - record (ID uiElm, StateMark stateMark) + recordState (ID uiElm, StateMark stateMark) { storage_.record (uiElm, stateMark); } private: void - replayPropertiesOf (Iter entry) + replayPropertiesOf (Record entry) { ID uiElm = Storage::getID (entry); for (auto& stateMark : Storage::getState (entry)) diff --git a/tests/gui/bus-term-test.cpp b/tests/gui/bus-term-test.cpp index ef57d89fe..cdf318926 100644 --- a/tests/gui/bus-term-test.cpp +++ b/tests/gui/bus-term-test.cpp @@ -117,7 +117,7 @@ namespace test { * from the Hub. */ void - attachNewBusTerm () + attachNewBusTerm() { MARK_TEST_FUN; // our dummy will be linked with this identity @@ -180,7 +180,7 @@ namespace test { /** @test perform the full command binding and invocation protocol */ void - commandInvocation () + commandInvocation() { MARK_TEST_FUN gui::test::Nexus::startNewLog(); @@ -238,7 +238,7 @@ namespace test { * We use a test version of the PresentationStateManager, * based on the same building blocks as _the real thing_ */ void - captureStateMark () + captureStateMark() { MARK_TEST_FUN gui::test::Nexus::startNewLog(); @@ -279,7 +279,7 @@ namespace test { /** @test replay previously captured state information" */ void - replayStateMark () + replayStateMark() { MARK_TEST_FUN PresentationStateManager& stateManager = gui::test::Nexus::getMockStateManager(); @@ -316,28 +316,28 @@ namespace test { void - verifyNotifications () + verifyNotifications() { UNIMPLEMENTED ("send notifications to a distinct element"); } void - clearStates () + clearStates() { UNIMPLEMENTED ("broadcast state reset"); } void - pushDiff () + pushDiff() { UNIMPLEMENTED ("push a mutation diff towards an interface element"); } void - destroy () + destroy() { UNIMPLEMENTED ("detach and destroy the test BusTerm"); } diff --git a/tests/gui/test/test-nexus.cpp b/tests/gui/test/test-nexus.cpp index 8e0a5cbbd..f29d43d70 100644 --- a/tests/gui/test/test-nexus.cpp +++ b/tests/gui/test/test-nexus.cpp @@ -590,7 +590,7 @@ namespace test{ testNexus().installStateMarkHandler( [&](ID const& elementID, lib::diff::GenNode const& stateMark) { - stateManager().record (elementID, stateMark); + stateManager().recordState (elementID, stateMark); }); return getMockStateManager();