TreeWidgetBuilder.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <functional>
4 #include <map>
5 #include <sstream>
6 
7 #include <QTreeWidget>
8 
10 
11 namespace armarx
12 {
13 
14  /**
15  * A class to efficiently build and maintain sorted items of `QTreeWidget`
16  * or `QTreeWidgetItem` based on a sorted container matching the intended structure.
17  */
18  template <class _ElementT>
19  struct TreeWidgetBuilder
20  {
21  using ElementT = _ElementT;
22 
23  /// Return < 0 if `element < item`, 0 if `element == item`, and > 0 if `element > item`.
24  using CompareFn = std::function<int(const ElementT& element, QTreeWidgetItem* item)>;
25  using NameFn = std::function<std::string(const ElementT& element)>;
26  using MakeItemFn = std::function<QTreeWidgetItem*(const ElementT& element)>;
27  using UpdateItemFn = std::function<bool(const ElementT& element, QTreeWidgetItem* item)>;
28 
29 
30  TreeWidgetBuilder() = default;
31 
32  /// Constructor to automatically derive the template argument.
34  {
35  }
36 
38  MakeItemFn makeItemFn,
39  UpdateItemFn updateItemFn = NoUpdate) :
40  compareFn(compareFn), makeItemFn(makeItemFn), updateItemFn(updateItemFn)
41  {
42  }
43 
45  MakeItemFn makeItemFn,
46  UpdateItemFn updateItemFn = NoUpdate,
47  int nameColumn = 0) :
48  compareFn(MakeCompareNameFn(nameFn, nameColumn)),
49  makeItemFn(makeItemFn),
50  updateItemFn(updateItemFn)
51  {
52  }
53 
54  void
56  {
57  this->compareFn = compareFn;
58  }
59 
60  void
61  setNameFn(NameFn nameFn, int nameColumn = 0)
62  {
63  compareFn = MakeCompareNameFn(nameFn, nameColumn);
64  }
65 
66  void
68  {
69  this->makeItemFn = makeItemFn;
70  }
71 
72  void
74  {
75  this->updateItemFn = updateItemFn;
76  }
77 
78  void
79  setExpand(bool expand)
80  {
81  this->expand = expand;
82  }
83 
84 
85  /**
86  * @brief Update the tree according to the elements iterated over by `iteratorFn`.
87  *
88  * @param parent
89  * The parent, i.e. the tree widget or a tree widget item.
90  * @param iteratorFn
91  * Function taking a function `bool fn(const ElementT& element)`
92  * and calling it for each element in the underlying container, i.e. like:
93  * void iteratorFn(bool (*elementFn)(const ElementT& element));
94  */
95  template <class ParentT, class IteratorFn>
96  void updateTreeWithIterator(ParentT* parent, IteratorFn&& iteratorFn);
97 
98  /**
99  * @brief Update the tree with the iterable container.
100  *
101  * @param parent
102  * The parent, i.e. the tree widget or a tree widget item.
103  * @param iteratorFn
104  * Function taking a function `bool fn(const ElementT& element)`
105  * and calling it for each element in the underlying container, i.e. like:
106  * void iteratorFn(bool (*elementFn)(const ElementT& element));
107  */
108  template <class ParentT, class ContainerT>
109  void updateTreeWithContainer(ParentT* parent, const ContainerT& elements);
110 
111  /// No update function (default).
112  static bool
113  NoUpdate(const ElementT& element, QTreeWidgetItem* item)
114  {
115  (void)element, (void)item;
116  return true;
117  }
118 
119  /// Uses the name for comparison.
120  static CompareFn MakeCompareNameFn(NameFn nameFn, int nameColumn);
121 
122 
123  private:
124  CompareFn compareFn;
125  MakeItemFn makeItemFn;
126  UpdateItemFn updateItemFn;
127 
128  /// Whether to expand items on first creation.
129  bool expand = false;
130  };
131 
132  /**
133  * A class to efficiently build and maintain sorted items of `QTreeWidget`
134  * or `QTreeWidgetItem` based on a map matching the intended structure.
135  */
136  template <class KeyT, class ValueT>
138  {
139  using MapT = std::map<KeyT, ValueT>;
141  using ElementT = typename Base::ElementT;
142 
143  using CompareFn = std::function<int(const ElementT& element, QTreeWidgetItem* item)>;
144  using NameFn = std::function<std::string(const KeyT& key, const ValueT& value)>;
145 
146  using MakeItemFn = std::function<QTreeWidgetItem*(const KeyT& key, const ValueT& value)>;
147  using UpdateItemFn =
148  std::function<bool(const KeyT& key, const ValueT& value, QTreeWidgetItem* item)>;
149 
151  {
153  }
154 
155  /// Allows declaring instance from container without explicit template arguments.
157  {
158  }
159 
160  MapTreeWidgetBuilder(MakeItemFn makeItemFn, UpdateItemFn updateItemFn = NoUpdate) :
162  {
163  setMakeItemFn(makeItemFn);
164  setUpdateItemFn(updateItemFn);
165  }
166 
168  MakeItemFn makeItemFn,
169  UpdateItemFn updateItemFn = NoUpdate)
170  {
171  setNameFn(nameFn);
172  setMakeItemFn(makeItemFn);
173  setUpdateItemFn(updateItemFn);
174  }
175 
176  void
178  {
179  builder.setNameFn(
180  [nameFn](const ElementT& element)
181  {
182  const auto& [key, value] = element;
183  return nameFn(key, value);
184  });
185  }
186 
187  void
189  {
190  builder.setCompareFn(compareFn);
191  }
192 
193  void
195  {
196  builder.setMakeItemFn(
197  [makeItemFn](const ElementT& element)
198  {
199  const auto& [key, value] = element;
200  return makeItemFn(key, value);
201  });
202  }
203 
204  void
206  {
207  builder.setUpdateItemFn(
208  [updateItemFn](const ElementT& element, QTreeWidgetItem* item)
209  {
210  const auto& [key, value] = element;
211  return updateItemFn(key, value, item);
212  });
213  }
214 
215  void
216  setExpand(bool expand)
217  {
218  builder.setExpand(expand);
219  }
220 
221  template <class ParentT>
222  void
223  updateTree(ParentT* tree, const MapT& elements)
224  {
225  builder.updateTreeWithContainer(tree, elements);
226  }
227 
228  /// A name function using the key as name.
229  static std::string
230  KeyAsName(const KeyT& key, const ValueT& value)
231  {
232  (void)value;
233  if constexpr (std::is_same<KeyT, std::string>())
234  {
235  return key;
236  }
237  else
238  {
239  std::stringstream ss;
240  ss << key;
241  return ss.str();
242  }
243  }
244 
245  /// No update function (default).
246  static bool
247  NoUpdate(const KeyT& key, const ValueT& value, QTreeWidgetItem* item)
248  {
249  (void)key, (void)value, (void)item;
250  return true;
251  }
252 
253 
254  private:
256  };
257 
258  namespace detail
259  {
260  template <class ParentT>
261  struct ParentAPI;
262 
263  template <>
264  struct ParentAPI<QTreeWidget>
265  {
266  static int
267  getItemCount(QTreeWidget* tree)
268  {
269  return tree->topLevelItemCount();
270  }
271 
272  static QTreeWidgetItem*
273  getItem(QTreeWidget* tree, int index)
274  {
275  return tree->topLevelItem(index);
276  }
277 
278  static void
279  insertItem(QTreeWidget* tree, int index, QTreeWidgetItem* item)
280  {
281  tree->insertTopLevelItem(index, item);
282  }
283 
284  static QTreeWidgetItem*
285  takeItem(QTreeWidget* tree, int index)
286  {
287  return tree->takeTopLevelItem(index);
288  }
289  };
290 
291  template <>
292  struct ParentAPI<QTreeWidgetItem>
293  {
294  static int
295  getItemCount(QTreeWidgetItem* parent)
296  {
297  return parent->childCount();
298  }
299 
300  static QTreeWidgetItem*
301  getItem(QTreeWidgetItem* parent, int index)
302  {
303  return parent->child(index);
304  }
305 
306  static QTreeWidgetItem*
307  takeItem(QTreeWidgetItem* parent, int index)
308  {
309  return parent->takeChild(index);
310  }
311 
312  static void
313  insertItem(QTreeWidgetItem* parent, int index, QTreeWidgetItem* item)
314  {
315  parent->insertChild(index, item);
316  }
317  };
318 
319  template <typename T>
320  int
321  compare(const T& lhs, const T& rhs)
322  {
323  if (lhs < rhs)
324  {
325  return -1;
326  }
327  else if (lhs == rhs)
328  {
329  return 0;
330  }
331  else
332  {
333  return 1;
334  }
335  }
336 
337  inline int
338  compare(const std::string& lhs, const std::string& rhs)
339  {
340  return lhs.compare(rhs);
341  }
342  } // namespace detail
343 
344  template <class ElementT>
345  auto
347  {
348  return [nameFn, nameColumn](const ElementT& element, QTreeWidgetItem* item)
349  { return detail::compare(nameFn(element), item->text(nameColumn).toStdString()); };
350  }
351 
352  template <class ElementT>
353  template <class ParentT, class ContainerT>
354  void
356  const ContainerT& elements)
357  {
358  this->updateTreeWithIterator(parent,
359  [&elements](auto&& elementFn)
360  {
361  for (const auto& element : elements)
362  {
363  if (not elementFn(element))
364  {
365  break;
366  }
367  }
368  });
369  }
370 
371  template <class ElementT>
372  template <class ParentT, class IteratorFn>
373  void
374  TreeWidgetBuilder<ElementT>::updateTreeWithIterator(ParentT* parent, IteratorFn&& iteratorFn)
375  {
376  using api = detail::ParentAPI<ParentT>;
377 
378  ARMARX_CHECK_NOT_NULL(makeItemFn) << "makeItemFn must be set";
379  ARMARX_CHECK_NOT_NULL(updateItemFn) << "updateItemFn must be set";
380  ARMARX_CHECK_NOT_NULL(compareFn) << "compareFn must be set";
381 
382  int currentIndex = 0;
383  iteratorFn(
384  [this, &parent, &currentIndex](const auto& element)
385  {
386  bool inserted = false;
387  QTreeWidgetItem* item = nullptr;
388  if (currentIndex >= api::getItemCount(parent))
389  {
390  // Add elements to the end of the list.
391  ARMARX_CHECK_NOT_NULL(makeItemFn);
392  item = makeItemFn(element);
393  api::insertItem(parent, api::getItemCount(parent), item);
394  ++currentIndex;
395  inserted = true;
396  }
397  else
398  {
399  QTreeWidgetItem* currentItem = api::getItem(parent, currentIndex);
400  while (currentItem != nullptr && compareFn(element, currentItem) > 0)
401  {
402  delete api::takeItem(parent, currentIndex);
403  currentItem = api::getItem(parent, currentIndex);
404  }
405  if (currentItem == nullptr || compareFn(element, currentItem) < 0)
406  {
407  // Insert new item before child.
408  item = makeItemFn(element);
409  api::insertItem(parent, currentIndex, item);
410  ++currentIndex;
411  inserted = true;
412  }
413  else if (currentItem != nullptr && compareFn(element, currentItem) == 0)
414  {
415  // Already existing.
416  item = currentItem;
417  ++currentIndex;
418  }
419  }
420  ARMARX_CHECK_NOT_NULL(item);
421  bool cont = updateItemFn(element, item);
422  if (inserted && expand)
423  {
424  item->setExpanded(true);
425  }
426  return cont;
427  });
428  // Remove superfluous items. (currentIndex must point behind the last item)
429  while (api::getItemCount(parent) > currentIndex)
430  {
431  delete api::takeItem(parent, api::getItemCount(parent) - 1);
432  }
433  ARMARX_CHECK_EQUAL(currentIndex, api::getItemCount(parent));
434  }
435 
436 } // namespace armarx
armarx::detail::ParentAPI< QTreeWidgetItem >::getItemCount
static int getItemCount(QTreeWidgetItem *parent)
Definition: TreeWidgetBuilder.h:295
armarx::detail::ParentAPI< QTreeWidget >::insertItem
static void insertItem(QTreeWidget *tree, int index, QTreeWidgetItem *item)
Definition: TreeWidgetBuilder.h:279
armarx::TreeWidgetBuilder::MakeCompareNameFn
static CompareFn MakeCompareNameFn(NameFn nameFn, int nameColumn)
Uses the name for comparison.
Definition: TreeWidgetBuilder.h:346
armarx::detail::ParentAPI< QTreeWidgetItem >::insertItem
static void insertItem(QTreeWidgetItem *parent, int index, QTreeWidgetItem *item)
Definition: TreeWidgetBuilder.h:313
armarx::TreeWidgetBuilder< armarx::armem::server::wm::ProviderSegment >::MakeItemFn
std::function< QTreeWidgetItem *(const ElementT &element)> MakeItemFn
Definition: TreeWidgetBuilder.h:26
armarx::TreeWidgetBuilder::TreeWidgetBuilder
TreeWidgetBuilder(CompareFn compareFn, MakeItemFn makeItemFn, UpdateItemFn updateItemFn=NoUpdate)
Definition: TreeWidgetBuilder.h:37
index
uint8_t index
Definition: EtherCATFrame.h:59
armarx::TreeWidgetBuilder< armarx::armem::server::wm::ProviderSegment >::NameFn
std::function< std::string(const ElementT &element)> NameFn
Definition: TreeWidgetBuilder.h:25
armarx::MapTreeWidgetBuilder::setUpdateItemFn
void setUpdateItemFn(UpdateItemFn updateItemFn)
Definition: TreeWidgetBuilder.h:205
armarx::MapTreeWidgetBuilder< std::string, const armarx::armem::server::wm::Memory * >::MapT
std::map< std::string, const armarx::armem::server::wm::Memory * > MapT
Definition: TreeWidgetBuilder.h:139
armarx::detail::ParentAPI< QTreeWidget >::getItemCount
static int getItemCount(QTreeWidget *tree)
Definition: TreeWidgetBuilder.h:267
ARMARX_CHECK_NOT_NULL
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
Definition: ExpressionException.h:206
armarx::MapTreeWidgetBuilder< std::string, const armarx::armem::server::wm::Memory * >::UpdateItemFn
std::function< bool(const std::string &key, const const armarx::armem::server::wm::Memory * &value, QTreeWidgetItem *item)> UpdateItemFn
Definition: TreeWidgetBuilder.h:148
armarx::MapTreeWidgetBuilder
A class to efficiently build and maintain sorted items of QTreeWidget or QTreeWidgetItem based on a m...
Definition: TreeWidgetBuilder.h:137
armarx::MapTreeWidgetBuilder::setExpand
void setExpand(bool expand)
Definition: TreeWidgetBuilder.h:216
armarx::MapTreeWidgetBuilder::MapTreeWidgetBuilder
MapTreeWidgetBuilder(const MapT &)
Allows declaring instance from container without explicit template arguments.
Definition: TreeWidgetBuilder.h:156
armarx::detail::ParentAPI< QTreeWidgetItem >::takeItem
static QTreeWidgetItem * takeItem(QTreeWidgetItem *parent, int index)
Definition: TreeWidgetBuilder.h:307
detail
Definition: OpenCVUtil.cpp:128
armarx::MapTreeWidgetBuilder< std::string, const armarx::armem::server::wm::Memory * >::MakeItemFn
std::function< QTreeWidgetItem *(const std::string &key, const const armarx::armem::server::wm::Memory * &value)> MakeItemFn
Definition: TreeWidgetBuilder.h:146
armarx::MapTreeWidgetBuilder::MapTreeWidgetBuilder
MapTreeWidgetBuilder()
Definition: TreeWidgetBuilder.h:150
armarx::MapTreeWidgetBuilder::updateTree
void updateTree(ParentT *tree, const MapT &elements)
Definition: TreeWidgetBuilder.h:223
armarx::TreeWidgetBuilder::setNameFn
void setNameFn(NameFn nameFn, int nameColumn=0)
Definition: TreeWidgetBuilder.h:61
armarx::TreeWidgetBuilder::NoUpdate
static bool NoUpdate(const ElementT &element, QTreeWidgetItem *item)
No update function (default).
Definition: TreeWidgetBuilder.h:113
armarx::TreeWidgetBuilder::updateTreeWithIterator
void updateTreeWithIterator(ParentT *parent, IteratorFn &&iteratorFn)
Update the tree according to the elements iterated over by iteratorFn.
Definition: TreeWidgetBuilder.h:374
armarx::MapTreeWidgetBuilder::setNameFn
void setNameFn(NameFn nameFn)
Definition: TreeWidgetBuilder.h:177
armarx::TreeWidgetBuilder::updateTreeWithContainer
void updateTreeWithContainer(ParentT *parent, const ContainerT &elements)
Update the tree with the iterable container.
Definition: TreeWidgetBuilder.h:355
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
armarx::MapTreeWidgetBuilder::KeyAsName
static std::string KeyAsName(const KeyT &key, const ValueT &value)
A name function using the key as name.
Definition: TreeWidgetBuilder.h:230
armarx::MapTreeWidgetBuilder< std::string, const armarx::armem::server::wm::Memory * >::CompareFn
std::function< int(const ElementT &element, QTreeWidgetItem *item)> CompareFn
Definition: TreeWidgetBuilder.h:143
armarx::TreeWidgetBuilder::TreeWidgetBuilder
TreeWidgetBuilder()=default
armarx::detail::ParentAPI< QTreeWidget >::getItem
static QTreeWidgetItem * getItem(QTreeWidget *tree, int index)
Definition: TreeWidgetBuilder.h:273
armarx::TreeWidgetBuilder< typename MapT::value_type >
armarx::TreeWidgetBuilder::setUpdateItemFn
void setUpdateItemFn(UpdateItemFn updateItemFn)
Definition: TreeWidgetBuilder.h:73
armarx::detail::ParentAPI
Definition: TreeWidgetBuilder.h:261
armarx::armem::server::wm::ProviderSegment
Definition: memory_definitions.h:52
armarx::TreeWidgetBuilder::setMakeItemFn
void setMakeItemFn(MakeItemFn makeItemFn)
Definition: TreeWidgetBuilder.h:67
armarx::detail::compare
int compare(const T &lhs, const T &rhs)
Definition: TreeWidgetBuilder.h:321
armarx::MapTreeWidgetBuilder< std::string, const armarx::armem::server::wm::Memory * >::NameFn
std::function< std::string(const std::string &key, const const armarx::armem::server::wm::Memory * &value)> NameFn
Definition: TreeWidgetBuilder.h:144
armarx::MapTreeWidgetBuilder< std::string, const armarx::armem::server::wm::Memory * >::ElementT
typename Base::ElementT ElementT
Definition: TreeWidgetBuilder.h:141
ExpressionException.h
armarx::MapTreeWidgetBuilder::setMakeItemFn
void setMakeItemFn(MakeItemFn makeItemFn)
Definition: TreeWidgetBuilder.h:194
armarx::detail::ParentAPI< QTreeWidget >::takeItem
static QTreeWidgetItem * takeItem(QTreeWidget *tree, int index)
Definition: TreeWidgetBuilder.h:285
armarx::TreeWidgetBuilder< armarx::armem::server::wm::ProviderSegment >::CompareFn
std::function< int(const ElementT &element, QTreeWidgetItem *item)> CompareFn
Return < 0 if element < item, 0 if element == item, and > 0 if element > item.
Definition: TreeWidgetBuilder.h:24
armarx::TreeWidgetBuilder::TreeWidgetBuilder
TreeWidgetBuilder(NameFn nameFn, MakeItemFn makeItemFn, UpdateItemFn updateItemFn=NoUpdate, int nameColumn=0)
Definition: TreeWidgetBuilder.h:44
armarx::TreeWidgetBuilder< typename MapT::value_type >::ElementT
typename MapT::value_type ElementT
Definition: TreeWidgetBuilder.h:21
armarx::TreeWidgetBuilder< armarx::armem::server::wm::ProviderSegment >::UpdateItemFn
std::function< bool(const ElementT &element, QTreeWidgetItem *item)> UpdateItemFn
Definition: TreeWidgetBuilder.h:27
T
float T
Definition: UnscentedKalmanFilterTest.cpp:38
ARMARX_CHECK_EQUAL
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
Definition: ExpressionException.h:130
armarx::detail::ParentAPI< QTreeWidgetItem >::getItem
static QTreeWidgetItem * getItem(QTreeWidgetItem *parent, int index)
Definition: TreeWidgetBuilder.h:301
armarx::TreeWidgetBuilder::setExpand
void setExpand(bool expand)
Definition: TreeWidgetBuilder.h:79
armarx::TreeWidgetBuilder::TreeWidgetBuilder
TreeWidgetBuilder(const ElementT &)
Constructor to automatically derive the template argument.
Definition: TreeWidgetBuilder.h:33
armarx::MapTreeWidgetBuilder::MapTreeWidgetBuilder
MapTreeWidgetBuilder(NameFn nameFn, MakeItemFn makeItemFn, UpdateItemFn updateItemFn=NoUpdate)
Definition: TreeWidgetBuilder.h:167
armarx::MapTreeWidgetBuilder::NoUpdate
static bool NoUpdate(const KeyT &key, const ValueT &value, QTreeWidgetItem *item)
No update function (default).
Definition: TreeWidgetBuilder.h:247
armarx::MapTreeWidgetBuilder::setCompareFn
void setCompareFn(CompareFn compareFn)
Definition: TreeWidgetBuilder.h:188
armarx::TreeWidgetBuilder::setCompareFn
void setCompareFn(CompareFn compareFn)
Definition: TreeWidgetBuilder.h:55
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::MapTreeWidgetBuilder::MapTreeWidgetBuilder
MapTreeWidgetBuilder(MakeItemFn makeItemFn, UpdateItemFn updateItemFn=NoUpdate)
Definition: TreeWidgetBuilder.h:160