Introduce predefined constants for magic IDs in UI communication

...these magical strings are already spreading dangerously throughout the code base


PS: also fixup for c6b8811af0  (broken whitespace in test definition)
This commit is contained in:
Fischlurch 2018-10-08 05:00:06 +02:00
parent 08ed6e1ee8
commit 9894542bf9
20 changed files with 258 additions and 98 deletions

View file

@ -150,7 +150,7 @@ namespace gui {
ERROR_LOG_AND_IGNORE (guifacade, "trigger shutdown of the GUI");
}
bool
bool
checkRunningState () noexcept override
{
return bool(facade);
@ -210,15 +210,6 @@ namespace gui {
{
return bool(facade);
}
} // namespace gui
/*
// Local Variables:
// mode: C++
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,62 @@
/*
UiProtocol - magic keys used for communication with the Lumiera UI
Copyright (C) Lumiera.org
2018, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file ui-protocol.cpp
** Storage for key constants and basic definitions used for interfacing with the GUI.
*/
//#include "gui/gtk-base.hpp" /////////////////////TODO necessary?
#include "include/ui-protocol.hpp"
namespace gui {
const Symbol META_kind{"kind"};
const Symbol TYPE_Fork{"Fork"};
const Symbol TYPE_Clip{"Clip"};
const Symbol TYPE_Marker{"Marker"};
const Symbol TYPE_Channel{"Channel"};
const Symbol TYPE_Effect{"Effect"};
const Symbol ATTR_name{"name"};
const Symbol ATTR_fork{"fork"};
/* ======== UI-Element protocol ======== */
const Symbol MARK_reset{"reset"};
const Symbol MARK_clearErr{"clearErr"};
const Symbol MARK_clearMsg{"clearMsg"};
const Symbol MARK_expand{"expand"};
const Symbol MARK_reveal{"reveal"};
const Symbol MARK_Flash{"Flash"};
const Symbol MARK_Error{"Error"};
const Symbol MARK_Warning{"Warning"};
const Symbol MARK_Message{"Message"};
/** */
}// namespace gui

View file

@ -147,7 +147,7 @@ namespace ctrl {
virtual void
doMark (GenNode const& stateMark) override
{
if (stateMark.idi.getSym() == "Warning")
if (stateMark.idi.getSym() == MARK_Warning)
getWidget().addWarn (stateMark.data.get<string>());
else
// forward to default handler

View file

@ -59,6 +59,7 @@
#include "gui/ctrl/bus-term.hpp"
#include "gui/ctrl/state-manager.hpp"
#include "gui/ctrl/state-map-grouping-storage.hpp"
#include "include/ui-protocol.hpp"
#include <string>
@ -174,14 +175,14 @@ namespace ctrl {
void
recordState (ID uiElm, StateMark stateMark)
{
if ("reset" == stateMark.idi.getSym())
if (MARK_reset == stateMark.idi.getSym())
storage_.clearState (uiElm);
else
if ("clearErr" == stateMark.idi.getSym())
storage_.clearProperty (uiElm, "Error");
if (MARK_clearErr == stateMark.idi.getSym())
storage_.clearProperty (uiElm, string{MARK_Error});
else
if ("clearMsg" == stateMark.idi.getSym())
storage_.clearProperty (uiElm, "Message");
if (MARK_clearMsg == stateMark.idi.getSym())
storage_.clearProperty (uiElm, string{MARK_Message});
else
storage_.record (uiElm, stateMark);
}

View file

@ -44,6 +44,7 @@
#include "gui/ctrl/bus-term.hpp"
#include "gui/model/tangible.hpp"
#include "proc/cmd.hpp"
#include "include/ui-protocol.hpp"
#include "include/gui-notification-facade.h"
#include "lib/scoped-ptrvect.hpp"
#include "lib/diff/gen-node.hpp"
@ -225,12 +226,12 @@ namespace dialog {
trig_4_.set_tooltip_markup (_("trigger Proc-command, which in turn\n"
"sends an <b>state mark</b> message, using\n"
"the message action-ID from the combobox"));
actionID_.append ("Flash");
actionID_.append ("revealYourself");
actionID_.append ("clearErr");
actionID_.append ("clearMsg");
actionID_.append ("expand");
actionID_.append ("reset");
actionID_.append (cuString{MARK_Flash});
actionID_.append (cuString{MARK_reveal});
actionID_.append (cuString{MARK_clearErr});
actionID_.append (cuString{MARK_clearMsg});
actionID_.append (cuString{MARK_expand});
actionID_.append (cuString{MARK_reset});
actionID_.set_active(1);
actionID_.set_tooltip_markup("select the specific action-ID\n"
"when sending a <b>mark</b> message.\n"

View file

@ -36,7 +36,7 @@
**
** The base class of all [tangible UI elements](\ref Tangible) provides a default implementation
** for these generic interaction mechanisms: It offers slots to connect UI signals against, and
** it understands the \em `mark` messages `"expand"` and `"revealYourself"`. These are implemented
** it understands the \em `mark` messages `"expand"` and `"reveal"`. These are implemented
** by delegating to the \ref Expander and \ref Revealer functors respectively. Moreover, this
** default implementation automatically detects a resulting state change and emits an appropriate
** \em `note` message on the UI-Bus, so to make those state changes persistent. However, in order

View file

@ -33,6 +33,7 @@
#include "gui/model/tangible.hpp"
#include "gui/model/widget.hpp"
#include "gui/model/controller.hpp"
#include "include/ui-protocol.hpp"
#include "lib/diff/gen-node.hpp"
@ -60,7 +61,7 @@ namespace model {
Tangible::reset()
{
if (this->doReset())
uiBus_.note (GenNode{"reset", true});
uiBus_.note (GenNode{string{MARK_reset}, true});
}
@ -82,7 +83,7 @@ namespace model {
Tangible::clearErr()
{
if (this->doClearErr())
uiBus_.note (GenNode{"clearErr", true});
uiBus_.note (GenNode{string{MARK_clearErr}, true});
}
@ -93,7 +94,7 @@ namespace model {
Tangible::clearMsg()
{
if (this->doClearMsg())
uiBus_.note (GenNode{"clearMsg", true});
uiBus_.note (GenNode{string{MARK_clearMsg}, true});
}
@ -125,7 +126,7 @@ namespace model {
Tangible::markMsg (string message)
{
if (this->doMsg (message))
uiBus_.note (GenNode{"Message", message});
uiBus_.note (GenNode{string{MARK_Message}, message});
}
@ -136,7 +137,7 @@ namespace model {
Tangible::markErr (string error)
{
if (this->doErr (error))
uiBus_.note (GenNode("Error", error));
uiBus_.note (GenNode{string{MARK_Error}, error});
}
@ -156,7 +157,7 @@ namespace model {
Tangible::slotExpand()
{
if (this->doExpand(true))
uiBus_.note (GenNode("expand", true));
uiBus_.note (GenNode{string{MARK_expand}, true});
}
@ -168,7 +169,7 @@ namespace model {
Tangible::slotCollapse()
{
if (this->doExpand(false))
uiBus_.note (GenNode("expand", false));
uiBus_.note (GenNode{string{MARK_expand}, false});
}
@ -192,9 +193,9 @@ namespace model {
* Cause the element to be brought into sight.
* This is a generic Slot to connect UI signals against;
* the same action can also be triggered by sending a **mark**
* message over the UI-Bus with the symbol "`revealYourself`".
* message over the UI-Bus with the symbol "`reveal`".
* @note this is an optional feature and requires the actual widget or controller
* either to override the ::doRevealYourself() extension point, or to
* either to override the ::doReveal() extension point, or to
* [install a suitable closure](\ref installRevealer()). Typically this
* is not in itself a persistent state change; however, it might incur
* expanding some widgets, which is recorded as persistent UI state.
@ -207,7 +208,7 @@ namespace model {
void
Tangible::slotReveal()
{
this->doRevealYourself();
this->doReveal();
}
@ -217,7 +218,7 @@ namespace model {
* explicitly to enable this functionality.
*/
void
Tangible::doRevealYourself()
Tangible::doReveal()
{
if (reveal_.canReveal())
reveal_();
@ -245,13 +246,13 @@ namespace model {
void
Tangible::mark (GenNode const& stateMark)
{
if (stateMark.idi.getSym() == "Flash")
if (stateMark.idi.getSym() == MARK_Flash)
this->doFlash();
else
if (stateMark.idi.getSym() == "Error")
if (stateMark.idi.getSym() == MARK_Error)
this->markErr (stateMark.data.get<string>());
else
if (stateMark.idi.getSym() == "Message")
if (stateMark.idi.getSym() == MARK_Message)
this->markMsg (stateMark.data.get<string>());
else
this->doMark(stateMark);
@ -267,10 +268,10 @@ namespace model {
* It is up to the concrete element to give this a tangible meaning, e.g. a track
* might switch to detail view and a clip might reveal attached effects.
* - *reset* restores the element to the hard wired default, by invoking `doReset()`
* - *revealYourself* prompts the element to take the necessary actions to bring
* itself into view. There is no requirement for an element to even implement
* this call, but those which do typically know some kind of _"parent object"_
* to forward this request, by invoking `doReveal(myID)` on this parent.
* - *reveal* prompts the element to take the necessary actions to bring itself
* into view. There is no requirement for an element to even implement this call,
* but those which do typically know some kind of _"parent object"_ to forward
* this request, by invoking `doReveal(myID)` on this parent.
* For instance, a clip might ask the enclosing track, which in turn might
* call the enclosing timeline display for help, resulting in a scroll action
* to bring the clip into sight.
@ -280,23 +281,23 @@ namespace model {
void
Tangible::doMark (GenNode const& stateMark)
{
if (stateMark.idi.getSym() == "expand")
if (stateMark.idi.getSym() == MARK_expand)
{
if (this->doExpand (stateMark.data.get<bool>()))
uiBus_.note (GenNode("expand", true)); // possibly reentrant (yet harmless)
uiBus_.note (GenNode(string{MARK_expand}, true)); // possibly reentrant (yet harmless)
}
else
if (stateMark.idi.getSym() == "reset")
if (stateMark.idi.getSym() == MARK_reset)
this->reset();
else
if (stateMark.idi.getSym() == "clearMsg")
if (stateMark.idi.getSym() == MARK_clearMsg)
this->clearMsg();
else
if (stateMark.idi.getSym() == "clearErr")
if (stateMark.idi.getSym() == MARK_clearErr)
this->clearErr();
else
if (stateMark.idi.getSym() == "revealYourself")
this->doRevealYourself();
if (stateMark.idi.getSym() == MARK_reveal)
this->doReveal();
}

View file

@ -217,7 +217,7 @@ namespace model {
virtual bool doClearMsg() =0;
virtual bool doClearErr() =0;
virtual bool doExpand (bool yes);
virtual void doRevealYourself();
virtual void doReveal ();
virtual bool doMsg (string) =0;
virtual bool doErr (string) =0;
@ -287,9 +287,9 @@ namespace model {
/**
* Configure the (optional) functionality to bring the UI-Element into sight.
* @param how_to_uncover_the_element a lambda or function<void()> to actually cause the necessary actions.
* @note unless this setup function is invoked, the "`revealYourself`" functionality remains disabled.
* @note unless this setup function is invoked, the "`reveal`" functionality remains disabled.
* Typically this setup will be done by an owning parent container, binding to some internals
* and also recursively invoking the "`revealYourself`" action on the container.
* and also recursively invoking the "`reveal`" action on the container.
*/
inline void
Tangible::installRevealer (Revealer::RevealeItFun how_to_uncover_the_element)

View file

@ -56,6 +56,7 @@
#include "gui/ctrl/ui-dispatcher.hpp"
#include "gui/notification-service.hpp"
#include "gui/interact/wizard.hpp"
#include "include/ui-protocol.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/diff/gen-node.hpp"
@ -113,7 +114,7 @@ namespace gui {
markNote (errorLogID, text);
break;
case NOTE_WARN:
mark (errorLogID, GenNode{"Warning", text});
mark (errorLogID, GenNode{string{MARK_Warning}, text});
break;
default:
throw lumiera::error::Logic (_Fmt{"UI Notification with invalid severity %d encountered. "
@ -124,14 +125,14 @@ namespace gui {
void
NotificationService::markError (ID uiElement, string const& text)
{
dispatchMsg (uiElement, GenNode{"Error", text});
dispatchMsg (uiElement, GenNode{string{MARK_Error}, text});
}
void
NotificationService::markNote (ID uiElement, string const& text)
{
dispatchMsg (uiElement, GenNode{"Message", text});
dispatchMsg (uiElement, GenNode{string{MARK_Message}, text});
}

View file

@ -31,6 +31,7 @@
#include "gui/gtk-base.hpp"
#include "include/ui-protocol.hpp"
#include "gui/timeline/clip-presenter.hpp"
#include "gui/timeline/marker-widget.hpp"
@ -94,7 +95,7 @@ namespace timeline {
.attach (collection(markers_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{ // »Selector« : require object-like sub scope with type-field "Marker"
return "Marker" == spec.data.recordType();
return TYPE_Marker == spec.data.recordType();
})
.matchElement ([&](GenNode const& spec, PMarker const& elm) -> bool
{
@ -113,7 +114,7 @@ namespace timeline {
.attach (collection(effects_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{ // »Selector« : require object-like sub scope with type-field "Effect"
return "Effect" == spec.data.recordType();
return TYPE_Effect == spec.data.recordType();
})
.matchElement ([&](GenNode const& spec, PEffect const& elm) -> bool
{
@ -132,7 +133,7 @@ namespace timeline {
.attach (collection(channels_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{ // »Selector« : require object-like sub scope with type-field "Channel"
return "Channel" == spec.data.recordType();
return TYPE_Channel == spec.data.recordType();
})
.matchElement ([&](GenNode const& spec, PChannel const& elm) -> bool
{

View file

@ -31,6 +31,7 @@
#include "gui/gtk-base.hpp"
#include "include/ui-protocol.hpp"
#include "gui/timeline/marker-widget.hpp"
//#include "gui/ui-bus.hpp"
@ -82,11 +83,11 @@ namespace timeline {
{
buffer.create (
TreeMutator::build()
.change("name", [&](string val)
.change(ATTR_name, [&](string val)
{
name_ = val;
})
.change("kind", [&](string val)
.change(META_kind, [&](string val)
{
if (val == "LOOP") kind_ = LOOP;
else kind_ = MARK;

View file

@ -39,6 +39,7 @@
#include "gui/gtk-base.hpp"
#include "include/ui-protocol.hpp"
#include "gui/timeline/timeline-controller.hpp"
#include "gui/timeline/track-presenter.hpp"
#include "gui/timeline/marker-widget.hpp"
@ -155,12 +156,12 @@ namespace timeline {
target->buildMutator (buff); // - delegate to child to build nested TreeMutator
return true;
}))
.mutateAttrib("fork", [&](TreeMutator::Handle buff)
.mutateAttrib(ATTR_fork, [&](TreeMutator::Handle buff)
{ // »Attribute Mutator« : how enter an object field as nested scope
REQUIRE (fork_);
fork_->buildMutator(buff);
})
.change("name", [&](string val)
.change(ATTR_name, [&](string val)
{ // »Attribute Setter« : how assign a new value to some object field
name_ = val;
}));

View file

@ -31,6 +31,7 @@
#include "gui/gtk-base.hpp"
#include "include/ui-protocol.hpp"
#include "gui/timeline/track-presenter.hpp"
#include "gui/timeline/clip-presenter.hpp"
#include "gui/timeline/marker-widget.hpp"
@ -104,7 +105,7 @@ namespace timeline {
.attach (collection(markers_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{ // »Selector« : require object-like sub scope with type-field "Marker"
return "Marker" == spec.data.recordType();
return TYPE_Marker == spec.data.recordType();
})
.matchElement ([&](GenNode const& spec, PMarker const& elm) -> bool
{
@ -123,7 +124,7 @@ namespace timeline {
.attach (collection(clips_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{ // »Selector« : require object-like sub scope with type-field "Clip"
return "Clip" == spec.data.recordType();
return TYPE_Clip == spec.data.recordType();
})
.matchElement ([&](GenNode const& spec, PClip const& elm) -> bool
{
@ -142,7 +143,7 @@ namespace timeline {
.attach (collection(subFork_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{ // »Selector« : require object-like sub scope with type-field "Fork"
return "Fork" == spec.data.recordType();
return TYPE_Fork == spec.data.recordType();
})
.matchElement ([&](GenNode const& spec, PFork const& elm) -> bool
{

View file

@ -0,0 +1,93 @@
/*
UI-PROTOCOL.h - magic keys used for communication with the Lumiera UI
Copyright (C) Lumiera.org
2018, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file ui-protocol.hpp
** Hard wired key constants and basic definitions for communication with the GUI.
** The Lumiera UI is connected to the application core via message oriented interfaces,
** running an asynchronous communication protocol.
** - the [UI-Bus](\ref ui-bus.hpp) allows for some specific kinds of messages to be
** sent either "upstream" (towards the CoreService) or "downstream" to individual
** [UI-Elements](\ref gui::model::Tangible) known by ID.
** - these ["tangible interface elements"](\ref tangible.hpp) themselves define a
** basic set of actions and "state mark" messages, known as the "element protocol"
** - and changes to the structure of tangible elements exposed through the UI are
** conducted by pushing up [»diff messages«](\ref mutation-message.hpp) into the
** UI via UI-Bus. These messages need to comply to an underlying structural
** model of elements to be edited within the session and exposed for GUI
** manipulation. This is referred to as "Session Model Scheme"
**
** These protocols are basically _implementation defined_ conventions and not
** rigorously formalised. To a large extent, they are guided by the types and
** corresponding API interfaces. However, since the lumiera session allows for
** quite flexible structures, these protocols are kept open for local extensions.
** At various levels, magic ID-Values are used to initiate specific interactions.
** This header supplies the hard wired key constants and IDs thereby employed.
**
** @see common/ui-protocol.cpp (translation unit backing those constants)
*/
#ifndef GUI_INTERFACE_UI_PROTOCOL_H
#define GUI_INTERFACE_UI_PROTOCOL_H
#include "lib/symbol.hpp"
namespace Glib {
//class ustring; /////////////////////////////TODO needed?
}
namespace gui {
//using lib::Literal;
using lib::Symbol;
//using cuString = const Glib::ustring;
extern const Symbol META_kind;
extern const Symbol TYPE_Fork;
extern const Symbol TYPE_Clip;
extern const Symbol TYPE_Marker;
extern const Symbol TYPE_Channel;
extern const Symbol TYPE_Effect;
extern const Symbol ATTR_name;
extern const Symbol ATTR_fork;
/* ======== UI-Element protocol ======== */
extern const Symbol MARK_reset;
extern const Symbol MARK_clearErr;
extern const Symbol MARK_clearMsg;
extern const Symbol MARK_expand;
extern const Symbol MARK_reveal;
extern const Symbol MARK_Flash;
extern const Symbol MARK_Error;
extern const Symbol MARK_Warning;
extern const Symbol MARK_Message;
}// namespace gui
#endif /*GUI_INTERFACE_UI_PROTOCOL_H*/

View file

@ -33,7 +33,8 @@
** Such an architecture allows for tight cooperation between strictly separated
** components, without the need of a fixed, predefined and shared data structure.
**
** \par Basic Assumptions
** # Basic Assumptions
**
** While the \em linearisation folds knowledge about the underlying data structure
** down into the actual diff, we deliberately assume that the data to be diffed is
** \em structured data. Moreover, we'll assume implicitly that this data is \em typed,
@ -44,7 +45,8 @@
** send the actual content data this way, or to serve as redundancy to verify
** proper application of the changes at the diff receiver downstream.
**
** \par Solution Pattern
** # Solution Pattern
**
** The representation of this linearised diff language relies on a specialised form
** of the <b>visitor pattern</b>: We assume the vocabulary of the diff language to be
** relatively fixed, while the actual effect when consuming the stream of diff tokens

View file

@ -38,6 +38,7 @@
#include "proc/cmd.hpp"
#include "proc/control/command-def.hpp"
//#include "proc/mobject/session.hpp"
#include "include/ui-protocol.hpp" //////////////////////////////////////////////////////////////TICKET #1140 : verify if this include is required
#include "include/gui-notification-facade.h"
#include "gui/interact/wizard.hpp" //////////////////////////////////////////////////////////////TICKET #1140 : include needed temporarily
#include "lib/diff/gen-node.hpp"
@ -54,6 +55,7 @@ using gui::NOTE_INFO;
using gui::NOTE_WARN;
using gui::NOTE_ERROR;
using gui::NotifyLevel;
using gui::MARK_expand;
using gui::GuiNotification;
using lib::diff::GenNode;
//using util::cStr;
@ -214,8 +216,8 @@ COMMAND_DEFINITION (test_meta_markAction)
{
ID errorLogID = gui::interact::Wizard::getErrorLogID();
GuiNotification::facade().mark (errorLogID
,actionID=="expand"? GenNode{actionID, isYes(message)}
: GenNode{actionID, message});
,actionID==MARK_expand? GenNode{actionID, isYes(message)}
: GenNode{actionID, message});
})
.captureUndo ([](string actionID, string message) -> string
{

View file

@ -705,8 +705,8 @@ TEST "util: sanitised identifier" UtilSanitizedIdentifier_test <<END
out-lit: 'Word' --> 'Word'
out-lit: 'a Sentence' --> 'a_Sentence'
out-lit: 'trailing Withespace
out-lit: ' --> 'trailing_Withespace'
out-lit: 'with a lot
out-lit: ' --> 'trailing_Withespace'
out-lit: 'with a lot
out-lit: of Whitespace' --> 'with_a_lot_of_Whitespace'
out-lit: 'with"much (punctuation)[]!' --> 'withmuch_(punctuation)'
out-lit: '§&Ω%€ leading garbage' --> 'leading_garbage'

View file

@ -470,7 +470,7 @@ namespace test {
}
/** @test configure a handler for the (optional) "revealYourself" functionality.
/** @test configure a handler for the (optional) "reveal yourself" functionality.
* We install a lambda to supply the actual implementation action, which can then
* either be triggered by a signal/slot invocation, or by sending a "state mark".
*/
@ -494,7 +494,7 @@ namespace test {
bool revealed = false;
mock.installRevealer([&]()
{ // NOTE: our mock "implementation" of the revealYourself functionality
{ // NOTE: our mock "implementation" of the »reveal yourself« functionality
mock.slotExpand(); // explicitly prompts the element to expand itself,
revealed = true; // and then via closure sets a flag we can verify.
});
@ -504,7 +504,7 @@ namespace test {
CHECK (true == revealed);
CHECK (mock.isExpanded());
CHECK (mock.verifyEvent("create","target")
.beforeCall("revealYourself")
.beforeCall("reveal")
.beforeCall("expand").arg(true)
.beforeEvent("expanded"));
@ -515,28 +515,28 @@ namespace test {
// second test: the same can be achieved via UI-Bus message...
revealed = false;
auto stateMark = GenNode{"revealYourself", 47}; // (payload argument irrelevant)
auto stateMark = GenNode{"reveal", 47}; // (payload argument irrelevant)
auto& uiBus = gui::test::Nexus::testUI();
CHECK (nexusLog.ensureNot("revealYourself"));
CHECK (nexusLog.ensureNot("reveal"));
uiBus.mark (targetID, stateMark); // send the state mark message to reveal the element
CHECK (true == revealed);
CHECK (mock.verifyMark("revealYourself", 47)
CHECK (mock.verifyMark("reveal", 47)
.afterEvent("expanded")
.beforeCall("revealYourself")
.beforeCall("reveal")
.beforeCall("expand").arg(true));
CHECK (nexusLog.verifyCall("mark").arg(targetID, stateMark)
.after("handling state-mark")
.before("revealYourself")
.before("reveal")
.beforeEvent("delivered mark"));
// Note the fine point: the target element /was/ already expanded
// and thus there is no second "expanded" event, nor is there a
// second state mark emitted into the UI-Bus...
CHECK (mock.ensureNot("expanded")
.afterCall("revealYourself")
.afterCall("reveal")
.afterEvent("expanded"));
CHECK (nexusLog.ensureNot("note")
.afterCall("mark").arg(targetID, stateMark)

View file

@ -30,6 +30,7 @@
#include "lib/sync.hpp"
#include "lib/sync-classlock.hpp"
#include "backend/thread-wrapper.hpp"
#include "include/ui-protocol.hpp"
#include "gui/ctrl/bus-term.hpp"
#include "gui/ctrl/state-manager.hpp"
#include "proc/control/command.hpp"
@ -190,8 +191,8 @@ namespace test {
CHECK (nexusLog.verifyCall("note").on("TestNexus").arg(elmID, "GenNode-ID(\"expand\")-DataCap|«bool»|true"));
// send a state mark down to the mock element
gui::test::Nexus::testUI().mark (elmID, GenNode("Flash", 23));
CHECK (nexusLog.verifyCall("mark").on("TestNexus").arg(elmID, "Flash")
gui::test::Nexus::testUI().mark (elmID, GenNode(string{MARK_Flash}, 23));
CHECK (nexusLog.verifyCall("mark").on("TestNexus").arg(elmID, MARK_Flash)
.beforeEvent("TestNexus", "mark to bID-zeitgeist"));
CHECK (elmLog.verifyCall("doFlash").on("zeitgeist"));
@ -202,9 +203,9 @@ namespace test {
CHECK (nexusLog.verifyCall("routeDetach").on("TestNexus").arg(elmID)
.beforeEvent("TestNexus", "removed route to bID-zeitgeist"));
gui::test::Nexus::testUI().mark (elmID, GenNode("Flash", 88));
gui::test::Nexus::testUI().mark (elmID, GenNode({MARK_Flash}, 88));
CHECK (nexusLog.verify("removed route to bID-zeitgeist")
.beforeCall("mark").on("TestNexus").arg(elmID, "Flash")
.beforeCall("mark").on("TestNexus").arg(elmID, MARK_Flash)
.beforeEvent("warn","discarding mark to unknown bID-zeitgeist"));
CHECK (elmLog.ensureNot("Flash")
.afterEvent("destroy","zeitgeist"));
@ -367,8 +368,8 @@ namespace test {
CHECK (not mockB.isTouched());
CHECK (not mockC.isTouched());
uiBus.mark (alpha, GenNode{"Message", "Centauri"});
uiBus.mark (bravo, GenNode{"Flash", true});
uiBus.mark (alpha, GenNode{"Message", "Centauri"});
uiBus.mark (bravo, GenNode{"Flash", true});
uiBus.mark (charly, GenNode{"Message", "Delta"});
uiBus.mark (charly, GenNode{"Error", "Echo"});
@ -497,8 +498,8 @@ namespace test {
auto& stateManager = gui::test::Nexus::getMockStateManager();
CHECK (stateManager.currentState(alpha, "expand") == GenNode("expand", false ));
CHECK (stateManager.currentState(bravo, "expand") == GenNode("expand", true ));
CHECK (stateManager.currentState(charly, "expand") == Ref::NO);
CHECK (stateManager.currentState(charly, "Error") == GenNode("Error", "Echo")); // sticky error state was recorded
CHECK (stateManager.currentState(charly,"expand") == Ref::NO);
CHECK (stateManager.currentState(charly, "Error") == GenNode("Error", "Echo")); // sticky error state was recorded
// reset error state(s)
uiBus.markAll (GenNode{"clearErr", true});
@ -509,9 +510,9 @@ namespace test {
CHECK (stateManager.currentState(alpha, "expand") == GenNode("expand", false ));
CHECK (stateManager.currentState(bravo, "expand") == GenNode("expand", true ));
CHECK (stateManager.currentState(charly, "expand") == Ref::NO);
CHECK (stateManager.currentState(charly, "Error") == Ref::NO); // sticky error state was cleared,
// because charly sent a clearErr state mark notification back
CHECK (stateManager.currentState(charly,"expand") == Ref::NO);
CHECK (stateManager.currentState(charly, "Error") == Ref::NO); // sticky error state was cleared,
// because charly sent a clearErr state mark notification back
// send global sweeping reset
uiBus.markAll (GenNode{"reset", true});

View file

@ -61,6 +61,7 @@
#include "lib/error.hpp"
#include "include/ui-protocol.hpp"
#include "lib/test/event-log.hpp"
#include "gui/model/tangible.hpp"
#include "lib/diff/record.hpp"
@ -126,7 +127,7 @@ namespace test{
virtual bool
doReset() override
{
log_.call(this->identify(), "reset");
log_.call(this->identify(), string{MARK_reset});
if (virgin_)
return false; // there was nothing to reset
@ -134,22 +135,22 @@ namespace test{
message_ = "";
expanded_ = false;
virgin_ = true;
log_.event("reset");
log_.event(string{MARK_reset});
return true; // we did indeed reset something
} // and thus a state mark should be captured
virtual bool
doExpand (bool yes) override
{
log_.call(this->identify(), "expand", yes);
log_.call(this->identify(), string{MARK_expand}, yes);
return Tangible::doExpand (yes);
}
virtual void
doRevealYourself() override
doReveal() override
{
log_.call(this->identify(), "revealYourself");
Tangible::doRevealYourself(); // NOTE: without specific configuration this is NOP
log_.call(this->identify(), string{MARK_reveal});
Tangible::doReveal(); // NOTE: without specific configuration this is NOP
}
virtual bool