creativity  v1.3.0
Agent-based model of creativity and piracy
MemberStore.hpp
1 #pragma once
2 #include <memory>
3 #include <algorithm>
4 #include <gtkmm/treemodel.h>
5 #include <gtkmm/treesortable.h>
6 #include <gtkmm/treeview.h>
7 #include <gtkmm/treepath.h>
8 #include "creativity/state/State.hpp"
9 
10 namespace creativity { namespace gui {
11 
20 template <class M>
21 class MemberStore : public virtual Gtk::TreeModel, public virtual Gtk::TreeSortable {
22  public:
23  MemberStore() = delete;
24 
26  virtual void appendColumnsTo(Gtk::TreeView &v) const = 0;
27 
29  const M& member(const Path &path) const;
30 
32  const M& member(const iterator &iter) const;
33 
47  Path find(eris::eris_id_t id, size_t hint = 0) const;
48 
55  Path find(eris::eris_id_t id, const iterator &iter) const;
56 
63  Path find(eris::eris_id_t id, const Path &hint) const;
64 
65  protected:
79  MemberStore(std::shared_ptr<const state::State> &&state);
80 
82  virtual Gtk::TreeModelFlags get_flags_vfunc() const override;
83 
85  virtual int get_n_columns_vfunc() const override = 0;
86 
93  virtual GType get_column_type_vfunc(int index) const override = 0;
94 
101  virtual bool get_iter_vfunc(const Path &path, iterator& iter) const override;
102 
110  virtual bool iter_next_vfunc(const iterator &iter, iterator &iter_next) const override;
112  virtual bool iter_children_vfunc(const iterator&, iterator&) const override;
114  virtual bool iter_parent_vfunc(const iterator&, iterator&) const override;
116  virtual bool iter_nth_child_vfunc(const iterator&, int, iterator&) const override;
118  virtual bool iter_has_child_vfunc(const iterator &) const override;
120  virtual int iter_n_children_vfunc(const iterator &) const override;
128  virtual bool iter_nth_root_child_vfunc(int n, iterator &iter) const override;
130  virtual int iter_n_root_children_vfunc() const override;
132  virtual Path get_path_vfunc(const iterator &iter) const override;
133 
141  virtual void get_value_vfunc(const iterator &iter, int column, Glib::ValueBase &value) const override = 0;
142 
145  template <typename T>
146  static void copy_value_(Glib::ValueBase &valueobj, const T &val);
147 
157  virtual bool get_sort_column_id_vfunc(int *sort_column_id, Gtk::SortType *order) const override;
158 
163  virtual void set_sort_column_id_vfunc(int sort_column_id, Gtk::SortType order) override = 0;
164 
180  virtual void sort_members(
181  std::function<bool(const M &a, const M &b)> &compare,
182  int sort_column_id,
183  Gtk::SortType order);
184 
195  template <typename T, typename = typename std::enable_if<std::is_base_of<Gtk::TreeModelColumnBase, T>::value>>
196  void appendCol(Gtk::TreeView &v, const std::string &label, T &col, int width, bool sortable = true) const {
197  v.append_column(label, col);
198  auto *c = v.get_column(v.get_n_columns()-1);
199  c->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED);
200  c->set_fixed_width(width);
201  if (sortable)
202  c->set_sort_column(col);
203  }
204 
206  const std::shared_ptr<const state::State> state_;
208  std::vector<std::reference_wrapper<const M>> members_;
210  int stamp_ = 1;
211 
212  private:
214  int sort_by_ = Gtk::TreeSortable::DEFAULT_UNSORTED_COLUMN_ID;
216  Gtk::SortType sort_order_ = Gtk::SORT_ASCENDING;
217 };
218 
219 template <class M> MemberStore<M>::MemberStore(std::shared_ptr<const state::State> &&state) : state_{std::move(state)} {}
220 
221 template <class M> Gtk::TreeModelFlags MemberStore<M>::get_flags_vfunc() const {
222  return Gtk::TREE_MODEL_LIST_ONLY;
223 }
224 
225 template <class M> const M& MemberStore<M>::member(const Path &path) const {
226  return members_.at(path.back());
227 }
228 
229 template <class M> const M& MemberStore<M>::member(const iterator &iter) const {
230  return members_.at((size_t) iter.gobj()->user_data);
231 }
232 
233 template <class M> Gtk::TreeModel::Path MemberStore<M>::find(eris::eris_id_t id, size_t hint) const {
234  Gtk::TreeModel::Path p;
235  const long max = members_.size();
236  // Loop through members_ starting at hint with two counters: one starting at hint and going down
237  // to 0, the other starting at hint+1 and going up to max. This makes us search positions
238  // closer to hint first.
239  long a = std::min<long>(hint, max-1), b = hint + 1;
240  while (b < max or a >= 0) {
241  if (a >= 0) {
242  if (members_[a].get().id == id) {
243  p.push_back(a);
244  break;
245  }
246  a--;
247  }
248  if (b < max) {
249  if (members_[b].get().id == id) {
250  p.push_back(b);
251  break;
252  }
253  b++;
254  }
255  }
256  return p;
257 }
258 template <class M> Gtk::TreeModel::Path MemberStore<M>::find(eris::eris_id_t id, const iterator &hint) const {
259  return find(id, (size_t) hint.gobj()->user_data);
260 }
261 template <class M> Gtk::TreeModel::Path MemberStore<M>::find(eris::eris_id_t id, const Path &hint) const {
262  return find(id, hint.empty() ? 0 : hint.back());
263 }
264 
265 template <class M> bool MemberStore<M>::get_iter_vfunc(const Path &path, iterator& iter) const {
266  size_t i = path.back();
267  if (i >= members_.size()) return false;
268 
269  iter.set_stamp(stamp_);
270  iter.gobj()->user_data = (void*) i;
271  return true;
272 }
273 
274 template <class M> bool MemberStore<M>::iter_next_vfunc(const iterator &iter, iterator &iter_next) const {
275  if (iter.get_stamp() != stamp_) return false;
276  size_t i = 1 + (size_t) iter.gobj()->user_data;
277  if (i >= members_.size()) return false;
278 
279  iter_next.set_stamp(stamp_);
280  iter_next.gobj()->user_data = (void*) i;
281  return true;
282 }
283 
284 template <class M> bool MemberStore<M>::iter_children_vfunc(const iterator&, iterator&) const {
285  return false; // No nesting
286 }
287 
288 template <class M> bool MemberStore<M>::iter_parent_vfunc(const iterator&, iterator&) const {
289  return false; // No nesting
290 }
291 
292 template <class M> bool MemberStore<M>::iter_nth_child_vfunc(const iterator&, int, iterator&) const {
293  return false; // No nesting
294 }
295 
296 template <class M> bool MemberStore<M>::iter_nth_root_child_vfunc(int n, iterator &iter) const {
297  size_t i = n;
298  if (i >= members_.size()) return false;
299 
300  iter.set_stamp(stamp_);
301  iter.gobj()->user_data = (void*) i;
302  return true;
303 }
304 
305 template <class M> bool MemberStore<M>::iter_has_child_vfunc(const iterator &) const {
306  return false; // No nesting
307 }
308 
309 template <class M> int MemberStore<M>::iter_n_children_vfunc(const iterator &) const {
310  return 0; // No nesting
311 }
312 
313 template <class M> int MemberStore<M>::iter_n_root_children_vfunc() const {
314  return (int) members_.size();
315 }
316 
317 template <class M> Gtk::TreeModel::Path MemberStore<M>::get_path_vfunc(const iterator &iter) const {
318  size_t i = (size_t) iter.gobj()->user_data;
319  Gtk::TreeModel::Path ret;
320  ret.push_back(i);
321  return ret;
322 }
323 
324 template <class M> bool MemberStore<M>::get_sort_column_id_vfunc(int *sort_column_id, Gtk::SortType *order) const {
325  if (sort_column_id) *sort_column_id = sort_by_;
326  if (order) *order = sort_order_;
327  return not(sort_by_ == DEFAULT_UNSORTED_COLUMN_ID or sort_by_ == DEFAULT_SORT_COLUMN_ID);
328 }
329 
330 template <class M> void MemberStore<M>::sort_members(
331  std::function<bool(const M &a, const M &b)> &compare,
332  int sort_column_id,
333  Gtk::SortType order) {
334  if (not compare) return;
335 
336  // The rows_reordered signal needs a vector where v[new_pos] == old_pos,
337  // so store all the old positions before we sort.
338  std::unordered_map<eris::eris_id_t, int> old_pos;
339  int i = 0;
340  for (const M &m : members_)
341  old_pos[m.id] = i++;
342 
343  if (sort_by_ != sort_column_id or sort_order_ != order) {
344  sort_by_ = sort_column_id;
345  sort_order_ = order;
346  sort_column_changed();
347  }
348 
349  std::stable_sort(members_.begin(), members_.end(), compare);
350 
351  // The sort invalidates our tree iterators, so increment the stamp
352  stamp_++;
353 
354  std::vector<int> new_order;
355  new_order.reserve(members_.size());
356  bool actual_reordering = false;
357  for (const M &m : members_) {
358  if (not actual_reordering and old_pos[m.id] != (int) new_order.size()) actual_reordering = true;
359  new_order.push_back(old_pos[m.id]);
360  }
361 
362  // If sorting actually changed anything, fire the rows-reordered signal
363  if (actual_reordering) rows_reordered(Path(), new_order);
364 }
365 
366 template <class M> template <class T> void MemberStore<M>::copy_value_(Glib::ValueBase &valueobj, const T &val) {
367  Glib::Value<T> v;
368  v.init(v.value_type());
369  v.set(val);
370  valueobj.init(v.gobj());
371 }
372 
373 }}
virtual int iter_n_root_children_vfunc() const override
Returns the number of readers stored in this model.
Definition: MemberStore.hpp:313
virtual bool iter_nth_root_child_vfunc(int n, iterator &iter) const override
Obtains an iterator to the nth reader.
Definition: MemberStore.hpp:296
virtual bool get_iter_vfunc(const Path &path, iterator &iter) const override
Converts a path to an iterator.
Definition: MemberStore.hpp:265
Primary namespace for all Creativity library code.
Definition: config.hpp:4
virtual Gtk::TreeModelFlags get_flags_vfunc() const override
Returns Gtk::TreeModel flags (specifically, the LIST_ONLY flag).
Definition: MemberStore.hpp:221
virtual GType get_column_type_vfunc(int index) const override=0
Returns the column type of the given position.
virtual void sort_members(std::function< bool(const M &a, const M &b)> &compare, int sort_column_id, Gtk::SortType order)
Called by subclasses, typically in set_sort_column_id_vfunc, to resort the current list of members us...
Definition: MemberStore.hpp:330
Base class for a flat list of simulation members.
Definition: MemberStore.hpp:21
virtual bool iter_children_vfunc(const iterator &, iterator &) const override
Returns false always: MemberStore elements cannot have children.
Definition: MemberStore.hpp:284
virtual bool iter_next_vfunc(const iterator &iter, iterator &iter_next) const override
Takes an iterator, returns an iterator to the next item.
Definition: MemberStore.hpp:274
virtual bool get_sort_column_id_vfunc(int *sort_column_id, Gtk::SortType *order) const override
Accesses the current sort column and order.
Definition: MemberStore.hpp:324
virtual void set_sort_column_id_vfunc(int sort_column_id, Gtk::SortType order) override=0
Sets the model sort column and sort order.
static void copy_value_(Glib::ValueBase &valueobj, const T &val)
Helper method for the crap needed in get_value_vfunc(): creates a Glib::Value of the right type and c...
Definition: MemberStore.hpp:366
Path find(eris::eris_id_t id, size_t hint=0) const
Returns the Path to the member with the given id.
Definition: MemberStore.hpp:233
void appendCol(Gtk::TreeView &v, const std::string &label, T &col, int width, bool sortable=true) const
Appends a single column to the given view using the given label, width, and sortability.
Definition: MemberStore.hpp:196
std::vector< std::reference_wrapper< const M > > members_
The vector of members. Subclasses need to add all member references to this vector.
Definition: MemberStore.hpp:208
const M & member(const Path &path) const
Gets the M Member from a Path.
Definition: MemberStore.hpp:225
virtual bool iter_has_child_vfunc(const iterator &) const override
Returns false always: MemberStore elements cannot have children.
Definition: MemberStore.hpp:305
virtual int get_n_columns_vfunc() const override=0
Returns obj.columns.size(), the number of model columns.
const std::shared_ptr< const state::State > state_
The state this MemberStore represents.
Definition: MemberStore.hpp:206
virtual Path get_path_vfunc(const iterator &iter) const override
Converts iterator iter into a Path.
Definition: MemberStore.hpp:317
int stamp_
Tracks model changes by being incremented whenever such a change occurs.
Definition: MemberStore.hpp:210
virtual void appendColumnsTo(Gtk::TreeView &v) const =0
Takes a Gtk::TreeView and adds this object&#39;s columns to it.
virtual bool iter_parent_vfunc(const iterator &, iterator &) const override
Returns false always: MemberStore elemenets cannot have children/parents.
Definition: MemberStore.hpp:288
virtual int iter_n_children_vfunc(const iterator &) const override
Returns 0 always: MemberStore elements have no children.
Definition: MemberStore.hpp:309
virtual bool iter_nth_child_vfunc(const iterator &, int, iterator &) const override
Returns false always: MemberStore elements cannot have children.
Definition: MemberStore.hpp:292
virtual void get_value_vfunc(const iterator &iter, int column, Glib::ValueBase &value) const override=0
Accesses a column value.