summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt55
-rw-r--r--boost_any_to_qvariant.hpp67
-rw-r--r--friendly_fusion.hpp129
-rw-r--r--fusion_model.hpp52
-rw-r--r--fusion_static_dispatch.hpp127
-rw-r--r--gui_item_delegate.cpp21
-rw-r--r--gui_item_delegate.hpp18
-rw-r--r--index_list.hpp16
-rw-r--r--main.cpp75
-rw-r--r--meta_types.hpp5
-rw-r--r--qt_adapter.hpp69
12 files changed, 635 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index f35e3c0..87751cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
*build*
+*.txt.user
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a6c35f3..1d5e0d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,61 @@ project(msc-scriptie)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11")
+function(MY_QT5_WRAP_UI outfiles )
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs OPTIONS)
+
+ cmake_parse_arguments(_WRAP_UI "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(ui_files ${_WRAP_UI_UNPARSED_ARGUMENTS})
+ set(ui_options ${_WRAP_UI_OPTIONS})
+
+ foreach(it ${ui_files})
+ get_filename_component(outfile ${it} NAME_WE)
+ get_filename_component(infile ${it} ABSOLUTE)
+ set(outfile ${CMAKE_CURRENT_SOURCE_DIR}/ui_${outfile}.hpp)
+ add_custom_command(OUTPUT ${outfile}
+ COMMAND ${Qt5Widgets_UIC_EXECUTABLE}
+ ARGS ${ui_options} -o ${outfile} ${infile}
+ MAIN_DEPENDENCY ${infile}
+ VERBATIM)
+ list(APPEND ${outfiles} ${outfile})
+ endforeach()
+ set(${outfiles} ${${outfiles}} PARENT_SCOPE)
+endfunction()
+
+find_package(Qt5Widgets REQUIRED)
+add_definitions(${Qt5Widgets_DEFINITIONS})
+include_directories(SYSTEM ${Qt5Widgets_INCLUDE_DIRS})
+
+find_package(Qt5Gui REQUIRED)
+add_definitions(${Qt5Gui_DEFINITIONS})
+include_directories(SYSTEM ${Qt5Gui_INCLUDE_DIRS})
+
+find_package(Qt5Core REQUIRED)
+add_definitions(${Qt5Core_DEFINITIONS})
+include_directories(SYSTEM ${Qt5Core_INCLUDE_DIRS})
+
+qt5_wrap_cpp(qt_sources
+ gui_item_delegate.hpp
+)
+
add_executable(msc-scriptie
+ fusion_model.hpp
+ index_list.hpp
+ qt_adapter.hpp
+ friendly_fusion.hpp
+ fusion_static_dispatch.hpp
+ meta_types.hpp
+ boost_any_to_qvariant.hpp
+ gui_item_delegate.hpp gui_item_delegate.cpp
+ ${qt_sources}
main.cpp
)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS} ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
+target_link_libraries(msc-scriptie ${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Core_LIBRARIES})
+
+
+
diff --git a/boost_any_to_qvariant.hpp b/boost_any_to_qvariant.hpp
new file mode 100644
index 0000000..6172c09
--- /dev/null
+++ b/boost_any_to_qvariant.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "friendly_fusion.hpp"
+#include "index_list.hpp"
+
+#include <QVariant>
+
+#include <boost/any.hpp>
+
+#include <string>
+
+template<typename value_type>
+QVariant convert(boost::any const& x)
+{
+ return QVariant::fromValue<value_type>(boost::any_cast<value_type>(x));
+}
+
+template <typename T, int n>
+QVariant convert(boost::any const& x)
+{
+ typedef friendly_fusion::result_of::begin<T> begin;
+ typedef friendly_fusion::result_of::advance_c<typename begin::type, n> adv_it;
+ typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
+ typedef typename std::decay<typename deref::type>::type value_type;
+ return convert<value_type>(x);
+}
+
+#if defined( __GNUC__ ) && !defined( __clang__ )
+template <typename T, int index>
+std::function<QVariant(boost::any const&)> convert_lambda()
+{
+ return [](boost::any const& any)
+ {
+ return convert<T, index>(any);
+ };
+}
+
+#endif //defined( __GNUC__ ) && !defined( __clang__ )
+
+template<typename T, int... Indices>
+QVariant to_qvariant(boost::any const& any, int index, indices<Indices...>)
+{
+ typedef std::function<QVariant(boost::any const&)> 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
+ convert_lambda<T, Indices>()
+ ...
+#else
+ [](boost::any const& any){return convert<T, Indices>(any);}
+ ...
+#endif //defined( __GNUC__ ) && !defined( __clang__ )
+ };
+
+ return table[index](any);
+}
+
+
+template <typename T>
+QVariant to_qvariant(boost::any const& x, int index)
+{
+ typedef typename friendly_fusion::result_of::size<T>::type seq_size;
+ typedef typename build_indices<seq_size::value>::type indices_type;
+
+ return to_qvariant<T>(x, index, indices_type{});
+} \ No newline at end of file
diff --git a/friendly_fusion.hpp b/friendly_fusion.hpp
new file mode 100644
index 0000000..b014bd8
--- /dev/null
+++ b/friendly_fusion.hpp
@@ -0,0 +1,129 @@
+#pragma once
+
+#include <boost/fusion/include/size.hpp>
+#include <boost/fusion/include/begin.hpp>
+#include <boost/fusion/include/deref.hpp>
+#include <boost/fusion/include/value_of.hpp>
+#include <boost/fusion/include/distance.hpp>
+#include <boost/fusion/include/advance.hpp>
+#include <boost/fusion/include/is_view.hpp>
+#include <boost/fusion/include/is_sequence.hpp>
+#include <boost/fusion/include/is_iterator.hpp>
+#include <boost/fusion/include/struct.hpp>
+#include <boost/fusion/adapted/struct/detail/adapt_base.hpp>
+
+#include <boost/mpl/or.hpp>
+
+namespace friendly_fusion {
+
+namespace traits {
+
+template <typename T, bool NoCheck = true>
+struct is_sequence : public boost::fusion::traits::is_sequence<T>
+{
+ static_assert(NoCheck || boost::fusion::traits::is_sequence<T>::value, "Template parameter: T, is not a fusion adapted struct.");
+};
+
+template <typename T, bool NoCheck = true>
+struct is_fusion_iterator : public boost::fusion::is_fusion_iterator<T>
+{
+ static_assert(NoCheck || boost::fusion::is_fusion_iterator<T>::value, "Template parameter: T. Is not a fusion iterator.");
+};
+
+template <typename T, bool NoCheck = true>
+struct is_view : public boost::fusion::traits::is_view<T> {
+ static_assert(NoCheck || boost::fusion::traits::is_view<T>::value, "Template parameter: T, is not a fusion view");
+};
+
+template <typename T, bool NoCheck = true>
+struct is_sequence_or_view : public boost::mpl::or_<typename boost::fusion::traits::is_sequence<T>, typename boost::fusion::traits::is_view<T>> {
+ static_assert(NoCheck || (boost::fusion::traits::is_sequence<T>::value || boost::fusion::traits::is_view<T>::value), "Template parameter: T, is not a fusion sequence or a view");
+};
+
+}
+
+template <typename T>
+typename std::enable_if<traits::is_fusion_iterator<T, false>::value, typename boost::fusion::result_of::deref<T>::type>::type
+deref(T const& x)
+{
+ return boost::fusion::deref(x);
+}
+
+template <int N, typename T>
+typename std::enable_if<traits::is_fusion_iterator<T, false>::value, typename boost::fusion::result_of::advance_c<T, N>::type>::type
+advance_c(T const& x)
+{
+ return boost::fusion::advance_c<N>(x);
+}
+
+template <typename T>
+typename std::enable_if<traits::is_sequence_or_view<T, false>::value, typename boost::fusion::result_of::begin<T>::type>::type const
+begin(T& x)
+{
+ return boost::fusion::begin(x);
+}
+
+template <typename T>
+typename std::enable_if<traits::is_sequence_or_view<T, false>::value, typename boost::fusion::result_of::begin<T const>::type>::type const
+begin(T const& x)
+{
+ return boost::fusion::begin(x);
+}
+
+template <typename T>
+typename std::enable_if<traits::is_sequence_or_view<T, false>::value, typename boost::fusion::result_of::end<T>::type>::type const
+end(T& x)
+{
+ return boost::fusion::end(x);
+}
+
+template <typename T>
+typename std::enable_if<traits::is_sequence_or_view<T, false>::value, typename boost::fusion::result_of::end<T const>::type>::type const
+end(T const& x)
+{
+ return boost::fusion::end(x);
+}
+
+namespace result_of {
+
+template <typename T>
+struct size : private traits::is_sequence_or_view<T, false>, public boost::fusion::result_of::size<T>
+{
+ using typename boost::fusion::result_of::size<T>::type;
+};
+
+template <typename T>
+struct begin : private traits::is_sequence_or_view<T, false>, public boost::fusion::result_of::begin<T>
+{
+ using typename boost::fusion::result_of::begin<T>::type;
+};
+
+template <typename T>
+struct end : private traits::is_sequence_or_view<T, false>, public boost::fusion::result_of::end<T>
+{
+ using typename boost::fusion::result_of::end<T>::type;
+};
+
+template <typename T, int N>
+struct advance_c : private traits::is_fusion_iterator<T, false>, public boost::fusion::result_of::advance_c<T, N>
+{
+ using typename boost::fusion::result_of::advance_c<T, N>::type;
+};
+
+template <typename T>
+struct deref : private traits::is_fusion_iterator<T, false>, public boost::fusion::result_of::deref<T>
+{
+ using typename boost::fusion::result_of::deref<T>::type;
+};
+
+}
+
+namespace extension {
+
+template<typename T, int index>
+struct struct_member_name : private traits::is_sequence<T, false>, public boost::fusion::extension::struct_member_name<T, index>
+{};
+
+}
+
+} \ No newline at end of file
diff --git a/fusion_model.hpp b/fusion_model.hpp
new file mode 100644
index 0000000..ace8f51
--- /dev/null
+++ b/fusion_model.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "fusion_static_dispatch.hpp"
+
+#include <boost/fusion/include/is_sequence.hpp>
+#include <boost/fusion/include/size.hpp>
+
+#include <boost/any.hpp>
+
+#include <vector>
+#include <map>
+
+template <typename T>
+struct fusion_model {
+
+};
+
+template <typename T>
+struct fusion_model<std::vector<T>>
+{
+ static_assert(boost::fusion::traits::is_sequence<T>::type::value, "T is not a boost fusion sequence");
+
+ typedef std::vector<T> data_type;
+
+ std::vector<T> data;
+
+ size_t row_count() const
+ {
+ return data.size();
+ }
+
+ size_t column_count() const
+ {
+ return boost::fusion::result_of::size<T>::type::value;
+ }
+
+ std::string horizontal_header_data(size_t section) const
+ {
+ return get_nth_name<T>(section);
+ }
+
+ boost::any get_cell(size_t row, size_t column) const
+ {
+ return get_nth(data[row], column);
+ }
+};
+
+template <typename T, typename U>
+struct fusion_model<std::map<T, U>>
+{
+ std::map<T, U> data;
+}; \ No newline at end of file
diff --git a/fusion_static_dispatch.hpp b/fusion_static_dispatch.hpp
new file mode 100644
index 0000000..17b6ff4
--- /dev/null
+++ b/fusion_static_dispatch.hpp
@@ -0,0 +1,127 @@
+#pragma once
+
+#include "index_list.hpp"
+#include "friendly_fusion.hpp"
+
+#include <boost/any.hpp>
+
+template <typename T, int index>
+struct TypeAt {
+ typedef friendly_fusion::result_of::begin<T> begin;
+ 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;
+};
+
+#if defined( __GNUC__ ) && !defined( __clang__ )
+template<int index, typename T>
+std::function<boost::any(T)> make_at_c_lambda(T seq)
+{
+ return [](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...>)
+{
+ 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);
+}
+
+template<typename T>
+struct get_nth_functor
+{
+ boost::any operator()(T seq, int index)
+ {
+ typedef typename friendly_fusion::result_of::size<T>::type seq_size;
+ typedef typename build_indices<seq_size::value>::type indices_type;
+
+ return get_nth_impl(seq, index, indices_type{});
+ }
+};
+
+template <typename T>
+boost::any get_nth(T x, int index)
+{
+ return get_nth_functor<T>()(x, index);
+}
+
+#if defined( __GNUC__ ) && !defined( __clang__ )
+template<int index, typename T>
+std::function<std::string()> make_struct_member_name_lambda()
+{
+ return []{
+ 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 {
+
+ get_nth_name_impl() = default;
+
+ template<int... Indices>
+ std::string operator()(int index, indices<Indices...>)
+ {
+ 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]();
+ }
+};
+
+template <typename T>
+struct get_nth_name_functor
+{
+ std::string operator()(int index)
+ {
+ typedef typename friendly_fusion::result_of::size<T>::type seq_size;
+ typedef typename build_indices<seq_size::value>::type indices_type;
+
+ return get_nth_name_impl<T>()(index, indices_type{});
+ }
+};
+
+template <typename T, typename U>
+struct get_nth_name_functor<boost::fusion::joint_view<T,U>>
+{
+ std::string operator()(int index)
+ {
+ constexpr size_t size_of_T = friendly_fusion::result_of::size<T>::type::value;
+ if(index < size_of_T){
+ return get_nth_name_functor<T>()(index);
+ } else {
+ return get_nth_name_functor<U>()(index - size_of_T);
+ }
+ }
+};
+
+template <typename T>
+std::string get_nth_name(int index)
+{
+ return get_nth_name_functor<T>()(index);
+}
diff --git a/gui_item_delegate.cpp b/gui_item_delegate.cpp
new file mode 100644
index 0000000..aba0727
--- /dev/null
+++ b/gui_item_delegate.cpp
@@ -0,0 +1,21 @@
+#include "meta_types.hpp"
+
+#include "gui_item_delegate.hpp"
+
+GuiItemDelegate::GuiItemDelegate(QObject *parent) :
+QStyledItemDelegate(parent)
+{
+}
+
+QString GuiItemDelegate::displayText(const QVariant &value, const QLocale &locale) const
+{
+ QString ret;
+ static int string_id = qMetaTypeId<std::string>();
+
+ if(string_id == value.userType()) {
+ ret = QString::fromStdString(value.value<std::string>());
+ } else {
+ ret = QStyledItemDelegate::displayText(value, locale);
+ }
+ return ret;
+}
diff --git a/gui_item_delegate.hpp b/gui_item_delegate.hpp
new file mode 100644
index 0000000..d715dc2
--- /dev/null
+++ b/gui_item_delegate.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <QStyledItemDelegate>
+
+class GuiItemDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ explicit GuiItemDelegate(QObject *parent = 0);
+ virtual ~GuiItemDelegate() = default;
+
+ virtual QString displayText(const QVariant &value, const QLocale &locale) const override final;
+
+signals:
+
+public slots:
+
+};
diff --git a/index_list.hpp b/index_list.hpp
new file mode 100644
index 0000000..f363dc3
--- /dev/null
+++ b/index_list.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+template<int... Indices>
+struct indices {
+ typedef indices<Indices..., sizeof...(Indices)> next;
+};
+
+template<int N>
+struct build_indices {
+ typedef typename build_indices<N - 1>::type::next type;
+};
+
+template<>
+struct build_indices<0> {
+ typedef indices<> type;
+};
diff --git a/main.cpp b/main.cpp
index fc047f7..1ca2350 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,5 +1,80 @@
+#include "fusion_model.hpp"
+#include "qt_adapter.hpp"
+#include "gui_item_delegate.hpp"
+
+#include <boost/fusion/adapted.hpp>
+
+#include <iostream>
+
+#include <QMainWindow>
+#include <QApplication>
+
+struct Data {
+ std::string name;
+ uint32_t number;
+ float ratio;
+ bool lolwut;
+};
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Data,
+ (std::string, name)
+ (uint32_t, number)
+ (float, ratio)
+ (bool, lolwut)
+)
+
+struct DataModel : public fusion_model<std::vector<Data>> {
+
+ void add_data(Data d) {
+ data.push_back(d);
+ }
+};
+
int main()
{
+ DataModel model;
+
+ model.add_data({"Pietje", 2, 3.333f, true});
+ model.add_data({"Jantje", 3, 1.5f, false});
+ model.add_data({"Sjaakje", 1, 0.1337f, false});
+
+ auto adapter = make_qt_adapter(model);
+
+ int argc = 0;
+ QApplication qapp(argc, nullptr);
+
+ QMainWindow w;
+
+ decltype(adapter)::element_type::view view;
+
+ view.setModel(adapter.get());
+
+ GuiItemDelegate delegate;
+ view.setItemDelegate(&delegate);
+
+ view.show();
+
+ qapp.exec();
+
+ for(int column = 0; column < model.column_count(); ++column)
+ {
+ std::cout << model.horizontal_header_data(column) << "\t";
+ }
+ std::cout << std::endl;
+
+ for(int row = 0; row < model.row_count(); ++row)
+ {
+ for(int column = 0; column < model.column_count(); ++column) {
+ if(column == 0) {
+ std::cout << boost::any_cast<std::string>(model.get_cell(row, column)) << "\t";
+ } else {
+ std::cout << boost::any_cast<uint32_t>(model.get_cell(row, column)) << "\t";
+ }
+ }
+ std::cout << std::endl;
+ }
+
return 0;
}
diff --git a/meta_types.hpp b/meta_types.hpp
new file mode 100644
index 0000000..265d9e9
--- /dev/null
+++ b/meta_types.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <QMetaType>
+
+Q_DECLARE_METATYPE(std::string) \ No newline at end of file
diff --git a/qt_adapter.hpp b/qt_adapter.hpp
new file mode 100644
index 0000000..2843667
--- /dev/null
+++ b/qt_adapter.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "fusion_model.hpp"
+#include "boost_any_to_qvariant.hpp"
+#include "meta_types.hpp"
+
+#include <QAbstractTableModel>
+#include <QTableView>
+#include <QMetaType>
+
+#include <memory>
+
+
+
+template <typename T>
+struct QtModelType
+{
+ typedef void type;
+};
+
+template <typename V>
+struct QtModelType<std::vector<V>>
+{
+ typedef QAbstractTableModel type;
+};
+
+template <typename T, typename Q>
+struct QtAdapter : public Q {
+
+ typedef void view;
+
+ QtAdapter(T)
+ {}
+};
+
+template <typename T>
+struct QtAdapter<T, QAbstractTableModel> : public QAbstractTableModel
+{
+ typedef QTableView view;
+
+ T model;
+
+ QtAdapter(T model)
+ : model(model)
+ {}
+
+ virtual int rowCount(QModelIndex const&) const override
+ {
+ return model.row_count();
+ }
+
+ virtual int columnCount(QModelIndex const&) const override
+ {
+ return model.column_count();
+ }
+
+ virtual QVariant data(QModelIndex const& index, int role) const
+ {
+ if(role != Qt::DisplayRole) return QVariant();
+
+ return to_qvariant<typename T::data_type::value_type>(model.get_cell(index.row(), index.column()), index.column());
+ }
+};
+
+
+template <typename T>
+std::shared_ptr<QtAdapter<T, typename QtModelType<typename T::data_type>::type>> make_qt_adapter(T value) {
+ return std::make_shared<QtAdapter<T, typename QtModelType<typename T::data_type>::type>>(value);
+}