state: Qt6::Sensors + libinput both built — 2 of 3 platform prerequisites resolved
Platform prerequisite status: - Qt6::Sensors: BUILT (v6.11.0, 520KB pkgar, dummy backend) - libinput: BUILT (v1.30.2, with libevdev v1.13.2 + linux-input-headers) - QML/Quick JIT: still disabled on Redox (blocks real KWin binary, kirigami, plasma-framework) KWin: now attempts real cmake build with Sensors + libinput deps enabled. Falls back to redbear-compositor shim on cmake failure (QML/Quick gate). Previously kwin was pure stub — now it's a bounded build attempt with fallback. Enabled in config (new this session): - qt6-sensors, libevdev, libinput, kdecoration, kf6-kcmutils Previously OOTB dependencies now resolved: - libevdev → libinput → KWin real build path opened - linux-input-headers → libevdev → libinput chain - qt6-sensors → KWin Sensors dependency satisfied
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(TARGET Qt::Widgets)
|
||||
add_subdirectory(sensor_explorer_widgets)
|
||||
endif()
|
||||
if (TARGET Qt::Quick)
|
||||
add_subdirectory(sensorclerk)
|
||||
add_subdirectory(sensor_explorer_qml)
|
||||
endif()
|
||||
@@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(tst_manual_sensor_explorer_qml LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Qml Quick Sensors)
|
||||
|
||||
qt_add_executable(tst_manual_sensor_explorer_qml
|
||||
main.cpp
|
||||
sensormodels.cpp sensormodels.h
|
||||
)
|
||||
|
||||
set_target_properties(tst_manual_sensor_explorer_qml PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(tst_manual_sensor_explorer_qml PUBLIC
|
||||
Qt::Qml
|
||||
Qt::Quick
|
||||
Qt::Sensors
|
||||
)
|
||||
|
||||
qt_add_qml_module(tst_manual_sensor_explorer_qml
|
||||
URI SensorModels
|
||||
VERSION 1.0
|
||||
QML_FILES sensor_explorer.qml
|
||||
NO_RESOURCE_TARGET_PATH
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtQml>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine(QUrl("qrc:///sensor_explorer.qml"));
|
||||
QObject *topLevel = engine.rootObjects().value(0);
|
||||
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
|
||||
if (!window) {
|
||||
qWarning("Error: Your root item has to be a Window.");
|
||||
return -1;
|
||||
}
|
||||
window->show();
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>sensor_explorer.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import SensorModels
|
||||
|
||||
Window {
|
||||
id: window
|
||||
width: 400
|
||||
height: 600
|
||||
|
||||
AvailableSensorsModel {
|
||||
id: availableSensorsModel
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
GroupBox {
|
||||
id: availableSensorsModelGroup
|
||||
title: qsTr("Available Sensors")
|
||||
Layout.preferredWidth: window.width - 4 // 4 = 2x2 margins
|
||||
Layout.preferredHeight: window.height * 0.4
|
||||
Layout.margins: 2
|
||||
|
||||
ListView {
|
||||
id: sensorsView
|
||||
anchors.fill: parent
|
||||
currentIndex: -1 // no initial selection
|
||||
spacing: 1
|
||||
clip: true
|
||||
model: availableSensorsModel
|
||||
delegate: Item {
|
||||
id: sensorRow
|
||||
width: sensorsView.width
|
||||
height: 30
|
||||
property color rowColor: {
|
||||
if (sensorsView.currentIndex == index)
|
||||
return "lightsteelblue" // highlight
|
||||
return (index % 2 == 0) ? "#CCCCCC" : "#AAAAAA"
|
||||
}
|
||||
RowLayout {
|
||||
spacing: 1
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
color: sensorRow.rowColor
|
||||
Layout.preferredWidth: sensorRow.width * 0.8
|
||||
Layout.preferredHeight: sensorRow.height
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: display.type + "::" + display.identifier
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
color: sensorRow.rowColor
|
||||
Layout.preferredWidth: sensorRow.width * 0.2
|
||||
Layout.preferredHeight: sensorRow.height
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: display.active ? qsTr("Active") : qsTr("Inactive")
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: sensorsView.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SensorPropertyModel {
|
||||
id: propertyModel
|
||||
sensor: availableSensorsModel.get(sensorsView.currentIndex)
|
||||
}
|
||||
|
||||
Button {
|
||||
id: activateButton
|
||||
Layout.preferredHeight: 30
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
enabled: propertyModel.sensor
|
||||
text: !propertyModel.sensor ? qsTr("Select sensor")
|
||||
: (propertyModel.sensor.active ? qsTr("Deactivate sensor")
|
||||
: qsTr("Activate sensor"))
|
||||
onClicked: propertyModel.sensor.active = !propertyModel.sensor.active
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: qsTr("Selected sensor's properties")
|
||||
Layout.preferredWidth: window.width - 4 // 4 = 2x2 margins
|
||||
Layout.preferredHeight: window.height * 0.55 - activateButton.height
|
||||
Layout.margins: 2
|
||||
enabled: sensorsView.currentIndex != -1
|
||||
|
||||
TableView {
|
||||
id: propertyView
|
||||
anchors.fill: parent
|
||||
model: propertyModel
|
||||
columnSpacing: 1
|
||||
rowSpacing: 1
|
||||
boundsMovement: Flickable.StopAtBounds
|
||||
clip: true
|
||||
|
||||
delegate: Rectangle {
|
||||
implicitHeight: 30
|
||||
implicitWidth: propertyView.width * 0.5
|
||||
color: (model.row % 2 == 0) ? "#CCCCCC" : "#AAAAAA"
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: display
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include "sensormodels.h"
|
||||
#include "qsensor.h"
|
||||
#include "qorientationsensor.h"
|
||||
#include <QtCore/QDebug>
|
||||
#include <qsensor.h>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaProperty>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QByteArray rangelistToByteArray(const qrangelist& list)
|
||||
{
|
||||
QStringList ranges;
|
||||
for (const qrange &r : list) {
|
||||
if (r.first == r.second)
|
||||
ranges << QString("%1 Hz").arg(r.first);
|
||||
else
|
||||
ranges << QString("%1-%2 Hz").arg(r.first).arg(r.second);
|
||||
}
|
||||
if (ranges.size() > 0)
|
||||
return ranges.join(", ").toLatin1();
|
||||
return "-";
|
||||
}
|
||||
|
||||
QByteArray outputrangelistToByteArray(const qoutputrangelist& list)
|
||||
{
|
||||
QStringList ranges;
|
||||
for (const qoutputrange &r : list) {
|
||||
ranges << QString("(%1, %2) += %3").arg(r.minimum).arg(r.maximum).arg(r.accuracy);
|
||||
}
|
||||
if (ranges.size() > 0)
|
||||
return ranges.join(", ").toLatin1();
|
||||
return "-";
|
||||
}
|
||||
|
||||
AvailableSensorsModel::AvailableSensorsModel(QObject* parent) : QAbstractListModel(parent)
|
||||
{
|
||||
// Some valuetypes do not convert nicely to presentable strings, add converters for them
|
||||
QMetaType::registerConverter<qrangelist, QByteArray>(rangelistToByteArray);
|
||||
QMetaType::registerConverter<qoutputrangelist, QByteArray>(outputrangelistToByteArray);
|
||||
|
||||
// Populate the available sensors list
|
||||
loadSensors();
|
||||
}
|
||||
|
||||
/*
|
||||
Load all available sensors and store them in a list.
|
||||
*/
|
||||
void AvailableSensorsModel::loadSensors()
|
||||
{
|
||||
beginResetModel();
|
||||
m_availableSensors.clear();
|
||||
|
||||
for (const QByteArray &type : QSensor::sensorTypes()) {
|
||||
for (const QByteArray &identifier : QSensor::sensorsForType(type)) {
|
||||
QSensor* sensor = new QSensor(type, this);
|
||||
sensor->setIdentifier(identifier);
|
||||
// Don't put in sensors we can't connect to
|
||||
if (!sensor->connectToBackend())
|
||||
continue;
|
||||
m_availableSensors.append(sensor);
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int AvailableSensorsModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_availableSensors.size();
|
||||
}
|
||||
|
||||
QVariant AvailableSensorsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
return QVariant::fromValue<QSensor*>(m_availableSensors.at(index.row()));
|
||||
}
|
||||
|
||||
QSensor* AvailableSensorsModel::get(int index) const
|
||||
{
|
||||
if (index < 0 || index >= m_availableSensors.size())
|
||||
return nullptr;
|
||||
return m_availableSensors[index];
|
||||
}
|
||||
|
||||
// -- SensorPropertyModel
|
||||
|
||||
static QSet<QByteArray> ignoredProperties = {"reading", "identifier", "active",
|
||||
"connectedToBackend", "busy"};
|
||||
|
||||
SensorPropertyModel::SensorPropertyModel(QObject* parent) : QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int SensorPropertyModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
if (!m_sensor)
|
||||
return 0;
|
||||
return m_values.size();
|
||||
}
|
||||
|
||||
int SensorPropertyModel::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return 2; // 2 = property name + value columns
|
||||
}
|
||||
|
||||
QVariant SensorPropertyModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
return (index.column() == 0) ? std::get<0>(m_values.at(index.row()))
|
||||
: std::get<1>(m_values.at(index.row()));
|
||||
}
|
||||
|
||||
void SensorPropertyModel::setSensor(QSensor *sensor)
|
||||
{
|
||||
if (m_sensor == sensor)
|
||||
return;
|
||||
if (m_sensor)
|
||||
m_sensor->disconnect(this);
|
||||
m_sensor = sensor;
|
||||
|
||||
beginResetModel();
|
||||
m_values.clear();
|
||||
if (m_sensor) {
|
||||
// Use metobject to read the available properties. This allows the model to support all
|
||||
// available sensors without knowing their properties in advance / compile-time.
|
||||
|
||||
// 1. Read properties of the 'reading' object if available
|
||||
int firstProperty = QSensorReading::staticMetaObject.propertyOffset();
|
||||
QSensorReading *reading = m_sensor->reading();
|
||||
if (reading) {
|
||||
const QMetaObject *mo = reading->metaObject();
|
||||
for (int i = firstProperty; i < mo->propertyCount(); ++i) {
|
||||
QByteArray name = mo->property(i).name();
|
||||
m_values.append(std::tuple<QByteArray, QByteArray>
|
||||
(name, reading->property(name).toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Read properties of the 'sensor' object
|
||||
const QMetaObject *mo1 = m_sensor->metaObject();
|
||||
firstProperty = QSensorReading::staticMetaObject.propertyOffset();
|
||||
for (int i = firstProperty; i < mo1->propertyCount(); ++i) {
|
||||
QByteArray name = mo1->property(i).name();
|
||||
if (ignoredProperties.contains(name))
|
||||
continue;
|
||||
m_values.append(std::tuple<QByteArray, QByteArray>
|
||||
(name, m_sensor->property(name).toByteArray()));
|
||||
}
|
||||
QObject::connect(m_sensor, &QSensor::readingChanged,
|
||||
this, &SensorPropertyModel::onReadingChanged);
|
||||
}
|
||||
endResetModel();
|
||||
emit sensorChanged();
|
||||
}
|
||||
|
||||
QSensor* SensorPropertyModel::sensor() const
|
||||
{
|
||||
return m_sensor;
|
||||
}
|
||||
|
||||
void SensorPropertyModel::onReadingChanged()
|
||||
{
|
||||
QSensorReading *reading = m_sensor->reading();
|
||||
const QMetaObject *mo = reading->metaObject();
|
||||
int firstProperty = QSensorReading::staticMetaObject.propertyOffset();
|
||||
|
||||
int valueMapIndex = 0;
|
||||
for (int i = firstProperty; i < mo->propertyCount(); ++i) {
|
||||
QByteArray name = mo->property(i).name();
|
||||
// Update the value and signal the change. Note: here we rely that the "reading"
|
||||
// properties are first on the m_values, and in same order as after the initial
|
||||
// population. This should be true as we access the static metabobject (dynamic
|
||||
// property changes shouldn't impact)
|
||||
m_values[valueMapIndex++] = std::tuple<QByteArray, QByteArray>
|
||||
(name, reading->property(name).toByteArray());
|
||||
}
|
||||
emit dataChanged(createIndex(0,1), createIndex(valueMapIndex,1), {Qt::DisplayRole});
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2017 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#ifndef QSEONSOREXPLORER_H
|
||||
#define QSEONSOREXPLORER_H
|
||||
|
||||
#include <QtSensors/qsensor.h>
|
||||
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QtCore/QAbstractListModel>
|
||||
#include <QtCore/QAbstractTableModel>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class AvailableSensorsModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
public:
|
||||
explicit AvailableSensorsModel(QObject* parent = nullptr);
|
||||
int rowCount(const QModelIndex & = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
Q_INVOKABLE QSensor* get(int index) const;
|
||||
|
||||
private:
|
||||
void loadSensors();
|
||||
QList<QSensor*> m_availableSensors;
|
||||
};
|
||||
|
||||
class SensorPropertyModel: public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QSensor* sensor READ sensor WRITE setSensor NOTIFY sensorChanged)
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
explicit SensorPropertyModel(QObject* parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex & = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex & = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
void setSensor(QSensor* sensor);
|
||||
QSensor* sensor() const;
|
||||
|
||||
signals:
|
||||
void sensorChanged();
|
||||
|
||||
private slots:
|
||||
void onReadingChanged();
|
||||
|
||||
private:
|
||||
QSensor* m_sensor = nullptr;
|
||||
// m_values is used to cache sensor property values to avoid
|
||||
// full metaobject iteration on every sensor reading change
|
||||
QList<std::tuple<QByteArray, QByteArray>> m_values;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSEONSOREXPLORER_H
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## sensor_explorer Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_manual_test(tst_manual_sensor_explorer_widgets
|
||||
GUI
|
||||
SOURCES
|
||||
explorer.cpp explorer.h explorer.ui
|
||||
main.cpp
|
||||
LIBRARIES
|
||||
Qt::Sensors
|
||||
Qt::Widgets
|
||||
ENABLE_AUTOGEN_TOOLS
|
||||
uic
|
||||
)
|
||||
+406
@@ -0,0 +1,406 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include "explorer.h"
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <qsensor.h>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaProperty>
|
||||
|
||||
Explorer::Explorer(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_sensor(0)
|
||||
, ignoreItemChanged(false)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
// Clear out example data from the .ui file
|
||||
ui.sensors->clear();
|
||||
clearSensorProperties();
|
||||
clearReading();
|
||||
|
||||
// Force types to be registered
|
||||
(void)QSensor::sensorTypes();
|
||||
// Listen for changes to the registered types
|
||||
QSensor *sensor = new QSensor(QByteArray(), this);
|
||||
connect(sensor, SIGNAL(availableSensorsChanged()), this, SLOT(loadSensors()));
|
||||
}
|
||||
|
||||
Explorer::~Explorer()
|
||||
{
|
||||
}
|
||||
|
||||
void Explorer::loadSensors()
|
||||
{
|
||||
qDebug() << "Explorer::loadSensors";
|
||||
|
||||
// Clear out anything that's in there now
|
||||
ui.sensors->clear();
|
||||
|
||||
for (const QByteArray &type : QSensor::sensorTypes()) {
|
||||
qDebug() << "Found type" << type;
|
||||
for (const QByteArray &identifier : QSensor::sensorsForType(type)) {
|
||||
qDebug() << "Found identifier" << identifier;
|
||||
// Don't put in sensors we can't connect to
|
||||
QSensor sensor(type);
|
||||
sensor.setIdentifier(identifier);
|
||||
if (!sensor.connectToBackend()) {
|
||||
qDebug() << "Couldn't connect to" << identifier;
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug() << "Adding identifier" << identifier;
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << QString::fromLatin1(identifier));
|
||||
item->setData(0, Qt::UserRole, QString::fromLatin1(type));
|
||||
ui.sensors->addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (ui.sensors->topLevelItemCount() == 0) {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << tr("No Sensors Found"));
|
||||
item->setData(0, Qt::UserRole, QString());
|
||||
ui.sensors->addTopLevelItem(item);
|
||||
}
|
||||
|
||||
ui.sensors->setCurrentItem(0);
|
||||
ui.scrollArea->hide();
|
||||
|
||||
resizeSensors();
|
||||
}
|
||||
|
||||
void Explorer::resizeSensors()
|
||||
{
|
||||
ui.sensors->resizeColumnToContents(0);
|
||||
int length = ui.sensors->header()->length() + 4;
|
||||
ui.sensors->setFixedWidth(length);
|
||||
}
|
||||
|
||||
void Explorer::on_sensors_currentItemChanged()
|
||||
{
|
||||
qDebug() << "Explorer::sensorSelected";
|
||||
|
||||
// Clear out anything that's in there now
|
||||
if (m_sensor) {
|
||||
delete m_sensor;
|
||||
m_sensor = 0;
|
||||
}
|
||||
clearSensorProperties();
|
||||
clearReading();
|
||||
ui.scrollArea->hide();
|
||||
|
||||
// Check that we've selected an item
|
||||
QTreeWidgetItem *item = ui.sensors->currentItem();
|
||||
if (!item) {
|
||||
qWarning() << "Didn't select an item!";
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray type = item->data(0, Qt::UserRole).toString().toLatin1();
|
||||
QByteArray identifier = item->data(0, Qt::DisplayRole).toString().toLatin1();
|
||||
|
||||
if (type.isEmpty()) {
|
||||
// Uh oh, there aren't any sensors.
|
||||
// The user has clicked the dummy list entry so just ignore it.
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect to the sensor so we can probe it
|
||||
m_sensor = new QSensor(type, this);
|
||||
connect(m_sensor, SIGNAL(readingChanged()), this, SLOT(sensor_changed()));
|
||||
m_sensor->setIdentifier(identifier);
|
||||
if (!m_sensor->connectToBackend()) {
|
||||
delete m_sensor;
|
||||
m_sensor = 0;
|
||||
qWarning() << "Can't connect to the sensor!";
|
||||
return;
|
||||
}
|
||||
|
||||
ui.scrollArea->show();
|
||||
loadSensorProperties();
|
||||
loadReading();
|
||||
|
||||
adjustTableColumns(ui.sensorprops);
|
||||
adjustTableColumns(ui.reading);
|
||||
QTimer::singleShot(100, this, SLOT(adjustSizes()));
|
||||
}
|
||||
|
||||
void Explorer::clearReading()
|
||||
{
|
||||
ui.reading->setRowCount(0);
|
||||
}
|
||||
|
||||
void Explorer::loadReading()
|
||||
{
|
||||
// Probe the reading using Qt's meta-object facilities
|
||||
QSensorReading *reading = m_sensor->reading();
|
||||
if (!reading)
|
||||
return;
|
||||
const QMetaObject *mo = reading->metaObject();
|
||||
int firstProperty = QSensorReading::staticMetaObject.propertyOffset();
|
||||
|
||||
ui.reading->setRowCount(mo->propertyCount() - firstProperty);
|
||||
|
||||
for (int i = firstProperty; i < mo->propertyCount(); ++i) {
|
||||
int row = i - firstProperty;
|
||||
QTableWidgetItem *index;
|
||||
if (row == 0)
|
||||
// timestamp is not available via index
|
||||
index = new QTableWidgetItem(QLatin1String("N/A"));
|
||||
else
|
||||
index = new QTableWidgetItem(QVariant(row - 1).toString());
|
||||
QTableWidgetItem *prop = new QTableWidgetItem(mo->property(i).name());
|
||||
QString typeName = QLatin1String(mo->property(i).typeName());
|
||||
int delimiter = typeName.lastIndexOf("::");
|
||||
if (delimiter != -1)
|
||||
typeName = typeName.mid(delimiter + 2);
|
||||
QTableWidgetItem *type = new QTableWidgetItem(typeName);
|
||||
QTableWidgetItem *value = new QTableWidgetItem();
|
||||
|
||||
index->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
prop->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
type->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
value->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
|
||||
ui.reading->setItem(row, 0, index);
|
||||
ui.reading->setItem(row, 1, prop);
|
||||
ui.reading->setItem(row, 2, type);
|
||||
ui.reading->setItem(row, 3, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Explorer::clearSensorProperties()
|
||||
{
|
||||
ui.sensorprops->setRowCount(0);
|
||||
}
|
||||
|
||||
void Explorer::loadSensorProperties()
|
||||
{
|
||||
ignoreItemChanged = true;
|
||||
|
||||
// Probe the sensor using Qt's meta-object facilities
|
||||
const QMetaObject *mo = m_sensor->metaObject();
|
||||
int firstProperty = QSensor::staticMetaObject.propertyOffset();
|
||||
|
||||
int rows = mo->propertyCount() - firstProperty;
|
||||
ui.sensorprops->setRowCount(rows);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = firstProperty; i < mo->propertyCount(); ++i) {
|
||||
int row = i - firstProperty - offset;
|
||||
QLatin1String name(mo->property(i).name());
|
||||
if (name == "identifier" ||
|
||||
//name == "type" ||
|
||||
name == "reading" ||
|
||||
name == "connected" ||
|
||||
name == "running" ||
|
||||
name == "supportsPolling") {
|
||||
++offset;
|
||||
continue;
|
||||
}
|
||||
QTableWidgetItem *prop = new QTableWidgetItem(name);
|
||||
QString typeName = QLatin1String(mo->property(i).typeName());
|
||||
int delimiter = typeName.lastIndexOf("::");
|
||||
if (delimiter != -1)
|
||||
typeName = typeName.mid(delimiter + 2);
|
||||
QTableWidgetItem *type = new QTableWidgetItem(typeName);
|
||||
QVariant v = mo->property(i).read(m_sensor);
|
||||
QString val;
|
||||
if (typeName == "qrangelist") {
|
||||
qrangelist rl = v.value<qrangelist>();
|
||||
QStringList out;
|
||||
for (const qrange &r : rl) {
|
||||
if (r.first == r.second)
|
||||
out << QString("%1 Hz").arg(r.first);
|
||||
else
|
||||
out << QString("%1-%2 Hz").arg(r.first).arg(r.second);
|
||||
}
|
||||
val = out.join(", ");
|
||||
} else if (typeName == "qoutputrangelist") {
|
||||
qoutputrangelist rl = v.value<qoutputrangelist>();
|
||||
QStringList out;
|
||||
for (const qoutputrange &r : rl)
|
||||
out << QString("(%1, %2) += %3").arg(r.minimum).arg(r.maximum).arg(r.accuracy);
|
||||
val = out.join(", ");
|
||||
} else {
|
||||
val = v.toString();
|
||||
}
|
||||
QTableWidgetItem *value = new QTableWidgetItem(val);
|
||||
|
||||
prop->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
type->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
if (!mo->property(i).isWritable()) {
|
||||
// clear the editable flag
|
||||
value->setFlags(value->flags() ^ Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
ui.sensorprops->setItem(row, 0, prop);
|
||||
ui.sensorprops->setItem(row, 1, type);
|
||||
ui.sensorprops->setItem(row, 2, value);
|
||||
}
|
||||
|
||||
// We don't add all properties
|
||||
ui.sensorprops->setRowCount(rows - offset);
|
||||
|
||||
ignoreItemChanged = false;
|
||||
}
|
||||
|
||||
void Explorer::showEvent(QShowEvent *event)
|
||||
{
|
||||
// Once we're visible, load the sensors
|
||||
// (don't delay showing the UI while we load plugins, connect to backends, etc.)
|
||||
QTimer::singleShot(0, this, SLOT(loadSensors()));
|
||||
|
||||
QMainWindow::showEvent(event);
|
||||
}
|
||||
|
||||
// Resize columns to fit the space.
|
||||
// This shouldn't be so hard!
|
||||
void Explorer::adjustTableColumns(QTableWidget *table)
|
||||
{
|
||||
if (table->rowCount() == 0) {
|
||||
table->setFixedHeight(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// At least this is easy to do
|
||||
table->resizeColumnsToContents();
|
||||
int length = table->verticalHeader()->length();
|
||||
length += (length / static_cast<qreal>(table->verticalHeader()->count())); // Add 1 more (the header itself)
|
||||
table->setFixedHeight(length);
|
||||
|
||||
int columns = table->columnCount();
|
||||
QList<int> width;
|
||||
int suggestedWidth = 0;
|
||||
for (int i = 0; i < columns; ++i) {
|
||||
int cwidth = table->columnWidth(i);
|
||||
width << cwidth;
|
||||
suggestedWidth += cwidth;
|
||||
}
|
||||
|
||||
int actualWidth = table->size().width();
|
||||
//qDebug() << "suggestedWidth" << suggestedWidth << "actualWidth" << actualWidth;
|
||||
|
||||
// We only scale the columns up, we don't scale down
|
||||
if (actualWidth <= suggestedWidth)
|
||||
return;
|
||||
|
||||
qreal multiplier = actualWidth / static_cast<qreal>(suggestedWidth);
|
||||
int currentSpace = 4;
|
||||
for (int i = 0; i < columns; ++i) {
|
||||
width[i] = multiplier * width[i];
|
||||
currentSpace += width[i];
|
||||
}
|
||||
|
||||
// It ends up too big due to cell decorations or something.
|
||||
// Make things smaller one pixel at a time in round robin fashion until we're good.
|
||||
int i = 0;
|
||||
while (currentSpace > actualWidth) {
|
||||
--width[i];
|
||||
--currentSpace;
|
||||
i = (i + 1) % columns;
|
||||
}
|
||||
|
||||
for (int i = 0; i < columns; ++i) {
|
||||
table->setColumnWidth(i, width[i]);
|
||||
}
|
||||
|
||||
table->setMinimumWidth(suggestedWidth);
|
||||
}
|
||||
|
||||
void Explorer::adjustSizes()
|
||||
{
|
||||
adjustTableColumns(ui.reading);
|
||||
adjustTableColumns(ui.sensorprops);
|
||||
}
|
||||
|
||||
void Explorer::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
resizeSensors();
|
||||
adjustSizes();
|
||||
|
||||
QMainWindow::resizeEvent(event);
|
||||
}
|
||||
|
||||
void Explorer::on_start_clicked()
|
||||
{
|
||||
m_sensor->start();
|
||||
QTimer::singleShot(0, this, SLOT(loadSensorProperties()));
|
||||
}
|
||||
|
||||
void Explorer::on_stop_clicked()
|
||||
{
|
||||
m_sensor->stop();
|
||||
QTimer::singleShot(0, this, SLOT(loadSensorProperties()));
|
||||
}
|
||||
|
||||
void Explorer::sensor_changed()
|
||||
{
|
||||
QSensorReading *reading = m_sensor->reading();
|
||||
filter(reading);
|
||||
}
|
||||
|
||||
bool Explorer::filter(QSensorReading *reading)
|
||||
{
|
||||
const QMetaObject *mo = reading->metaObject();
|
||||
int firstProperty = QSensorReading::staticMetaObject.propertyOffset();
|
||||
|
||||
for (int i = firstProperty; i < mo->propertyCount(); ++i) {
|
||||
int row = i - firstProperty;
|
||||
QString typeName = QLatin1String(mo->property(i).typeName());
|
||||
int delimiter = typeName.lastIndexOf("::");
|
||||
if (delimiter != -1)
|
||||
typeName = typeName.mid(delimiter + 2);
|
||||
QLatin1String name(mo->property(i).name());
|
||||
QTableWidgetItem *value = ui.reading->item(row, 3);
|
||||
QVariant val = mo->property(i).read(reading);
|
||||
if (typeName == "LightLevel") {
|
||||
QString text;
|
||||
switch (val.toInt()) {
|
||||
case 1:
|
||||
text = "Dark";
|
||||
break;
|
||||
case 2:
|
||||
text = "Twilight";
|
||||
break;
|
||||
case 3:
|
||||
text = "Light";
|
||||
break;
|
||||
case 4:
|
||||
text = "Bright";
|
||||
break;
|
||||
case 5:
|
||||
text = "Sunny";
|
||||
break;
|
||||
default:
|
||||
text = "Undefined";
|
||||
break;
|
||||
}
|
||||
value->setText(text);
|
||||
} else {
|
||||
value->setText(val.toString());
|
||||
}
|
||||
}
|
||||
|
||||
adjustTableColumns(ui.reading);
|
||||
//QTimer::singleShot(0, this, SLOT(adjustSizes()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Explorer::on_sensorprops_itemChanged(QTableWidgetItem *item)
|
||||
{
|
||||
if (ignoreItemChanged)
|
||||
return;
|
||||
if (!(item->flags() & Qt::ItemIsEditable))
|
||||
return;
|
||||
|
||||
int row = item->row();
|
||||
QString name = ui.sensorprops->item(row, 0)->text();
|
||||
QVariant value = item->text();
|
||||
|
||||
qDebug() << "setProperty" << name << value;
|
||||
m_sensor->setProperty(name.toLatin1().constData(), QVariant(value));
|
||||
|
||||
QTimer::singleShot(0, this, SLOT(loadSensorProperties()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#ifndef EXPLORER_H
|
||||
#define EXPLORER_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <ui_explorer.h>
|
||||
#include <qsensor.h>
|
||||
|
||||
|
||||
class Explorer : public QMainWindow, public QSensorFilter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Explorer(QWidget *parent = 0);
|
||||
~Explorer();
|
||||
|
||||
bool filter(QSensorReading *reading) override;
|
||||
|
||||
private slots:
|
||||
void loadSensors();
|
||||
void on_sensors_currentItemChanged();
|
||||
void on_sensorprops_itemChanged(QTableWidgetItem *item);
|
||||
void on_start_clicked();
|
||||
void on_stop_clicked();
|
||||
void sensor_changed();
|
||||
void adjustSizes();
|
||||
void loadSensorProperties();
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
void clearReading();
|
||||
void loadReading();
|
||||
void clearSensorProperties();
|
||||
void adjustTableColumns(QTableWidget *table);
|
||||
void resizeSensors();
|
||||
|
||||
Ui::Explorer ui;
|
||||
QSensor *m_sensor;
|
||||
bool ignoreItemChanged;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Explorer</class>
|
||||
<widget class="QMainWindow" name="Explorer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>760</width>
|
||||
<height>636</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Sensors that were detected on the device are listed in the list on the left, grouped by type. The reading properties for the sensor will be presented on the right.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Sensor</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sensors</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="sensors">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">Sensor</string>
|
||||
</property>
|
||||
</column>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">dummy.accelerometer</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>477</width>
|
||||
<height>556</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Sensor Properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="sensorprops">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</row>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</column>
|
||||
<item row="0" column="0">
|
||||
<property name="text">
|
||||
<string notr="true">supportedIntervals</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<property name="text">
|
||||
<string notr="true">qrangelist</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="start">
|
||||
<property name="text">
|
||||
<string>start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="stop">
|
||||
<property name="text">
|
||||
<string>stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_5" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Reading Properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="reading">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string notr="true">2</string>
|
||||
</property>
|
||||
</row>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Index</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</column>
|
||||
<item row="0" column="0">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<property name="text">
|
||||
<string notr="true">x</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<property name="text">
|
||||
<string notr="true">qreal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<property name="text">
|
||||
<string>9.8</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<property name="text">
|
||||
<string notr="true">changeOfBeingEaten</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<property name="text">
|
||||
<string notr="true">bool</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<property name="text">
|
||||
<string>true</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include "explorer.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
Explorer explorer;
|
||||
explorer.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## sensorclerk Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_manual_test(tst_manual_sensor_clerk
|
||||
GUI
|
||||
SOURCES
|
||||
collector.cpp collector.h
|
||||
main.cpp
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::Quick
|
||||
Qt::Sensors
|
||||
)
|
||||
|
||||
set(qml_files
|
||||
"qml/main.qml"
|
||||
)
|
||||
|
||||
qt_internal_add_resource(tst_manual_sensor_clerk "qml_files"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${qml_files}
|
||||
)
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright (C) 2017 Lorn Potter.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QtCore/QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QtSensors>
|
||||
#include <QDir>
|
||||
#include <QtSensors/QAccelerometer>
|
||||
#include <QtSensors/QIRProximitySensor>
|
||||
#include <QtSensors/QOrientationSensor>
|
||||
#include <QtSensors/QProximitySensor>
|
||||
#include <QDebug>
|
||||
|
||||
#include "collector.h"
|
||||
|
||||
Collector::Collector(QObject *parent)
|
||||
: QObject(parent),
|
||||
accel(0),
|
||||
orientation(0),
|
||||
proximity(0),
|
||||
irProx(0),
|
||||
tapSensor(0),
|
||||
dataFile(QDir::tempPath()+"/sensordump_0.dat")
|
||||
, isActive(0),
|
||||
fileCounter(0)
|
||||
{
|
||||
accel = new QAccelerometer(this);
|
||||
accel->connectToBackend();
|
||||
accel->setDataRate(100);
|
||||
connect(accel,SIGNAL(readingChanged()),this,SLOT(accelChanged()));
|
||||
|
||||
orientation = new QOrientationSensor(this);
|
||||
orientation->connectToBackend();
|
||||
orientation->setDataRate(100);
|
||||
connect(orientation,SIGNAL(readingChanged()),this,SLOT(orientationChanged()));
|
||||
|
||||
proximity = new QProximitySensor(this);
|
||||
proximity->connectToBackend();
|
||||
connect(proximity,SIGNAL(readingChanged()),this,SLOT(proximityChanged()));
|
||||
|
||||
irProx = new QIRProximitySensor(this);
|
||||
irProx->connectToBackend();
|
||||
irProx->setDataRate(50);
|
||||
connect(irProx,SIGNAL(readingChanged()),this,SLOT(irProximityChanged()));
|
||||
|
||||
tapSensor = new QTapSensor(this);
|
||||
tapSensor->connectToBackend();
|
||||
connect(tapSensor,SIGNAL(readingChanged()),this,SLOT(tapChanged()));
|
||||
}
|
||||
|
||||
Collector::~Collector()
|
||||
{
|
||||
}
|
||||
|
||||
void Collector::accelChanged()
|
||||
{
|
||||
const qreal x = accel->reading()->x();
|
||||
const qreal y = accel->reading()->y();
|
||||
const qreal z = accel->reading()->z();
|
||||
const quint64 ts = accel->reading()->timestamp();
|
||||
|
||||
QTextStream out(&dataFile);
|
||||
out << QString("accelerometer: %1,%2,%3,%4").arg(ts).arg(x).arg(y).arg(z) << "\n";
|
||||
}
|
||||
|
||||
void Collector::orientationChanged()
|
||||
{
|
||||
const QOrientationReading *orientationReading = orientation->reading();
|
||||
QOrientationReading::Orientation o = orientationReading->orientation();
|
||||
const quint64 ts = orientationReading->timestamp();
|
||||
|
||||
QTextStream out(&dataFile);
|
||||
out << QString("orientation: %1,%2").arg(ts).arg(o) << "\n";
|
||||
}
|
||||
|
||||
void Collector::proximityChanged()
|
||||
{
|
||||
const QProximityReading *proximityReading = proximity->reading();
|
||||
const quint64 ts = proximityReading->timestamp();
|
||||
const bool prox = proximityReading->close();
|
||||
|
||||
QTextStream out(&dataFile);
|
||||
out << QString("proximity: %1,%2").arg(ts).arg(prox) << "\n";
|
||||
}
|
||||
|
||||
void Collector::irProximityChanged()
|
||||
{
|
||||
const QIRProximityReading *irProximityReading = irProx->reading();
|
||||
const quint64 ts = irProximityReading->timestamp();
|
||||
const qreal ref = irProximityReading->reflectance();
|
||||
|
||||
QTextStream out(&dataFile);
|
||||
out << QString("irProximity: %1,%2").arg(ts).arg(ref) << "\n";
|
||||
}
|
||||
|
||||
void Collector::tapChanged()
|
||||
{
|
||||
const QTapReading *tapReading = tapSensor->reading();
|
||||
const quint64 ts = tapReading->timestamp();
|
||||
const bool dTap = tapReading->isDoubleTap();
|
||||
|
||||
QTextStream out(&dataFile);
|
||||
out << QString("tap: %1,%2").arg(ts).arg(dTap) << "\n";
|
||||
}
|
||||
|
||||
void Collector::startCollecting()
|
||||
{
|
||||
if (dataFile.exists()) {
|
||||
fileCounter++;
|
||||
for (size_t i = 0; i < fileCounter; i++) {
|
||||
if (!QFileInfo(QString(QDir::tempPath()+"/sensordump_%1.dat").arg(fileCounter)).exists())
|
||||
dataFile.setFileName(QString(QDir::tempPath()+"/sensordump_%1.dat").arg(fileCounter));
|
||||
break;
|
||||
fileCounter++;
|
||||
}
|
||||
}
|
||||
if (!dataFile.exists()) {
|
||||
if (dataFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
accel->start();
|
||||
orientation->start();
|
||||
proximity->start();
|
||||
irProx->start();
|
||||
tapSensor->start();
|
||||
|
||||
isActive = true;
|
||||
} else {
|
||||
qDebug() << "dump file not opened";
|
||||
}
|
||||
} else {
|
||||
startCollecting();
|
||||
}
|
||||
}
|
||||
|
||||
void Collector::stopCollecting()
|
||||
{
|
||||
if (isActive) {
|
||||
accel->stop();
|
||||
orientation->stop();
|
||||
proximity->stop();
|
||||
irProx->stop();
|
||||
tapSensor->stop();
|
||||
isActive = !isActive;
|
||||
}
|
||||
if (dataFile.isOpen())
|
||||
dataFile.close();
|
||||
}
|
||||
|
||||
|
||||
QML_DECLARE_TYPE(Collector)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2017 Lorn Potter.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#ifndef COLLECTOR_H
|
||||
#define COLLECTOR_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
#include <QFile>
|
||||
|
||||
class QAccelerometer;
|
||||
class QOrientationSensor;
|
||||
class QProximitySensor;
|
||||
class QIRProximitySensor;
|
||||
class QTapSensor;
|
||||
|
||||
class Collector : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Collector(QObject *parent = 0);
|
||||
~Collector();
|
||||
|
||||
public slots:
|
||||
void startCollecting();
|
||||
void stopCollecting();
|
||||
|
||||
private Q_SLOTS:
|
||||
void accelChanged();
|
||||
void orientationChanged();
|
||||
void proximityChanged();
|
||||
void irProximityChanged();
|
||||
void tapChanged();
|
||||
|
||||
private:
|
||||
|
||||
QAccelerometer *accel;
|
||||
QOrientationSensor *orientation;
|
||||
QProximitySensor *proximity;
|
||||
QIRProximitySensor *irProx;
|
||||
QTapSensor *tapSensor;
|
||||
QFile dataFile;
|
||||
|
||||
bool isActive;
|
||||
size_t fileCounter;
|
||||
|
||||
Q_DISABLE_COPY(Collector)
|
||||
};
|
||||
|
||||
#endif // COLLECTOR_H
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2017 Lorn Potter.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QtQuick/QQuickView>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
#include "collector.h"
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
QGuiApplication app( argc, argv );
|
||||
qmlRegisterType<Collector>("Collector", 1, 0, "Collector");
|
||||
QQuickView view;
|
||||
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
view.setSource(QUrl("qrc:qml/main.qml"));
|
||||
view.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2017 Lorn Potter.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Collector
|
||||
import QtSensors
|
||||
|
||||
Rectangle {
|
||||
Collector {
|
||||
id: writer
|
||||
}
|
||||
|
||||
Text {
|
||||
id: label
|
||||
text: "Sensor Clerk<br> push to start and stop<br> sensor dump";
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Button {
|
||||
id: startCollectingButton
|
||||
text: depressed ? "Stop" : "Start"
|
||||
property bool depressed: false
|
||||
anchors.top: label.bottom
|
||||
enabled: true;
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onClicked: {
|
||||
if (!depressed) {
|
||||
writer.startCollecting()
|
||||
depressed = true
|
||||
} else {
|
||||
writer.stopCollecting()
|
||||
depressed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user