From 18b6a388a07aa04010bb90cd20b2e9656e2e8f6b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 14 Feb 2016 03:42:10 +0100 Subject: [PATCH] implement state reset handlers / mock handlers --- src/gui/model/controller.hpp | 34 +++++--- src/gui/model/tangible.cpp | 148 ++++++++++++++++++++++++++++++----- src/gui/model/tangible.hpp | 31 +++----- src/gui/model/widget.hpp | 34 +++++--- tests/gui/bus-term-test.cpp | 4 +- tests/gui/test/mock-elm.hpp | 30 ++++++- 6 files changed, 210 insertions(+), 71 deletions(-) diff --git a/src/gui/model/controller.hpp b/src/gui/model/controller.hpp index 9c0ac8637..cd9393185 100644 --- a/src/gui/model/controller.hpp +++ b/src/gui/model/controller.hpp @@ -64,57 +64,67 @@ namespace model { virtual bool doReset() override { - UNIMPLEMENTED ("reset"); + UNIMPLEMENTED ("Controller reset"); } virtual bool doExpand (bool yes) override { - UNIMPLEMENTED ("mock doExpand"); + UNIMPLEMENTED ("Controller doExpand"); } virtual void doReveal (ID child) override { - UNIMPLEMENTED ("mock doReveal"); + UNIMPLEMENTED ("Controller doReveal"); } virtual void doRevealYourself() override { - UNIMPLEMENTED ("mock doRevealYourself"); + UNIMPLEMENTED ("Controller doRevealYourself"); } - virtual void + virtual bool doMsg (string text) override { - UNIMPLEMENTED ("mock doMsg"); + UNIMPLEMENTED ("Controller doMsg"); } - virtual void + virtual bool + doClearMsg () override + { + UNIMPLEMENTED ("Controller doClearMsg"); + } + + virtual bool doErr (string text) override { - UNIMPLEMENTED ("mock doErr"); + UNIMPLEMENTED ("Controller doErr"); + } + + virtual bool + doClearErr () override + { + UNIMPLEMENTED ("Controller doClearErr"); } virtual void doFlash() override { - UNIMPLEMENTED ("mock doFlash"); + UNIMPLEMENTED ("Controller doFlash"); } virtual void doMark (GenNode const& mark) override { - UNIMPLEMENTED ("mock doMark"); + UNIMPLEMENTED ("Controller doMark"); } public: using Tangible::Tangible; - protected: - string maybe () const; }; diff --git a/src/gui/model/tangible.cpp b/src/gui/model/tangible.cpp index 14492b15c..f47cc5f8c 100644 --- a/src/gui/model/tangible.cpp +++ b/src/gui/model/tangible.cpp @@ -48,41 +48,96 @@ namespace model { /** invoke the generic reset hook * @note the actual subclass has to override the doReset() hook * to perform the actual clean-up work. + * @note in case an actual reset happened, the implementation should + * return `true` from this `doReset()` hook. As a consequence, + * a new "reset" state mark is emitted, which causes the + * PresentationStateManager to discard any state + * previously recorded for this element. * @remarks the intention is that, after invoking reset(), the * interface element or controller is in pristine (presentation) state */ void Tangible::reset() { - this->doReset(); - uiBus_.note (GenNode("reset", true)); + if (this->doReset()) + uiBus_.note (GenNode{"reset", true}); } - /** - * Prepare a command or action for actual invocation, once the execution context - * has been established. The action is not executed right away, but it is now ready - * and bound to the concrete arguments supplied with the [record](\ref lib::diff::Rec). - * @param prototype handle to a command instantiation, to be readied for invocation - * @param arguments suitable tuple of values, to be used to outfit the prototype + /** invoke the hook to clear error markers + * @note the actual subclass has to override the doClearErr() hook... + * @note and similar to the reset() call, also the implementation should + * return `true` in case any actual (sticky) error state has been cleared. + * Again, this causes emitting of a "resetErr" state mark, which will + * purge any sticky error state remembered within the state manager. + * @remarks usually, most error markers are _not sticky_, that is, they will + * be forgotten when the session ends. In this case, the implementation + * doesn't need to care for anything special. Only in those cases, where + * actually an error state has to be preserved, the implementation should + * - emit an "Error" state mark, with the sticky error state in payload + * - be prepared to recognise when this sticky error state is fed back + * - actually signal the sticky state has to be purged when it is cleared. */ void - Tangible::prepareCommand (Cmd const& prototype, Rec&& arguments) - { - uiBus_.act (prototype.bind (std::forward(arguments))); - } + Tangible::clearErr() + { + if (this->doClearErr()) + uiBus_.note (GenNode{"clearErr", true}); + } - /** - * Actually trigger execution of an action or command. - * @param preparedAction handle pointing to a command definition, - * which needs to be outfitted with arguments and ready for invocation. + /** invoke the hook to clear notification messages + * @remarks everything is symmetrical to reset() and clearErr() here... */ void - Tangible::issueCommand (Cmd const& preparedAction) - { - uiBus_.act (preparedAction.bang()); - } + Tangible::clearMsg() + { + if (this->doClearMsg()) + uiBus_.note (GenNode{"clearMsg", true}); + } + + + /** highlight the element visually to catch the user's attention + * @remarks this is meant as a short transient visual change, + * just to indicate something of relevance happened here. + */ + void + Tangible::markFlash() + { + this->doFlash(); + } + + + /** push a notification (or warning) message to the element. + * @param message notification text + * @note the actual interface response need to be coded + * in the concrete subclass within doMsg(). + * @remarks the intention is for this message to be somehow + * visible at this element, e.g. as mouse over. + * When this notification is meant to be "sticky" / permanent, + * then the mentioned doMsg() implementation function should + * return true; in this case we'll emit a "state mark notification", + * which will be recorded by the PresentationStateManager, under + * the property name "`Message`" for this UI-Element. + * This mechanism allows to persist such UI states. + */ + void + Tangible::markMsg (string message) + { + if (this->doMsg (message)) + uiBus_.note (GenNode{"Message", message}); + } + + + /** push an error state tag to the element + * @remarks everything detailed at markMsg applies here too. + */ + void + Tangible::markErr (string error) + { + if (this->doErr (error)) + uiBus_.note (GenNode("Error", error)); + } /** @@ -131,6 +186,51 @@ namespace model { } + + /** + * Prepare a command or action for actual invocation, once the execution context + * has been established. The action is not executed right away, but it is now ready + * and bound to the concrete arguments supplied with the [record](\ref lib::diff::Rec). + * @param prototype handle to a command instantiation, to be readied for invocation + * @param arguments suitable tuple of values, to be used to outfit the prototype + */ + void + Tangible::prepareCommand (Cmd const& prototype, Rec&& arguments) + { + uiBus_.act (prototype.bind (std::forward(arguments))); + } + + + /** + * Actually trigger execution of an action or command. + * @param preparedAction handle pointing to a command definition, + * which needs to be outfitted with arguments and ready for invocation. + */ + void + Tangible::issueCommand (Cmd const& preparedAction) + { + uiBus_.act (preparedAction.bang()); + } + + + + /** generic handler for all incoming "state mark" messages */ + void + Tangible::mark (GenNode const& stateMark) + { + if (stateMark.idi.getSym() == "Flash") + this->doFlash(); + else + if (stateMark.idi.getSym() == "Error") + this->markErr (stateMark.data.get()); + else + if (stateMark.idi.getSym() == "Message") + this->markMsg (stateMark.data.get()); + else + this->doMark(stateMark); + } + + /** * default implementation and catch-all handler for receiving »state mark« messages. * Such messages serve either to cause a presentation state effect specific to this @@ -157,7 +257,13 @@ namespace model { this->doExpand (stateMark.data.get()); else if (stateMark.idi.getSym() == "reset") - this->doReset(); + this->reset(); + else + if (stateMark.idi.getSym() == "clearMsg") + this->clearMsg(); + else + if (stateMark.idi.getSym() == "clearErr") + this->clearErr(); else if (stateMark.idi.getSym() == "revealYourself") this->doRevealYourself(); diff --git a/src/gui/model/tangible.hpp b/src/gui/model/tangible.hpp index c1456cb38..07a1f2c5c 100644 --- a/src/gui/model/tangible.hpp +++ b/src/gui/model/tangible.hpp @@ -174,6 +174,8 @@ namespace model { operator ID() const { return uiBus_.getID();} void reset(); + void clearMsg(); + void clearErr(); template void prepareCommand (Cmd const& prototype, ARGS&&...); @@ -185,19 +187,21 @@ namespace model { void slotReveal(ID child); - void markMsg (string m) { this->doMsg(m); } - void markErr (string e) { this->doErr(e); } - void markFlash() { this->doFlash();} + void markFlash(); + void markMsg (string message); + void markErr (string error); void mark(GenNode const&); protected: virtual bool doReset() =0; + virtual bool doClearMsg() =0; + virtual bool doClearErr() =0; virtual bool doExpand (bool yes) =0; virtual void doReveal (ID child) =0; virtual void doRevealYourself () =0; - virtual void doMsg (string) =0; - virtual void doErr (string) =0; + virtual bool doMsg (string) =0; + virtual bool doErr (string) =0; virtual void doFlash() =0; virtual void doMark(GenNode const&) =0; private: @@ -219,23 +223,6 @@ namespace model { - /** generic handler for all incoming "state mark" messages */ - inline void - Tangible::mark (GenNode const& stateMark) - { - if (stateMark.idi.getSym() == "Flash") - this->doFlash(); - else - if (stateMark.idi.getSym() == "Error") - this->doErr (stateMark.data.get()); - else - if (stateMark.idi.getSym() == "Message") - this->doMsg (stateMark.data.get()); - else - this->doMark(stateMark); - } - - }} // namespace gui::model #endif /*GUI_MODEL_TANGIBLE_H*/ diff --git a/src/gui/model/widget.hpp b/src/gui/model/widget.hpp index 3c6882e79..5302cfbd5 100644 --- a/src/gui/model/widget.hpp +++ b/src/gui/model/widget.hpp @@ -64,57 +64,67 @@ namespace model { virtual bool doReset() override { - UNIMPLEMENTED ("reset"); + UNIMPLEMENTED ("Widget reset"); } virtual bool doExpand (bool yes) override { - UNIMPLEMENTED ("mock doExpand"); + UNIMPLEMENTED ("Widget doExpand"); } virtual void doReveal (ID child) override { - UNIMPLEMENTED ("mock doReveal"); + UNIMPLEMENTED ("Widget doReveal"); } virtual void doRevealYourself() override { - UNIMPLEMENTED ("mock doRevealYourself"); + UNIMPLEMENTED ("Widget doRevealYourself"); } - virtual void + virtual bool doMsg (string text) override { - UNIMPLEMENTED ("mock doMsg"); + UNIMPLEMENTED ("Widget doMsg"); } - virtual void + virtual bool + doClearMsg () override + { + UNIMPLEMENTED ("Widget doClearMsg"); + } + + virtual bool doErr (string text) override { - UNIMPLEMENTED ("mock doErr"); + UNIMPLEMENTED ("Widget doErr"); + } + + virtual bool + doClearErr () override + { + UNIMPLEMENTED ("Widget doClearErr"); } virtual void doFlash() override { - UNIMPLEMENTED ("mock doFlash"); + UNIMPLEMENTED ("Widget doFlash"); } virtual void doMark (GenNode const& mark) override { - UNIMPLEMENTED ("mock doMark"); + UNIMPLEMENTED ("Widget doMark"); } public: using Tangible::Tangible; - protected: - string maybe () const; }; diff --git a/tests/gui/bus-term-test.cpp b/tests/gui/bus-term-test.cpp index d35d9781a..b8d00f011 100644 --- a/tests/gui/bus-term-test.cpp +++ b/tests/gui/bus-term-test.cpp @@ -444,7 +444,7 @@ namespace test { CHECK ("Centauri" == mockA.getMessage()); // reset all notification messages - uiBus.markAll (GenNode{"resetMsg", true}); + uiBus.markAll (GenNode{"clearMsg", true}); CHECK (mockB.isExpanded()); CHECK (mockC.isError()); CHECK (isnil (mockA.getMessage())); @@ -455,7 +455,7 @@ namespace test { mockA.slotCollapse(); // reset error state(s) - uiBus.markAll (GenNode{"resetErr", true}); + uiBus.markAll (GenNode{"clearErr", true}); CHECK (not mockB.isExpanded()); CHECK (mockB.isExpanded()); CHECK ("miss" == mockB.getMessage()); diff --git a/tests/gui/test/mock-elm.hpp b/tests/gui/test/mock-elm.hpp index bda4c79d5..07e23f6ee 100644 --- a/tests/gui/test/mock-elm.hpp +++ b/tests/gui/test/mock-elm.hpp @@ -154,7 +154,7 @@ namespace test{ UNIMPLEMENTED ("mock doRevealYourself"); } - virtual void + virtual bool doMsg (string text) override { log_.call (this->identify(), "doMsg", text); @@ -162,9 +162,22 @@ namespace test{ message_ = text; virgin_ = false; log_.note ("type=mark", "ID=Message", text); + + return false; // messages not sticky for this mock implementation } - virtual void + virtual bool + doClearMsg () override + { + log_.call (this->identify(), "doClearMsg"); + if (isnil (message_)) + return false; + + message_ = ""; + log_.note ("type=mark", "ID=Message", "Message notification cleared"); + } + + virtual bool doErr (string text) override { log_.call (this->identify(), "doErr", text); @@ -172,6 +185,19 @@ namespace test{ error_ = text; virgin_ = false; log_.note ("type=mark", "ID=Error", text); + + return true; // error states are sticky for this mock implementation + } + + virtual bool + doClearErr () override + { + log_.call (this->identify(), "doClearErr"); + if (not isError()) + return false; + + error_ = ""; + log_.note ("type=mark", "ID=Error", "Error state cleared"); } virtual void