diff --git a/libshvvisu/CMakeLists.txt b/libshvvisu/CMakeLists.txt
index 5483d6f65..d97a549f6 100644
--- a/libshvvisu/CMakeLists.txt
+++ b/libshvvisu/CMakeLists.txt
@@ -1,5 +1,6 @@
add_library(libshvvisu
images/images.qrc
+ src/logview/dataviewwidget.cpp
src/logview/dlgloginspector.cpp
src/logview/logmodel.cpp
src/logview/logsortfilterproxymodel.cpp
@@ -28,6 +29,7 @@ add_library(libshvvisu
src/timeline/sample.cpp
src/widgets/timezonecombobox.cpp
+ include/shv/visu/logview/dataviewwidget.h
include/shv/visu/logview/dlgloginspector.h
include/shv/visu/logview/logsortfilterproxymodel.h
include/shv/visu/logview/logmodel.h
diff --git a/libshvvisu/images/filter-off.svg b/libshvvisu/images/filter-off.svg
new file mode 100644
index 000000000..476c929a3
--- /dev/null
+++ b/libshvvisu/images/filter-off.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libshvvisu/images/filter.svg b/libshvvisu/images/filter.svg
new file mode 100644
index 000000000..5844d0eca
--- /dev/null
+++ b/libshvvisu/images/filter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/libshvvisu/images/images.qrc b/libshvvisu/images/images.qrc
index 2c41c3148..75fbc19a7 100644
--- a/libshvvisu/images/images.qrc
+++ b/libshvvisu/images/images.qrc
@@ -1,5 +1,7 @@
+ filter.svg
+ filter-off.svg
pencil.svg
clock.svg
ok.svg
diff --git a/libshvvisu/include/shv/visu/logview/dataviewwidget.h b/libshvvisu/include/shv/visu/logview/dataviewwidget.h
new file mode 100644
index 000000000..4a62abdd1
--- /dev/null
+++ b/libshvvisu/include/shv/visu/logview/dataviewwidget.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+
+namespace shv {
+namespace visu {
+namespace logview {
+
+namespace Ui {
+class DataViewWidget;
+}
+
+class DataViewWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit DataViewWidget(QWidget *parent = nullptr);
+ ~DataViewWidget();
+
+ void init(const QString &site_path, timeline::Graph *graph);
+
+private:
+ void onShowChannelFilterClicked();
+
+ timeline::Graph *m_graph = nullptr;
+ QString m_sitePath;
+
+ Ui::DataViewWidget *ui;
+};
+
+}}}
diff --git a/libshvvisu/include/shv/visu/logview/dlgloginspector.h b/libshvvisu/include/shv/visu/logview/dlgloginspector.h
index ad4d8b544..8265bd9c2 100644
--- a/libshvvisu/include/shv/visu/logview/dlgloginspector.h
+++ b/libshvvisu/include/shv/visu/logview/dlgloginspector.h
@@ -54,16 +54,8 @@ class SHVVISU_DECL_EXPORT DlgLogInspector : public QDialog
void setTimeZone(const QTimeZone &tz);
#endif
- void applyFilters(const QStringList &channel_paths);
- void onChannelsFilterClicked();
void onGraphChannelFilterChanged();
- void initVisualSettingSelector(const QString &shv_path);
- void onSaveViewClicked();
- void onDeleteViewClicked();
- void onViewSelected(int index);
- void setView(const QString &name);
-
private:
Ui::DlgLogInspector *ui;
@@ -79,7 +71,6 @@ class SHVVISU_DECL_EXPORT DlgLogInspector : public QDialog
shv::visu::timeline::GraphModel *m_graphModel = nullptr;
shv::visu::timeline::Graph *m_graph = nullptr;
shv::visu::timeline::GraphWidget *m_graphWidget = nullptr;
- shv::visu::timeline::ChannelFilterDialog *m_channelFilterDialog = nullptr;
};
}}}
diff --git a/libshvvisu/include/shv/visu/logview/logsortfilterproxymodel.h b/libshvvisu/include/shv/visu/logview/logsortfilterproxymodel.h
index 299bb45b9..72d3771db 100644
--- a/libshvvisu/include/shv/visu/logview/logsortfilterproxymodel.h
+++ b/libshvvisu/include/shv/visu/logview/logsortfilterproxymodel.h
@@ -5,6 +5,7 @@
#include "../timeline/fulltextfilter.h"
#include
+#include
namespace shv {
namespace visu {
@@ -18,7 +19,7 @@ class SHVVISU_DECL_EXPORT LogSortFilterProxyModel : public QSortFilterProxyModel
public:
explicit LogSortFilterProxyModel(QObject *parent = nullptr);
- void setChannelFilter(const shv::visu::timeline::ChannelFilter &filter);
+ void setChannelFilter(const std::optional &filter);
void setShvPathColumn(int column);
void setValueColumn(int column);
void setFulltextFilter(const shv::visu::timeline::FullTextFilter &filter);
@@ -26,7 +27,7 @@ class SHVVISU_DECL_EXPORT LogSortFilterProxyModel : public QSortFilterProxyModel
bool filterAcceptsRow(int source_rrow, const QModelIndex &source_parent) const override;
private:
- shv::visu::timeline::ChannelFilter m_channelFilter;
+ std::optional m_channelFilter;
shv::visu::timeline::FullTextFilter m_fulltextFilter;
int m_shvPathColumn = -1;
int m_valueColumn = -1;
diff --git a/libshvvisu/include/shv/visu/timeline/channelfilter.h b/libshvvisu/include/shv/visu/timeline/channelfilter.h
index 4a487e5fe..9ca4b4817 100644
--- a/libshvvisu/include/shv/visu/timeline/channelfilter.h
+++ b/libshvvisu/include/shv/visu/timeline/channelfilter.h
@@ -13,19 +13,20 @@ class SHVVISU_DECL_EXPORT ChannelFilter
{
public:
ChannelFilter();
- ChannelFilter(const QStringList &matching_paths);
+ ChannelFilter(const QSet &permitted_paths, const QString &name = {});
- void addMatchingPath(const QString &shv_path);
- void removeMatchingPath(const QString &shv_path);
+ void addPermittedPath(const QString &path);
+ void removePermittedPath(const QString &path);
- QStringList matchingPaths() const;
- void setMatchingPaths(const QStringList &paths);
+ QSet permittedPaths() const;
+ void setPermittedPaths(const QSet &paths);
+
+ bool isPathPermitted(const QString &path) const;
+ QString name();
- bool isPathMatch(const QString &path) const;
- bool isValid() const;
private:
- QStringList m_matchingPaths;
- bool m_isValid;
+ QString m_name;
+ QSet m_permittedPaths;
};
}
diff --git a/libshvvisu/include/shv/visu/timeline/channelfilterdialog.h b/libshvvisu/include/shv/visu/timeline/channelfilterdialog.h
index c72d1e1e8..0ae932e67 100644
--- a/libshvvisu/include/shv/visu/timeline/channelfilterdialog.h
+++ b/libshvvisu/include/shv/visu/timeline/channelfilterdialog.h
@@ -1,8 +1,10 @@
#pragma once
#include "../shvvisuglobal.h"
+#include
#include
+#include
namespace shv {
namespace visu {
@@ -20,20 +22,29 @@ class SHVVISU_DECL_EXPORT ChannelFilterDialog : public QDialog
Q_OBJECT
public:
- explicit ChannelFilterDialog(QWidget *parent = nullptr);
+ explicit ChannelFilterDialog(QWidget *parent, const QString &site_path, Graph *graph);
~ChannelFilterDialog();
- void init(const QString &site_path, const QStringList &logged_paths);
-
- QStringList selectedChannels();
- void setSelectedChannels(const QStringList &channels);
+ std::optional channelFilter();
private:
void applyTextFilter();
+ void reloadDataViewsCombobox();
+
+ void saveDataView();
+ void saveDataViewAs();
+ void discardUserChanges();
+ void deleteDataView();
+ void exportDataView();
+ void importDataView();
+
+ void refreshActions();
void setVisibleItemsCheckState(Qt::CheckState state);
void setVisibleItemsCheckState_helper(const QModelIndex &mi, Qt::CheckState state);
+ void loadChannelFilterFomGraph();
+ void onDataViewComboboxChanged(int index);
void onCustomContextMenuRequested(QPoint pos);
void onPbCheckItemsClicked();
@@ -43,9 +54,19 @@ class SHVVISU_DECL_EXPORT ChannelFilterDialog : public QDialog
void onChbFindRegexChanged(int state);
Ui::ChannelFilterDialog *ui;
+ shv::visu::timeline::Graph *m_graph = nullptr;
ChannelFilterModel *m_channelsFilterModel = nullptr;
ChannelFilterSortFilterProxyModel *m_channelsFilterProxyModel = nullptr;
QString m_sitePath;
+ QString m_recentSettingsDir;
+
+ QAction *m_saveViewAction = nullptr;
+ QAction *m_saveViewAsAction = nullptr;
+ QAction *m_revertViewAction = nullptr;
+ QAction *m_resetViewAction = nullptr;
+ QAction *m_deleteViewAction = nullptr;
+ QAction *m_exportViewAction = nullptr;
+ QAction *m_importViewAction = nullptr;
};
}
diff --git a/libshvvisu/include/shv/visu/timeline/channelfiltermodel.h b/libshvvisu/include/shv/visu/timeline/channelfiltermodel.h
index b2a3c7766..0f5f0b622 100644
--- a/libshvvisu/include/shv/visu/timeline/channelfiltermodel.h
+++ b/libshvvisu/include/shv/visu/timeline/channelfiltermodel.h
@@ -21,10 +21,10 @@ class SHVVISU_DECL_EXPORT ChannelFilterModel : public QStandardItemModel
ChannelFilterModel(QObject *parent = nullptr);
~ChannelFilterModel() Q_DECL_OVERRIDE;
- void createNodes(const QStringList &channels);
+ void createNodes(const QSet &channels);
- QStringList selectedChannels();
- void setSelectedChannels(const QStringList &channels);
+ QSet permittedChannels();
+ void setPermittedChannels(const QSet &channels);
void setItemCheckState(const QModelIndex &mi, Qt::CheckState check_state);
void fixCheckBoxesIntegrity();
protected:
@@ -38,7 +38,7 @@ class SHVVISU_DECL_EXPORT ChannelFilterModel : public QStandardItemModel
void createNodesForPath(const QString &path);
- void selectedChannels_helper(QStringList *channels, QStandardItem *it);
+ void selectedChannels_helper(QSet *channels, QStandardItem *it);
bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
void setChildItemsCheckedState(QStandardItem *it, Qt::CheckState check_state);
void fixChildItemsCheckBoxesIntegrity(QStandardItem *it);
diff --git a/libshvvisu/include/shv/visu/timeline/graph.h b/libshvvisu/include/shv/visu/timeline/graph.h
index b43e43c04..b94a29158 100644
--- a/libshvvisu/include/shv/visu/timeline/graph.h
+++ b/libshvvisu/include/shv/visu/timeline/graph.h
@@ -1,16 +1,17 @@
#pragma once
-#include
-#include
-#include
-#include
-#include
-#include
+#include "channelfilter.h"
+#include "channelprobe.h"
+#include "graphchannel.h"
+#include "graphbuttonbox.h"
+#include "sample.h"
+#include "../shvvisuglobal.h"
#include
#include
#include
+#include
#include
#include
#include
@@ -93,8 +94,8 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
QString toJson() const;
static VisualSettings fromJson(const QString &json);
- bool isValid() const;
QVector channels;
+ QString name;
};
Graph(QObject *parent = nullptr);
@@ -111,12 +112,10 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
#endif
void setSettingsUserName(const QString &user);
-
- void reset();
+
enum class SortChannels { No = 0, Yes };
void createChannelsFromModel(SortChannels sorted = SortChannels::Yes);
void resetChannelsRanges();
- bool isInitialView() const;
qsizetype channelCount() const;
void clearChannels();
@@ -128,10 +127,10 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
QString channelName(qsizetype channel) const;
void showAllChannels();
- QStringList channelPaths();
+ QSet channelPaths();
void hideFlatChannels();
- const ChannelFilter& channelFilter() const;
- void setChannelFilter(const ChannelFilter &filter);
+ const std::optional &channelFilter() const;
+ void setChannelFilter(const std::optional &filter);
void setChannelVisible(qsizetype channel_ix, bool is_visible);
void setChannelMaximized(qsizetype channel_ix, bool is_maximized);
@@ -226,7 +225,7 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
static QString rectToString(const QRect &r);
VisualSettings visualSettings() const;
- void setVisualSettings(const VisualSettings &settings);
+ void setVisualSettingsAndChannelFilter(const VisualSettings &settings);
void resizeChannelHeight(qsizetype ix, int delta_px);
void resizeVerticalHeaderWidth(int delta_px);
@@ -234,6 +233,8 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
void deleteVisualSettings(const QString &settings_id, const QString &name) const;
QStringList savedVisualSettingsNames(const QString &settings_id) const;
void loadVisualSettings(const QString &settings_id, const QString &name);
+ QString loadedVisualSettingsId();
+ bool isChannelFilterValid() const;
protected:
void sanityXRangeZoom();
@@ -270,6 +271,8 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
virtual void drawCurrentTime(QPainter *painter, int channel_ix);
void drawCurrentTimeMarker(QPainter *painter, time_t time);
+ virtual void applyCustomChannelStyle(GraphChannel *channel);
+
QVariantMap mergeMaps(const QVariantMap &base, const QVariantMap &overlay) const;
void makeXAxis();
void makeYAxis(qsizetype channel);
@@ -290,7 +293,7 @@ class SHVVISU_DECL_EXPORT Graph : public QObject
QVector m_channelProbes;
QVector m_channels;
- ChannelFilter m_channelFilter;
+ std::optional m_channelFilter;
struct SHVVISU_DECL_EXPORT XAxis
{
diff --git a/libshvvisu/src/logview/dataviewwidget.cpp b/libshvvisu/src/logview/dataviewwidget.cpp
new file mode 100644
index 000000000..146812c69
--- /dev/null
+++ b/libshvvisu/src/logview/dataviewwidget.cpp
@@ -0,0 +1,53 @@
+#include "ui_dataviewwidget.h"
+
+#include
+#include
+#include
+
+#include "shv/core/log.h"
+
+namespace tl = shv::visu::timeline;
+
+namespace shv::visu::logview {
+
+DataViewWidget::DataViewWidget(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::DataViewWidget)
+{
+ ui->setupUi(this);
+
+ connect(ui->pbShowChannelFilterDialog, &QToolButton::clicked, this, &DataViewWidget::onShowChannelFilterClicked);
+}
+
+DataViewWidget::~DataViewWidget()
+{
+ delete ui;
+}
+
+void DataViewWidget::init(const QString &site_path, timeline::Graph *graph)
+{
+ if (m_graph != nullptr) {
+ shvWarning() << "Dialog is allready initialized.";
+ return;
+ }
+
+ m_graph = graph;
+ m_sitePath = site_path;
+
+ connect(graph, &timeline::Graph::channelFilterChanged, this, [this](){
+ ui->pbShowChannelFilterDialog->setIcon(m_graph->isChannelFilterValid()? QIcon(QStringLiteral(":/shv/visu/images/filter.svg")): QIcon(QStringLiteral(":/shv/visu/images/filter-off.svg")));
+ });
+}
+
+void DataViewWidget::onShowChannelFilterClicked()
+{
+ auto *channel_filter_dialog = new tl::ChannelFilterDialog(this, m_sitePath, m_graph);
+
+ if (channel_filter_dialog->exec() == QDialog::Accepted) {
+ m_graph->setChannelFilter(channel_filter_dialog->channelFilter());
+ }
+
+ channel_filter_dialog->deleteLater();
+}
+
+}
diff --git a/libshvvisu/src/logview/dataviewwidget.ui b/libshvvisu/src/logview/dataviewwidget.ui
new file mode 100644
index 000000000..e769098f1
--- /dev/null
+++ b/libshvvisu/src/logview/dataviewwidget.ui
@@ -0,0 +1,49 @@
+
+
+ shv::visu::logview::DataViewWidget
+
+
+
+ 0
+ 0
+ 24
+ 25
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ Show filter dialog
+
+
+ ...
+
+
+
+ :/shv/visu/images/filter-off.svg:/shv/visu/images/filter-off.svg
+
+
+
+
+
+
+
+
+
+
diff --git a/libshvvisu/src/logview/dlgloginspector.cpp b/libshvvisu/src/logview/dlgloginspector.cpp
index e12444d0a..98ce65e5e 100644
--- a/libshvvisu/src/logview/dlgloginspector.cpp
+++ b/libshvvisu/src/logview/dlgloginspector.cpp
@@ -222,7 +222,7 @@ DlgLogInspector::DlgLogInspector(const QString &shv_path, QWidget *parent) :
m_graph->setModel(m_graphModel);
m_graphWidget->setGraph(m_graph);
- m_channelFilterDialog = new shv::visu::timeline::ChannelFilterDialog(this);
+ ui->wDataView->init(ui->edShvPath->text(), m_graph);
#if SHVVISU_HAS_TIMEZONE
connect(ui->cbxTimeZone, &QComboBox::currentTextChanged, this, [this](const QString &) {
@@ -237,22 +237,12 @@ DlgLogInspector::DlgLogInspector(const QString &shv_path, QWidget *parent) :
connect(ui->btLoad, &QPushButton::clicked, this, &DlgLogInspector::downloadLog);
connect(m_graph, &shv::visu::timeline::Graph::channelFilterChanged, this, &DlgLogInspector::onGraphChannelFilterChanged);
- connect(ui->pbChannelsFilter, &QPushButton::clicked, this, &DlgLogInspector::onChannelsFilterClicked);
connect(ui->btResizeColumnsToFitWidth, &QAbstractButton::clicked, this, [this]() {
ui->tblData->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);
});
loadSettings();
-
- initVisualSettingSelector(shv_path);
- ui->cbViews->setCurrentIndex(VIEW_SELECTOR_NO_VIEW_INDEX);
-
- connect(ui->cbViews, QOverload::of(&QComboBox::activated), this, &DlgLogInspector::onViewSelected);
-
- connect(ui->pbDeleteView, &QPushButton::clicked, this, &DlgLogInspector::onDeleteViewClicked);
- connect(ui->pbSaveView, &QPushButton::clicked, this, &DlgLogInspector::onSaveViewClicked);
- onViewSelected(VIEW_SELECTOR_NO_VIEW_INDEX);
}
DlgLogInspector::~DlgLogInspector()
@@ -268,60 +258,6 @@ void DlgLogInspector::loadSettings()
restoreGeometry(ba);
}
-void DlgLogInspector::initVisualSettingSelector(const QString &shv_path)
-{
- ui->cbViews->clear();
-
- ui->cbViews->addItem(tr("Initial view"));
- for (const QString &view_name : m_graph->savedVisualSettingsNames(shv_path)) {
- ui->cbViews->addItem(view_name);
- }
-}
-
-void DlgLogInspector::onSaveViewClicked()
-{
- QString current_name = ui->cbViews->currentText();
- if (current_name.isEmpty() || current_name == ui->cbViews->itemText(0)) {
- return;
- }
- if (ui->cbViews->findText(current_name) == -1) {
- int index = ui->cbViews->count();
- ui->cbViews->addItem(current_name);
- ui->cbViews->setCurrentIndex(index);
- }
- m_graph->saveVisualSettings(shvPath(), current_name);
-}
-
-void DlgLogInspector::onDeleteViewClicked()
-{
- int index = ui->cbViews->currentIndex();
- const QString ¤t_name = ui->cbViews->currentText();
- if (ui->cbViews->findText(current_name) == -1) {
- ui->cbViews->setEditText(ui->cbViews->itemText(index));
- return;
- }
-
- m_graph->deleteVisualSettings(shvPath(), current_name);
- ui->cbViews->removeItem(index);
- ui->cbViews->setCurrentIndex(VIEW_SELECTOR_NO_VIEW_INDEX);
- onViewSelected(VIEW_SELECTOR_NO_VIEW_INDEX);
-}
-
-void DlgLogInspector::onViewSelected(int index)
-{
- if (index == VIEW_SELECTOR_NO_VIEW_INDEX) {
- m_graph->reset();
- }
- else {
- setView(ui->cbViews->currentText());
- }
-}
-
-void DlgLogInspector::setView(const QString &name)
-{
- m_graph->loadVisualSettings(shvPath(), name);
-}
-
void DlgLogInspector::saveSettings()
{
QSettings settings;
@@ -485,11 +421,7 @@ void DlgLogInspector::parseLog(shv::chainpack::RpcValue log)
}
m_graph->createChannelsFromModel();
-
- QStringList channel_paths = m_graph->channelPaths();
- m_channelFilterDialog->init(shvPath(), channel_paths);
ui->graphView->makeLayout();
- applyFilters(channel_paths);
}
void DlgLogInspector::showInfo(const QString &msg, bool is_error)
@@ -547,22 +479,6 @@ void DlgLogInspector::setTimeZone(const QTimeZone &tz)
}
#endif
-void DlgLogInspector::applyFilters(const QStringList &channel_paths)
-{
- auto graph_filter = m_graph->channelFilter();
- graph_filter.setMatchingPaths(channel_paths);
- m_graph->setChannelFilter(graph_filter);
-}
-
-void DlgLogInspector::onChannelsFilterClicked()
-{
- m_channelFilterDialog->setSelectedChannels(m_graph->channelFilter().matchingPaths());
-
- if(m_channelFilterDialog->exec() == QDialog::Accepted) {
- applyFilters(m_channelFilterDialog->selectedChannels());
- }
-}
-
void DlgLogInspector::onGraphChannelFilterChanged()
{
m_logSortFilterProxy->setChannelFilter(m_graph->channelFilter());
diff --git a/libshvvisu/src/logview/dlgloginspector.ui b/libshvvisu/src/logview/dlgloginspector.ui
index c0fb98051..fa1489a43 100644
--- a/libshvvisu/src/logview/dlgloginspector.ui
+++ b/libshvvisu/src/logview/dlgloginspector.ui
@@ -65,7 +65,7 @@
1999
12
- 20
+ 17
@@ -116,7 +116,7 @@
1999
12
- 19
+ 16
@@ -427,47 +427,7 @@
-
-
-
- Saved views:
-
-
-
- -
-
-
- true
-
-
-
- -
-
-
-
-
-
-
- :/shv/visu/images/file-save.svg:/shv/visu/images/file-save.svg
-
-
-
- -
-
-
-
-
-
-
- :/shv/visu/images/delete.svg:/shv/visu/images/delete.svg
-
-
-
- -
-
-
- Channels filter
-
-
+
@@ -505,7 +465,7 @@
0
0
1152
- 368
+ 354
@@ -598,16 +558,22 @@
+
+ shv::visu::TimeZoneComboBox
+ QComboBox
+ shv/visu/timezonecombobox.h
+
shv::visu::timeline::GraphView
QScrollArea
- shv/visu/timeline/graphview.h
+ shv/visu/timeline/graphview.h
1
- shv::visu::TimeZoneComboBox
- QComboBox
- src/widgets/timezonecombobox.h
+ shv::visu::logview::DataViewWidget
+ QWidget
+ shv/visu/logview/dataviewwidget.h
+ 1
diff --git a/libshvvisu/src/logview/logsortfilterproxymodel.cpp b/libshvvisu/src/logview/logsortfilterproxymodel.cpp
index 31d315e96..519e086d8 100644
--- a/libshvvisu/src/logview/logsortfilterproxymodel.cpp
+++ b/libshvvisu/src/logview/logsortfilterproxymodel.cpp
@@ -11,7 +11,7 @@ LogSortFilterProxyModel::LogSortFilterProxyModel(QObject *parent) :
}
-void LogSortFilterProxyModel::setChannelFilter(const shv::visu::timeline::ChannelFilter &filter)
+void LogSortFilterProxyModel::setChannelFilter(const std::optional &filter)
{
m_channelFilter = filter;
invalidateFilter();
@@ -50,33 +50,24 @@ bool startsWithPath(const QStringView &str, const QStringView &path)
bool LogSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
- bool row_accepted = false;
+ bool is_row_accepted = true;
+
if (m_shvPathColumn >= 0) {
QModelIndex ix = sourceModel()->index(source_row, m_shvPathColumn, source_parent);
- row_accepted = !m_channelFilter.isValid();
- if (!row_accepted) {
- for (const QString &selected_path : m_channelFilter.matchingPaths()) {
- auto row_path = sourceModel()->data(ix).toString();
- if (selected_path.startsWith(row_path)) {
- row_accepted = true;
- break;
- }
+ is_row_accepted = (m_channelFilter) ? m_channelFilter.value().isPathPermitted(sourceModel()->data(ix).toString()) : true;
+
+ if (is_row_accepted && !m_fulltextFilter.pattern().isEmpty()) {
+ bool is_fulltext_filter_matched = m_fulltextFilter.matches(sourceModel()->data(ix).toString());
+
+ if (m_valueColumn >= 0) {
+ ix = sourceModel()->index(source_row, m_valueColumn, source_parent);
+ is_fulltext_filter_matched = is_fulltext_filter_matched || m_fulltextFilter.matches(sourceModel()->data(ix).toString());
}
+ is_row_accepted = is_row_accepted && is_fulltext_filter_matched;
}
}
- if (row_accepted && !m_fulltextFilter.pattern().isEmpty()) {
- bool fulltext_match = false;
- {
- QModelIndex ix = sourceModel()->index(source_row, m_shvPathColumn, source_parent);
- fulltext_match = fulltext_match || m_fulltextFilter.matches(sourceModel()->data(ix).toString());
- }
- if (m_valueColumn >= 0) {
- QModelIndex ix = sourceModel()->index(source_row, m_valueColumn, source_parent);
- fulltext_match = fulltext_match || m_fulltextFilter.matches(sourceModel()->data(ix).toString());
- }
- row_accepted = fulltext_match;
- }
- return row_accepted;
+
+ return is_row_accepted;
}
}
diff --git a/libshvvisu/src/timeline/channelfilter.cpp b/libshvvisu/src/timeline/channelfilter.cpp
index 80bd0aa4a..34541e8db 100644
--- a/libshvvisu/src/timeline/channelfilter.cpp
+++ b/libshvvisu/src/timeline/channelfilter.cpp
@@ -4,47 +4,42 @@
namespace shv::visu::timeline {
-ChannelFilter::ChannelFilter()
- : m_isValid(false)
-{
-}
+ChannelFilter::ChannelFilter() = default;
-ChannelFilter::ChannelFilter(const QStringList &matching_paths)
- : m_isValid(true)
+ChannelFilter::ChannelFilter(const QSet &permitted_paths, const QString &name)
{
- setMatchingPaths(matching_paths);
+ m_permittedPaths = permitted_paths;
+ m_name = name;
}
-QStringList ChannelFilter::matchingPaths() const
+QSet ChannelFilter::permittedPaths() const
{
- return m_matchingPaths;
+ return m_permittedPaths;
}
-void ChannelFilter::addMatchingPath(const QString &shv_path)
+void ChannelFilter::addPermittedPath(const QString &path)
{
- m_isValid = true;
- m_matchingPaths << shv_path;
+ m_permittedPaths.insert(path);
}
-void ChannelFilter::removeMatchingPath(const QString &shv_path)
+void ChannelFilter::removePermittedPath(const QString &path)
{
- m_isValid = true;
- m_matchingPaths.removeOne(shv_path);
+ m_permittedPaths.remove(path);
}
-void ChannelFilter::setMatchingPaths(const QStringList &paths)
+void ChannelFilter::setPermittedPaths(const QSet &paths)
{
- m_isValid = true;
- m_matchingPaths = paths;
+ m_permittedPaths = paths;
}
-bool ChannelFilter::isPathMatch(const QString &path) const
+bool ChannelFilter::isPathPermitted(const QString &path) const
{
- return m_matchingPaths.contains(path);
+ return m_permittedPaths.contains(path);
}
-bool ChannelFilter::isValid() const
+QString ChannelFilter::name()
{
- return m_isValid;
+ return m_name;
}
+
}
diff --git a/libshvvisu/src/timeline/channelfilterdialog.cpp b/libshvvisu/src/timeline/channelfilterdialog.cpp
index 9e4a31cd4..504bb41c3 100644
--- a/libshvvisu/src/timeline/channelfilterdialog.cpp
+++ b/libshvvisu/src/timeline/channelfilterdialog.cpp
@@ -2,22 +2,31 @@
#include "channelfiltersortfilterproxymodel.h"
#include
-
#include
#include
+#include
+#include
#include
#include
+#include
+#include
namespace shv::visu::timeline {
-ChannelFilterDialog::ChannelFilterDialog(QWidget *parent) :
+static const QString FLATLINE_VIEW_SETTINGS_FILE_TYPE = QStringLiteral("FlatlineViewSettings");
+static const QString FLATLINE_VIEW_SETTINGS_FILE_EXTENSION = QStringLiteral(".fvs");
+
+ChannelFilterDialog::ChannelFilterDialog(QWidget *parent, const QString &site_path, Graph *graph) :
QDialog(parent),
ui(new Ui::ChannelFilterDialog)
{
ui->setupUi(this);
+ m_sitePath = site_path;
+ m_graph = graph;
+
m_channelsFilterModel = new ChannelFilterModel(this);
m_channelsFilterProxyModel = new ChannelFilterSortFilterProxyModel(this);
@@ -28,8 +37,35 @@ ChannelFilterDialog::ChannelFilterDialog(QWidget *parent) :
ui->tvChannelsFilter->setModel(m_channelsFilterProxyModel);
ui->tvChannelsFilter->header()->hide();
ui->tvChannelsFilter->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
- connect(ui->tvChannelsFilter, &QTreeView::customContextMenuRequested, this, &ChannelFilterDialog::onCustomContextMenuRequested);
+ auto *view_menu = new QMenu(this);
+ m_resetViewAction = view_menu->addAction(tr("Discard changes"), this, &ChannelFilterDialog::discardUserChanges);
+ m_saveViewAction = view_menu->addAction(tr("Save"), this, &ChannelFilterDialog::saveDataView);
+ m_saveViewAsAction = view_menu->addAction(tr("Save as"), this, &ChannelFilterDialog::saveDataViewAs);
+ m_deleteViewAction = view_menu->addAction(tr("Delete"), this, &ChannelFilterDialog::deleteDataView);
+ m_exportViewAction = view_menu->addAction(tr("Export"), this, &ChannelFilterDialog::exportDataView);
+ m_importViewAction = view_menu->addAction(tr("Import"), this, &ChannelFilterDialog::importDataView);
+ ui->pbActions->setMenu(view_menu);
+ ui->gbFilterSettings->setChecked(false);
+
+ m_channelsFilterModel->createNodes(graph->channelPaths());
+
+ ui->gbFilterSettings->setChecked(m_graph->isChannelFilterValid());
+
+ loadChannelFilterFomGraph();
+ reloadDataViewsCombobox();
+
+ std::optional chf = m_graph->channelFilter();
+
+ if (chf && !chf.value().name().isEmpty())
+ ui->cbDataView->setCurrentText(chf.value().name());
+ else
+ ui->cbDataView->setCurrentIndex(-1);
+
+ refreshActions();
+
+ connect(ui->cbDataView, qOverload(&QComboBox::currentIndexChanged), this, &ChannelFilterDialog::onDataViewComboboxChanged);
+ connect(ui->tvChannelsFilter, &QTreeView::customContextMenuRequested, this, &ChannelFilterDialog::onCustomContextMenuRequested);
connect(ui->leMatchingFilterText, &QLineEdit::textChanged, this, &ChannelFilterDialog::onLeMatchingFilterTextChanged);
connect(ui->pbClearMatchingText, &QPushButton::clicked, this, &ChannelFilterDialog::onPbClearMatchingTextClicked);
connect(ui->pbCheckItems, &QPushButton::clicked, this, &ChannelFilterDialog::onPbCheckItemsClicked);
@@ -41,30 +77,117 @@ ChannelFilterDialog::~ChannelFilterDialog()
delete ui;
}
-void ChannelFilterDialog::init(const QString &site_path, const QStringList &logged_paths)
+std::optional ChannelFilterDialog::channelFilter()
{
- m_sitePath = site_path;
- m_channelsFilterModel->createNodes(logged_paths);
+ if (ui->gbFilterSettings->isChecked()) {
+ return ChannelFilter(m_channelsFilterModel->permittedChannels(), ui->cbDataView->currentText());
+ }
+
+ return std::nullopt;
}
-QStringList ChannelFilterDialog::selectedChannels()
+void ChannelFilterDialog::applyTextFilter()
{
- return m_channelsFilterModel->selectedChannels();
+ m_channelsFilterProxyModel->setFilterString(ui->leMatchingFilterText->text());
+
+ if (m_channelsFilterProxyModel->rowCount() == 1) {
+ ui->tvChannelsFilter->setCurrentIndex(m_channelsFilterProxyModel->index(0, 0));
+ ui->tvChannelsFilter->expandRecursively(ui->tvChannelsFilter->currentIndex());
+ }
}
-void ChannelFilterDialog::setSelectedChannels(const QStringList &channels)
+void ChannelFilterDialog::reloadDataViewsCombobox()
{
- m_channelsFilterModel->setSelectedChannels(channels);
+ ui->cbDataView->clear();
+ ui->cbDataView->addItems(m_graph->savedVisualSettingsNames(m_sitePath));
}
-void ChannelFilterDialog::applyTextFilter()
+void ChannelFilterDialog::deleteDataView()
{
- m_channelsFilterProxyModel->setFilterString(ui->leMatchingFilterText->text());
+ m_graph->deleteVisualSettings(m_sitePath, ui->cbDataView->currentText());
+ reloadDataViewsCombobox();
+ ui->cbDataView->setCurrentIndex(ui->cbDataView->count() - 1);
+}
- if (m_channelsFilterProxyModel->rowCount() == 1){
- ui->tvChannelsFilter->setCurrentIndex(m_channelsFilterProxyModel->index(0, 0));
- ui->tvChannelsFilter->expandRecursively(ui->tvChannelsFilter->currentIndex());
+void ChannelFilterDialog::exportDataView()
+{
+ QString file_name = QFileDialog::getSaveFileName(this, tr("Input file name"), m_recentSettingsDir, "*" + FLATLINE_VIEW_SETTINGS_FILE_EXTENSION);
+ if (!file_name.isEmpty()) {
+ if (!file_name.endsWith(FLATLINE_VIEW_SETTINGS_FILE_EXTENSION)) {
+ file_name.append(FLATLINE_VIEW_SETTINGS_FILE_EXTENSION);
+ }
+
+ m_graph->setChannelFilter(channelFilter());
+
+ QSettings settings(file_name, QSettings::Format::IniFormat);
+ settings.setValue("fileType", FLATLINE_VIEW_SETTINGS_FILE_TYPE);
+ settings.setValue("settings", m_graph->visualSettings().toJson());
+
+ m_recentSettingsDir = QFileInfo(file_name).path();
+ }
+}
+
+void ChannelFilterDialog::importDataView()
+{
+ QString file_name = QFileDialog::getOpenFileName(this, tr("Input file name"), m_recentSettingsDir, "*" + FLATLINE_VIEW_SETTINGS_FILE_EXTENSION);
+ if (!file_name.isEmpty()) {
+ QString view_name = QInputDialog::getText(this, tr("Import as"), tr("Input view name"));
+
+ if (!view_name.isEmpty()) {
+ QSettings settings_file(file_name, QSettings::Format::IniFormat);
+ if (settings_file.value("fileType").toString() != FLATLINE_VIEW_SETTINGS_FILE_TYPE) {
+ QMessageBox::warning(this, tr("Error"), tr("This file is not flatline view setting file"));
+ return;
+ }
+
+ Graph::VisualSettings visual_settings = Graph::VisualSettings::fromJson(settings_file.value("settings").toString());
+ visual_settings.name = view_name;
+ m_graph->setVisualSettingsAndChannelFilter(visual_settings);
+ m_graph->saveVisualSettings(m_sitePath, view_name);
+ reloadDataViewsCombobox();
+ ui->cbDataView->setCurrentText(view_name);
+
+ m_recentSettingsDir = QFileInfo(file_name).path();
+ }
+ }
+}
+
+void ChannelFilterDialog::refreshActions()
+{
+ m_saveViewAction->setEnabled(!ui->cbDataView->currentText().isEmpty());
+ m_deleteViewAction->setEnabled(!ui->cbDataView->currentText().isEmpty());
+ m_resetViewAction->setEnabled(!ui->cbDataView->currentText().isEmpty());
+}
+
+void ChannelFilterDialog::saveDataView()
+{
+ if(ui->cbDataView->currentText().isEmpty()) {
+ shvWarning() << "Failed to save empty filter name.";
+ return;
+ }
+
+ m_graph->setChannelFilter(channelFilter());
+ m_graph->saveVisualSettings(m_sitePath, ui->cbDataView->currentText());
+}
+
+void ChannelFilterDialog::saveDataViewAs()
+{
+ QString view_name = QInputDialog::getText(this, tr("Save as"), tr("Input view name"));
+
+ if (view_name.isEmpty()) {
+ QMessageBox::warning(this, tr("Error"), tr("Failed to save view: name is empty."));
}
+ else {
+ m_graph->setChannelFilter(channelFilter());
+ m_graph->saveVisualSettings(m_sitePath, view_name);
+ reloadDataViewsCombobox();
+ ui->cbDataView->setCurrentText(view_name);
+ }
+}
+
+void ChannelFilterDialog::discardUserChanges()
+{
+ onDataViewComboboxChanged(ui->cbDataView->currentIndex());
}
void ChannelFilterDialog::onCustomContextMenuRequested(QPoint pos)
@@ -118,6 +241,12 @@ void ChannelFilterDialog::onChbFindRegexChanged(int state)
applyTextFilter();
}
+void ChannelFilterDialog::loadChannelFilterFomGraph()
+{
+ std::optional f = m_graph->channelFilter();
+ m_channelsFilterModel->setPermittedChannels((f) ? f.value().permittedPaths() : QSet{});
+}
+
void ChannelFilterDialog::setVisibleItemsCheckState(Qt::CheckState state)
{
for (int row = 0; row < m_channelsFilterProxyModel->rowCount(); row++) {
@@ -140,4 +269,13 @@ void ChannelFilterDialog::setVisibleItemsCheckState_helper(const QModelIndex &mi
}
}
+void ChannelFilterDialog::onDataViewComboboxChanged(int index)
+{
+ if (index >= 0) { //ignore event with index = -1, which is emmited from clear() method
+ m_graph->loadVisualSettings(m_sitePath, ui->cbDataView->currentText());
+ loadChannelFilterFomGraph();
+ }
+ refreshActions();
+}
+
}
diff --git a/libshvvisu/src/timeline/channelfilterdialog.ui b/libshvvisu/src/timeline/channelfilterdialog.ui
index 605a948d2..f8cfe573b 100644
--- a/libshvvisu/src/timeline/channelfilterdialog.ui
+++ b/libshvvisu/src/timeline/channelfilterdialog.ui
@@ -6,81 +6,160 @@
0
0
- 407
+ 391
802
Channels filter dialog
-
+
+
+ 0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- :/shv/visu/images/check-box-outline.svg:/shv/visu/images/check-box-outline.svg
-
-
-
- -
-
-
-
-
-
-
- :/shv/visu/images/checkbox-blank-outline.svg:/shv/visu/images/checkbox-blank-outline.svg
-
-
-
-
-
- -
-
-
- Matching text
-
-
-
- -
-
-
- 0
-
-
-
-
-
-
- 1
- 0
-
-
-
-
- -
-
-
-
-
-
-
- :/shv/visu/images/delete.svg:/shv/visu/images/delete.svg
-
-
-
-
-
-
-
- -
-
+
+
+ Channel filter is enabled
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ true
+
+
+ false
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
-
+
+
-
+
+
+
+ true
+
+
+
+ Data view
+
+
+
+ -
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+
+
+
+
+ :/shv/visu/images/hamburger-menu.svg:/shv/visu/images/hamburger-menu.svg
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 10
+ 10
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+
+ :/shv/visu/images/check-box-outline.svg:/shv/visu/images/check-box-outline.svg
+
+
+
+ -
+
+
+
+
+
+
+ :/shv/visu/images/checkbox-blank-outline.svg:/shv/visu/images/checkbox-blank-outline.svg
+
+
+
+ -
+
+
+ Matching text
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+
+ 1
+ 0
+
+
+
+
+ -
+
+
+
+
+
+
+ :/shv/visu/images/delete.svg:/shv/visu/images/delete.svg
+
+
+
+
+
+
+
+ -
+
+
+
+
-
@@ -88,7 +167,7 @@
Qt::Horizontal
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+ QDialogButtonBox::Ok
diff --git a/libshvvisu/src/timeline/channelfiltermodel.cpp b/libshvvisu/src/timeline/channelfiltermodel.cpp
index 82155149d..1c0a329de 100644
--- a/libshvvisu/src/timeline/channelfiltermodel.cpp
+++ b/libshvvisu/src/timeline/channelfiltermodel.cpp
@@ -17,27 +17,31 @@ ChannelFilterModel::ChannelFilterModel(QObject *parent)
ChannelFilterModel::~ChannelFilterModel() = default;
-void ChannelFilterModel::createNodes(const QStringList &channels)
+void ChannelFilterModel::createNodes(const QSet &channels)
{
beginResetModel();
- for (const auto &shv_path: channels) {
- createNodesForPath(shv_path);
+ QStringList sorted_channels = QStringList(channels.begin(), channels.end());
+ sorted_channels.sort(Qt::CaseInsensitive);
+
+ for (const auto &p: sorted_channels) {
+ createNodesForPath(p);
}
+
endResetModel();
}
-QStringList ChannelFilterModel::selectedChannels()
+QSet ChannelFilterModel::permittedChannels()
{
- QStringList channels;
+ QSet channels;
selectedChannels_helper(&channels, invisibleRootItem());
return channels;
}
-void ChannelFilterModel::selectedChannels_helper(QStringList *channels, QStandardItem *it)
+void ChannelFilterModel::selectedChannels_helper(QSet *channels, QStandardItem *it)
{
if ((it != invisibleRootItem()) && (it->data(UserData::ValidLogEntry).toBool()) && (it->checkState() == Qt::CheckState::Checked)){
- (*channels) << shvPathFromItem(it);
+ channels->insert(shvPathFromItem(it));
}
for (int row = 0; row < it->rowCount(); row++) {
@@ -46,7 +50,7 @@ void ChannelFilterModel::selectedChannels_helper(QStringList *channels, QStandar
}
}
-void ChannelFilterModel::setSelectedChannels(const QStringList &channels)
+void ChannelFilterModel::setPermittedChannels(const QSet &channels)
{
setChildItemsCheckedState(invisibleRootItem(), Qt::CheckState::Unchecked);
diff --git a/libshvvisu/src/timeline/graph.cpp b/libshvvisu/src/timeline/graph.cpp
index 08575f3de..21e01136d 100644
--- a/libshvvisu/src/timeline/graph.cpp
+++ b/libshvvisu/src/timeline/graph.cpp
@@ -18,12 +18,12 @@
#include
+namespace shv::visu::timeline {
+
static const QString USER_PROFILES_KEY = QStringLiteral("userProfiles");
static const QString SITES_KEY = QStringLiteral("sites");
static const QString VIEWS_KEY = QStringLiteral("channelViews");
-namespace shv::visu::timeline {
-
const QString Graph::DEFAULT_USER_PROFILE = QStringLiteral("default");
static const int VALUE_NOT_AVILABLE_Y = std::numeric_limits::max();
@@ -103,58 +103,12 @@ QTimeZone Graph::timeZone() const
}
#endif
-bool Graph::isInitialView() const
-{
- if (m_channelFilter.isValid()) {
- return false;
- }
- GraphChannel::Style default_style;
-
- QMap path_to_model_index;
- for (qsizetype i = 0; i < m_model->channelCount(); ++i) {
- QString shv_path = m_model->channelShvPath(i);
- path_to_model_index[shv_path] = i;
- }
- QString previous_shv_path;
- for (GraphChannel *channel : m_channels) {
- if (channel->style().heightMax() != default_style.heightMax()) {
- return false;
- }
- QString channel_shv_path = m_model->channelShvPath(channel->modelIndex());
- if (channel_shv_path < previous_shv_path) {
- return false;
- }
- previous_shv_path = channel_shv_path;
- }
- return true;
-}
-
-void Graph::reset()
-{
- createChannelsFromModel();
- m_channelFilter = ChannelFilter();
- Q_EMIT layoutChanged();
- Q_EMIT channelFilterChanged();
-}
-
void Graph::createChannelsFromModel(shv::visu::timeline::Graph::SortChannels sorted)
{
- static QVector colors {
- Qt::magenta,
- Qt::cyan,
- Qt::blue,
- QColor(0xe6, 0x3c, 0x33), //red
- QColor("orange"),
- QColor(0x6d, 0xa1, 0x3a), // green
- };
- QMap orig_styles;
- for (int i = 0; i < channelCount(); ++i) {
- auto *ch = channelAt(i);
- orig_styles[ch->shvPath()] = ch->style();
- }
clearChannels();
if(!m_model)
return;
+
QList model_ixs;
if(sorted == SortChannels::Yes) {
// sort channels alphabetically
@@ -172,17 +126,11 @@ void Graph::createChannelsFromModel(shv::visu::timeline::Graph::SortChannels sor
}
for(auto model_ix : model_ixs) {
GraphChannel *ch = appendChannel(model_ix);
- auto channel_ix = channelCount() - 1;
- if (orig_styles.contains(ch->shvPath())) {
- ch->setStyle(orig_styles[ch->shvPath()]);
- }
- else {
- GraphChannel::Style style = ch->style();
- style.setColor(colors.value(channel_ix % colors.count()));
- ch->setStyle(style);
- }
+ applyCustomChannelStyle(ch);
}
+
resetChannelsRanges();
+ setChannelFilter(std::nullopt);
}
void Graph::resetChannelsRanges()
@@ -275,35 +223,36 @@ void Graph::moveChannel(qsizetype channel, qsizetype new_pos)
void Graph::showAllChannels()
{
- m_channelFilter.setMatchingPaths(channelPaths());
-
- emit layoutChanged();
- emit channelFilterChanged();
+ setChannelFilter(std::nullopt);
}
-QStringList Graph::channelPaths()
+QSet Graph::channelPaths()
{
- QStringList shv_paths;
+ QSet ret;
for (int i = 0; i < m_channels.count(); ++i) {
- shv_paths << m_channels[i]->shvPath();
+ ret.insert(m_channels[i]->shvPath());
}
- return shv_paths;
+ return ret;
}
void Graph::hideFlatChannels()
{
- QStringList matching_paths = (m_channelFilter.isValid()) ? m_channelFilter.matchingPaths() : channelPaths();
+ QSet permitted_paths = (m_channelFilter) ? m_channelFilter.value().permittedPaths() : channelPaths();
for (qsizetype i = 0; i < m_channels.count(); ++i) {
GraphChannel *ch = m_channels[i];
if(isChannelFlat(ch)) {
- matching_paths.removeOne(ch->shvPath());
+ permitted_paths.remove(ch->shvPath());
}
}
- m_channelFilter.setMatchingPaths(matching_paths);
+ if (m_channelFilter == std::nullopt)
+ m_channelFilter = ChannelFilter();
+
+ if (m_channelFilter)
+ m_channelFilter.value().setPermittedPaths(permitted_paths);
emit layoutChanged();
emit channelFilterChanged();
@@ -315,14 +264,15 @@ bool Graph::isChannelFlat(GraphChannel *ch)
return yrange.isEmpty();
}
-void Graph::setChannelFilter(const ChannelFilter &filter)
+void Graph::setChannelFilter(const std::optional &filter)
{
m_channelFilter = filter;
+
emit layoutChanged();
emit channelFilterChanged();
}
-const ChannelFilter& Graph::channelFilter() const
+const std::optional& Graph::channelFilter() const
{
return m_channelFilter;
}
@@ -331,14 +281,17 @@ void Graph::setChannelVisible(qsizetype channel_ix, bool is_visible)
{
GraphChannel *ch = channelAt(channel_ix);
- if (!m_channelFilter.isValid()) {
- m_channelFilter.setMatchingPaths(channelPaths());
- }
- if (is_visible) {
- m_channelFilter.addMatchingPath(ch->shvPath());
+ if (!m_channelFilter && !is_visible) {
+ m_channelFilter = ChannelFilter(channelPaths());
}
- else {
- m_channelFilter.removeMatchingPath(ch->shvPath());
+
+ if (m_channelFilter) {
+ if (is_visible) {
+ m_channelFilter.value().addPermittedPath(ch->shvPath());
+ }
+ else {
+ m_channelFilter.value().removePermittedPath(ch->shvPath());
+ }
}
emit layoutChanged();
@@ -1196,10 +1149,10 @@ QVector Graph::visibleChannels() const
if (maximized_channel >= 0) {
visible_channels << maximized_channel;
}
- else if(m_channelFilter.isValid()) {
+ else if (isChannelFilterValid()) {
for (int i = 0; i < m_channels.count(); ++i) {
QString shv_path = model()->channelInfo(m_channels[i]->modelIndex()).shvPath;
- if(m_channelFilter.isPathMatch(shv_path)) {
+ if(m_channelFilter && m_channelFilter.value().isPathPermitted(shv_path)) {
visible_channels << i;
}
}
@@ -1212,31 +1165,24 @@ QVector Graph::visibleChannels() const
return visible_channels;
}
-void Graph::setVisualSettings(const VisualSettings &settings)
+void Graph::setVisualSettingsAndChannelFilter(const VisualSettings &settings)
{
- if (settings.isValid()) {
- QStringList new_filter;
- createChannelsFromModel();
- for (int i = 0; i < settings.channels.count(); ++i) {
- const VisualSettings::Channel &channel_settings = settings.channels[i];
- for (int j = i; j < m_channels.count(); ++j) {
- GraphChannel *channel = m_channels[j];
- if (channel->shvPath() == channel_settings.shvPath) {
- new_filter << channel_settings.shvPath;
- channel->setStyle(channel_settings.style);
- m_channels.insert(i, m_channels.takeAt(j));
- break;
- }
+ QSet permitted_paths;
+
+ for (int i = 0; i < settings.channels.count(); ++i) {
+ const VisualSettings::Channel &channel_settings = settings.channels[i];
+ for (int j = i; j < m_channels.count(); ++j) {
+ GraphChannel *channel = m_channels[j];
+ if (channel->shvPath() == channel_settings.shvPath) {
+ permitted_paths.insert(channel_settings.shvPath);
+ channel->setStyle(channel_settings.style);
+ m_channels.insert(i, m_channels.takeAt(j));
+ break;
}
}
-
- m_channelFilter.setMatchingPaths(new_filter);
- Q_EMIT layoutChanged();
- Q_EMIT channelFilterChanged();
- }
- else {
- reset();
}
+
+ setChannelFilter(ChannelFilter(permitted_paths, settings.name));
}
void Graph::resizeChannelHeight(qsizetype ix, int delta_px)
@@ -1252,7 +1198,7 @@ void Graph::resizeChannelHeight(qsizetype ix, int delta_px)
ch_style.setHeightMax(h);
ch_style.setHeightMin(h);
ch->setStyle(ch_style);
- Q_EMIT layoutChanged();
+ emit layoutChanged();
}
}
}
@@ -1263,20 +1209,19 @@ void Graph::resizeVerticalHeaderWidth(int delta_px)
if (w > MIN_VERTICAL_HEADER_WIDTH && w < MAX_VERTICAL_HEADER_WIDTH) {
m_style.setVerticalHeaderWidth(w);
- Q_EMIT layoutChanged();
+ emit layoutChanged();
}
}
Graph::VisualSettings Graph::visualSettings() const
{
- VisualSettings view;
- if (!isInitialView()) {
- for (int ix : visibleChannels()) {
- const GraphChannel *channel = channelAt(ix);
- view.channels << VisualSettings::Channel{ channel->shvPath(), channel->style() };
- }
+ VisualSettings visual_settings;
+ for (int ix : visibleChannels()) {
+ const GraphChannel *channel = channelAt(ix);
+ visual_settings.channels << VisualSettings::Channel{ channel->shvPath(), channel->style() };
}
- return view;
+
+ return visual_settings;
}
int Graph::maximizedChannelIndex() const
@@ -2293,6 +2238,13 @@ void Graph::drawCurrentTimeMarker(QPainter *painter, time_t time)
drawCenterTopText(painter, p1, text, m_style.font(), color.darker(400), color);
}
+void Graph::applyCustomChannelStyle(GraphChannel *channel)
+{
+ GraphChannel::Style style = channel->style();
+ style.setColor(Qt::cyan);
+ channel->setStyle(style);
+}
+
QString Graph::timeToStringTZ(timemsec_t time) const
{
QDateTime dt = QDateTime::fromMSecsSinceEpoch(time);
@@ -2326,14 +2278,20 @@ void Graph::saveVisualSettings(const QString &settings_id, const QString &name)
void Graph::loadVisualSettings(const QString &settings_id, const QString &name)
{
- VisualSettings graph_view;
QSettings settings;
settings.beginGroup(USER_PROFILES_KEY);
settings.beginGroup(m_settingsUserName);
settings.beginGroup(SITES_KEY);
settings.beginGroup(settings_id);
settings.beginGroup(VIEWS_KEY);
- setVisualSettings(VisualSettings::fromJson(settings.value(name).toString()));
+ VisualSettings vs = VisualSettings::fromJson(settings.value(name).toString());
+ vs.name = settings_id;
+ setVisualSettingsAndChannelFilter(vs);
+}
+
+bool Graph::isChannelFilterValid() const
+{
+ return (m_channelFilter != std::nullopt);
}
void Graph::deleteVisualSettings(const QString &settings_id, const QString &name) const
@@ -2360,19 +2318,15 @@ QStringList Graph::savedVisualSettingsNames(const QString &settings_id) const
QString Graph::VisualSettings::toJson() const
{
- if (isValid()) {
- QJsonArray settings;
+ QJsonArray settings;
- for (int i = 0; i < channels.count(); ++i) {
- settings << QJsonObject {
- { "shvPath", channels[i].shvPath },
- { "style", QJsonObject::fromVariantMap(channels[i].style) }
- };
+ for (int i = 0; i < channels.count(); ++i) {
+ settings << QJsonObject {
+ { "shvPath", channels[i].shvPath },
+ { "style", QJsonObject::fromVariantMap(channels[i].style) }
+ };
}
- return QJsonDocument(QJsonObject{{ "channels", settings }}).toJson(QJsonDocument::Compact);
- }
-
- return QString();
+ return QJsonDocument(QJsonObject{{ "channels", settings }}).toJson(QJsonDocument::Compact);
}
Graph::VisualSettings Graph::VisualSettings::fromJson(const QString &json)
@@ -2395,12 +2349,8 @@ Graph::VisualSettings Graph::VisualSettings::fromJson(const QString &json)
shvWarning() << "Error on parsing user settings" << parse_error.errorString();
}
}
- return settings;
-}
-bool Graph::VisualSettings::isValid() const
-{
- return channels.count();
+ return settings;
}
Graph::XAxis::XAxis() = default;
diff --git a/libshvvisu/src/timeline/graphwidget.cpp b/libshvvisu/src/timeline/graphwidget.cpp
index c2f683b7c..2e45777c0 100644
--- a/libshvvisu/src/timeline/graphwidget.cpp
+++ b/libshvvisu/src/timeline/graphwidget.cpp
@@ -763,7 +763,11 @@ void GraphWidget::showGraphContextMenu(const QPoint &mouse_pos)
menu.addAction(tr("Hide channels without changes"), this, [this]() {
m_graph->hideFlatChannels();
});
- menu.addAction(tr("Reset channels to defaults"), m_graph, &Graph::reset);
+
+ menu.addAction(tr("Reset channels to defaults"), this, [this]() {
+ m_graph->createChannelsFromModel();
+ });
+
if (m_graph->isYAxisVisible()) {
menu.addAction(tr("Hide Y axis"), this, [this]() {
m_graph->setYAxisVisible(false);