From ac4f0bc6db4eff7c258fa23e45c2479e3d1f6c63 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 13 Apr 2018 02:39:46 +0200 Subject: [PATCH] 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. --- src/gui/ctrl/elem-access-dir.hpp | 1 + src/gui/model/element-access.hpp | 71 +++++++++++++++++++++----- tests/gui/ctrl/element-access-test.cpp | 9 +++- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/gui/ctrl/elem-access-dir.hpp b/src/gui/ctrl/elem-access-dir.hpp index 54f1c5028..c39028d65 100644 --- a/src/gui/ctrl/elem-access-dir.hpp +++ b/src/gui/ctrl/elem-access-dir.hpp @@ -58,6 +58,7 @@ namespace ctrl{ // using util::isnil; // using std::string; + using interact::UICoord; /** diff --git a/src/gui/model/element-access.hpp b/src/gui/model/element-access.hpp index 648341d97..fe7d00560 100644 --- a/src/gui/model/element-access.hpp +++ b/src/gui/model/element-access.hpp @@ -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 @@ -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 + struct TypeConverter; + }; + + + namespace { + using TypeSeq = Types; + + using lib::meta::Node; + using lib::meta::NullType; + + template + struct Identity + { + using Type = T; + }; + + template class _P_> + struct FirstMatching + { + static_assert(not sizeof(TYPES), "None of the possible Types fulfils the condition"); + }; + template class _P_> + struct FirstMatching, _P_> + : FirstMatching::List, _P_> + { }; + template class _P_> + struct FirstMatching, _P_> + : std::conditional_t<_P_::value, Identity, FirstMatching> + { }; + + } + template + struct ElementAccess::TypeConverter + : RawResult::Visitor + { + Result result; + + template + using canCast = std::is_convertible; + + using Base = typename FirstMatching::Type; + + void + accept (Base* pb) + { + if (pb) + result = *dynamic_cast (pb); + } }; @@ -145,21 +198,11 @@ namespace model { inline ElementAccess::Result ElementAccess::access_or_create (UICoord destination, size_t limitCreation) { - struct TypeConverter - : RawResult::Visitor - { - Result result; - - void accept (model::Tangible* t) { result = util::AccessCasted::access (t); } - void accept (Gtk::Widget* w) { result = util::AccessCasted::access (w); } - }; -///////////////////////////////////////////////////////////////////////////////////////////////////TODO Verdammter Mist!!!! es werden WIEDER beide Zweige compiliert, aber nur einer geht!!! + TypeConverter converter; RawResult targetElm = performAccessTo (destination, limitCreation); - if (targetElm.tangible) - return util::AccessCasted::access (targetElm.tangible); - else - if (targetElm.gtkWidget) - return util::AccessCasted::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); } diff --git a/tests/gui/ctrl/element-access-test.cpp b/tests/gui/ctrl/element-access-test.cpp index b8d98fcf2..acbba4cfb 100644 --- a/tests/gui/ctrl/element-access-test.cpp +++ b/tests/gui/ctrl/element-access-test.cpp @@ -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::value, "lalü"); AccessAPI accessAPI; auto answer = accessAPI().access (location);