summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2014-05-15 14:52:31 +0200
committerDennis Brentjes <d.brentjes@gmail.com>2014-05-15 14:52:31 +0200
commit2f6c50d2764138583dcf89d86b13440a23f217cf (patch)
tree08cc78ff875c1501375f7a28401da3b3fd327d82
parent6a1e6120c4efc46f1d192b0e5fabc06b780113cc (diff)
downloadgeneric-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.hpp43
-rw-r--r--fusion_static_dispatch.hpp79
-rw-r--r--main.cpp20
-rw-r--r--qt_adapter.hpp27
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]();
diff --git a/main.cpp b/main.cpp
index 3ff490e..d817367 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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