Skip to content

Commit

Permalink
Merge pull request #52477 from nirvn/sensor_imp
Browse files Browse the repository at this point in the history
Sensors UI/UX improvements
  • Loading branch information
nirvn committed Apr 1, 2023
2 parents 36fcb79 + b80ca54 commit 3667d28
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 17 deletions.
10 changes: 10 additions & 0 deletions python/core/auto_generated/sensor/qgsabstractsensor.sip.in
Expand Up @@ -114,6 +114,11 @@ Returns the latest captured data from the sensor.
void setData( const QgsAbstractSensor::SensorData &data );
%Docstring
Sets the latest captured data from the sensor.
%End

QString errorString() const;
%Docstring
Returns the last error message.
%End

bool writeXml( QDomElement &parentElement, QDomDocument &document ) const;
Expand Down Expand Up @@ -163,6 +168,11 @@ Emitted when the sensor status has changed.
void dataChanged();
%Docstring
Emitted when the captured sensor data has changed.
%End

void errorOccurred( const QString &errorString );
%Docstring
Emitted when an error has occurred. The ``errorString`` describes the error.
%End

protected:
Expand Down
5 changes: 5 additions & 0 deletions python/core/auto_generated/sensor/qgssensormanager.sip.in
Expand Up @@ -131,6 +131,11 @@ Emitted when a sensor status has changed.
void sensorDataCaptured( const QString &id );
%Docstring
Emitted when newly captured data from a sensor has occurred.
%End

void sensorErrorOccurred( const QString &id );
%Docstring
Emitted when a sensor error has occurred.
%End

};
Expand Down
13 changes: 13 additions & 0 deletions src/app/sensor/qgsprojectsensorsettingswidget.cpp
Expand Up @@ -29,6 +29,11 @@ QgsProjectSensorSettingsWidget::QgsProjectSensorSettingsWidget( QWidget *parent

QgsSensorTableWidget *widget = new QgsSensorTableWidget( this );
mPanelStack->setMainPanel( widget );
connect( widget, &QgsPanelWidget::showPanel, this, [ = ]( QgsPanelWidget * panel )
{
mSensorIntroductionLabel->setVisible( false );
connect( panel, &QgsPanelWidget::panelAccepted, this, [ = ]() { mSensorIntroductionLabel->setVisible( true ); } );
} );

QDomElement sensorElem = QgsProject::instance()->sensorManager()->writeXml( mPreviousSensors );
mPreviousSensors.appendChild( sensorElem );
Expand All @@ -41,6 +46,14 @@ QgsProjectSensorSettingsWidget::QgsProjectSensorSettingsWidget( QWidget *parent
mConnectedSensors << sensor->id();
}
}

connect( QgsProject::instance()->sensorManager(), &QgsSensorManager::sensorErrorOccurred, this, [ = ]( const QString & id )
{
if ( QgsAbstractSensor *sensor = QgsProject::instance()->sensorManager()->sensor( id ) )
{
mMessageBar->pushCritical( tr( "Sensor Error" ), QStringLiteral( "%1: %2" ).arg( sensor->name(), sensor->errorString() ) );
}
} );
}

void QgsProjectSensorSettingsWidget::cancel()
Expand Down
1 change: 1 addition & 0 deletions src/app/sensor/qgssensortablewidget.cpp
Expand Up @@ -55,6 +55,7 @@ QgsSensorSettingsWidget::QgsSensorSettingsWidget( QgsAbstractSensor *sensor, QWi
mButtonBox->button( QDialogButtonBox::Apply )->setEnabled( false );
connect( mButtonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, [ = ]()
{
mButtonBox->button( QDialogButtonBox::Apply )->setEnabled( false );
apply();
} );

Expand Down
5 changes: 5 additions & 0 deletions src/core/sensor/qgsabstractsensor.cpp
Expand Up @@ -63,6 +63,11 @@ void QgsAbstractSensor::setData( const QgsAbstractSensor::SensorData &data )
emit dataChanged();
}

QString QgsAbstractSensor::errorString() const
{
return mErrorString;
}

void QgsAbstractSensor::connectSensor()
{
setStatus( Qgis::DeviceConnectionStatus::Connecting );
Expand Down
9 changes: 9 additions & 0 deletions src/core/sensor/qgsabstractsensor.h
Expand Up @@ -143,6 +143,11 @@ class CORE_EXPORT QgsAbstractSensor : public QObject
*/
void setData( const QgsAbstractSensor::SensorData &data );

/**
* Returns the last error message.
*/
QString errorString() const;

/**
* Write generic sensor properties into a DOM element.
* \param parentElement parent DOM element (e.g 'Sensors' element)
Expand Down Expand Up @@ -182,6 +187,9 @@ class CORE_EXPORT QgsAbstractSensor : public QObject
//! Emitted when the captured sensor data has changed.
void dataChanged();

//! Emitted when an error has occurred. The \a errorString describes the error.
void errorOccurred( const QString &errorString );

protected:

/**
Expand All @@ -197,6 +205,7 @@ class CORE_EXPORT QgsAbstractSensor : public QObject
virtual void handleDisconnect() = 0;

QgsAbstractSensor::SensorData mData;
QString mErrorString;

private:

Expand Down
83 changes: 83 additions & 0 deletions src/core/sensor/qgsiodevicesensor.cpp
Expand Up @@ -57,6 +57,13 @@ QgsTcpSocketSensor::QgsTcpSocketSensor( QObject *parent )
, mTcpSocket( new QTcpSocket() )
{
connect( mTcpSocket, &QAbstractSocket::stateChanged, this, &QgsTcpSocketSensor::socketStateChanged );

#if QT_VERSION < QT_VERSION_CHECK( 5, 15, 0 )
connect( mTcpSocket, qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::error ), this, &QgsTcpSocketSensor::handleError );
#else
connect( mTcpSocket, qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::errorOccurred ), this, &QgsTcpSocketSensor::handleError );
#endif

initIODevice( mTcpSocket );
}

Expand Down Expand Up @@ -112,6 +119,27 @@ void QgsTcpSocketSensor::handleDisconnect()
mTcpSocket->close();
}

void QgsTcpSocketSensor::handleError( QAbstractSocket::SocketError error )
{
switch ( error )
{
case QAbstractSocket::HostNotFoundError:
mErrorString = tr( "Could not find the remote host" );
break;
case QAbstractSocket::NetworkError:
mErrorString = tr( "Attempt to read or write from socket returned an error" );
break;
case QAbstractSocket::ConnectionRefusedError:
mErrorString = tr( "The connection was refused by the remote host" );
break;
default:
mErrorString = tr( "%1" ).arg( QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( error ) );
break;
}

emit errorOccurred( mErrorString );
}

void QgsTcpSocketSensor::socketStateChanged( const QAbstractSocket::SocketState socketState )
{
switch ( socketState )
Expand Down Expand Up @@ -178,6 +206,12 @@ QgsUdpSocketSensor::QgsUdpSocketSensor( QObject *parent )
}
} );

#if QT_VERSION < QT_VERSION_CHECK( 5, 15, 0 )
connect( mUdpSocket.get(), qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::error ), this, &QgsUdpSocketSensor::handleError );
#else
connect( mUdpSocket.get(), qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::errorOccurred ), this, &QgsUdpSocketSensor::handleError );
#endif

initIODevice( mBuffer );
}

Expand Down Expand Up @@ -236,6 +270,27 @@ void QgsUdpSocketSensor::handleDisconnect()
mBuffer->close();
}

void QgsUdpSocketSensor::handleError( QAbstractSocket::SocketError error )
{
switch ( error )
{
case QAbstractSocket::HostNotFoundError:
mErrorString = tr( "Could not find the remote host" );
break;
case QAbstractSocket::NetworkError:
mErrorString = tr( "Attempt to read or write from socket returned an error" );
break;
case QAbstractSocket::ConnectionRefusedError:
mErrorString = tr( "The connection was refused by the remote host" );
break;
default:
mErrorString = tr( "%1" ).arg( QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( error ) );
break;
}

emit errorOccurred( mErrorString );
}

void QgsUdpSocketSensor::socketStateChanged( const QAbstractSocket::SocketState socketState )
{
switch ( socketState )
Expand Down Expand Up @@ -279,6 +334,8 @@ QgsSerialPortSensor::QgsSerialPortSensor( QObject *parent )
: QgsIODeviceSensor( parent )
, mSerialPort( new QSerialPort() )
{
connect( mSerialPort, qOverload<QSerialPort::SerialPortError>( &QSerialPort::errorOccurred ), this, &QgsSerialPortSensor::handleError );

initIODevice( mSerialPort );
}

Expand Down Expand Up @@ -324,6 +381,32 @@ void QgsSerialPortSensor::handleDisconnect()
mSerialPort->close();
}

void QgsSerialPortSensor::handleError( QSerialPort::SerialPortError error )
{
if ( error == QSerialPort::NoError )
{
return;
}

switch ( error )
{
case QSerialPort::DeviceNotFoundError:
mErrorString = tr( "Could not find the serial port device" );
break;
case QSerialPort::ReadError:
mErrorString = tr( "Attempt to read from the serial port returned an error" );
break;
case QSerialPort::PermissionError:
mErrorString = tr( "The connection was refused due to not having enough permission" );
break;
default:
mErrorString = tr( "%1" ).arg( QMetaEnum::fromType<QSerialPort::SerialPortError>().valueToKey( error ) );
break;
}

emit errorOccurred( mErrorString );
}

bool QgsSerialPortSensor::writePropertiesToElement( QDomElement &element, QDomDocument & ) const
{
element.setAttribute( QStringLiteral( "portName" ), mPortName );
Expand Down
10 changes: 8 additions & 2 deletions src/core/sensor/qgsiodevicesensor.h
Expand Up @@ -135,7 +135,8 @@ class CORE_EXPORT QgsTcpSocketSensor : public QgsIODeviceSensor

private slots:

virtual void socketStateChanged( const QAbstractSocket::SocketState socketState );
void socketStateChanged( const QAbstractSocket::SocketState socketState );
void handleError( QAbstractSocket::SocketError error );

private:

Expand Down Expand Up @@ -205,7 +206,8 @@ class CORE_EXPORT QgsUdpSocketSensor : public QgsIODeviceSensor

private slots:

virtual void socketStateChanged( const QAbstractSocket::SocketState socketState );
void socketStateChanged( const QAbstractSocket::SocketState socketState );
void handleError( QAbstractSocket::SocketError error );

private:

Expand Down Expand Up @@ -266,6 +268,10 @@ class CORE_EXPORT QgsSerialPortSensor : public QgsIODeviceSensor
void handleConnect() override;
void handleDisconnect() override;

private slots:

void handleError( QSerialPort::SerialPortError error );

private:

QSerialPort *mSerialPort = nullptr;
Expand Down
10 changes: 10 additions & 0 deletions src/core/sensor/qgssensormanager.cpp
Expand Up @@ -88,6 +88,7 @@ void QgsSensorManager::addSensor( QgsAbstractSensor *sensor )
connect( sensor, &QgsAbstractSensor::nameChanged, this, &QgsSensorManager::handleSensorNameChanged );
connect( sensor, &QgsAbstractSensor::statusChanged, this, &QgsSensorManager::handleSensorStatusChanged );
connect( sensor, &QgsAbstractSensor::dataChanged, this, &QgsSensorManager::captureSensorData );
connect( sensor, &QgsAbstractSensor::errorOccurred, this, &QgsSensorManager::handleSensorErrorOccurred );
mSensors << sensor;

emit sensorAdded( sensor->id() );
Expand Down Expand Up @@ -147,6 +148,15 @@ void QgsSensorManager::captureSensorData()
emit sensorDataCaptured( sensor->id() );
}

void QgsSensorManager::handleSensorErrorOccurred( const QString & )
{
const QgsAbstractSensor *sensor = qobject_cast<QgsAbstractSensor *>( sender() );
if ( !sensor )
return;

emit sensorErrorOccurred( sensor->id() );
}

bool QgsSensorManager::readXml( const QDomElement &element, const QDomDocument &document )
{
clear();
Expand Down
4 changes: 4 additions & 0 deletions src/core/sensor/qgssensormanager.h
Expand Up @@ -131,11 +131,15 @@ class CORE_EXPORT QgsSensorManager : public QObject
//! Emitted when newly captured data from a sensor has occurred.
void sensorDataCaptured( const QString &id );

//! Emitted when a sensor error has occurred.
void sensorErrorOccurred( const QString &id );

private slots:

void handleSensorNameChanged();
void handleSensorStatusChanged();
void captureSensorData();
void handleSensorErrorOccurred( const QString &errorMessage );

private:

Expand Down
15 changes: 0 additions & 15 deletions src/ui/qgisapp.ui
Expand Up @@ -2854,21 +2854,6 @@ Shift+click to snap rotation to 45 degree steps.</string>
<string>Show Statistical Summary</string>
</property>
</action>
<action name="mActionSensorDock">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mSensorDock.svg</normaloff>:/images/themes/default/mSensorDock.svg</iconset>
</property>
<property name="text">
<string>Sensors</string>
</property>
<property name="toolTip">
<string>Show Sensors</string>
</property>
</action>
<action name="mActionShowAlignRasterTool">
<property name="text">
<string>Align Rasters…</string>
Expand Down
19 changes: 19 additions & 0 deletions src/ui/sensor/qgsprojectsensorettingswidgetbase.ui
Expand Up @@ -26,6 +26,9 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QgsMessageBar" name="mMessageBar" native="true"/>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
Expand All @@ -35,6 +38,16 @@
<item>
<widget class="QgsPanelWidgetStack" name="mPanelStack" native="true"/>
</item>
<item>
<widget class="QLabel" name="mSensorIntroductionLabel">
<property name="text">
<string>When connected, a sensor will passively capture data in the background. The latest captured data can be accessed within expressions using the &lt;i&gt;sensor_data('sensor name')&lt;/i&gt; function.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand All @@ -47,6 +60,12 @@
<header>qgspanelwidgetstack.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsMessageBar</class>
<extends>QWidget</extends>
<header>qgsmessagebar.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down

0 comments on commit 3667d28

Please sign in to comment.