ElementAccess: possibly working solution based on lib::variant
With this solution, somewhere deep down within the implementation the knowledge about the actual result type would be encoded into the embedded VTable within a lib::variant. At interface level, ther will be a double dispatch based on that result type and the desired result type, leading either to a successful access or an error response.
This commit is contained in:
parent
35ea547fd1
commit
ac4f0bc6db
3 changed files with 66 additions and 15 deletions
|
|
@ -58,6 +58,7 @@ namespace ctrl{
|
|||
|
||||
// using util::isnil;
|
||||
// using std::string;
|
||||
using interact::UICoord;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -57,11 +57,13 @@
|
|||
#include "lib/result.hpp"
|
||||
#include "include/limits.h"
|
||||
#include "lib/variant.hpp"
|
||||
#include "lib/meta/typelist-manip.hpp"
|
||||
#include "lib/access-casted.hpp"
|
||||
#include "gui/interact/ui-coord.hpp"
|
||||
//#include "lib/format-string.hpp"
|
||||
//#include "lib/symbol.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/test/test-helper.hpp" ////////TOD-o
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -111,6 +113,57 @@ namespace model {
|
|||
|
||||
/** @internal drill down according to coordinates, maybe create element */
|
||||
virtual RawResult performAccessTo (UICoord, size_t limitCreation) =0;
|
||||
|
||||
private:
|
||||
template<class TAR>
|
||||
struct TypeConverter;
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
using TypeSeq = Types<model::Tangible*, Gtk::Widget*>;
|
||||
|
||||
using lib::meta::Node;
|
||||
using lib::meta::NullType;
|
||||
|
||||
template<typename T>
|
||||
struct Identity
|
||||
{
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
template<class TYPES, template<class> class _P_>
|
||||
struct FirstMatching
|
||||
{
|
||||
static_assert(not sizeof(TYPES), "None of the possible Types fulfils the condition");
|
||||
};
|
||||
template<class...TYPES, template<class> class _P_>
|
||||
struct FirstMatching<Types<TYPES...>, _P_>
|
||||
: FirstMatching<typename Types<TYPES...>::List, _P_>
|
||||
{ };
|
||||
template<class T, class TYPES, template<class> class _P_>
|
||||
struct FirstMatching<Node<T,TYPES>, _P_>
|
||||
: std::conditional_t<_P_<T>::value, Identity<T>, FirstMatching<TYPES, _P_>>
|
||||
{ };
|
||||
|
||||
}
|
||||
template<class TAR>
|
||||
struct ElementAccess::TypeConverter
|
||||
: RawResult::Visitor
|
||||
{
|
||||
Result<TAR&> result;
|
||||
|
||||
template<typename X>
|
||||
using canCast = std::is_convertible<TAR*, X>;
|
||||
|
||||
using Base = typename FirstMatching<TypeSeq, canCast>::Type;
|
||||
|
||||
void
|
||||
accept (Base* pb)
|
||||
{
|
||||
if (pb)
|
||||
result = *dynamic_cast<TAR*> (pb);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -145,21 +198,11 @@ namespace model {
|
|||
inline ElementAccess::Result<TAR&>
|
||||
ElementAccess::access_or_create (UICoord destination, size_t limitCreation)
|
||||
{
|
||||
struct TypeConverter
|
||||
: RawResult::Visitor
|
||||
{
|
||||
Result<TAR&> result;
|
||||
|
||||
void accept (model::Tangible* t) { result = util::AccessCasted<TAR&>::access (t); }
|
||||
void accept (Gtk::Widget* w) { result = util::AccessCasted<TAR&>::access (w); }
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////TODO Verdammter Mist!!!! es werden WIEDER beide Zweige compiliert, aber nur einer geht!!!
|
||||
TypeConverter<TAR> converter;
|
||||
RawResult targetElm = performAccessTo (destination, limitCreation);
|
||||
if (targetElm.tangible)
|
||||
return util::AccessCasted<TAR&>::access (targetElm.tangible);
|
||||
else
|
||||
if (targetElm.gtkWidget)
|
||||
return util::AccessCasted<TAR&>::access (targetElm.gtkWidget);
|
||||
targetElm.accept (converter);
|
||||
if (converter.result.isValid())
|
||||
return converter.result;
|
||||
else
|
||||
return "In current UI, there is no element at location "+string(destination);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
//#include "gui/interact/view-spec-dsl.hpp"
|
||||
#include "test/test-element-access.hpp"
|
||||
#include "gui/interact/ui-coord.hpp"
|
||||
#include "test/mock-elm.hpp"
|
||||
//#include "gen-node-location-query.hpp"
|
||||
#include "lib/depend-inject.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
|
|
@ -64,10 +65,13 @@ namespace test {
|
|||
namespace { //Test fixture...
|
||||
|
||||
class DummyWidget
|
||||
: util::NonCopyable
|
||||
: public gui::test::MockElm
|
||||
{
|
||||
protected:
|
||||
virtual ~DummyWidget() { } ///< is an interface
|
||||
DummyWidget()
|
||||
: MockElm("DummyWidget")
|
||||
{ }
|
||||
};
|
||||
|
||||
class DummyTab
|
||||
|
|
@ -120,6 +124,9 @@ namespace test {
|
|||
fakeDirectory->expectedQuery = location;
|
||||
fakeDirectory->expectedAnswer = &dummyTab;
|
||||
|
||||
DummyWidget* duf = &dummyTab;
|
||||
model::Tangible* luf{duf};
|
||||
static_assert (std::is_convertible<DummyWidget*, model::Tangible*>::value, "lalü");
|
||||
AccessAPI accessAPI;
|
||||
auto answer = accessAPI().access<DummyWidget> (location);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue