mirror of
https://github.com/Lurkki14/tuxclocker.git
synced 2025-02-25 18:55:24 -06:00
Merge 5b421550d1
into 3da3b425f6
This commit is contained in:
commit
b9f3c69df6
@ -1,5 +1,5 @@
|
|||||||
qt5 = import('qt5')
|
qt5 = import('qt5')
|
||||||
qt5_dep = dependency('qt5', modules: ['DBus', 'Charts', 'Widgets'])
|
qt5_dep = dependency('qt5', modules: ['DBus', 'Charts', 'Widgets', 'PrintSupport'])
|
||||||
|
|
||||||
# signals2
|
# signals2
|
||||||
boost_dep = dependency('boost')
|
boost_dep = dependency('boost')
|
||||||
@ -9,6 +9,8 @@ moc_files = qt5.preprocess(moc_headers: ['MainWindow.hpp',
|
|||||||
'data/AssignableItem.hpp',
|
'data/AssignableItem.hpp',
|
||||||
'data/AssignableProxy.hpp',
|
'data/AssignableProxy.hpp',
|
||||||
'data/DeviceModel.hpp',
|
'data/DeviceModel.hpp',
|
||||||
|
'monitor/Monitor.hpp',
|
||||||
|
'monitor/qcustomplot.h',
|
||||||
'data/DynamicReadableConnection.hpp',
|
'data/DynamicReadableConnection.hpp',
|
||||||
'data/DynamicReadableProxy.hpp',
|
'data/DynamicReadableProxy.hpp',
|
||||||
'widgets/AbstractAssignableEditor.hpp',
|
'widgets/AbstractAssignableEditor.hpp',
|
||||||
@ -28,6 +30,10 @@ sources = ['main.cpp',
|
|||||||
'data/DynamicReadableProxy.cpp',
|
'data/DynamicReadableProxy.cpp',
|
||||||
'widgets/DeviceBrowser.cpp',
|
'widgets/DeviceBrowser.cpp',
|
||||||
'widgets/DeviceTreeView.cpp',
|
'widgets/DeviceTreeView.cpp',
|
||||||
|
'monitor/Monitor.cpp',
|
||||||
|
'monitor/Metric.cpp',
|
||||||
|
'monitor/QColorProvider.cpp',
|
||||||
|
'monitor/qcustomplot.cpp',
|
||||||
'widgets/DragChartView.cpp',
|
'widgets/DragChartView.cpp',
|
||||||
'widgets/EnumEditor.cpp',
|
'widgets/EnumEditor.cpp',
|
||||||
'widgets/FlagEditor.cpp',
|
'widgets/FlagEditor.cpp',
|
||||||
|
92
src/tuxclocker-qt/monitor/Metric.cpp
Normal file
92
src/tuxclocker-qt/monitor/Metric.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "Metric.hpp"
|
||||||
|
|
||||||
|
#include <QtDBus/QtDBus>
|
||||||
|
#include <QtDBus/QDBusConnection>
|
||||||
|
#include <QtDBus/QDBusVariant>
|
||||||
|
#include <QtDBus/QDBusInterface>
|
||||||
|
#include <QtDBus/QDBusArgument>
|
||||||
|
#include <QtDBus/QDBusReply>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct BooleanValue
|
||||||
|
{
|
||||||
|
bool my_bool;
|
||||||
|
QDBusVariant val;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(BooleanValue);
|
||||||
|
|
||||||
|
// Marshall the MyStructure data into a D-Bus argument
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const BooleanValue &mystruct)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << mystruct.my_bool << mystruct.val;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the MyStructure data from the D-Bus argument
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, BooleanValue &mystruct)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> mystruct.my_bool >> mystruct.val;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
Metric::Metric(QString dbus_obj_path) : dbus_obj_path(dbus_obj_path) {
|
||||||
|
qDBusRegisterMetaType<BooleanValue>();
|
||||||
|
|
||||||
|
dynamic_readable_interface = new QDBusInterface(
|
||||||
|
"org.tuxclocker",
|
||||||
|
dbus_obj_path,
|
||||||
|
"org.tuxclocker.DynamicReadable",
|
||||||
|
QDBusConnection::systemBus()
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!dynamic_readable_interface->isValid()){
|
||||||
|
qDebug() << "WARNING: Metric got an invalid dynamic_readable_interface";
|
||||||
|
qDebug() << " ==> path" << dbus_obj_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchName();
|
||||||
|
};
|
||||||
|
|
||||||
|
void Metric::fetchName(){
|
||||||
|
QDBusInterface *node_interface = new QDBusInterface(
|
||||||
|
"org.tuxclocker",
|
||||||
|
dbus_obj_path,
|
||||||
|
"org.tuxclocker.Node",
|
||||||
|
QDBusConnection::systemBus()
|
||||||
|
);
|
||||||
|
|
||||||
|
name = node_interface->property("name").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metric::fetchValue(){
|
||||||
|
if(dynamic_readable_interface->isValid()){
|
||||||
|
QDBusReply<BooleanValue> reply = dynamic_readable_interface->call("value");
|
||||||
|
|
||||||
|
if(!reply.isValid()){
|
||||||
|
qDebug() << "WARNING: fetchValue had an invalid DBus reply";
|
||||||
|
qDebug() << "error message: " << reply.error().message();
|
||||||
|
qDebug() << "error name: " << reply.error().name();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: actually request double precision on DBus call method signature
|
||||||
|
actualValue = reply.value().val.variant().toDouble();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metric::asyncFetchValue(){
|
||||||
|
// TODO: Allow cancellation. There are cases where we may be innecessary blocking
|
||||||
|
// if we delay more time that the next time we are called.
|
||||||
|
futureValue = async(launch::async, &Metric::fetchValue, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Metric::value(){
|
||||||
|
return actualValue;
|
||||||
|
}
|
24
src/tuxclocker-qt/monitor/Metric.hpp
Normal file
24
src/tuxclocker-qt/monitor/Metric.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <QtDBus/QDBusInterface>
|
||||||
|
#include <QString>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
#ifndef MetricHPP
|
||||||
|
#define MetricHPP
|
||||||
|
|
||||||
|
class Metric {
|
||||||
|
public:
|
||||||
|
QDBusInterface *dynamic_readable_interface;
|
||||||
|
QString dbus_obj_path;
|
||||||
|
QString name;
|
||||||
|
float actualValue = 0;
|
||||||
|
std::future<void> futureValue;
|
||||||
|
|
||||||
|
Metric(QString dbus_readable);
|
||||||
|
|
||||||
|
void fetchName();
|
||||||
|
void fetchValue();
|
||||||
|
void asyncFetchValue();
|
||||||
|
double value();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
130
src/tuxclocker-qt/monitor/Monitor.cpp
Normal file
130
src/tuxclocker-qt/monitor/Monitor.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "Monitor.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Monitor::Monitor(QWidget *parent) : QCustomPlot(parent), color_provider() {
|
||||||
|
setMinimumWidth(1700);
|
||||||
|
setMinimumHeight(400);
|
||||||
|
|
||||||
|
setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom));
|
||||||
|
|
||||||
|
setOpenGl(true);
|
||||||
|
//setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
setAntialiasedElements(QCP::AntialiasedElement::aeNone);
|
||||||
|
|
||||||
|
setBackground(QColor(48, 56, 65));
|
||||||
|
//setAutoAddMonitortableToLegend(false);
|
||||||
|
|
||||||
|
xAxis->setRange(0, 60);
|
||||||
|
yAxis->setRange(0, 5000);
|
||||||
|
|
||||||
|
collect_metrics_timer.callOnTimeout(this, &Monitor::collect_metrics);
|
||||||
|
collect_metrics_timer.setInterval(100);
|
||||||
|
|
||||||
|
// With 100 it's low profile like gnome-system-monitor
|
||||||
|
// With 20 it looks nice but may use a bit more cpu (40% of an i7-9750h core)
|
||||||
|
replot_timer.callOnTimeout(this, &Monitor::replot);
|
||||||
|
replot_timer.setInterval(20);
|
||||||
|
|
||||||
|
setupYAxisTick();
|
||||||
|
setupLessImportant();
|
||||||
|
|
||||||
|
QObject::connect(yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(onRangeChanged(QCPRange)));
|
||||||
|
};
|
||||||
|
|
||||||
|
void Monitor::onRangeChanged(QCPRange range){
|
||||||
|
setupYAxisTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::setupYAxisTick(){
|
||||||
|
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
|
||||||
|
|
||||||
|
yAxis->setTicker(textTicker);
|
||||||
|
|
||||||
|
double size = yAxis->range().size();
|
||||||
|
double lower = yAxis->range().lower;
|
||||||
|
|
||||||
|
textTicker->addTick(lower, "0%");
|
||||||
|
textTicker->addTick(lower + 0.2 * size, "20%");
|
||||||
|
textTicker->addTick(lower + 0.4 * size, "40%");
|
||||||
|
textTicker->addTick(lower + 0.6 * size, "60%");
|
||||||
|
textTicker->addTick(lower + 0.8 * size, "80%");
|
||||||
|
textTicker->addTick(yAxis->range().upper, "100%");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Monitor::setupLessImportant(){
|
||||||
|
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
|
||||||
|
timeTicker->setTimeFormat("%m:%s:%z");
|
||||||
|
timeTicker->setTickCount(8);
|
||||||
|
xAxis->setTicker(timeTicker);
|
||||||
|
|
||||||
|
xAxis->setTickLabelFont(QFont(QFont().family(), 12));
|
||||||
|
yAxis->setTickLabelFont(QFont(QFont().family(), 12));
|
||||||
|
xAxis->setTickLabelColor(QColor(200, 200, 200));
|
||||||
|
yAxis->setTickLabelColor(QColor(200, 200, 200));
|
||||||
|
|
||||||
|
xAxis2->setVisible(true);
|
||||||
|
yAxis2->setVisible(true);
|
||||||
|
xAxis2->setTicks(false);
|
||||||
|
yAxis2->setTicks(false);
|
||||||
|
xAxis2->setTickLabels(false);
|
||||||
|
yAxis2->setTickLabels(false);
|
||||||
|
|
||||||
|
legend->setVisible(true);
|
||||||
|
legend->setBrush(QColor(255, 255, 255, 150));
|
||||||
|
}
|
||||||
|
|
||||||
|
double Monitor::timenow(){
|
||||||
|
return ((double) QDateTime::currentDateTime().time().msecsSinceStartOfDay()) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::collect_initial_metrics(){
|
||||||
|
for(auto metric : metrics){
|
||||||
|
metric->fetchValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::collect_metrics(){
|
||||||
|
double now = timenow();
|
||||||
|
|
||||||
|
for(int m = 0; m < metrics.count(); m++){
|
||||||
|
graph(m)->data()->add(QCPGraphData (now, metrics[m]->value()));
|
||||||
|
|
||||||
|
// TODO: I dont know how to correctly tell Qt5
|
||||||
|
// to make the dbus call async, for example by using
|
||||||
|
// callWithCallback()
|
||||||
|
metrics[m]->asyncFetchValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
graph()->data()->removeBefore(now - 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::replot(){
|
||||||
|
rescaleAxes();
|
||||||
|
|
||||||
|
double now = timenow();
|
||||||
|
xAxis->setRange(now - 60, now);
|
||||||
|
QCustomPlot::replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::setupGraphs(){
|
||||||
|
clearGraphs();
|
||||||
|
|
||||||
|
for(auto metric : metrics){
|
||||||
|
addGraph();
|
||||||
|
|
||||||
|
graph()->setName(metric->name);
|
||||||
|
graph()->setLineStyle(QCPGraph::lsLine);
|
||||||
|
QPen pen(color_provider.pick());
|
||||||
|
pen.setWidth(1);
|
||||||
|
graph()->setPen(pen);
|
||||||
|
graph()->setAdaptiveSampling(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monitor::start(){
|
||||||
|
collect_initial_metrics();
|
||||||
|
collect_metrics_timer.start();
|
||||||
|
replot_timer.start();
|
||||||
|
}
|
36
src/tuxclocker-qt/monitor/Monitor.hpp
Normal file
36
src/tuxclocker-qt/monitor/Monitor.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <QTimer>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "qcustomplot.h"
|
||||||
|
|
||||||
|
#include "QColorProvider.hpp"
|
||||||
|
#include "Metric.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Monitor : public QCustomPlot {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QTimer collect_metrics_timer;
|
||||||
|
QTimer replot_timer;
|
||||||
|
|
||||||
|
QColorProvider color_provider;
|
||||||
|
QVector<shared_ptr<Metric>> metrics;
|
||||||
|
|
||||||
|
Monitor(QWidget *parent);
|
||||||
|
|
||||||
|
void setupLessImportant();
|
||||||
|
double timenow();
|
||||||
|
void collect_initial_metrics();
|
||||||
|
void collect_metrics();
|
||||||
|
void replot();
|
||||||
|
void setupGraphs();
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void setupYAxisTick();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onRangeChanged(QCPRange range);
|
||||||
|
};
|
11
src/tuxclocker-qt/monitor/QColorProvider.cpp
Normal file
11
src/tuxclocker-qt/monitor/QColorProvider.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "QColorProvider.hpp"
|
||||||
|
|
||||||
|
QColorProvider::QColorProvider(){};
|
||||||
|
|
||||||
|
QColor QColorProvider::pick(){
|
||||||
|
if(current >= colors.count()){
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors.at(current++);
|
||||||
|
}
|
35
src/tuxclocker-qt/monitor/QColorProvider.hpp
Normal file
35
src/tuxclocker-qt/monitor/QColorProvider.hpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <QColor>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
class QColorProvider {
|
||||||
|
public:
|
||||||
|
int current = 0;
|
||||||
|
|
||||||
|
QVector<QColor> colors = {
|
||||||
|
QColor(230, 25, 75, 170), // Red
|
||||||
|
QColor(245, 130, 49, 170), // Orange
|
||||||
|
QColor(255, 255, 25, 170), // Yellow
|
||||||
|
QColor(191, 239, 69, 170), // Lime
|
||||||
|
QColor(60, 180, 75, 170), // Green
|
||||||
|
QColor(66, 212, 244, 170), // Cyan
|
||||||
|
QColor(67, 99, 216, 170), // Navy
|
||||||
|
QColor(240, 50, 230, 170), // Dark Green
|
||||||
|
QColor(145, 30, 180, 170), // Dark Blue
|
||||||
|
QColor(250, 190, 190, 170), // Peach
|
||||||
|
QColor(255, 216, 177, 170), // Tan
|
||||||
|
QColor(255, 250, 200, 170), // Light Blue
|
||||||
|
QColor(128, 0, 255, 170), // Purple
|
||||||
|
QColor(255, 128, 128, 170), // Pink
|
||||||
|
QColor(128, 255, 128, 170), // Light Green
|
||||||
|
QColor(128, 128, 255, 170), // Sky Blue
|
||||||
|
QColor(255, 255, 128, 170), // Light Yellow
|
||||||
|
QColor(255, 128, 255, 170), // Light Pink
|
||||||
|
QColor(128, 255, 255, 170), // Light Turquoise
|
||||||
|
QColor(192, 192, 192, 170) // Gray
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
QColorProvider();
|
||||||
|
|
||||||
|
QColor pick();
|
||||||
|
};
|
35529
src/tuxclocker-qt/monitor/qcustomplot.cpp
Normal file
35529
src/tuxclocker-qt/monitor/qcustomplot.cpp
Normal file
File diff suppressed because it is too large
Load Diff
7774
src/tuxclocker-qt/monitor/qcustomplot.h
Normal file
7774
src/tuxclocker-qt/monitor/qcustomplot.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,7 @@
|
|||||||
#include "DeviceBrowser.hpp"
|
#include "DeviceBrowser.hpp"
|
||||||
#include "AssignableItemData.hpp"
|
#include "AssignableItemData.hpp"
|
||||||
|
#include "./monitor/Monitor.hpp"
|
||||||
|
#include "./monitor/Metric.hpp"
|
||||||
#include "qnamespace.h"
|
#include "qnamespace.h"
|
||||||
|
|
||||||
#include <Globals.hpp>
|
#include <Globals.hpp>
|
||||||
@ -11,6 +13,8 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <Settings.hpp>
|
#include <Settings.hpp>
|
||||||
#include <Utils.hpp>
|
#include <Utils.hpp>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
#define _(String) gettext(String)
|
#define _(String) gettext(String)
|
||||||
|
|
||||||
@ -20,6 +24,48 @@ using namespace TuxClocker::Device;
|
|||||||
Q_DECLARE_METATYPE(AssignableItemData)
|
Q_DECLARE_METATYPE(AssignableItemData)
|
||||||
Q_DECLARE_METATYPE(AssignableProxy *)
|
Q_DECLARE_METATYPE(AssignableProxy *)
|
||||||
|
|
||||||
|
class MonitorDropBox : public QLabel{
|
||||||
|
public:
|
||||||
|
Monitor monitor;
|
||||||
|
QWidget widget;
|
||||||
|
|
||||||
|
MonitorDropBox(QWidget *parent) : QLabel(parent), monitor(nullptr), widget(nullptr){
|
||||||
|
setAcceptDrops(true);
|
||||||
|
setFrameStyle(QFrame::Box);
|
||||||
|
setLineWidth(1);
|
||||||
|
setText("Monitor");
|
||||||
|
setAlignment(Qt::AlignCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupMonitor(QStringList dbus_paths){
|
||||||
|
monitor.setParent(&widget);
|
||||||
|
widget.show();
|
||||||
|
|
||||||
|
monitor.metrics.clear();
|
||||||
|
|
||||||
|
for(QString dbus_path : dbus_paths){
|
||||||
|
monitor.metrics.append(std::make_shared<Metric>(dbus_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor.setupGraphs();
|
||||||
|
|
||||||
|
monitor.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dropEvent(QDropEvent *event) override {
|
||||||
|
QStringList dbus_paths = event->mimeData()->text().split(",");
|
||||||
|
|
||||||
|
if(dbus_paths.count()){
|
||||||
|
setupMonitor(dbus_paths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dragEnterEvent(QDragEnterEvent *event) override {
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
DeviceBrowser::DeviceBrowser(DeviceModel &model, QWidget *parent)
|
DeviceBrowser::DeviceBrowser(DeviceModel &model, QWidget *parent)
|
||||||
: QWidget(parent), m_deviceModel(model) {
|
: QWidget(parent), m_deviceModel(model) {
|
||||||
m_layout = new QGridLayout(this);
|
m_layout = new QGridLayout(this);
|
||||||
@ -75,9 +121,12 @@ DeviceBrowser::DeviceBrowser(DeviceModel &model, QWidget *parent)
|
|||||||
Globals::g_mainStack->setCurrentWidget(m_settings);
|
Globals::g_mainStack->setCurrentWidget(m_settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_layout->addWidget(toolButton, 0, 0);
|
auto monitorDropBox = new MonitorDropBox{this};
|
||||||
|
|
||||||
m_layout->addWidget(m_flagLabel, 0, 1, 1, 1, Qt::AlignRight);
|
m_layout->addWidget(toolButton, 0, 0);
|
||||||
|
m_layout->addWidget(monitorDropBox, 0, 1);
|
||||||
|
|
||||||
|
m_layout->addWidget(m_flagLabel, 0, 2, 1, 0, Qt::AlignRight);
|
||||||
m_layout->addWidget(m_flagEditor, 0, 2);
|
m_layout->addWidget(m_flagEditor, 0, 2);
|
||||||
m_layout->addWidget(m_treeView, 1, 0, 1, 3);
|
m_layout->addWidget(m_treeView, 1, 0, 1, 3);
|
||||||
m_layout->addWidget(m_apply, 2, 0, 1, 3);
|
m_layout->addWidget(m_apply, 2, 0, 1, 3);
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <Utils.hpp>
|
#include <Utils.hpp>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QDrag>
|
||||||
|
|
||||||
using namespace mpark::patterns;
|
using namespace mpark::patterns;
|
||||||
using namespace TuxClocker::Device;
|
using namespace TuxClocker::Device;
|
||||||
@ -26,6 +28,7 @@ DeviceTreeView::DeviceTreeView(QWidget *parent) : QTreeView(parent) {
|
|||||||
setSortingEnabled(true);
|
setSortingEnabled(true);
|
||||||
setEditTriggers(SelectedClicked | EditKeyPressed);
|
setEditTriggers(SelectedClicked | EditKeyPressed);
|
||||||
setContextMenuPolicy(Qt::DefaultContextMenu);
|
setContextMenuPolicy(Qt::DefaultContextMenu);
|
||||||
|
setDragEnabled(true);
|
||||||
|
|
||||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
@ -69,6 +72,42 @@ DeviceTreeView::DeviceTreeView(QWidget *parent) : QTreeView(parent) {
|
|||||||
setItemDelegate(m_delegate);
|
setItemDelegate(m_delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceTreeView::mouseMoveEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (!(event->buttons() & Qt::LeftButton))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QDrag *drag = new QDrag(this);
|
||||||
|
QMimeData *mimeData = new QMimeData;
|
||||||
|
mimeData->setData("text/plain", selected_dbus_readables.join(",").toUtf8());
|
||||||
|
drag->setMimeData(mimeData);
|
||||||
|
|
||||||
|
Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceTreeView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected){
|
||||||
|
selected_dbus_readables.clear();
|
||||||
|
|
||||||
|
for(auto selection : selected){
|
||||||
|
QModelIndexList selectedIndexes = selection.indexes();
|
||||||
|
auto duplicated = std::unique(selectedIndexes.begin(), selectedIndexes.end(), [](QModelIndex &indexA, QModelIndex &indexB){
|
||||||
|
return indexA.row() == indexB.row();
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedIndexes.erase(duplicated, selectedIndexes.end());
|
||||||
|
|
||||||
|
for(auto model_index : selectedIndexes){
|
||||||
|
auto dynProxyV = model_index.data(DeviceModel::DynamicReadableProxyRole);
|
||||||
|
|
||||||
|
if (dynProxyV.isValid()) {
|
||||||
|
auto proxy = qvariant_cast<DynamicReadableProxy *>(dynProxyV);
|
||||||
|
|
||||||
|
selected_dbus_readables.append(proxy->dbusPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceTreeView::suspendChildren(const QModelIndex &index) {
|
void DeviceTreeView::suspendChildren(const QModelIndex &index) {
|
||||||
// Somehow can be true when we collapse nodes from cache
|
// Somehow can be true when we collapse nodes from cache
|
||||||
if (!Globals::g_deviceModel)
|
if (!Globals::g_deviceModel)
|
||||||
|
@ -39,6 +39,8 @@ protected:
|
|||||||
// TODO: allow to start editing with the keyboard
|
// TODO: allow to start editing with the keyboard
|
||||||
EditTriggers editTriggers() { return QAbstractItemView::AllEditTriggers; }
|
EditTriggers editTriggers() { return QAbstractItemView::AllEditTriggers; }
|
||||||
void dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &) override;
|
void dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &) override;
|
||||||
|
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *event);
|
||||||
private:
|
private:
|
||||||
void saveCollapsed(QAbstractItemModel *model);
|
void saveCollapsed(QAbstractItemModel *model);
|
||||||
void restoreCollapsed(QAbstractItemModel *model);
|
void restoreCollapsed(QAbstractItemModel *model);
|
||||||
@ -52,4 +54,5 @@ private:
|
|||||||
QModelIndexList m_editSelection;
|
QModelIndexList m_editSelection;
|
||||||
QModelIndex m_editedIndex;
|
QModelIndex m_editedIndex;
|
||||||
DeviceModelDelegate *m_delegate;
|
DeviceModelDelegate *m_delegate;
|
||||||
|
QStringList selected_dbus_readables;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user