31 #include <QMessageBox>
32 #include <QMouseEvent>
33 #include <QTreeWidget>
42 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
44 _signal_helper = signal_helper;
46 _main_layout =
new QVBoxLayout(
this);
47 _main_layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
48 _main_layout->setContentsMargins(0, 0, 0, 0);
50 QHBoxLayout* title_layout =
new QHBoxLayout;
51 title_layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
52 title_layout->setContentsMargins(5, 5, 5, 5);
53 title_layout->addWidget(
new QLabel(tr(
"Available Signals")));
55 _main_layout->addLayout(title_layout);
57 _signal_tree = createSignalTree();
58 _main_layout->addWidget(_signal_tree);
61 _main_layout->addSpacing(10);
64 SignalCollectionWidget::~SignalCollectionWidget() {}
66 QSize SignalCollectionWidget::sizeHint()
const {
return QSize(200, 800); }
68 ExtendedTreeWidget* SignalCollectionWidget::createSignalTree()
70 ExtendedTreeWidget* signal_tree =
new ExtendedTreeWidget;
71 signal_tree->viewport()->setBackgroundRole(QPalette::Background);
72 signal_tree->setAttribute(Qt::WA_MacShowFocusRect,
false);
76 signal_tree->setHeaderHidden(
true);
77 signal_tree->setIndentation(10);
78 signal_tree->setStyleSheet(
"QTreeView { border: none; }");
79 signal_tree->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
80 signal_tree->setContextMenuPolicy(Qt::CustomContextMenu);
81 signal_tree->connect(signal_tree, &QTreeWidget::customContextMenuRequested,
82 [
this, signal_tree](
const QPoint& point) { this->namespaceContextMenu(point, signal_tree); });
88 _current_task_id = _signal_helper->currentSeriesId();
90 QStringList namespaces = signal_data.
namespaces;
91 namespaces.pop_back();
93 QVector<QTreeWidgetItem*> namespace_items;
95 for (
const QString& group : namespaces)
98 QTreeWidgetItem* current_item =
nullptr;
99 if (namespace_items.empty())
101 QList<QTreeWidgetItem*> items = _signal_tree->findItems(group, Qt::MatchExactly);
102 if (!items.empty()) current_item = items.front();
107 for (
int i = 0; i < namespace_items.back()->childCount(); ++i)
109 if (namespace_items.back()->child(i)->text(0) == group)
111 current_item = namespace_items.back()->child(i);
119 QTreeWidgetItem* item =
new QTreeWidgetItem;
120 if (namespace_items.empty())
121 _signal_tree->addTopLevelItem(item);
123 namespace_items.back()->addChild(item);
124 item->setText(0, group);
125 namespace_items.push_back(item);
130 namespace_items.push_back(current_item);
136 int dimension = signal_data.
signal->header.value_dimension;
138 if (dimension == 0)
return;
140 QTreeWidgetItem* item =
new QTreeWidgetItem;
141 if (namespace_items.empty())
142 _signal_tree->addTopLevelItem(item);
144 namespace_items.back()->addChild(item);
149 SignalWidget* signal_widget =
new SignalWidget(signal_data.
short_name, key, 0);
151 _signal_tree->setItemWidget(item, 0, signal_widget);
156 item->setText(0, signal_data.
namespaces.back());
158 for (
int i = 0; i < dimension; ++i)
161 QTreeWidgetItem* subitem =
new QTreeWidgetItem;
162 item->addChild(subitem);
166 SignalWidget* signal_widget =
new SignalWidget(sublabel, key, i);
168 _signal_tree->setItemWidget(subitem, 0, signal_widget);
172 _signal_tree->updateSizeHint();
175 void SignalCollectionWidget::moveToRecent(
const QDateTime& dtime)
177 ExtendedTreeWidget* new_tree = createSignalTree();
178 QLayoutItem* current_tree = _main_layout->replaceWidget(_signal_tree, new_tree, Qt::FindDirectChildrenOnly);
179 _signal_tree = new_tree;
184 QString groupname =
"data_" + dtime.toString(
"yyyy_MM_dd_hh_mm_ss");
185 _signal_helper->getSignalTreeRef()[_current_task_id].setTopLevelGroupName(groupname.toStdString());
190 QVBoxLayout* layout =
new QVBoxLayout;
191 layout->setContentsMargins(15, 0, 0, 0);
192 layout->addItem(current_tree);
194 QString title = dtime.toString(
"dd.MM.yyyy hh:mm:ss");
195 CollapsableGroupBox* group =
new CollapsableGroupBox(title);
198 group->setContextMenuPolicy(Qt::CustomContextMenu);
199 int task_id = _current_task_id;
200 group->connect(group, &QTreeWidget::customContextMenuRequested,
201 [
this, group, task_id](
const QPoint& point) { this->recentGroupContextMenu(point, group, task_id); });
203 group->groupBox()->setLayout(layout);
205 _recent_signals.push_back(
std::make_tuple(group, current_tree->widget(), _current_task_id));
206 _main_layout->addWidget(group);
212 void SignalCollectionWidget::removeTreeItem(
const QString& key,
int value_idx)
216 SignalHelper::key2Name(key, name,
id);
218 CollapsableGroupBox* group_box =
nullptr;
219 QTreeWidget* tree =
nullptr;
220 auto group_it = _recent_signals.end();
223 if (
id == _current_task_id)
229 group_it = std::find_if(_recent_signals.begin(), _recent_signals.end(),
230 [
id](
const std::tuple<CollapsableGroupBox*, QWidget*, int> item) { return id == std::get<2>(item); });
231 if (group_it != _recent_signals.end())
233 group_box = std::get<0>(*group_it);
234 tree =
static_cast<QTreeWidget*
>(std::get<1>(*group_it));
241 QStringList namespaces;
242 SignalHelper::extractNamespace(name, namespaces);
245 QTreeWidgetItem* item =
nullptr;
246 QTreeWidgetItem* candidate =
nullptr;
250 for (
int n = 0;
n < namespaces.size() + 1; ++
n)
256 no_items = tree->topLevelItemCount();
258 no_items = item->childCount();
262 for (
int i = 0; i < no_items; ++i)
264 QTreeWidgetItem* child = (
n == 0) ? tree->topLevelItem(i) : item->child(i);
270 if (signal_widget->
key().compare(key) == 0)
272 if (signal_widget->
valueIdx() == value_idx || value_idx == SignalHelper::ALL_VALUES)
282 if (
n < namespaces.size() && child->text(0).compare(namespaces[
n]) == 0)
284 if (namespaces.size() ==
n + 1)
286 if (value_idx == SignalHelper::ALL_VALUES)
299 if (!candidate)
return;
302 QTreeWidgetItem* parent = candidate->parent();
303 QTreeWidgetItem* parent_candidate =
nullptr;
304 while (parent !=
nullptr)
306 if (parent->childCount() > 1)
break;
307 parent_candidate = parent;
308 parent = parent->parent();
311 if (parent_candidate)
312 delete parent_candidate;
317 if (group_box && group_it != _recent_signals.end() && tree->topLevelItemCount() == 0)
319 int task_id = std::get<2>(*group_it);
320 group_box->deleteLater();
321 _recent_signals.erase(group_it);
322 emit taskRemoved(task_id);
326 void SignalCollectionWidget::getGroupInfo(
const QTreeWidget* tree,
const QTreeWidgetItem* item, QString* name_out,
int* id_out)
329 int task_id = _current_task_id;
330 auto group_it = std::find_if(_recent_signals.begin(), _recent_signals.end(),
331 [tree](
const std::tuple<CollapsableGroupBox*, QWidget*, int> item) { return tree == std::get<1>(item); });
332 if (group_it != _recent_signals.end()) task_id = std::get<2>(*group_it);
334 if (id_out) *id_out = task_id;
339 const QTreeWidgetItem* parent = item->parent();
340 QString name = item->text(0);
341 while (parent !=
nullptr)
344 parent = parent->parent();
350 void SignalCollectionWidget::removeSignal(QTreeWidget* tree, QTreeWidgetItem* item)
353 int task_id = _current_task_id;
354 auto group_it = std::find_if(_recent_signals.begin(), _recent_signals.end(),
355 [tree](
const std::tuple<CollapsableGroupBox*, QWidget*, int> item) { return tree == std::get<1>(item); });
356 if (group_it != _recent_signals.end()) task_id = std::get<2>(*group_it);
359 SignalWidget* signal_widget =
dynamic_cast<SignalWidget*
>(tree->itemWidget(item, 0));
362 _signal_helper->removeSignal(signal_widget->key(), signal_widget->valueIdx());
367 QTreeWidgetItem* parent = item->parent();
368 QString name = item->text(0);
369 while (parent !=
nullptr)
372 parent = parent->parent();
374 _signal_helper->clearNamespace(name, task_id);
378 void SignalCollectionWidget::recentGroupContextMenu(
const QPoint& point, CollapsableGroupBox* group,
int task_id)
384 QAction* restore_param_action =
new QAction(tr(
"Restore Parameters"),
this);
385 connect(restore_param_action, &QAction::triggered, [
this, task_id]() {
386 if (QMessageBox::Yes ==
387 QMessageBox(QMessageBox::Information,
"Restore Parameters",
"Do you really want to restore parameters?",
388 QMessageBox::Yes | QMessageBox::No)
391 emit requestTaskParameterBackup(task_id);
394 menu.addAction(restore_param_action);
399 QMenu* menu_export = menu.addMenu(tr(
"Export to ..."));
401 auto it = _signal_helper->getSignalTreeRef().find(task_id);
402 if (it != _signal_helper->getSignalTreeRef().end())
410 if (exporter_in_factory->isSupportingSignalGroup())
412 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
413 connect(export_group_action, &QAction::triggered, [
this, signal_group, exporter_in_factory]() {
415 exporter_in_factory->getInstance();
416 QString format_name = QString::fromStdString(exporter->getFormatName());
417 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
419 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
421 exporter->exportSignalGroup(
filename, (*signal_group));
423 menu_export->addAction(export_group_action);
430 QAction* remove_action =
new QAction(tr(
"Remove Signals"),
this);
431 connect(remove_action, &QAction::triggered, [
this, task_id]() { _signal_helper->clearSeries(task_id); });
432 menu.addAction(remove_action);
434 menu.exec(group->mapToGlobal(point));
437 void SignalCollectionWidget::namespaceContextMenu(
const QPoint& point, QTreeWidget* tree)
442 if (tree == _signal_tree)
return;
444 QTreeWidgetItem* item = tree->itemAt(point);
450 SignalWidget* signal_widget =
dynamic_cast<SignalWidget*
>(tree->itemWidget(item, 0));
454 addContextActionsSingleValueSignal(*signal_widget, menu);
457 QAction* remove_action =
new QAction(tr(
"Remove Signal"),
this);
458 connect(remove_action, &QAction::triggered, [
this, tree, item]() { removeSignal(tree, item); });
459 menu.addAction(remove_action);
466 getGroupInfo(tree, item, &name, &
id);
469 QMenu* menu_export = menu.addMenu(tr(
"Export to ..."));
471 auto it = _signal_helper->getSignalTreeRef().find(
id);
472 if (it != _signal_helper->getSignalTreeRef().end())
474 CommonSignalTarget::SignalGroup* signal_group = it->second.getGroup(name.toStdString());
481 if (exporter_in_factory->isSupportingSignalGroup())
483 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
484 connect(export_group_action, &QAction::triggered, [
this, signal_group, exporter_in_factory]() {
488 QString format_name = QString::fromStdString(exporter->getFormatName());
489 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
490 std::string
filename = QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix,
491 format_name +
" File (* " + file_suffix +
")")
493 exporter->exportSignalGroup(
filename, (*signal_group));
495 menu_export->addAction(export_group_action);
505 addContextActionsMultiValueSignal(signal, menu, *menu_export);
516 QAction* remove_action =
new QAction(tr(
"Remove Signals"),
this);
517 connect(remove_action, &QAction::triggered, [
this, tree, item]() { removeSignal(tree, item); });
518 menu.addAction(remove_action);
521 menu.exec(tree->mapToGlobal(point));
524 void SignalCollectionWidget::addContextActionsSingleValueSignal(SignalWidget& signal_widget, QMenu& menu)
527 SignalHelper::SignalData* signal_data = _signal_helper->signalData(signal_widget.key());
528 int signal_value_idx = signal_widget.valueIdx();
529 if (!signal_data)
return;
535 addContextActionsTimeSeriesSignal(ts_signal, menu, signal_value_idx);
542 addContextActionsTimeSeriesSequenceSignal(ts_seq_signal, menu, signal_value_idx);
549 addContextActionsIndexedValuesSetSignal(ivs_signal, menu);
553 MatrixSignal::Ptr matrix_signal = std::dynamic_pointer_cast<MatrixSignal>(signal_data->signal);
556 addContextActionsMatrixSignal(matrix_signal, menu);
560 MatrixSetSignal::Ptr matrix_set_signal = std::dynamic_pointer_cast<MatrixSetSignal>(signal_data->signal);
561 if (matrix_set_signal)
563 addContextActionsMatrixSetSignal(matrix_set_signal, menu);
567 void SignalCollectionWidget::addContextActionsMultiValueSignal(
SignalInterface::Ptr signal, QMenu& menu, QMenu& menu_export)
573 addContextActionsTimeSeriesSignal(ts_signal, menu, &menu_export);
580 addContextActionsTimeSeriesSequenceSignal(ts_seq_signal, menu, &menu_export);
587 addContextActionsIndexedValuesSetSignal(ivs_signal, menu, &menu_export);
591 void SignalCollectionWidget::addContextActionsTimeSeriesSignal(
TimeSeriesSignal::Ptr ts_signal, QMenu& menu,
int signal_value_idx, QMenu* menu_export)
593 if (!ts_signal)
return;
597 QMenu* menu_normalization = menu.addMenu(tr(
"Normalization"));
600 QAction* normalize_firstval_action =
new QAction(tr(
"Normalize by First Value"),
this);
601 connect(normalize_firstval_action, &QAction::triggered,
603 menu_normalization->addAction(normalize_firstval_action);
606 QAction* normalize_absmax_action =
new QAction(tr(
"Normalize by Absolute Maximum"),
this);
607 connect(normalize_absmax_action, &QAction::triggered, [ts_signal, signal_value_idx]() {
610 menu_normalization->addAction(normalize_absmax_action);
613 QAction* normalize_mean_action =
new QAction(tr(
"Normalize by Mean"),
this);
614 connect(normalize_mean_action, &QAction::triggered,
616 menu_normalization->addAction(normalize_mean_action);
621 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
627 if (exporter_in_factory->isSupportingTimeSeriesSignal())
629 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
630 connect(export_group_action, &QAction::triggered, [
this, ts_signal, exporter_in_factory]() {
632 exporter_in_factory->getInstance();
633 QString format_name = QString::fromStdString(exporter->getFormatName());
634 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
636 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
638 exporter->exportTimeSeriesSignal(
filename, (*ts_signal));
640 menu_export_aux->addAction(export_group_action);
645 void SignalCollectionWidget::addContextActionsTimeSeriesSignal(
TimeSeriesSignal::Ptr ts_signal, QMenu& menu, QMenu* menu_export)
647 if (!ts_signal)
return;
649 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
655 if (exporter_in_factory->isSupportingTimeSeriesSignal())
657 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
658 connect(export_group_action, &QAction::triggered, [
this, ts_signal, exporter_in_factory]() {
660 exporter_in_factory->getInstance();
661 QString format_name = QString::fromStdString(exporter->getFormatName());
662 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
664 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
666 exporter->exportTimeSeriesSignal(
filename, (*ts_signal));
668 menu_export_aux->addAction(export_group_action);
673 void SignalCollectionWidget::addContextActionsTimeSeriesSequenceSignal(
TimeSeriesSequenceSignal::Ptr ts_seq_signal, QMenu& menu,
int signal_value_idx,
676 if (!ts_seq_signal)
return;
678 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
684 if (exporter_in_factory->isSupportingTimeSeriesSequenceSignal())
686 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
687 connect(export_group_action, &QAction::triggered, [
this, ts_seq_signal, exporter_in_factory]() {
689 exporter_in_factory->getInstance();
690 QString format_name = QString::fromStdString(exporter->getFormatName());
691 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
693 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
695 exporter->exportTimeSeriesSequenceSignal(
filename, (*ts_seq_signal));
697 menu_export_aux->addAction(export_group_action);
702 void SignalCollectionWidget::addContextActionsTimeSeriesSequenceSignal(
TimeSeriesSequenceSignal::Ptr ts_seq_signal, QMenu& menu, QMenu* menu_export)
704 if (!ts_seq_signal)
return;
706 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
712 if (exporter_in_factory->isSupportingTimeSeriesSequenceSignal())
714 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
715 connect(export_group_action, &QAction::triggered, [
this, ts_seq_signal, exporter_in_factory]() {
717 exporter_in_factory->getInstance();
718 QString format_name = QString::fromStdString(exporter->getFormatName());
719 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
721 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
723 exporter->exportTimeSeriesSequenceSignal(
filename, (*ts_seq_signal));
725 menu_export_aux->addAction(export_group_action);
730 void SignalCollectionWidget::addContextActionsIndexedValuesSetSignal(
IndexedValuesSetSignal::Ptr ivs_signal, QMenu& menu, QMenu* menu_export)
732 if (!ivs_signal)
return;
734 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
740 if (exporter_in_factory->isSupportingIndexedValuesSetSignal())
742 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
743 connect(export_group_action, &QAction::triggered, [
this, ivs_signal, exporter_in_factory]() {
745 exporter_in_factory->getInstance();
746 QString format_name = QString::fromStdString(exporter->getFormatName());
747 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
749 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
751 exporter->exportIndexedValuesSetSignal(
filename, (*ivs_signal));
753 menu_export_aux->addAction(export_group_action);
758 void SignalCollectionWidget::addContextActionsMatrixSignal(
MatrixSignal::Ptr mat_signal, QMenu& menu, QMenu* menu_export)
760 if (!mat_signal)
return;
762 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
768 if (exporter_in_factory->isSupportingMatrixSignal())
770 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
771 connect(export_group_action, &QAction::triggered, [
this, mat_signal, exporter_in_factory]() {
773 exporter_in_factory->getInstance();
774 QString format_name = QString::fromStdString(exporter->getFormatName());
775 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
777 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
779 exporter->exportMatrixSignal(
filename, (*mat_signal));
781 menu_export_aux->addAction(export_group_action);
786 void SignalCollectionWidget::addContextActionsMatrixSetSignal(
MatrixSetSignal::Ptr mat_set_signal, QMenu& menu, QMenu* menu_export)
788 if (!mat_set_signal)
return;
790 QMenu* menu_export_aux = menu_export ? menu_export : menu.addMenu(tr(
"Export to ..."));
796 if (exporter_in_factory->isSupportingMatrixSetSignal())
798 QAction* export_group_action =
new QAction(QString::fromStdString(exporter_in_factory->getFormatName()),
this);
799 connect(export_group_action, &QAction::triggered, [
this, mat_set_signal, exporter_in_factory]() {
801 exporter_in_factory->getInstance();
802 QString format_name = QString::fromStdString(exporter->getFormatName());
803 QString file_suffix = QString::fromStdString(exporter->getFileSuffix());
805 QFileDialog::getSaveFileName(
this,
"Save " + format_name,
"data" + file_suffix, format_name +
" File (* " + file_suffix +
")")
807 exporter->exportMatrixSetSignal(
filename, (*mat_set_signal));
809 menu_export_aux->addAction(export_group_action);