DiffMessage: now uniformly plays the role of MutationMessage (closes #1066)

This commit is contained in:
Fischlurch 2017-08-13 07:09:06 +02:00
parent 82a12115c3
commit 937ad64596
22 changed files with 153 additions and 419 deletions

View file

@ -48,6 +48,12 @@ diff application::
_target_ of diff application. Typically we want to apply a diff to a data sequence, to mutate it
into a new shape, conforming with the shape of the diff's ``target sequence''
tree mutator::
a customisable intermediary, allowing to apply a diff sequence against an opaque data structure.
For the purpose of diff application, the TreeMutator serves as target object, while in fact it is itself
attached by a _binding_ to the actual target data structure, which remains a hidden implementation detail.
This allows to manipulate the target data structure without knowing its concrete representation.
diff generator::
a facility producing a diff, which is a sequence of diff verbs.
Typically, a diff generator works lazily, demand driven.

View file

@ -69,7 +69,7 @@
namespace lib {
namespace diff { class DiffMessage; }
namespace diff { class MutationMessage; }
}
namespace gui {
namespace model {
@ -79,7 +79,7 @@ namespace ctrl{
using lib::idi::EntryID;
using lib::diff::GenNode;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
using std::string;
@ -121,7 +121,7 @@ namespace ctrl{
virtual bool mark (ID subject, GenNode const& mark);
virtual size_t markAll (GenNode const& mark);
virtual bool change (ID subject, DiffMessage&& diff);
virtual bool change (ID subject, MutationMessage&& diff);
virtual operator string() const;

View file

@ -1,167 +0,0 @@
/*
MUTATION-MESSAGE.hpp - message on UI-Bus to cause changes to tangible UI elements
Copyright (C) Lumiera.org
2016, 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 mutation-message.hpp
** Message on the UI-Bus to cause changes on the targeted [UI-Element](\ref model::Tangible).
** The UI-Bus offers a dedicated API to direct MutationMessages towards Tangible elements,
** as designated by the given ID. Actually, such messages serve as capsule to transport a
** diff-sequence -- since a diff sequence as such is always concrete and tied to a specific context,
** we can not represent it easily as an abstract type on interface level. The receiver of a diff
** sequence must offer the ability to be reshaped through diff messages, which is expressed through
** the interface DiffMutable. In the case at question here, gui::model::Tangible offers this interface
** and thus the ability to construct a concrete lib::diff::TreeMutator, which in turn is bound to the
** internals of the actual UI-Element. Together this allows for a generic implementation of MutationMessage
** handling, where the designated UI-Element is reshaped by applying an embedded concrete diff message
** with the help of a `DiffApplicator<DiffMutable>`, based on the TreeMutator exposed.
**
** ## Creating mutation messages
** The UI-Bus invocation actually takes a reference to MutationMessage, and thus on usage a
** concrete instance needs to be created. This concrete Message embeds an actual diff sequence,
** which is some iterable sequence of lib::diff::DiffStep records.
** @warning be sure to understand that the diff sequence is really moved away and then consumed.
**
** @todo as of 1/2017 there is an unsolved problem how such messages can be passed from lower layers.
** A direct symptom is the dependency of this header on model::Tangible, which in turn requires
** `sigc::Trackable`. This is a challenging topic, since we need to hand over to the UI-Event Thread /////////////////////////////////TICKET #1066 : Concept for passing Diff Messages
**
** @see AbstractTangible_test
**
*/
#ifndef GUI_CTRL_MUTATION_MESSAGE_H
#define GUI_CTRL_MUTATION_MESSAGE_H
#include "lib/error.hpp"
#include "lib/opaque-holder.hpp"
#include "lib/diff/tree-diff-application.hpp"
#include "gui/model/tangible.hpp"
#include "lib/format-util.hpp"
#include <utility>
#include <string>
namespace gui {
namespace ctrl{
using std::string;
namespace diff_msg { // implementation details for embedding concrete diff messages
using lib::diff::DiffApplicator;
using model::Tangible;
using std::move;
class Holder
{
public:
virtual ~Holder() {}; ///< this is an interface
virtual void applyTo (Tangible&) =0;
virtual string describe() const =0;
};
template<typename DIFF>
class Wrapped
: public Holder
{
DIFF diff_;
virtual void
applyTo (Tangible& target) override
{
DiffApplicator<Tangible> applicator(target);
applicator.consume (move(diff_));
}
virtual string
describe() const override
{
DIFF copy(diff_); // NOTE: we copy, since each iteration consumes.
return ::util::join (move(copy));
}
public:
Wrapped (DIFF&& diffSeq)
: diff_(move(diffSeq))
{ }
};
/** standard size to reserve for the concrete diff representation
* @note this is a pragmatic guess, based on the actual usage pattern within Lumiera.
* This determines the size of the inline buffer within MutationMessage.
* You'll get an static assertion failure when creating a MutationMessage
* from a concrete diff representation requires more storage space...
*/
enum { SIZE_OF_DIFF_REPRESENTATION = sizeof(std::vector<string>)
+ sizeof(size_t)
+ sizeof(void*)
};
using Buffer = lib::InPlaceBuffer<Holder, SIZE_OF_DIFF_REPRESENTATION>;
}//(End) implementation details...
/**
* Message on the UI-Bus holding an embedded diff sequence.
* The Nexus (hub of the UI-Bus) will prompt the designated Tangible
* to expose a TreeMutator, and then apply the embedded diff.
*/
class MutationMessage
: public diff_msg::Buffer
{
public:
/** build a MutationMessage by _consuming_ the given diff sequence
* @param diffSeq some iterable DiffStep sequence.
* @warning parameter will be moved into the embedded buffer and consumed
*/
template<typename DIFF>
MutationMessage(DIFF&& diffSeq)
: diff_msg::Buffer{ embedType<diff_msg::Wrapped<DIFF>>()
, std::move(diffSeq)}
{ }
void
applyTo (model::Tangible& target)
{
access<diff_msg::Holder>()->applyTo(target);
}
operator string() const
{
return unConst(this)->access<diff_msg::Holder>()->describe();
}
protected:
};
}} // namespace gui::ctrl
#endif /*GUI_CTRL_MUTATION_MESSAGE_H*/

View file

@ -42,7 +42,7 @@
#include "lib/error.hpp"
#include "lib/idi/genfunc.hpp"
#include "lib/diff/diff-message.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/diff/tree-diff-application.hpp"
#include "gui/ctrl/bus-term.hpp"
#include "gui/model/tangible.hpp"
@ -122,7 +122,7 @@ namespace ctrl{
* subject to this change
*/
virtual bool
change (ID subject, DiffMessage&& diff) override
change (ID subject, MutationMessage&& diff) override
{
auto entry = routingTable_.find (subject);
if (entry == routingTable_.end())

View file

@ -54,7 +54,7 @@ namespace gui {
namespace lumiera {
namespace facade {
using gui::ID;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0)
, gui::GuiNotification
@ -70,9 +70,9 @@ namespace facade {
//----Proxy-Implementation-of-GuiNotification--------
void displayInfo (Level level, string const& text) override { _i_.displayInfo (level, cStr(text)); }
void markError (ID uiElement, string const& text) override { _i_.markError(uiElement.getHash().get(), cStr(text)); }
void markNote (ID uiElement, string const& text) override { _i_.markNote (uiElement.getHash().get(), cStr(text)); }
void mutate (ID uiElement, DiffMessage&& diff) override { _i_.mutate (uiElement.getHash().get(), &diff); }
void markError (ID uiElement, string const& text) override { _i_.markError(uiElement.getHash().get(), cStr(text)); }
void markNote (ID uiElement, string const& text) override { _i_.markNote (uiElement.getHash().get(), cStr(text)); }
void mutate (ID uiElement, MutationMessage&& diff) override { _i_.mutate (uiElement.getHash().get(), &diff); }
void triggerGuiShutdown (string const& cause) override { _i_.triggerGuiShutdown (cStr(cause)); }

View file

@ -39,8 +39,6 @@
** but before closing the GuiNotification facade will just be enqueued,
** but then dropped on destruction of the UiDispatcher PImpl.
**
** @todo 1/2017 find a solution for passing diff messages /////////////////////////////////////////////////TICKET #1066
**
** @see ui-dispatcher.hpp
**
*/
@ -50,7 +48,7 @@
#include "gui/ctrl/ui-manager.hpp"
#include "gui/ctrl/ui-dispatcher.hpp"
#include "gui/notification-service.hpp"
#include "lib/diff/diff-message.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/diff/gen-node.hpp"
#include "include/logging.h"
#include "lib/util.hpp"
@ -64,7 +62,7 @@ extern "C" {
using lib::diff::GenNode;
using lib::diff::TreeMutator;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
using gui::ctrl::UiDispatcher;
using gui::ctrl::BusTerm;
using std::string;
@ -111,7 +109,7 @@ namespace gui {
void
NotificationService::mutate (ID uiElement, DiffMessage&& diff)
NotificationService::mutate (ID uiElement, MutationMessage&& diff)
{
dispatch_->event ([=]() //////////////////////////////////TODO care for error handling!!!
{
@ -250,7 +248,7 @@ namespace gui {
{
if (!_instance) lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, "passing diff message");
else
_instance->mutate (reinterpret_cast<ID> (*element), move(*reinterpret_cast<DiffMessage*> (diff)));
_instance->mutate (reinterpret_cast<ID> (*element), move(*reinterpret_cast<MutationMessage*> (diff)));
}
)
, LUMIERA_INTERFACE_INLINE (triggerGuiShutdown,

View file

@ -83,7 +83,7 @@ namespace gui {
void displayInfo (NotifyLevel,string const& text) override;
void markError (ID uiElement, string const& text) override;
void markNote (ID uiElement, string const& text) override;
void mutate (ID uiElement, DiffMessage&&) override; ////////////////////////////////////////TICKET #1066 : how to pass a diff message
void mutate (ID uiElement, MutationMessage&&) override;
void triggerGuiShutdown (string const& cause) override;
private:

View file

@ -208,7 +208,7 @@ namespace ctrl {
* which consequently will reshape and remould itself accordingly.
*/
bool
BusTerm::change (ID subject, DiffMessage&& diff)
BusTerm::change (ID subject, MutationMessage&& diff)
{
return theBus_.change(subject, move(diff));
}

View file

@ -44,7 +44,7 @@
#ifdef __cplusplus /* ============== C++ Interface ================= */
#include "include/interfaceproxy.hpp"
#include "lib/diff/diff-message.hpp" ///////////////////////////////////////////////////////////STICKET #1066 : placeholder
#include "lib/diff/mutation-message.hpp"
#include "lib/idi/entry-id.hpp"
#include <string>
@ -53,7 +53,7 @@
namespace gui {
using std::string;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
using ID = lib::idi::BareEntryID const&;
@ -98,7 +98,7 @@ namespace gui {
* the UI model elements subject to this change.
* @see diff-language.hpp
*/
virtual void mutate (ID uiElement, DiffMessage&&) =0; /////////////////////////////////////TICKET #1066 : how to pass a diff message
virtual void mutate (ID uiElement, MutationMessage&&) =0;
/** causes the GUI to shut down unconditionally
* @param cause user visible explanation of the

View file

@ -25,14 +25,14 @@
** Generic building block for tree shaped (meta)data structures.
** A representation built from GenNode elements is intended to support
** (limited) introspection of data structures and exchange of mutations
** in the form of \link diff-language.hpp diff messages. \endlink
** in the form of [diff messages](\ref diff-language.hpp).
**
** Despite of the name, GenNode is \em not meant to be an universal
** data representation; rather it is limited to embody a fixed hard
** wired set of data types, able to stand-in for attributes
** and sub scope contents of the lumiera high-level data model.
**
** \par Anatomy of a GenNode
** # Anatomy of a GenNode
**
** GenNode is a polymorphic value with well defined identity and type.
** Each element is conceived to be »unique within context« -- as defined
@ -52,7 +52,7 @@
** addressable by-name and an (ordered) collection of elements treated
** as children within the scope of the given record.
**
** \par Requirements
** # Requirements
**
** GenNode elements are to be used in the diff detection and implementation.
** This implies some requirements for the (opaque) elements used in diff:
@ -68,7 +68,7 @@
** - finally, the handling of changes prompts us to support installation
** of a specifically typed <i>change handling closure</i>.
**
** \par monadic nature?
** ## monadic nature?
**
** As suggested by the usage for representation of tree shaped data, we acknowledge
** that GenNode could be a Monad. We support the basic operation \em construction,

View file

@ -1,5 +1,5 @@
/*
DIFF-MESSAGE.hpp - message to cause changes to generic model elements
MUTATION-MESSAGE.hpp - message to cause changes to generic model elements
Copyright (C) Lumiera.org
2017, Hermann Vosseler <Ichthyostega@web.de>
@ -87,8 +87,8 @@
*/
#ifndef LIB_DIFF_DIFF_MESSAGE_H
#define LIB_DIFF_DIFF_MESSAGE_H
#ifndef LIB_DIFF_MUTATION_MESSAGE_H
#define LIB_DIFF_MUTATION_MESSAGE_H
#include "lib/error.hpp"
@ -130,26 +130,26 @@ namespace diff{
* the production context of diff messages need to be conserved beyond the producer's
* thread context, because it will be pulled asynchronous from within the UI event thread!
*/
struct DiffMessage
struct MutationMessage
: DiffSource::iterator
{
using _FrontEnd = DiffSource::iterator;
DiffMessage() = default;
DiffMessage(DiffMessage&&) = default;
DiffMessage(DiffMessage const&) = default;
DiffMessage(DiffMessage& o) : DiffMessage((DiffMessage const&)o) { }
DiffMessage& operator= (DiffMessage const&) = default;
DiffMessage& operator= (DiffMessage &&) = default;
////////////////////////TICKET #963 Forwarding shadows copy operations
MutationMessage() = default;
MutationMessage(MutationMessage&&) = default;
MutationMessage(MutationMessage const&) = default;
MutationMessage(MutationMessage& o) : MutationMessage((MutationMessage const&)o) { }
MutationMessage& operator= (MutationMessage const&) = default;
MutationMessage& operator= (MutationMessage &&) = default;
////////////////////////TICKET #963 Forwarding shadows copy operations
/**
* DiffMessage builder:
* MutationMessage builder:
* take ownership of an opaque heap allocated context
* from which the concrete diff can be pulled on demand
*/
explicit
DiffMessage(DiffSource* diffGenerationContext)
MutationMessage(DiffSource* diffGenerationContext)
: _FrontEnd{DiffSource::build (diffGenerationContext)}
{ }
@ -158,8 +158,8 @@ namespace diff{
* @note initialiser elements will be _copied_ into a _heap alloacated_
* snapshot (vector), which is then managed by `shared_ptr`
*/
DiffMessage(std::initializer_list<DiffStep> const&& ili)
: DiffMessage{iter_stl::snapshot (move(ili))}
MutationMessage(std::initializer_list<DiffStep> const&& ili)
: MutationMessage{iter_stl::snapshot (move(ili))}
{ }
/**
@ -168,8 +168,8 @@ namespace diff{
* a _heap allocated snapshot_
*/
template<typename...ARGS>
DiffMessage(ARGS&& ...args)
: DiffMessage{ {std::forward<ARGS>(args)...} }
MutationMessage(ARGS&& ...args)
: MutationMessage{ {std::forward<ARGS>(args)...} }
{ }
/**
@ -177,7 +177,7 @@ namespace diff{
* @note source iterator is copied into a heap allocated IterSource
*/
template<class IT>
DiffMessage(IT&& ii, enable_if< can_IterForEach<IT>, void*> =nullptr)
MutationMessage(IT&& ii, enable_if< can_IterForEach<IT>, void*> =nullptr)
: _FrontEnd{iter_source::wrapIter (std::forward<IT>(ii))}
{ }
@ -187,7 +187,7 @@ namespace diff{
* @warning like with any classical iterators, the container must stay alive and accessible
*/
template<class CON>
DiffMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON>
MutationMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON>
,__not_<can_IterForEach<CON>>>, void*> =nullptr)
: _FrontEnd{iter_source::eachEntry(container)}
{ }
@ -196,11 +196,11 @@ namespace diff{
/**
* enable support to show content of the message.
* After calling this function, operator string() renders all DiffSteps
* @warning since by design a DiffMessage can only be ``pulled'' once,
* @warning since by design a MutationMessage can only be ``pulled'' once,
* this operation needs to impose a _side effect:_ it materialises
* the complete diff sequence at once into a heap allocated buffer.
*/
DiffMessage& updateDiagnostics();
MutationMessage& updateDiagnostics();
};
@ -211,7 +211,7 @@ namespace diff{
struct DiffSnapshot
: std::vector<DiffStep>
{
DiffSnapshot(DiffMessage& srcMsg)
DiffSnapshot(MutationMessage& srcMsg)
{
for ( ; srcMsg; ++srcMsg )
push_back (*srcMsg);
@ -223,7 +223,7 @@ namespace diff{
using _Wrapped = WrappedLumieraIter<_RangeIT>;
/**
* Decorator to be layered transparently on top of DiffMessage.
* Decorator to be layered transparently on top of MutationMessage.
* Actually, what we do is to discharge the diff generator into
* the DiffSnapshot buffer and then replace the link to the original
* generator to this decorator, which, when iterated, yields the
@ -231,12 +231,12 @@ namespace diff{
* are now stored into that DiffSnapshot _buffer we control,_ we're
* able to produce a diagnostic listing of the complete sequence.
*/
class MaterialisedDiffMessageBuffer
class MaterialisedDiffBuffer
: private DiffSnapshot
, public _Wrapped
{
public:
MaterialisedDiffMessageBuffer(DiffMessage& srcMsg)
MaterialisedDiffBuffer(MutationMessage& srcMsg)
: DiffSnapshot{srcMsg}
, _Wrapped{_RangeIT{DiffSnapshot::begin(), DiffSnapshot::end()}}
{ }
@ -259,10 +259,10 @@ namespace diff{
* process can be repeated and then the [diagnostics](operator string())
* will show the remainder of the sequence _left at that point._
*/
inline DiffMessage&
DiffMessage::updateDiagnostics()
inline MutationMessage&
MutationMessage::updateDiagnostics()
{
return *this = DiffMessage{new MaterialisedDiffMessageBuffer(*this)};
return *this = MutationMessage{new MaterialisedDiffBuffer(*this)};
}
@ -270,4 +270,4 @@ namespace diff{
}} // namespace lib::diff
#endif /*LIB_DIFF_DIFF_MESSAGE_H*/
#endif /*LIB_DIFF_MUTATION_MESSAGE_H*/

View file

@ -26,13 +26,12 @@
** To be used in a context where introspection, open, extensible definitions
** and loose coupling of data representation matters. Typically, structures
** defined in terms of Record elements are linked to the actual \em core
** representation of the same entities relying on
** \link diff-language.hpp diff messages. \endlink
** representation of the same entities relying on [diff messages](\ref diff-language.hpp).
** Record is one of the supported flavours within the DataCap of GenNode elements,
** which in turn serve as the standard handle to refer to other elements, entities,
** attributes or references within the "backbone" of the Lumiera GUI.
**
** \par design decisions
** ## design decisions
** The Record type is shaped from its intended use: It serves to symbolically represent
** \em objects in the "external tree description". Here, \em objects means objects for
** real, i.e. with types, fields and an enclosed scope. But \em external means that we

View file

@ -69,7 +69,7 @@
** it depends on the concrete setup of the data binding (TreeMutator), if some
** expression in diff language will be deemed incompatible -- which happens when
** in the end no "onion layer" of the concrete binding was able to absorb and
** comply to the diff message.
** comply to the MutationMessage.
**
** Another architectural consideration is relevant to the way attribute bindings are
** constructed: we rather construct a separate binding for each individual attribute,

View file

@ -66,11 +66,11 @@
** just supporting move construction, as will happen when using the DSL functions on
** the builder. This is also the only supported usage pattern: you create an anonymous
** TreeMutator sub type by using the Builder functions right within the scope about to
** consume one strike of diff messages. These messages should cover anything to confirm
** or reshape _all of the target's contents_. After that, you must not refer to the
** exhausted TreeMutator anymore, just let it fall out of scope. Incidentally, this
** also means that _any failure or exception encountered_ while applying a diff will
** leave a **corrupted target data structure**. The basic assumption is that
** consume one strike of DiffStep entries from a MutationMessage. These diff steps
** should cover anything to confirm or reshape _all of the target's contents_. After that,
** you must not refer to the exhausted TreeMutator anymore, just let it fall out of scope.
** Incidentally, this also means that _any failure or exception encountered_ while applying
** a diff will leave a **corrupted target data structure**. The basic assumption is that
** - the target data structure will actually be built through diff messages solely
** - and that all received diff messages are sane, as being drawn from a
** semantically and structurally equivalent source structure
@ -426,7 +426,7 @@ namespace diff{
/** set up binding to a GenNode tree: Special setup to build a concrete `TreeMutator`.
* This decorator is already outfitted with the necessary closures to work on a
* diff::Record<GenNode> -- which is typically used as "meta representation" of
* object-like structures. Thus this binding allows to apply a diff message onto
* object-like structures. Thus this binding allows to apply a MutationMessage onto
* such a given »External Tree Description«, mutating it into new shape.
* @remarks our meta representation of "objects" is based on Record<GenNode>, which
* is implemented through two STL collections, one for the attributes and

View file

@ -25,8 +25,3 @@ END
PLANNED "Concept demonstration: retrieve session contents" SessionStructureMapping_test <<END
return: 0
END
PLANNED "Concept demonstration: update hierarchical elements" TangibleUpdate_test <<END
return: 0
END

View file

@ -52,7 +52,7 @@
#include "lib/idi/genfunc.hpp"
#include "lib/idi/entry-id.hpp"
#include "proc/control/command-def.hpp"
#include "lib/diff/diff-message.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/diff/tree-diff.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/format-cout.hpp"
@ -74,7 +74,7 @@ using lib::diff::Rec;
using lib::diff::MakeRec;
using lib::diff::GenNode;
using lib::diff::DataCap;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
using proc::control::Command;
using proc::control::CommandDef;
@ -151,7 +151,7 @@ namespace test {
* - state mark replay
* - message casting
* - error state indication
* - structural changes by diff message
* - structural changes by MutationMessage
*
* This test documents a generic interaction protocol supported by all
* "tangible" elements of the Lumiera GTK UI. This works by connecting any
@ -549,7 +549,7 @@ namespace test {
/** @test mutate the mock element through diff messages
* This test performs the basic mechanism used to populate the UI
* or to change structure or settings within individual elements.
* This is done by sending a »Diff Message« via UI-Bus, which is
* This is done by sending a MutationMessage via UI-Bus, which is
* handled and applied to the receiver by Lumiera's diff framework.
*
* This test uses the MockElem to simulate real UI elements;
@ -571,7 +571,7 @@ namespace test {
* Here in this test case, we use a hard wired diff sequence,
* so we can check the expected structural changes actually took place.
*
* @see DiffMessage_test
* @see MutationMessage_test
*/
void
mutate ()
@ -601,14 +601,14 @@ namespace test {
{
using lib::diff::Ref;
return DiffMessage{ after(Ref::ATTRIBS) // start after the existing attributes (of root)
, ins(CHILD_1) // insert first child (with name "a")
, ins(CHILD_2) // insert second child (with name "b")
, set(ATTRIB_AL) // assign a new value to attribute "α" <- "quadrant"
, mut(CHILD_2) // open nested scope of child "b" for recursive mutation
, ins(ATTRIB_PI) // ..within nested scope, add a new attribute "π" := 3.14159265
, emu(CHILD_2) // leave nested scope
};
return MutationMessage{ after(Ref::ATTRIBS) // start after the existing attributes (of root)
, ins(CHILD_1) // insert first child (with name "a")
, ins(CHILD_2) // insert second child (with name "b")
, set(ATTRIB_AL) // assign a new value to attribute "α" <- "quadrant"
, mut(CHILD_2) // open nested scope of child "b" for recursive mutation
, ins(ATTRIB_PI) // ..within nested scope, add a new attribute "π" := 3.14159265
, emu(CHILD_2) // leave nested scope
};
}
}
diffSrc;

View file

@ -36,7 +36,7 @@
#include "test/test-nexus.hpp"
#include "test/mock-elm.hpp"
#include "lib/diff/gen-node.hpp"
#include "lib/diff/diff-message.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/idi/entry-id.hpp"
#include "lib/iter-adapter-stl.hpp"
#include "lib/iter-stack.hpp"
@ -73,7 +73,7 @@ namespace test {
using gui::ctrl::StateManager;
using gui::ctrl::BusTerm;
using gui::test::MockElm;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
using lib::diff::TreeDiffLanguage;
using lib::diff::DiffSource;
using lib::diff::DiffStep;
@ -705,7 +705,7 @@ namespace test {
uiDispatcher.feed ([&, diffGenerator]()
{
// apply and consume diff message stored within closure
uiBus.change (rootID, DiffMessage{diffGenerator});
uiBus.change (rootID, MutationMessage{diffGenerator});
});
};

View file

@ -1,105 +0,0 @@
/*
TangibleUpdate(Test) - how to update nested tangible UI elements
Copyright (C) Lumiera.org
2015, 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 tangible-update-test.cpp
** This test is a concept study regarding a generic structure of UI elements.
** Such gui::model::Tangible elements share the ability to be updated through
** a structural diff message. Which implies this test to be also an integration
** test of Lumiera's tree diff handling framework
**
** @note as of 1/2015 this is a draft into the blue...
** @todo WIP ///////////////////////TICKET #959
** @todo WIP ///////////////////////TICKET #961
**
** @see gui::UiBus
**
*/
#include "lib/test/run.hpp"
//#include "gui/model/session-facade.hpp"
//#include "gui/model/diagnostics.hpp"
//#include "lib/util.hpp"
//#include <string>
//using util::contains;
//using std::string;
namespace gui {
namespace model{
namespace test {
namespace { // test fixture...
}//(End) test fixture
/***********************************************************************//**
* @test demonstrate the fundamental patterns to access the current
* session structure and contents from the GUI, and to receive
* a notification with the updated structure and contents.
* - since we focus on the mapping and enumeration mechanism,
* the explored content is faked diagnostic data
* - in reality, these operations are intended to be run from
* within the GUI event thread and immediately interwoven
* with GTK / Cairo display code
* - it is the responsibility of the "Gui Model" (#SessionFacade)
* to ensure a read barrier, so the retrieved data can not be
* corrupted by concurrent session mutation operations.
*
* @see SessionElementQuery_test
* @see gui::model::SessionFacade
*/
class TangibleUpdate_test : public Test
{
virtual void
run (Arg)
{
}
/** @test how to retrieve and enumerate session contents
* as operation initiated from GUI display code
*/
void
retrieveSessionStructure ()
{
}
};
/** Register this test class... */
LAUNCHER (TangibleUpdate_test, "unit gui");
}}} // namespace gui::model::test

View file

@ -51,7 +51,7 @@
#include "proc/control/command.hpp"
#include "gui/ctrl/nexus.hpp"
#include "gui/ctrl/state-recorder.hpp"
#include "lib/diff/diff-message.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/diff/gen-node.hpp"
#include "lib/idi/entry-id.hpp"
#include "lib/idi/genfunc.hpp"
@ -70,7 +70,7 @@ using lib::transformIterator;
using lib::diff::Rec;
using lib::diff::GenNode;
using lib::diff::DataCap;
using lib::diff::DiffMessage;
using lib::diff::MutationMessage;
using lib::idi::instanceTypeID;
using lib::test::EventLog;
using gui::ctrl::BusTerm;
@ -156,7 +156,7 @@ namespace test{
}
virtual bool
change (ID subject, DiffMessage&& diff) override
change (ID subject, MutationMessage&& diff) override
{
string diffSeqLog = diff.updateDiagnostics(); // snapshot of generated diff sequence
log_.call (this, "change", subject, diffSeqLog);
@ -307,7 +307,7 @@ namespace test{
}
virtual bool
change (ID subject, DiffMessage&& diff) override
change (ID subject, MutationMessage&& diff) override
{
log().call(this, "change", subject, diff);
log().error ("request to apply a diff message via ZombieNexus");

View file

@ -96,8 +96,8 @@ namespace test{
* [variant data node](\ref diff::GenNode). The key point to note
* is the usage of Record elements as payload within GenNode, which
* allows to represent tree shaped object like data structures.
* @note literally the same test case is repeated in DiffMessage_test,
* just there the diff is transported in a DiffMessage capsule,
* @note literally the same test case is repeated in MutationMessage_test,
* just there the diff is transported in a MutationMessage capsule,
* as is the case in the real application as well.
* @see DiffComplexApplication_test handling arbitrary data structures
* @see GenericRecordRepresentation_test

View file

@ -1,5 +1,5 @@
/*
DiffMessage(Test) - demonstrate the basics of tree diff representation
MutationMessage(Test) - demonstrate the basics of tree diff representation
Copyright (C) Lumiera.org
2017, Hermann Vosseler <Ichthyostega@web.de>
@ -20,14 +20,14 @@
* *****************************************************/
/** @file diff-message-test.cpp
** unit test \ref DiffMessage_test
/** @file mutation-message-test.cpp
** unit test \ref MutationMessage_test
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/diff/diff-message.hpp"
#include "lib/diff/mutation-message.hpp"
#include "lib/diff/tree-diff-application.hpp"
#include "lib/iter-adapter-stl.hpp"
#include "lib/time/timevalue.hpp"
@ -94,7 +94,7 @@ namespace test{
* - moreover we provide a simplified builder function to create
* hard wired diff messages in a concise way
* - and finally this test repeats the scenario of DiffTreeApplication_test,
* but this time the diff sequences are encapsulated as DiffMessage.
* but this time the diff sequences are encapsulated as MutationMessage.
* @remarks like all the other _diff related_ tests, this code might be hard
* to follow, unless you're familiar with the underlying concepts. Basically,
* a _Diff_ is represented as _a linearised sequence of verb tokens_. Together
@ -112,10 +112,10 @@ namespace test{
* @see DiffTreeApplication_test change a tree-like data structure by diff
* @see DiffComplexApplication_test handling arbitrary data structures
* @see DiffListApplication_test
* @see DiffMessage
* @see MutationMessage
* @see ui-bus.hpp
*/
class DiffMessage_test
class MutationMessage_test
: public Test
, TreeDiffLanguage
{
@ -163,7 +163,7 @@ namespace test{
CHECK (0 == instances);
{
DiffMessage diffMsg{new Generator};
MutationMessage diffMsg{new Generator};
CHECK (!isnil (diffMsg));
CHECK (1 == instances);
@ -186,7 +186,7 @@ namespace test{
// cloning is allowed, yet implementation defined
// in the actual case the underlying generator is based on a vector + a pointer
// and thus the full state can be cloned into an independent instance
DiffMessage clone{diffMsg};
MutationMessage clone{diffMsg};
CHECK (clone == diffMsg);
CHECK (set(ATTRIB1) == *clone);
@ -210,7 +210,7 @@ namespace test{
// So better don't do this at home...
VERIFY_ERROR(ITER_EXHAUST, *diffMsg);
clone = DiffMessage{new Generator};
clone = MutationMessage{new Generator};
CHECK (2 == instances); // now we got two independent generator instances
CHECK (clone);
CHECK (ins(TYPE_X) == *clone);
@ -228,9 +228,9 @@ namespace test{
void
verify_builder()
{
DiffMessage diffMsg{ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)};
MutationMessage diffMsg{ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)};
CHECK (!isnil (diffMsg));
CHECK (ins(TYPE_X) == *diffMsg);
@ -242,10 +242,10 @@ namespace test{
// likewise works with a std::initializer_list
diffMsg = DiffMessage{{ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)}
};
diffMsg = MutationMessage{{ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)}
};
CHECK (!isnil (diffMsg));
CHECK (ins(TYPE_X) == *diffMsg);
@ -256,10 +256,10 @@ namespace test{
// even passing any suitable iterable works
diffMsg = DiffMessage{snapshot({ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)})
};
diffMsg = MutationMessage{snapshot({ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)})
};
CHECK (!isnil (diffMsg));
CHECK (ins(TYPE_X) == *diffMsg);
@ -276,7 +276,7 @@ namespace test{
,set(ATTRIB1)
,del(CHILD_T)}), steps);
diffMsg = DiffMessage{steps};
diffMsg = MutationMessage{steps};
CHECK (!isnil (diffMsg));
CHECK (ins(TYPE_X) == *diffMsg);
@ -289,9 +289,9 @@ namespace test{
void
verify_diagnostics()
{
DiffMessage diffMsg{ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)};
MutationMessage diffMsg{ins(TYPE_X)
,set(ATTRIB1)
,del(CHILD_T)};
// initially only the default diagnostics of IterSource is shown (rendering the element type)
CHECK (string(diffMsg) == "IterSource<DiffLanguage<TreeDiffInterpreter, GenNode>::DiffStep>");
@ -328,7 +328,7 @@ namespace test{
DiffMessage
MutationMessage
populationDiff()
{
return { ins(TYPE_X)
@ -347,7 +347,7 @@ namespace test{
}
DiffMessage
MutationMessage
mutationDiff()
{
// prepare for direct assignment of new value
@ -382,7 +382,7 @@ namespace test{
};
}
/** @test use DiffMessage to transport and apply changes to target data
/** @test use MutationMessage to transport and apply changes to target data
* @remarks this almost literally repeats the DiffTreeApplication_test */
void
demonstrate_treeApplication()
@ -435,7 +435,7 @@ namespace test{
/** Register this test class... */
LAUNCHER (DiffMessage_test, "unit common");
LAUNCHER (MutationMessage_test, "unit common");

View file

@ -866,21 +866,29 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1484797822403" ID="ID_364545191" MODIFIED="1502403195803" TEXT="Diff">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502401930856" ID="ID_634125084" MODIFIED="1502411444653" TEXT="#1066 concept how to hand over diff messages">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502410099141" ID="ID_1388523431" MODIFIED="1502410145757" TEXT="unn&#xf6;tig: zwei Abstraktions-Typen">
<node CREATED="1484797822403" ID="ID_364545191" MODIFIED="1502600252607" TEXT="Diff">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1502401930856" FOLDED="true" ID="ID_634125084" MODIFIED="1502600187137" TEXT="#1066 concept how to hand over diff messages">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502410099141" ID="ID_1388523431" MODIFIED="1502600145767" TEXT="unn&#xf6;tig: zwei Abstraktions-Typen">
<icon BUILTIN="stop-sign"/>
<node CREATED="1502410126058" ID="ID_30550435" MODIFIED="1502410130301" TEXT="MutationMessage"/>
<node CREATED="1502410130889" ID="ID_1402431306" MODIFIED="1502410134844" TEXT="DiffMessage"/>
<node CREATED="1502410126058" ID="ID_30550435" MODIFIED="1502600145767" TEXT="MutationMessage"/>
<node CREATED="1502410130889" ID="ID_1402431306" MODIFIED="1502600145767" TEXT="DiffMessage"/>
</node>
<node CREATED="1502410149463" ID="ID_1909971032" MODIFIED="1502410164196" TEXT="Entscheidung f&#xfc;r DiffMessage">
<icon BUILTIN="help"/>
<node CREATED="1502410149463" FOLDED="true" ID="ID_1909971032" MODIFIED="1502600145767" TEXT="Entscheidung f&#xfc;r DiffMessage">
<icon BUILTIN="yes"/>
<node CREATED="1502599977964" ID="ID_249258988" MODIFIED="1502599992798" TEXT="ist das bessere Konzept"/>
<node CREATED="1502599993338" ID="ID_1306432135" MODIFIED="1502600003260" TEXT="abstrahierter Iterator">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502410165980" ID="ID_1450795292" MODIFIED="1502410361731" TEXT="MutationMessage entfernen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1502410176619" ID="ID_1188430411" MODIFIED="1502410189933" TEXT="AbstractTangible_test umschreiben"/>
<node CREATED="1502410190737" ID="ID_1036564813" MODIFIED="1502410317567" TEXT="operator string() in DiffMessage &#xfc;bernehmen">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502600004168" ID="ID_1865027243" MODIFIED="1502600026244" TEXT="aber Name &#xbb;MutationMessage&#xab; beibehalten">
<icon BUILTIN="yes"/>
</node>
</node>
<node COLOR="#338800" CREATED="1502410165980" ID="ID_1450795292" MODIFIED="1502600145767" TEXT="MutationMessage entfernen">
<icon BUILTIN="button_ok"/>
<node CREATED="1502410176619" ID="ID_1188430411" MODIFIED="1502600145767" TEXT="AbstractTangible_test umschreiben"/>
<node CREATED="1502410190737" ID="ID_1036564813" MODIFIED="1502600145767" TEXT="operator string() in DiffMessage &#xfc;bernehmen">
<richcontent TYPE="NOTE"><html>
<head>
@ -902,8 +910,8 @@
</richcontent>
<icon BUILTIN="help"/>
</node>
<node CREATED="1502410328279" ID="ID_1577461232" MODIFIED="1502410347776" TEXT="Tree-Diff-Aplikator direkt in Nexus verschieben"/>
<node CREATED="1502410351284" ID="ID_845679527" MODIFIED="1502410355455" TEXT="BusTerm-API &#xe4;ndern"/>
<node CREATED="1502410328279" ID="ID_1577461232" MODIFIED="1502600145767" TEXT="Tree-Diff-Aplikator direkt in Nexus verschieben"/>
<node CREATED="1502410351284" ID="ID_845679527" MODIFIED="1502600145767" TEXT="BusTerm-API &#xe4;ndern"/>
</node>
</node>
<node CREATED="1484799660822" ID="ID_1288003894" MODIFIED="1502410724019" TEXT="TreeMutator binden">
@ -920,7 +928,7 @@
<node CREATED="1502454601603" ID="ID_384770680" MODIFIED="1502454613220" TEXT="nein: MutationMessage wird &#xfc;berfl&#xfc;ssig">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1502401987033" ID="ID_1584846573" MODIFIED="1502454045750" TEXT="erfordert Festlegung der Natur der DiffMessage">
<node CREATED="1502401987033" ID="ID_1584846573" MODIFIED="1502600092049" TEXT="erfordert Festlegung der Natur der Diff Message">
<arrowlink COLOR="#bdbad3" DESTINATION="ID_89098030" ENDARROW="Default" ENDINCLINATION="821;-1406;" ID="Arrow_ID_554743885" STARTARROW="None" STARTINCLINATION="1459;870;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1502402004383" ID="ID_1491065212" MODIFIED="1502403195803" TEXT="generisch bleiben?">
@ -1037,7 +1045,7 @@
</node>
</node>
</node>
<node CREATED="1502403145431" ID="ID_636092614" MODIFIED="1502403225069" TEXT="DiffMessage ist selber der Iterator">
<node CREATED="1502403145431" ID="ID_636092614" MODIFIED="1502600122305" TEXT="DiffMessage ist selber der Iterator">
<arrowlink COLOR="#2579a2" DESTINATION="ID_1846096533" ENDARROW="Default" ENDINCLINATION="-5;149;" ID="Arrow_ID_896931950" STARTARROW="None" STARTINCLINATION="158;5;"/>
<icon BUILTIN="idea"/>
</node>
@ -1082,8 +1090,8 @@
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502459141531" ID="ID_301431029" MODIFIED="1502459212307" TEXT="Refactoring">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1502459141531" FOLDED="true" ID="ID_301431029" MODIFIED="1502600205239" TEXT="Refactoring">
<icon BUILTIN="button_ok"/>
<node CREATED="1502459182214" ID="ID_1601884743" MODIFIED="1502459221104" TEXT="MutationMessage wird &#xfc;berfl&#xfc;ssig">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="yes"/>
@ -1091,8 +1099,8 @@
<node CREATED="1502459190477" ID="ID_102437369" MODIFIED="1502459223854" TEXT="DiffMessage &#xfc;bernimmt deren Rolle">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1502459198611" ID="ID_1739527989" MODIFIED="1502459229225" TEXT="aber DiffMessage wird umbenannt in MutationMessage">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1502459198611" ID="ID_1739527989" MODIFIED="1502600170050" TEXT="aber DiffMessage wird umbenannt in MutationMessage">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -1302,8 +1310,8 @@
</node>
</node>
</node>
<node CREATED="1501939193031" HGAP="3" ID="ID_1045913810" MODIFIED="1501939200829" TEXT="Test" VSHIFT="20">
<icon BUILTIN="pencil"/>
<node CREATED="1501939193031" HGAP="3" ID="ID_1045913810" MODIFIED="1502600236002" TEXT="Test" VSHIFT="20">
<icon BUILTIN="bell"/>
<node COLOR="#338800" CREATED="1501939204166" ID="ID_383444966" MODIFIED="1502075950777" TEXT="CallQueue_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1501946847700" ID="ID_1917302142" MODIFIED="1501951434466" TEXT="basic">
@ -10870,7 +10878,7 @@
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1473352396906" FOLDED="true" HGAP="-48" ID="ID_392196966" MODIFIED="1502594174004" TEXT="Integration" VSHIFT="25">
<node COLOR="#338800" CREATED="1473352396906" FOLDED="true" HGAP="-48" ID="ID_392196966" MODIFIED="1502600276510" TEXT="Integration" VSHIFT="25">
<icon BUILTIN="button_ok"/>
<node CREATED="1473352465473" ID="ID_158999012" MODIFIED="1502453392316" TEXT="in Tangible">
<icon BUILTIN="button_ok"/>
@ -10956,7 +10964,7 @@
<node CREATED="1475342469085" ID="ID_218240539" MODIFIED="1475342487060" TEXT="Ausgangspunkt: DiffMutable">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1475342391631" ID="ID_1330153391" MODIFIED="1502550785252" TEXT="Transport per DiffMessage">
<node CREATED="1475342391631" ID="ID_1330153391" MODIFIED="1502599884276" TEXT="Transport per MutationMessage">
<icon BUILTIN="forward"/>
</node>
<node CREATED="1475342401278" ID="ID_1020722080" MODIFIED="1502453642509" TEXT="abstrakte Koppelung"/>
@ -11276,7 +11284,7 @@
<node COLOR="#338800" CREATED="1473352482502" ID="ID_1891838260" MODIFIED="1502593427480" TEXT="BusTerm_test">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1502453280050" ID="ID_60387485" MODIFIED="1502550710929" TEXT="DiffMessage_test">
<node COLOR="#338800" CREATED="1502453280050" ID="ID_60387485" MODIFIED="1502599865199" TEXT="MutationMessage_test">
<linktarget COLOR="#71e5ac" DESTINATION="ID_60387485" ENDARROW="Default" ENDINCLINATION="50;-12;" ID="Arrow_ID_1384671312" SOURCE="ID_667427572" STARTARROW="None" STARTINCLINATION="12;195;"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1502459245238" ID="ID_1193318639" MODIFIED="1502499469658" TEXT="Basisfall: Producer / Consumer">
@ -12023,7 +12031,7 @@
<arrowlink COLOR="#a9acc1" DESTINATION="ID_143203937" ENDARROW="Default" ENDINCLINATION="115;-2033;" ID="Arrow_ID_136706418" STARTARROW="None" STARTINCLINATION="1656;0;"/>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1502452875447" FOLDED="true" ID="ID_1363153586" MODIFIED="1502551001781" TEXT="DiffMessage">
<node CREATED="1502452875447" FOLDED="true" ID="ID_1363153586" MODIFIED="1502599790469" TEXT="MutationMessage">
<linktarget COLOR="#a7afc1" DESTINATION="ID_1363153586" ENDARROW="Default" ENDINCLINATION="931;-187;" ID="Arrow_ID_324877454" SOURCE="ID_336806935" STARTARROW="Default" STARTINCLINATION="835;592;"/>
<node CREATED="1502452903075" ID="ID_726723452" MODIFIED="1502453137630" TEXT="abstrahierter Iterator">
<node CREATED="1502453110640" ID="ID_1024081141" MODIFIED="1502453115659" TEXT="IterSource-Interface"/>
@ -14627,7 +14635,7 @@
<node CREATED="1448063874479" HGAP="43" ID="ID_739054690" MODIFIED="1481413149364" TEXT="UI-Modell" VSHIFT="1">
<icon BUILTIN="help"/>
</node>
<node CREATED="1434128074725" HGAP="28" ID="ID_933994138" MODIFIED="1488423307214" TEXT="Diff-System" VSHIFT="1">
<node CREATED="1434128074725" FOLDED="true" HGAP="28" ID="ID_933994138" MODIFIED="1502600324729" TEXT="Diff-System" VSHIFT="1">
<font NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="go"/>
<node CREATED="1434128278990" ID="ID_106354755" MODIFIED="1434128283641" TEXT="Diff-Darstellung"/>
@ -16723,7 +16731,7 @@
</node>
<node CREATED="1502452581379" HGAP="11" ID="ID_1651893758" MODIFIED="1502453059637" TEXT="Darstellung" VSHIFT="17">
<linktarget COLOR="#afb1bd" DESTINATION="ID_1651893758" ENDARROW="Default" ENDINCLINATION="-1257;0;" ID="Arrow_ID_1786455458" SOURCE="ID_1500100371" STARTARROW="None" STARTINCLINATION="1858;0;"/>
<node CREATED="1502452597604" FOLDED="true" ID="ID_172363215" MODIFIED="1502593538120" TEXT="DiffMessage">
<node CREATED="1502452597604" FOLDED="true" ID="ID_172363215" MODIFIED="1502599841674" TEXT="MutationMessage">
<icon BUILTIN="button_ok"/>
<node CREATED="1502454531772" ID="ID_445867436" MODIFIED="1502454536184" TEXT="abstrakter Iterator"/>
<node CREATED="1502454536636" ID="ID_643452930" MODIFIED="1502454542390" TEXT="opaque generation context"/>