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