curvetree_view.cpp
Go to the documentation of this file.
1 /*
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5  */
6 
7 #include "curvetree_view.h"
8 #include "curvelist_panel.h"
9 #include <QFontDatabase>
10 #include <QObject>
11 #include <QDebug>
12 #include <QToolTip>
13 #include <QKeySequence>
14 #include <QClipboard>
15 
16 class TreeWidgetItem : public QTreeWidgetItem
17 {
18 public:
19  TreeWidgetItem(QTreeWidgetItem* parent) : QTreeWidgetItem(parent)
20  {
21  }
22 
23  bool operator<(const QTreeWidgetItem& other) const
24  {
25  return doj::alphanum_impl(this->text(0).toLocal8Bit(), other.text(0).toLocal8Bit()) <
26  0;
27  }
28 };
29 
31  : QTreeWidget(parent), CurvesView(parent)
32 {
33  setColumnCount(2);
34  setEditTriggers(NoEditTriggers);
35  setDragEnabled(false);
36  setDefaultDropAction(Qt::IgnoreAction);
37  setDragDropOverwriteMode(false);
38  setMouseTracking(true);
39  setDragDropMode(NoDragDrop);
40  viewport()->installEventFilter(this);
41  setSelectionMode(ExtendedSelection);
42  setSelectionBehavior(QAbstractItemView::SelectRows);
43  setFocusPolicy(Qt::ClickFocus);
44 
45  header()->setVisible(false);
46  header()->setStretchLastSection(true);
47  header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
48  setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
49 
50  connect(this, &QTreeWidget::itemDoubleClicked, this,
51  [this](QTreeWidgetItem* item, int column) {
52  if (column == 0)
53  {
54  expandChildren(!item->isExpanded(), item);
55  }
56  });
57 
58  connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, [this]() {
59  if (getSelectedNames().empty())
60  {
61  // this looks nicer
62  clearFocus();
63  setFocusPolicy(Qt::NoFocus);
64  }
65  else
66  {
67  // this focus policy is needed to allow CurveListPanel::keyPressEvent to be called
68  setFocusPolicy(Qt::ClickFocus);
69  }
70  });
71 }
72 
73 void CurveTreeView::addItem(const QString& group_name, const QString& tree_name,
74  const QString& plot_ID)
75 {
76  QSettings settings; /*
77  * This Source Code Form is subject to the terms of the Mozilla
78  * Public License, v. 2.0. If a copy of the MPL was not distributed
79  * with this file, You can obtain one at
80  * https://mozilla.org/MPL/2.0/.
81  */
82 
83  bool use_separator = settings.value("Preferences::use_separator", true).toBool();
84 
85  QStringList parts;
86  if (use_separator)
87  {
88  parts = tree_name.split('/', QString::SplitBehavior::SkipEmptyParts);
89  }
90  else
91  {
92  parts.push_back(tree_name);
93  }
94 
95  if (parts.size() == 0)
96  {
97  return;
98  }
99 
100  bool prefix_is_group = tree_name.startsWith(group_name);
101  bool hasGroup = !group_name.isEmpty();
102  auto group_parts = group_name.split('/', QString::SplitBehavior::SkipEmptyParts);
103 
104  if (hasGroup && !prefix_is_group)
105  {
106  parts = group_parts + parts;
107  }
108 
109  QTreeWidgetItem* tree_parent = this->invisibleRootItem();
110 
111  for (int i = 0; i < parts.size(); i++)
112  {
113  bool is_leaf = (i == parts.size() - 1);
114  const auto& part = parts[i];
115 
116  QTreeWidgetItem* matching_child = nullptr;
117 
118  for (int c = 0; c < tree_parent->childCount(); c++)
119  {
120  QTreeWidgetItem* tree_child = tree_parent->child(c);
121  if (tree_child->text(0) == part)
122  {
123  matching_child = tree_child;
124  break;
125  }
126  }
127 
128  if (matching_child)
129  {
130  tree_parent = matching_child;
131  }
132  else
133  {
134  QTreeWidgetItem* child_item = new TreeWidgetItem(tree_parent);
135  child_item->setText(0, part);
136  child_item->setText(1, is_leaf ? "-" : "");
137 
138  bool isGroupCell = (i < group_parts.size());
139 
140  QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
141  font.setPointSize(_point_size);
142  // font.setBold(isGroupCell);
143  child_item->setFont(0, font);
144 
145  font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
146  font.setPointSize(_point_size - 2);
147  child_item->setFont(1, font);
148  child_item->setTextAlignment(1, Qt::AlignRight);
149 
150  tree_parent = child_item;
151 
152  auto current_flag = child_item->flags();
153 
154  if (isGroupCell)
155  {
156  child_item->setData(0, Name, group_name);
157  child_item->setData(0, IsGroupName, (i + 1) == group_parts.size());
158  }
159 
160  if (is_leaf)
161  {
162  child_item->setFlags(current_flag | Qt::ItemIsSelectable);
163  child_item->setData(0, Name, plot_ID);
164  }
165  else
166  {
167  child_item->setFlags(current_flag & (~Qt::ItemIsSelectable));
168  }
169  }
170  }
171  _leaf_count++;
172 }
173 
175 {
176  invisibleRootItem()->sortChildren(0, Qt::AscendingOrder);
177  treeVisitor([&](QTreeWidgetItem* item) { item->sortChildren(0, Qt::AscendingOrder); });
178  header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
179  // TODO emit updateFilter();
180 }
181 
182 std::vector<std::string> CurveTreeView::getSelectedNames()
183 {
184  std::vector<std::string> non_hidden_list;
185 
186  for (const auto& item : selectedItems())
187  {
188  non_hidden_list.push_back(item->data(0, Qt::UserRole).toString().toStdString());
189  }
190  return non_hidden_list;
191 }
192 
194 {
195  header()->setSectionResizeMode(0, QHeaderView::Fixed);
196  header()->setSectionResizeMode(1, QHeaderView::Fixed);
197 
198  treeVisitor([this](QTreeWidgetItem* item) {
199  auto font = item->font(0);
200  font.setPointSize(_point_size);
201  item->setFont(0, font);
202  font = item->font(1);
203  font.setPointSize(_point_size - 2);
204  item->setFont(1, font);
205  });
206 
207  header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
208  header()->setSectionResizeMode(1, QHeaderView::Stretch);
209 }
210 
211 bool CurveTreeView::applyVisibilityFilter(const QString& search_string)
212 {
213  bool updated = false;
214  _hidden_count = 0;
215 
216  QStringList spaced_items = search_string.split(' ', QString::SkipEmptyParts);
217 
218  auto hideFunc = [&](QTreeWidgetItem* item) {
219  QString name = item->data(0, Qt::UserRole).toString();
220  if (name.isEmpty())
221  {
222  return; // not a leaf
223  }
224  bool toHide = false;
225 
226  if (search_string.isEmpty() == false)
227  {
228  for (const auto& spaced_item : spaced_items)
229  {
230  if (name.contains(spaced_item, Qt::CaseInsensitive) == false)
231  {
232  toHide = true;
233  break;
234  }
235  }
236  }
237  if (toHide)
238  {
239  _hidden_count++;
240  }
241 
242  if (toHide != item->isHidden())
243  {
244  updated = true;
245  }
246 
247  item->setHidden(toHide);
248 
249  // hide the parent if necessary
250  auto parent = item->parent();
251  while (parent)
252  {
253  bool all_children_hidden = true;
254  for (int c = 0; c < parent->childCount(); c++)
255  {
256  if (!parent->child(c)->isHidden())
257  {
258  all_children_hidden = false;
259  break;
260  }
261  }
262  auto parent_hidden = parent->isHidden();
263  if (all_children_hidden != parent_hidden)
264  {
265  parent->setHidden(all_children_hidden);
266  parent = parent->parent();
267  }
268  else
269  {
270  break;
271  }
272  }
273  };
274 
275  treeVisitor(hideFunc);
276  //-------------
277 
278  return updated;
279 }
280 
281 bool CurveTreeView::eventFilter(QObject* object, QEvent* event)
282 {
283  if (event->type() == QEvent::MouseMove)
284  {
285  auto mouse_event = static_cast<QMouseEvent*>(event);
286  auto* item = itemAt(mouse_event->pos());
287  if (item)
288  {
289  auto tooltip = item->data(0, CustomRoles::ToolTip);
290  if (tooltip.isValid())
291  {
292  QToolTip::showText(mapToGlobal(mouse_event->pos()), tooltip.toString());
293  }
294  else
295  {
296  QToolTip::hideText();
297  }
298  }
299  }
300 
301  bool ret = CurvesView::eventFilterBase(object, event);
302  if (!ret)
303  {
304  return QWidget::eventFilter(object, event);
305  }
306  else
307  {
308  return true;
309  }
310 }
311 
312 void CurveTreeView::removeCurve(const QString& to_be_deleted)
313 {
314  auto removeFunc = [&](QTreeWidgetItem* item) {
315  QString curve_name = item->data(0, Qt::UserRole).toString();
316  if (curve_name == to_be_deleted)
317  {
318  _leaf_count--;
319  auto parent_item = item->parent();
320  if (!parent_item)
321  {
322  parent_item = invisibleRootItem();
323  }
324  parent_item->removeChild(item);
325 
326  while (parent_item->childCount() == 0 && parent_item != invisibleRootItem())
327  {
328  auto prev_item = parent_item;
329  parent_item = parent_item->parent();
330  if (!parent_item)
331  {
332  parent_item = invisibleRootItem();
333  }
334  parent_item->removeChild(prev_item);
335  }
336  }
337  };
338 
339  treeVisitor(removeFunc);
340 }
341 
343 {
344  setViewResizeEnabled(true);
345  setColumnHidden(1, hide);
346 }
347 
348 void CurveTreeView::treeVisitor(std::function<void(QTreeWidgetItem*)> visitor)
349 {
350  std::function<void(QTreeWidgetItem*)> recursiveFunction;
351  recursiveFunction = [&](QTreeWidgetItem* item) {
352  visitor(item);
353  for (int c = 0; c < item->childCount(); c++)
354  {
355  recursiveFunction(item->child(c));
356  }
357  };
358 
359  for (int c = 0; c < invisibleRootItem()->childCount(); c++)
360  {
361  recursiveFunction(invisibleRootItem()->child(c));
362  }
363 }
364 
365 void CurveTreeView::keyPressEvent(QKeyEvent* event)
366 {
367  if (event->matches(QKeySequence::Copy))
368  {
369  auto selected = selectedItems();
370  if (selected.size() > 0)
371  {
372  QClipboard* clipboard = QApplication::clipboard();
373  clipboard->setText(selected.front()->data(0, Name).toString());
374  }
375  }
376 }
377 
378 void CurveTreeView::expandChildren(bool expanded, QTreeWidgetItem* item)
379 {
380  int childCount = item->childCount();
381  for (int i = 0; i < childCount; i++)
382  {
383  const auto child = item->child(i);
384  // Recursively call the function for each child node.
385  if (child->childCount() > 0)
386  {
387  child->setExpanded(expanded);
388  expandChildren(expanded, child);
389  }
390  }
391 }
std::vector< std::string > getSelectedNames() override
void expandChildren(bool expanded, QTreeWidgetItem *item)
void removeCurve(const QString &name) override
void treeVisitor(std::function< void(QTreeWidgetItem *)> visitor)
TreeWidgetItem(QTreeWidgetItem *parent)
void addItem(const QString &prefix, const QString &tree_name, const QString &plot_ID) override
virtual void keyPressEvent(QKeyEvent *) override
bool eventFilter(QObject *object, QEvent *event) override
void refreshColumns() override
bool operator<(const QTreeWidgetItem &other) const
void refreshFontSize() override
CurveTreeView(CurveListPanel *parent)
void setViewResizeEnabled(bool) override
const std::string header
bool applyVisibilityFilter(const QString &filter_string) override
bool eventFilterBase(QObject *object, QEvent *event)
virtual void hideValuesColumn(bool hide) override


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:01