Skip to content

Commit

Permalink
Rework validation support
Browse files Browse the repository at this point in the history
* Add validation support to QGCTextField
* Rework FactTextField to use new QGCTextField support
* Validation errors tracked by count not bool: globals.validationErrorCount
* New mainWindow.allowViewSwitch function to check whether view switch should be allowed
  • Loading branch information
DonLakeFlyer committed Oct 13, 2024
1 parent 19ce078 commit 67324da
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 108 deletions.
38 changes: 4 additions & 34 deletions src/FactSystem/FactControls/FactTextField.qml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import QGroundControl.Controls
import QGroundControl.ScreenTools

QGCTextField {
id: control

id: control
text: fact ? fact.valueString : ""
unitsLabel: fact ? fact.units : ""
showUnits: true
Expand All @@ -18,50 +17,21 @@ QGCTextField {

signal updated()

property Fact fact: null

property string _validateString
property Fact fact: null

onEditingFinished: {
var errorString = fact.validate(text, false /* convertOnly */)
if (errorString === "") {
globals.validationError = false
validationToolTip.visible = false
clearValidationError()
fact.value = text
control.updated()
} else {
globals.validationError = true
validationToolTip.text = errorString
validationToolTip.visible = true
showValidationError(errorString, fact.valueString)
}
}

onHelpClicked: helpDialogComponent.createObject(mainWindow).open()

ToolTip {
id: validationToolTip

QGCMouseArea {
anchors.fill: parent
onClicked: {
control.text = fact.valueString
validationToolTip.visible = false
globals.validationError = false
}
}
}

Component {
id: validationErrorDialogComponent

ParameterEditorDialog {
title: qsTr("Invalid Value")
validate: true
validateValue: _validateString
fact: control.fact
}
}

Component {
id: helpDialogComponent

Expand Down
21 changes: 8 additions & 13 deletions src/QmlControls/QGCPopupDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ Popup {

property string title
property var buttons: Dialog.Ok
property bool acceptAllowed: acceptButton.visible
property bool rejectAllowed: rejectButton.visible
property alias acceptButtonEnabled: acceptButton.enabled
property alias rejectButtonEnabled: rejectButton.enabled
property var dialogProperties
Expand All @@ -66,20 +64,16 @@ Popup {
property var _qgcPal: QGroundControl.globalPalette
property real _frameSize: ScreenTools.defaultFontPixelWidth
property real _contentMargin: ScreenTools.defaultFontPixelHeight / 2
property bool _acceptAllowed: acceptButton.visible
property bool _rejectAllowed: rejectButton.visible

background: QGCMouseArea {
width: mainWindow.width
height: mainWindow.height

onClicked: {
if (closePolicy & Popup.CloseOnPressOutside) {
if (rejectAllowed) {
focus = true // Take focus to force FactTextFields to validate
_reject()
} else if (acceptAllowed) {
focus = true // Take focus to force FactTextFields to validate
_accept()
}
_reject()
}
}
}
Expand All @@ -99,7 +93,7 @@ Popup {
}

function _accept() {
if (acceptAllowed && !globals.validationError) {
if (_acceptAllowed && mainWindow.allowViewSwitch()) {
accepted()
if (preventClose) {
preventClose = false
Expand All @@ -110,7 +104,8 @@ Popup {
}

function _reject() {
if (rejectAllowed && !globals.validationError) {
// Dialogs with cancel button are allowed to close with validation errors
if (_rejectAllowed && ((buttons & Dialog.Cancel) || mainWindow.allowViewSwitch())) {
rejected()
if (preventClose) {
preventClose = false
Expand Down Expand Up @@ -183,7 +178,7 @@ Popup {
}

closePolicy = Popup.NoAutoClose
if (rejectAllowed) {
if (buttons & Dialog.Cancel) {
closePolicy |= Popup.CloseOnEscape
}
}
Expand Down Expand Up @@ -259,7 +254,7 @@ Popup {
focus: true

Keys.onPressed: (event) => {
if (event.key === Qt.Key_Escape && rejectAllowed) {
if (event.key === Qt.Key_Escape && _rejectAllowed) {
_reject()
event.accepted = true
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
Expand Down
51 changes: 45 additions & 6 deletions src/QmlControls/QGCTextField.qml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ TextField {
property string unitsLabel: ""
property string extraUnitsLabel: ""
property bool numericValuesOnly: false // true: Used as hint for mobile devices to show numeric only keyboard
property alias textColor: control.color
property alias textColor: control.color
property bool validationError: false

property real _helpLayoutWidth: 0
property real _marginPadding: ScreenTools.defaultFontPixelHeight / 3

signal helpClicked

Component.onCompleted: selectAllIfActiveFocus()
onActiveFocusChanged: selectAllIfActiveFocus()
Component.onCompleted: checkActiveFocus()
onActiveFocusChanged: checkActiveFocus()

QGCPalette { id: qgcPal; colorGroupEnabled: enabled }

Expand All @@ -46,15 +47,37 @@ TextField {
}
}

function selectAllIfActiveFocus() {
function checkActiveFocus() {
if (activeFocus) {
selectAll()
if (validationError) {
validationToolTip.visible = true
}
}
}

function showValidationError(errorString, originalValidValue = undefined) {
validationToolTip.text = errorString
validationToolTip.originalValidValue = originalValidValue
validationToolTip.visible = true
if (!validationError) {
validationError = true
globals.validationErrorCount++
}
}

function clearValidationError() {
validationToolTip.visible = false
validationToolTip.originalValidValue = undefined
if (validationError) {
validationError = false
globals.validationErrorCount--
}
}

background: Rectangle {
border.width: qgcPal.globalTheme === QGCPalette.Light ? 1 : 0
border.color: qgcPal.buttonBorder
border.width: control.validationError ? 2 : (qgcPal.globalTheme === QGCPalette.Light ? 1 : 0)
border.color: control.validationError ? qgcPal.colorRed : qgcPal.buttonBorder
radius: ScreenTools.buttonBorderRadius
color: qgcPal.textField
implicitWidth: ScreenTools.implicitTextFieldWidth
Expand Down Expand Up @@ -117,6 +140,22 @@ TextField {
}
}

ToolTip {
id: validationToolTip

property var originalValidValue: undefined

QGCMouseArea {
anchors.fill: parent
onClicked: {
if (validationToolTip.originalValidValue !== undefined) {
control.text = validationToolTip.originalValidValue
control.clearValidationError()
}
}
}
}

MouseArea {
anchors.top: parent.top
anchors.bottom: parent.bottom
Expand Down
12 changes: 5 additions & 7 deletions src/UI/AppSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,12 @@ Rectangle {
}

onClicked: {
focus = true
if (mainWindow.preventViewSwitch()) {
return
}
if (rightPanel.source !== url) {
rightPanel.source = url
if (mainWindow.allowViewSwitch()) {
if (rightPanel.source !== url) {
rightPanel.source = url
}
checked = true
}
checked = true
}

Component.onCompleted: {
Expand Down
27 changes: 17 additions & 10 deletions src/UI/MainRootWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@ ApplicationWindow {
readonly property var planMasterControllerFlyView: flyView.planController
readonly property var guidedControllerFlyView: flyView.guidedController

property bool validationError: false // There is a FactTextField somewhere with a validation error
// Number of QGCTextField's with validation errors. Used to prevent closing panels with validation errors.
property int validationErrorCount: 0

// Property to manage RemoteID quick acces to settings page
// Property to manage RemoteID quick access to settings page
property bool commingFromRIDIndicator: false
}

Expand All @@ -109,9 +110,13 @@ ApplicationWindow {
//-------------------------------------------------------------------------
//-- Global Scope Functions

/// @return true: View switches are not currently allowed
function preventViewSwitch() {
return globals.validationError
// This function is used to prevent view switching if there are validation errors
function allowViewSwitch() {
// Run validation on active focus control to ensure it is valid before switching views
if (mainWindow.activeFocusControl instanceof QGCTextField) {
mainWindow.activeFocusControl.onEditingFinished()
}
return globals.validationErrorCount === 0
}

function showPlanView() {
Expand Down Expand Up @@ -259,7 +264,7 @@ ApplicationWindow {
}

function showToolSelectDialog() {
if (!mainWindow.preventViewSwitch()) {
if (mainWindow.allowViewSwitch()) {
mainWindow.showIndicatorDrawer(toolSelectComponent, null)
}
}
Expand Down Expand Up @@ -291,7 +296,7 @@ ApplicationWindow {
text: qsTr("Vehicle Setup")
imageResource: "/qmlimages/Gears.svg"
onClicked: {
if (!mainWindow.preventViewSwitch()) {
if (mainWindow.allowViewSwitch()) {
mainWindow.closeIndicatorDrawer()
mainWindow.showVehicleSetupTool()
}
Expand All @@ -306,7 +311,7 @@ ApplicationWindow {
imageResource: "/qmlimages/Analyze.svg"
visible: QGroundControl.corePlugin.showAdvancedUI
onClicked: {
if (!mainWindow.preventViewSwitch()) {
if (mainWindow.allowViewSwitch()) {
mainWindow.closeIndicatorDrawer()
mainWindow.showAnalyzeTool()
}
Expand All @@ -322,7 +327,7 @@ ApplicationWindow {
imageColor: "transparent"
visible: !QGroundControl.corePlugin.options.combineSettingsAndSetup
onClicked: {
if (!mainWindow.preventViewSwitch()) {
if (mainWindow.allowViewSwitch()) {
drawer.close()
mainWindow.showSettingsTool()
}
Expand Down Expand Up @@ -498,7 +503,9 @@ ApplicationWindow {
x: parent.mapFromItem(backIcon, backIcon.x, backIcon.y).x
width: (backTextLabel.x + backTextLabel.width) - backIcon.x
onClicked: {
toolDrawer.visible = false
if (mainWindow.allowViewSwitch()) {
toolDrawer.visible = false
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/UI/preferences/LinkSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ SettingsPage {
id: linkDialogComponent

QGCPopupDialog {
title: originalConfig ? qsTr("Edit Link") : qsTr("Add New Link")
buttons: Dialog.Save | Dialog.Cancel
acceptAllowed: nameField.text !== ""
title: originalConfig ? qsTr("Edit Link") : qsTr("Add New Link")
buttons: Dialog.Save | Dialog.Cancel
acceptButtonEnabled: nameField.text !== ""

property var originalConfig
property var editingConfig
Expand Down
2 changes: 1 addition & 1 deletion src/UI/toolbar/RemoteIDIndicator.qml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Item {
}

function goToSettings() {
if (!mainWindow.preventViewSwitch()) {
if (mainWindow.allowViewSwitch()) {
globals.commingFromRIDIndicator = true
mainWindow.showSettingsTool()
}
Expand Down
2 changes: 1 addition & 1 deletion src/UI/toolbar/RemoteIDIndicatorPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ ToolIndicatorPage {
}

function goToSettings() {
if (!mainWindow.preventViewSwitch()) {
if (mainWindow.allowViewSwitch()) {
globals.commingFromRIDIndicator = true
mainWindow.showSettingsTool()
}
Expand Down
Loading

0 comments on commit 67324da

Please sign in to comment.