/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2013 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLQt/src/ICLQt/DataStore.h ** ** Module : ICLQt ** ** Authors: Christof Elbrechter ** ** ** ** ** ** GNU LESSER GENERAL PUBLIC LICENSE ** ** This file may be used under the terms of the GNU Lesser General ** ** Public License version 3.0 as published by the ** ** ** ** Free Software Foundation and appearing in the file LICENSE.LGPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the license requirements will ** ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** ********************************************************************/ #pragma once #include #include #include #include #include #include namespace icl{ namespace qt{ /// Extension of the associative container MultiTypeMap \ingroup UNCOMMON /** Adds an index operator[string] for direct access to contained values */ class ICLQt_API DataStore : public utils::MultiTypeMap{ public: /// Internal Exception type thrown if operator[] is given an unknown index string struct KeyNotFoundException : public utils::ICLException{ KeyNotFoundException(const std::string &key):utils::ICLException("Key not found: " + key){} }; /// Internal Exception type thrown if Data::operator= is called for incompatible values struct UnassignableTypesException : public utils::ICLException{ UnassignableTypesException(const std::string &tSrc, const std::string &tDst): utils::ICLException("Unable to assign "+ tDst+ " = "+ tSrc){} }; /// Arbitrary Data encapsulation type class Data{ /// internally reference DataStore entry DataArray *data; /// Constructor (private->only the parent DataStore is allowed to contruct Data's) inline Data(DataArray *data):data(data){} /// This is the mighty and magic conversion function ICLQt_API static void assign(void *src, const std::string &srcType, void *dst, const std::string &dstType) throw (UnassignableTypesException); public: /// Internally used Data- Structure struct Event{ Event(const std::string &msg="", void *data=0):message(msg),data(data){} Event(const std::string &msg, const utils::Function &cb): message(msg),data(0),cb(cb){} Event(const std::string &msg, const utils::Function &cb2): message(msg),data(0),cb2(cb2){} std::string message; void *data; utils::Function cb; utils::Function cb2; }; friend class DataStore; /// Trys to assign an instance of T to this Data-Element /** This will only work, if the data types are assignable */ template inline void operator=(const T &t) throw (UnassignableTypesException){ assign(const_cast(reinterpret_cast(&t)), get_type_name(),data->data,data->type); } /// Trys to convert a Data element into a (by template parameter) given type /** this will only work, if the data element is convertable to the desired type. Otherwise an exception is thrown*/ template inline T as() const throw (UnassignableTypesException){ T t; assign(data->data,data->type,&t,get_type_name()); return t; } /// implicit conversion into l-value type (little dangerous) template operator T() const throw (UnassignableTypesException){ return as(); } /// returns the internal type ID (obtained by C++'s RTTI) const std::string &getTypeID() const { return data->type; } /** Currently supported for Data-types ImageHandle, DrawHandle, FPSHandle and PlotHandle */ void render() throw (UnassignableTypesException){ *this = Event("render"); } /// links DrawWidget3D and GLCallback void link(void *data) throw (UnassignableTypesException){ *this = Event("link", data); } /// data must be of type MouseHandler* void install(void *data){ *this = Event("install",data); } /// installs a function directly ICLQt_API void install(utils::Function f); // installs a global function (should be implicit) //void install(void (*f)(const MouseEvent &)){ // install(function(f)); //} /// register simple callback type void registerCallback(const utils::Function &cb){ *this = Event("register",cb); } /// register simple callback type void registerCallback(const utils::Function &cb){ *this = Event("register-complex",cb); } /// possible for all handle-types void enable(){ *this = Event("enable"); } /// possible for all handle types void disable(){ *this = Event("disable"); } }; /// Allows to assign new values to a entry with given key (*NEW*) /** The returned Data-Element is a shallow Reference of a DataStore entry of internal type DataArray. Each entry is typed by C++'s RTTI, so, the function can determine if the assigned value is compatible to actual type of the data element. Internally a magic assignment system is used to determine whether two types can be assigned, and what to do if. Basically one can say, type assignments line T = T are of course allowed as well as type assignments A = B, if A and B are C++ built-in numerical type (int, float, etc.) Additionally a lot of GUIHandle types (contained by a GUI's DataStore) can be assigned (and updated, see void DataStore::Data::update()) with this mechanism A detailed description of all allowed assigmnet must ba added here: TODO... Here are some examples ... \code DataStore x; x.allocValue("hello",int(5)); x.allocValue("world",float(5)); x.allocValue("!",std::string("yes yes!")); x["hello"] = "44"; // string to int x["world"] = 4; // int to float x["!"] = 44; // int to string x["hello"] = 44; // int to int x.allocValue("image",ImgHandle(...)); x["image"] = icl::create("parrot"); // ImgQ to ImageHandle x.allocValue("sl",SliderHandle(...)); x["sl"] = 7; // sets slider value to 7 std::cout << "slider val is:" << x["sl"].as() << std::endl; x["sl"] = Range32s(3,9); // sets slider's Range ... \endcode */ Data operator[](const std::string &key) throw (KeyNotFoundException); /// convenience function that allows collecting data from different source entries /** This function can e.g. be used to obtain data from an array of 'float' GUI components */ template std::vector collect(const std::vector &keys){ std::vector v(keys.size()); for(unsigned int i=0;i static inline void register_assignment_rule(const std::string &srcTypeName, const std::string &dstTypeName, utils::Function assign){ struct TypeDependentAssign : public Assign{ utils::Function assign; TypeDependentAssign(const std::string &srcTypeName, const std::string &dstTypeName, utils::Function assign): Assign(srcTypeName, dstType, get_type_name(), get_type_name()),assign(assign){} virtual bool operator()(void *src, void *dst){ assign( *(const SRC*)src, *(DST*)dst ); return true; } }; register_assignment_rule(new TypeDependentAssign(srcTypeName,dstTypeName,assign)); } /// registers trivial assignment rule to the DataStore class /** Trivial assignments are performed using dst = src */ template static inline void register_trivial_assignment_rule(const std::string &srcTypeName, const std::string &dstTypeName){ struct TypeDependentTrivialAssign : public Assign{ TypeDependentTrivialAssign(const std::string &srcTypeName, const std::string &dstTypeName): Assign(srcTypeName, dstTypeName, get_type_name(), get_type_name()){} virtual bool operator()(void *src, void *dst){ *(DST*)dst = *(const SRC*)src; return true; } }; register_assignment_rule(new TypeDependentTrivialAssign(srcTypeName,dstTypeName)); } }; } // namespace qt }