diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2014-05-15 14:52:31 +0200 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2014-05-15 14:52:31 +0200 |
| commit | 2f6c50d2764138583dcf89d86b13440a23f217cf (patch) | |
| tree | 08cc78ff875c1501375f7a28401da3b3fd327d82 | |
| parent | 6a1e6120c4efc46f1d192b0e5fabc06b780113cc (diff) | |
| download | generic-gui-2f6c50d2764138583dcf89d86b13440a23f217cf.tar.gz generic-gui-2f6c50d2764138583dcf89d86b13440a23f217cf.tar.bz2 generic-gui-2f6c50d2764138583dcf89d86b13440a23f217cf.zip | |
3 major changes.
Renamed fusion_model to FusionModel to follow the naming convention.
Added observers so models can be shared over views and update properly.
Constness in datastructure now makes the data uneditable.
| -rw-r--r-- | fusion_model.hpp | 43 | ||||
| -rw-r--r-- | fusion_static_dispatch.hpp | 79 | ||||
| -rw-r--r-- | main.cpp | 20 | ||||
| -rw-r--r-- | qt_adapter.hpp | 27 |
4 files changed, 117 insertions, 52 deletions
diff --git a/fusion_model.hpp b/fusion_model.hpp index 282be11..3d84c87 100644 --- a/fusion_model.hpp +++ b/fusion_model.hpp @@ -9,11 +9,19 @@ #include <vector> #include <map> +#include <memory> + +struct FusionModelObserver +{ + virtual void cell_changed(int row, int column) {} + + virtual void append_row_begin() {} + virtual void append_row_end() {} +}; template <typename T> -struct fusion_model { -private: - fusion_model(T); +struct FusionModel { + FusionModel(T) = delete; }; template <bool> @@ -56,10 +64,30 @@ struct FusionModelInterface : public FusionModelWithHeaderH<has_header_h>, publi virtual size_t column_count() const = 0; virtual boost::any get_cell(size_t row, size_t column) const = 0; virtual void set_cell(size_t row, size_t column, boost::any const& value) = 0; + + std::vector<std::weak_ptr<FusionModelObserver>> observers; + void add_observer(std::weak_ptr<FusionModelObserver> obs) + { + observers.push_back(obs); + } + + template <typename U, typename... Args> + void call_on_observers(U f, Args... arguments) + { + for(auto it = observers.begin(); it != observers.end(); ++it) + { + auto s = it->lock(); + if(s) { + ((*s).*f)(arguments...); + } else { + it = observers.erase(it); + } + } + } }; template <typename T> -struct fusion_model<std::vector<T>> : public FusionModelInterface<true, false> +struct FusionModel<std::vector<T>> : public FusionModelInterface<true, false> { static_assert(friendly_fusion::traits::is_sequence<T>::type::value, "T is not a boost fusion sequence"); @@ -68,7 +96,7 @@ struct fusion_model<std::vector<T>> : public FusionModelInterface<true, false> std::vector<T> data; - fusion_model() = default; + FusionModel() = default; virtual size_t row_count() const override final { @@ -93,11 +121,12 @@ struct fusion_model<std::vector<T>> : public FusionModelInterface<true, false> virtual void set_cell(size_t row, size_t column, boost::any const& value) override final { set_nth<row_type>(data[row], column, value); + call_on_observers(&FusionModelObserver::cell_changed, row, column); } }; template <typename T> -struct fusion_model<std::map<std::string, T>> : public FusionModelInterface<true, true> +struct FusionModel<std::map<std::string, T>> : public FusionModelInterface<true, true> { static_assert(boost::fusion::traits::is_sequence<T>::type::value, "T is not a boost fusion sequence"); @@ -106,7 +135,7 @@ struct fusion_model<std::map<std::string, T>> : public FusionModelInterface<true std::map<std::string, T> data; - fusion_model() = default; + FusionModel() = default; virtual size_t row_count() const override final { diff --git a/fusion_static_dispatch.hpp b/fusion_static_dispatch.hpp index ce81c90..9240cc2 100644 --- a/fusion_static_dispatch.hpp +++ b/fusion_static_dispatch.hpp @@ -6,8 +6,36 @@ #include <boost/any.hpp> #include <functional> +#include <iostream> + +template <typename T, int... Indices> +bool is_const_impl(int index, indices<Indices...>) +{ + typedef std::function<bool()> element_type; + static element_type table[] = { + [] { + typedef friendly_fusion::result_of::begin<T> begin; + typedef friendly_fusion::result_of::advance_c<typename begin::type, Indices> adv_it; + typedef friendly_fusion::result_of::deref<typename adv_it::type> deref; + typedef std::remove_reference<typename deref::type> unreferenced_type; + + return std::is_const<typename unreferenced_type::type>::value; + } + ... + }; + + return table[index](); +} + +template <typename T> +bool is_const(int index) +{ + typedef typename friendly_fusion::result_of::size<T>::type seq_size; + typedef typename build_indices<seq_size::value>::type indices_type; + + return is_const_impl<T>(index, indices_type{}); +} -#if defined( __GNUC__ ) && !defined( __clang__ ) template<int index, typename T> std::function<boost::any(T)> make_at_c_lambda(T seq) { @@ -15,7 +43,6 @@ std::function<boost::any(T)> make_at_c_lambda(T seq) return boost::any(friendly_fusion::deref(friendly_fusion::advance_c<index>(friendly_fusion::begin(seq)))); }; } -#endif //defined( __GNUC__ ) && !defined( __clang__ ) template<typename T, int... Indices> boost::any get_nth_impl(T seq, int index, indices<Indices...>) @@ -23,14 +50,8 @@ boost::any get_nth_impl(T seq, int index, indices<Indices...>) typedef std::function<boost::any(T)> element_type; static element_type table[] = { -#if defined( __GNUC__ ) && !defined( __clang__ ) - //Workaround for gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 make_at_c_lambda<Indices>(seq) ... -#else - [](T seq){return boost::any(friendly_fusion::deref(friendly_fusion::advance_c<Indices>(friendly_fusion::begin(seq))));} - ... -#endif //defined( __GNUC__ ) && !defined( __clang__ ) }; return table[index](seq); @@ -54,7 +75,20 @@ boost::any get_nth(T x, int index) return get_nth_functor<T>()(x, index); } -#if defined( __GNUC__ ) && !defined( __clang__ ) +template <bool b, typename T, typename V> +typename std::enable_if<b, void>::type assign(T&, V) +{ + //this function will never be called, but has to be defined. + //We need to generate a assign statement for all members at compile time even when they are const. + return; +} + +template <bool b, typename T, typename V> +typename std::enable_if<!b, void>::type assign(T& lh, V rh) +{ + lh = rh; +} + template<int index, typename T> std::function<void(T&, boost::any const&)> make_set_nth_lambda() { @@ -63,11 +97,11 @@ std::function<void(T&, boost::any const&)> make_set_nth_lambda() typedef friendly_fusion::result_of::advance_c<typename begin::type, index> adv_it; typedef friendly_fusion::result_of::deref<typename adv_it::type> deref; typedef typename std::decay<typename deref::type>::type value_type; + typedef typename std::remove_reference<typename deref::type>::type unreferenced_type; - friendly_fusion::deref(friendly_fusion::advance_c<index>(friendly_fusion::begin(seq))) = boost::any_cast<value_type>(value); + assign<std::is_const<unreferenced_type>::value>(friendly_fusion::deref(friendly_fusion::advance_c<index>(friendly_fusion::begin(seq))), boost::any_cast<value_type>(value)); }; } -#endif //defined( __GNUC__ ) && !defined( __clang__ ) template <typename T, int... Indices> void set_nth_impl(T& seq, int index, boost::any const& value, indices<Indices...>) @@ -75,21 +109,8 @@ void set_nth_impl(T& seq, int index, boost::any const& value, indices<Indices... typedef std::function<void(T&, boost::any const&)> element_type; static element_type table[] = { - #if defined( __GNUC__ ) && !defined( __clang__ ) - make_set_nth_lambda<Indices, T>() - ... - #else - [](T& seq, boost::any const& value) - { - typedef friendly_fusion::result_of::begin<T> begin; - typedef friendly_fusion::result_of::advance_c<typename begin::type, Indices> adv_it; - typedef friendly_fusion::result_of::deref<typename adv_it::type> deref; - typedef typename std::decay<typename deref::type>::type value_type; - - friendly_fusion::deref(friendly_fusion::advance_c<Indices>(friendly_fusion::begin(seq))) = boost::any_cast<value_type>(value); - } + make_set_nth_lambda<Indices, T>() ... - #endif //defined( __GNUC__ ) && !defined( __clang__ ) }; table[index](seq, value); @@ -113,7 +134,6 @@ void set_nth(T& x, int index, boost::any const& value) set_nth_functor<T>()(x, index, value); } -#if defined( __GNUC__ ) && !defined( __clang__ ) template<int index, typename T> std::function<std::string()> make_struct_member_name_lambda() { @@ -121,8 +141,6 @@ std::function<std::string()> make_struct_member_name_lambda() return std::string(friendly_fusion::extension::struct_member_name<T, index>::call()); }; } -#endif //defined( __GNUC__ ) && !defined( __clang__ ) - template<typename T> struct get_nth_name_impl { @@ -133,14 +151,9 @@ struct get_nth_name_impl { { typedef std::function<std::string()> element_type; static element_type table[] = { - #if defined( __GNUC__ ) && !defined( __clang__ ) //Workaround for gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 make_struct_member_name_lambda<Indices, T>() ... - #else - []{return std::string(friendly_fusion::extension::struct_member_name<T, Indices>::call());} - ... - #endif //defined( __GNUC__ ) && !defined( __clang__ ) }; return table[index](); @@ -10,33 +10,35 @@ #include <iostream> struct Data { - std::string name; + const std::string name; uint32_t number; - double ratio1; - float ratio2; + const double ratio1; + double ratio2; bool boolean; }; BOOST_FUSION_ADAPT_STRUCT( Data, - (std::string, name) + (const std::string, name) (uint32_t, number) - (double, ratio1) - (float,ratio2) + (const double, ratio1) + (double,ratio2) (bool, boolean) ) -struct DataModel : public fusion_model<std::vector<Data>> { - +struct DataModel : public FusionModel<std::vector<Data>> { void add_data(Data d) { data.push_back(d); } + }; -struct DataMapping :public fusion_model<std::map<std::string, Data>> { +struct DataMapping :public FusionModel<std::map<std::string, Data>> { void add_data(std::string key, Data value) { + call_on_observers(&FusionModelObserver::append_row_begin); data.emplace(key, value); + call_on_observers(&FusionModelObserver::append_row_end); } }; diff --git a/qt_adapter.hpp b/qt_adapter.hpp index dea660f..23a8c9f 100644 --- a/qt_adapter.hpp +++ b/qt_adapter.hpp @@ -47,7 +47,6 @@ struct AdapterType; template <typename T, typename Model> struct QtWidget : public T { - GuiItemDelegate delegate; std::shared_ptr<typename AdapterType<Model>::type> model; @@ -56,14 +55,34 @@ struct QtWidget : public T { , delegate() , model(std::make_shared<typename AdapterType<Model>::type>(model)) { + model->add_observer(this->model); T::setModel(this->model.get()); T::setItemDelegate(&delegate); T::setEditTriggers(QAbstractItemView::DoubleClicked); } }; +template <typename Model> +struct QtAdapterBase : public Model, public FusionModelObserver +{ + virtual void cell_changed(int row, int column) override + { + emit this->dataChanged(this->createIndex(row, column), this->createIndex(row, column)); + } + + virtual void append_row_begin() override + { + this->beginInsertRows(QModelIndex(), this->rowCount(QModelIndex()), this->rowCount(QModelIndex())); + } + + virtual void append_row_end() override + { + this->endInsertRows(); + } +}; + template <typename T> -struct QtAdapter<T, QAbstractTableModel> : public QAbstractTableModel +struct QtAdapter<T, QAbstractTableModel> : public QtAdapterBase<QAbstractTableModel> { typedef QTableView view; typedef QtWidget<view, T> widget; @@ -95,7 +114,9 @@ struct QtAdapter<T, QAbstractTableModel> : public QAbstractTableModel virtual Qt::ItemFlags flags(const QModelIndex &index) const { - return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + bool constness = is_const<typename T::row_type>(index.column()); + + return QAbstractTableModel::flags(index) | (constness ? Qt::NoItemFlags : Qt::ItemIsEditable); } virtual QVariant data(QModelIndex const& index, int role) const override |
