implement state reset handlers / mock handlers

This commit is contained in:
Fischlurch 2016-02-14 03:42:10 +01:00
parent afeedfc288
commit 18b6a388a0
6 changed files with 210 additions and 71 deletions

View file

@ -64,57 +64,67 @@ namespace model {
virtual bool virtual bool
doReset() override doReset() override
{ {
UNIMPLEMENTED ("reset"); UNIMPLEMENTED ("Controller reset");
} }
virtual bool virtual bool
doExpand (bool yes) override doExpand (bool yes) override
{ {
UNIMPLEMENTED ("mock doExpand"); UNIMPLEMENTED ("Controller doExpand");
} }
virtual void virtual void
doReveal (ID child) override doReveal (ID child) override
{ {
UNIMPLEMENTED ("mock doReveal"); UNIMPLEMENTED ("Controller doReveal");
} }
virtual void virtual void
doRevealYourself() override doRevealYourself() override
{ {
UNIMPLEMENTED ("mock doRevealYourself"); UNIMPLEMENTED ("Controller doRevealYourself");
} }
virtual void virtual bool
doMsg (string text) override 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 doErr (string text) override
{ {
UNIMPLEMENTED ("mock doErr"); UNIMPLEMENTED ("Controller doErr");
}
virtual bool
doClearErr () override
{
UNIMPLEMENTED ("Controller doClearErr");
} }
virtual void virtual void
doFlash() override doFlash() override
{ {
UNIMPLEMENTED ("mock doFlash"); UNIMPLEMENTED ("Controller doFlash");
} }
virtual void virtual void
doMark (GenNode const& mark) override doMark (GenNode const& mark) override
{ {
UNIMPLEMENTED ("mock doMark"); UNIMPLEMENTED ("Controller doMark");
} }
public: public:
using Tangible::Tangible; using Tangible::Tangible;
protected:
string maybe () const;
}; };

View file

@ -48,41 +48,96 @@ namespace model {
/** invoke the generic reset hook /** invoke the generic reset hook
* @note the actual subclass has to override the doReset() hook * @note the actual subclass has to override the doReset() hook
* to perform the actual clean-up work. * 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 * @remarks the intention is that, after invoking reset(), the
* interface element or controller is in pristine (presentation) state * interface element or controller is in pristine (presentation) state
*/ */
void void
Tangible::reset() Tangible::reset()
{ {
this->doReset(); if (this->doReset())
uiBus_.note (GenNode("reset", true)); uiBus_.note (GenNode{"reset", true});
} }
/** /** invoke the hook to clear error markers
* Prepare a command or action for actual invocation, once the execution context * @note the actual subclass has to override the doClearErr() hook...
* has been established. The action is not executed right away, but it is now ready * @note and similar to the reset() call, also the implementation should
* and bound to the concrete arguments supplied with the [record](\ref lib::diff::Rec). * return `true` in case any actual (sticky) error state has been cleared.
* @param prototype handle to a command instantiation, to be readied for invocation * Again, this causes emitting of a "resetErr" state mark, which will
* @param arguments suitable tuple of values, to be used to outfit the prototype * 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 void
Tangible::prepareCommand (Cmd const& prototype, Rec&& arguments) Tangible::clearErr()
{ {
uiBus_.act (prototype.bind (std::forward<Rec>(arguments))); if (this->doClearErr())
} uiBus_.note (GenNode{"clearErr", true});
}
/** /** invoke the hook to clear notification messages
* Actually trigger execution of an action or command. * @remarks everything is symmetrical to reset() and clearErr() here...
* @param preparedAction handle pointing to a command definition,
* which needs to be outfitted with arguments and ready for invocation.
*/ */
void void
Tangible::issueCommand (Cmd const& preparedAction) Tangible::clearMsg()
{ {
uiBus_.act (preparedAction.bang()); 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<Rec>(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<string>());
else
if (stateMark.idi.getSym() == "Message")
this->markMsg (stateMark.data.get<string>());
else
this->doMark(stateMark);
}
/** /**
* default implementation and catch-all handler for receiving »state mark« messages. * default implementation and catch-all handler for receiving »state mark« messages.
* Such messages serve either to cause a presentation state effect specific to this * Such messages serve either to cause a presentation state effect specific to this
@ -157,7 +257,13 @@ namespace model {
this->doExpand (stateMark.data.get<bool>()); this->doExpand (stateMark.data.get<bool>());
else else
if (stateMark.idi.getSym() == "reset") 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 else
if (stateMark.idi.getSym() == "revealYourself") if (stateMark.idi.getSym() == "revealYourself")
this->doRevealYourself(); this->doRevealYourself();

View file

@ -174,6 +174,8 @@ namespace model {
operator ID() const { return uiBus_.getID();} operator ID() const { return uiBus_.getID();}
void reset(); void reset();
void clearMsg();
void clearErr();
template<typename...ARGS> template<typename...ARGS>
void prepareCommand (Cmd const& prototype, ARGS&&...); void prepareCommand (Cmd const& prototype, ARGS&&...);
@ -185,19 +187,21 @@ namespace model {
void slotReveal(ID child); void slotReveal(ID child);
void markMsg (string m) { this->doMsg(m); } void markFlash();
void markErr (string e) { this->doErr(e); } void markMsg (string message);
void markFlash() { this->doFlash();} void markErr (string error);
void mark(GenNode const&); void mark(GenNode const&);
protected: protected:
virtual bool doReset() =0; virtual bool doReset() =0;
virtual bool doClearMsg() =0;
virtual bool doClearErr() =0;
virtual bool doExpand (bool yes) =0; virtual bool doExpand (bool yes) =0;
virtual void doReveal (ID child) =0; virtual void doReveal (ID child) =0;
virtual void doRevealYourself () =0; virtual void doRevealYourself () =0;
virtual void doMsg (string) =0; virtual bool doMsg (string) =0;
virtual void doErr (string) =0; virtual bool doErr (string) =0;
virtual void doFlash() =0; virtual void doFlash() =0;
virtual void doMark(GenNode const&) =0; virtual void doMark(GenNode const&) =0;
private: 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<string>());
else
if (stateMark.idi.getSym() == "Message")
this->doMsg (stateMark.data.get<string>());
else
this->doMark(stateMark);
}
}} // namespace gui::model }} // namespace gui::model
#endif /*GUI_MODEL_TANGIBLE_H*/ #endif /*GUI_MODEL_TANGIBLE_H*/

View file

@ -64,57 +64,67 @@ namespace model {
virtual bool virtual bool
doReset() override doReset() override
{ {
UNIMPLEMENTED ("reset"); UNIMPLEMENTED ("Widget reset");
} }
virtual bool virtual bool
doExpand (bool yes) override doExpand (bool yes) override
{ {
UNIMPLEMENTED ("mock doExpand"); UNIMPLEMENTED ("Widget doExpand");
} }
virtual void virtual void
doReveal (ID child) override doReveal (ID child) override
{ {
UNIMPLEMENTED ("mock doReveal"); UNIMPLEMENTED ("Widget doReveal");
} }
virtual void virtual void
doRevealYourself() override doRevealYourself() override
{ {
UNIMPLEMENTED ("mock doRevealYourself"); UNIMPLEMENTED ("Widget doRevealYourself");
} }
virtual void virtual bool
doMsg (string text) override 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 doErr (string text) override
{ {
UNIMPLEMENTED ("mock doErr"); UNIMPLEMENTED ("Widget doErr");
}
virtual bool
doClearErr () override
{
UNIMPLEMENTED ("Widget doClearErr");
} }
virtual void virtual void
doFlash() override doFlash() override
{ {
UNIMPLEMENTED ("mock doFlash"); UNIMPLEMENTED ("Widget doFlash");
} }
virtual void virtual void
doMark (GenNode const& mark) override doMark (GenNode const& mark) override
{ {
UNIMPLEMENTED ("mock doMark"); UNIMPLEMENTED ("Widget doMark");
} }
public: public:
using Tangible::Tangible; using Tangible::Tangible;
protected:
string maybe () const;
}; };

View file

@ -444,7 +444,7 @@ namespace test {
CHECK ("Centauri" == mockA.getMessage()); CHECK ("Centauri" == mockA.getMessage());
// reset all notification messages // reset all notification messages
uiBus.markAll (GenNode{"resetMsg", true}); uiBus.markAll (GenNode{"clearMsg", true});
CHECK (mockB.isExpanded()); CHECK (mockB.isExpanded());
CHECK (mockC.isError()); CHECK (mockC.isError());
CHECK (isnil (mockA.getMessage())); CHECK (isnil (mockA.getMessage()));
@ -455,7 +455,7 @@ namespace test {
mockA.slotCollapse(); mockA.slotCollapse();
// reset error state(s) // reset error state(s)
uiBus.markAll (GenNode{"resetErr", true}); uiBus.markAll (GenNode{"clearErr", true});
CHECK (not mockB.isExpanded()); CHECK (not mockB.isExpanded());
CHECK (mockB.isExpanded()); CHECK (mockB.isExpanded());
CHECK ("miss" == mockB.getMessage()); CHECK ("miss" == mockB.getMessage());

View file

@ -154,7 +154,7 @@ namespace test{
UNIMPLEMENTED ("mock doRevealYourself"); UNIMPLEMENTED ("mock doRevealYourself");
} }
virtual void virtual bool
doMsg (string text) override doMsg (string text) override
{ {
log_.call (this->identify(), "doMsg", text); log_.call (this->identify(), "doMsg", text);
@ -162,9 +162,22 @@ namespace test{
message_ = text; message_ = text;
virgin_ = false; virgin_ = false;
log_.note ("type=mark", "ID=Message", text); 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 doErr (string text) override
{ {
log_.call (this->identify(), "doErr", text); log_.call (this->identify(), "doErr", text);
@ -172,6 +185,19 @@ namespace test{
error_ = text; error_ = text;
virgin_ = false; virgin_ = false;
log_.note ("type=mark", "ID=Error", text); 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 virtual void