From 2f6c50d2764138583dcf89d86b13440a23f217cf Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Thu, 15 May 2014 14:52:31 +0200 Subject: 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. --- fusion_model.hpp | 43 +++++++++++++++++++++---- fusion_static_dispatch.hpp | 79 +++++++++++++++++++++++++++------------------- main.cpp | 20 ++++++------ 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 #include +#include + +struct FusionModelObserver +{ + virtual void cell_changed(int row, int column) {} + + virtual void append_row_begin() {} + virtual void append_row_end() {} +}; template -struct fusion_model { -private: - fusion_model(T); +struct FusionModel { + FusionModel(T) = delete; }; template @@ -56,10 +64,30 @@ struct FusionModelInterface : public FusionModelWithHeaderH, 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> observers; + void add_observer(std::weak_ptr obs) + { + observers.push_back(obs); + } + + template + 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 -struct fusion_model> : public FusionModelInterface +struct FusionModel> : public FusionModelInterface { static_assert(friendly_fusion::traits::is_sequence::type::value, "T is not a boost fusion sequence"); @@ -68,7 +96,7 @@ struct fusion_model> : public FusionModelInterface std::vector data; - fusion_model() = default; + FusionModel() = default; virtual size_t row_count() const override final { @@ -93,11 +121,12 @@ struct fusion_model> : public FusionModelInterface virtual void set_cell(size_t row, size_t column, boost::any const& value) override final { set_nth(data[row], column, value); + call_on_observers(&FusionModelObserver::cell_changed, row, column); } }; template -struct fusion_model> : public FusionModelInterface +struct FusionModel> : public FusionModelInterface { static_assert(boost::fusion::traits::is_sequence::type::value, "T is not a boost fusion sequence"); @@ -106,7 +135,7 @@ struct fusion_model> : public FusionModelInterface 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 #include +#include + +template +bool is_const_impl(int index, indices) +{ + typedef std::function element_type; + static element_type table[] = { + [] { + typedef friendly_fusion::result_of::begin begin; + typedef friendly_fusion::result_of::advance_c adv_it; + typedef friendly_fusion::result_of::deref deref; + typedef std::remove_reference unreferenced_type; + + return std::is_const::value; + } + ... + }; + + return table[index](); +} + +template +bool is_const(int index) +{ + typedef typename friendly_fusion::result_of::size::type seq_size; + typedef typename build_indices::type indices_type; + + return is_const_impl(index, indices_type{}); +} -#if defined( __GNUC__ ) && !defined( __clang__ ) template std::function make_at_c_lambda(T seq) { @@ -15,7 +43,6 @@ std::function make_at_c_lambda(T seq) return boost::any(friendly_fusion::deref(friendly_fusion::advance_c(friendly_fusion::begin(seq)))); }; } -#endif //defined( __GNUC__ ) && !defined( __clang__ ) template boost::any get_nth_impl(T seq, int index, indices) @@ -23,14 +50,8 @@ boost::any get_nth_impl(T seq, int index, indices) typedef std::function 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(seq) ... -#else - [](T seq){return boost::any(friendly_fusion::deref(friendly_fusion::advance_c(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()(x, index); } -#if defined( __GNUC__ ) && !defined( __clang__ ) +template +typename std::enable_if::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 +typename std::enable_if::type assign(T& lh, V rh) +{ + lh = rh; +} + template std::function make_set_nth_lambda() { @@ -63,11 +97,11 @@ std::function make_set_nth_lambda() typedef friendly_fusion::result_of::advance_c adv_it; typedef friendly_fusion::result_of::deref deref; typedef typename std::decay::type value_type; + typedef typename std::remove_reference::type unreferenced_type; - friendly_fusion::deref(friendly_fusion::advance_c(friendly_fusion::begin(seq))) = boost::any_cast(value); + assign::value>(friendly_fusion::deref(friendly_fusion::advance_c(friendly_fusion::begin(seq))), boost::any_cast(value)); }; } -#endif //defined( __GNUC__ ) && !defined( __clang__ ) template void set_nth_impl(T& seq, int index, boost::any const& value, indices) @@ -75,21 +109,8 @@ void set_nth_impl(T& seq, int index, boost::any const& value, indices element_type; static element_type table[] = { - #if defined( __GNUC__ ) && !defined( __clang__ ) - make_set_nth_lambda() - ... - #else - [](T& seq, boost::any const& value) - { - typedef friendly_fusion::result_of::begin begin; - typedef friendly_fusion::result_of::advance_c adv_it; - typedef friendly_fusion::result_of::deref deref; - typedef typename std::decay::type value_type; - - friendly_fusion::deref(friendly_fusion::advance_c(friendly_fusion::begin(seq))) = boost::any_cast(value); - } + make_set_nth_lambda() ... - #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()(x, index, value); } -#if defined( __GNUC__ ) && !defined( __clang__ ) template std::function make_struct_member_name_lambda() { @@ -121,8 +141,6 @@ std::function make_struct_member_name_lambda() return std::string(friendly_fusion::extension::struct_member_name::call()); }; } -#endif //defined( __GNUC__ ) && !defined( __clang__ ) - template struct get_nth_name_impl { @@ -133,14 +151,9 @@ struct get_nth_name_impl { { typedef std::function 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() ... - #else - []{return std::string(friendly_fusion::extension::struct_member_name::call());} - ... - #endif //defined( __GNUC__ ) && !defined( __clang__ ) }; return table[index](); diff --git a/main.cpp b/main.cpp index 3ff490e..d817367 100644 --- a/main.cpp +++ b/main.cpp @@ -10,33 +10,35 @@ #include 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> { - +struct DataModel : public FusionModel> { void add_data(Data d) { data.push_back(d); } + }; -struct DataMapping :public fusion_model> { +struct DataMapping :public FusionModel> { 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 struct QtWidget : public T { - GuiItemDelegate delegate; std::shared_ptr::type> model; @@ -56,14 +55,34 @@ struct QtWidget : public T { , delegate() , model(std::make_shared::type>(model)) { + model->add_observer(this->model); T::setModel(this->model.get()); T::setItemDelegate(&delegate); T::setEditTriggers(QAbstractItemView::DoubleClicked); } }; +template +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 -struct QtAdapter : public QAbstractTableModel +struct QtAdapter : public QtAdapterBase { typedef QTableView view; typedef QtWidget widget; @@ -95,7 +114,9 @@ struct QtAdapter : public QAbstractTableModel virtual Qt::ItemFlags flags(const QModelIndex &index) const { - return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + bool constness = is_const(index.column()); + + return QAbstractTableModel::flags(index) | (constness ? Qt::NoItemFlags : Qt::ItemIsEditable); } virtual QVariant data(QModelIndex const& index, int role) const override -- cgit v1.2.3-70-g09d2