#pragma once #include "fusion_static_dispatch.hpp" #include #include #include #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 FusionModel { FusionModel(T) = delete; }; template struct FusionModelWithHeaderH; template <> struct FusionModelWithHeaderH { static constexpr bool has_header_h = false; }; template <> struct FusionModelWithHeaderH { static constexpr bool has_header_h = true; virtual std::string field_name(size_t section) const = 0; }; template struct FusionModelWithHeaderV; template <> struct FusionModelWithHeaderV { static constexpr bool has_header_v = false; }; template <> struct FusionModelWithHeaderV { static constexpr bool has_header_v = true; virtual std::string key(size_t section) const = 0; }; template struct FusionModelInterface : public FusionModelWithHeaderH, public FusionModelWithHeaderV { virtual size_t row_count() const = 0; 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 FusionModel> : public FusionModelInterface { static_assert(friendly_fusion::traits::is_sequence::type::value, "T is not a boost fusion sequence"); typedef std::vector data_type; typedef T row_type; std::vector data; FusionModel() = default; virtual size_t row_count() const override final { return data.size(); } virtual size_t column_count() const override final { return boost::fusion::result_of::size::type::value; } virtual std::string field_name(size_t section) const override final { return get_nth_name(section); } virtual boost::any get_cell(size_t row, size_t column) const override final { return get_nth(data[row], column); } 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 FusionModel> : public FusionModelInterface { static_assert(boost::fusion::traits::is_sequence::type::value, "T is not a boost fusion sequence"); typedef std::map data_type; typedef T row_type; std::map data; FusionModel() = default; virtual size_t row_count() const override final { return data.size(); } virtual size_t column_count() const override final { return boost::fusion::result_of::size::type::value; } virtual std::string field_name(size_t section) const override final { return get_nth_name(section); } virtual std::string key(size_t section) const override final { auto cit = data.cbegin(); std::advance(cit, section); return cit->first; } virtual boost::any get_cell(size_t row, size_t column) const override final { auto cit = data.cbegin(); std::advance(cit, row); return get_nth(cit->second, column); } virtual void set_cell(size_t row, size_t column, boost::any const& value) override final { auto it = data.begin(); std::advance(it, row); set_nth(it->second, column, value); } };