diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f650a98b11..54d47f8cf2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -81,3 +81,9 @@ repos: files: .zenodo.json types: [json] args: ["--schemafile", "https://raw.githubusercontent.com/rouault/zenodo_json_schema/master/zenodo-json-schema.json"] + + +- repo: https://github.com/nrbnlulu/qt-hooks + rev: v0.1.0 # current revision + hooks: + - id: qml-format diff --git a/.qmlformat.ini b/.qmlformat.ini new file mode 100644 index 0000000000..909477791e --- /dev/null +++ b/.qmlformat.ini @@ -0,0 +1,5 @@ +[General] +IndentWidth=2 +NewlineType=native +NormalizeOrder= +UseTabs= diff --git a/src/qml/About.qml b/src/qml/About.qml index e7af0f4eb6..8d882b3b23 100644 --- a/src/qml/About.qml +++ b/src/qml/About.qml @@ -1,198 +1,190 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import Theme 1.0 import org.qfield 1.0 Item { - id: aboutPanel - - Rectangle { - color: "black" - opacity: 0.8 + id: aboutPanel + + Rectangle { + color: "black" + opacity: 0.8 + anchors.fill: parent + } + + ColumnLayout { + id: aboutContainer + spacing: 6 + anchors.fill: parent + anchors.margins: 20 + anchors.topMargin: 20 + mainWindow.sceneTopMargin + anchors.bottomMargin: 20 + mainWindow.sceneBottomMargin + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + contentItem: information + contentWidth: information.width + contentHeight: information.height + clip: true + + MouseArea { anchors.fill: parent - } + onClicked: aboutPanel.visible = false + } - ColumnLayout { - id: aboutContainer + ColumnLayout { + id: information spacing: 6 - anchors.fill: parent - anchors.margins: 20 - anchors.topMargin: 20 + mainWindow.sceneTopMargin - anchors.bottomMargin: 20 + mainWindow.sceneBottomMargin - - ScrollView { - Layout.fillWidth: true - Layout.fillHeight: true - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - ScrollBar.vertical.policy: ScrollBar.AsNeeded - contentItem: information - contentWidth: information.width - contentHeight: information.height - clip: true - - MouseArea { - anchors.fill: parent - onClicked: aboutPanel.visible = false - } - - ColumnLayout { - id: information - spacing: 6 - width: aboutPanel.width - 40 - height: Math.max(mainWindow.height - linksButton.height * 2 - qfieldAppDirectoryLabel.height - aboutContainer.spacing * 3 - aboutContainer.anchors.topMargin - aboutContainer.anchors.bottomMargin, - qfieldPart.height + opengisPart.height + spacing) - - ColumnLayout { - id: qfieldPart - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - - MouseArea { - Layout.preferredWidth: 138 - Layout.preferredHeight: 138 - Image { - id: qfieldLogo - width: parent.width - height: parent.height - source: "qrc:/images/qfield_logo.svg" - sourceSize.width: width * screen.devicePixelRatio - sourceSize.height: height * screen.devicePixelRatio - } - onClicked: Qt.openUrlExternally("https://qfield.org/") - } - - Label { - Layout.fillWidth: true - Layout.maximumWidth: parent.width - Layout.alignment: Qt.AlignCenter - horizontalAlignment: Text.AlignHCenter - font: Theme.strongFont - color: Theme.light - textFormat: Text.RichText - text: { - var links = '' + gitRev.substr(0, 6) + '' - - if (appVersion && appVersion !== '1.0.0') - links += ' ' + appVersion + '' - - return "QField
" + appVersionStr + " (" + links + ")
Qt " + qVersion - } - onLinkActivated: Qt.openUrlExternally(link) - } - } - - ColumnLayout { - id: opengisPart - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - - MouseArea { - Layout.preferredWidth: 91 - Layout.preferredHeight:113 - Image { - id: opengisLogo - width: parent.width - height: parent.height - source: "qrc:/images/opengis-logo.svg" - sourceSize.width: width * screen.devicePixelRatio - sourceSize.height: height * screen.devicePixelRatio - } - onClicked: Qt.openUrlExternally("https://opengis.ch") - } - - Label { - Layout.fillWidth: true - Layout.maximumWidth: parent.width - Layout.alignment: Qt.AlignCenter - horizontalAlignment: Text.AlignHCenter - font: Theme.strongFont - color: Theme.light - textFormat: Text.RichText - text: qsTr( "Developed by" ) + '
OPENGIS.ch' - onLinkActivated: Qt.openUrlExternally(link) - } - } + width: aboutPanel.width - 40 + height: Math.max(mainWindow.height - linksButton.height * 2 - qfieldAppDirectoryLabel.height - aboutContainer.spacing * 3 - aboutContainer.anchors.topMargin - aboutContainer.anchors.bottomMargin, qfieldPart.height + opengisPart.height + spacing) + + ColumnLayout { + id: qfieldPart + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + MouseArea { + Layout.preferredWidth: 138 + Layout.preferredHeight: 138 + Image { + id: qfieldLogo + width: parent.width + height: parent.height + source: "qrc:/images/qfield_logo.svg" + sourceSize.width: width * screen.devicePixelRatio + sourceSize.height: height * screen.devicePixelRatio } - } + onClicked: Qt.openUrlExternally("https://qfield.org/") + } - Label { - id: qfieldAppDirectoryLabel + Label { Layout.fillWidth: true Layout.maximumWidth: parent.width Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter - font: Theme.tinyFont + font: Theme.strongFont color: Theme.light - opacity: 0.6 - + textFormat: Text.RichText text: { - var dataDirs = platformUtilities.appDataDirs(); - if (dataDirs.length > 0) { - return (dataDirs.length > 1 - ? 'QField app directories' - : 'QField app directory') - + '\n' + dataDirs.join('\n'); - } - return ''; + var links = '' + gitRev.substr(0, 6) + ''; + if (appVersion && appVersion !== '1.0.0') + links += ' ' + appVersion + ''; + return "QField
" + appVersionStr + " (" + links + ")
Qt " + qVersion; } + onLinkActivated: Qt.openUrlExternally(link) + } } - QfButton { - id: sponsorshipButton + ColumnLayout { + id: opengisPart + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + MouseArea { + Layout.preferredWidth: 91 + Layout.preferredHeight: 113 + Image { + id: opengisLogo + width: parent.width + height: parent.height + source: "qrc:/images/opengis-logo.svg" + sourceSize.width: width * screen.devicePixelRatio + sourceSize.height: height * screen.devicePixelRatio + } + onClicked: Qt.openUrlExternally("https://opengis.ch") + } + + Label { Layout.fillWidth: true - icon.source: Theme.getThemeVectorIcon( 'ic_sponsor_white_24dp' ) + Layout.maximumWidth: parent.width + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + font: Theme.strongFont + color: Theme.light + textFormat: Text.RichText + text: qsTr("Developed by") + '
OPENGIS.ch' + onLinkActivated: Qt.openUrlExternally(link) + } + } + } + } - text: qsTr( 'Support QField') - onClicked: Qt.openUrlExternally("https://github.com/sponsors/opengisch") + Label { + id: qfieldAppDirectoryLabel + Layout.fillWidth: true + Layout.maximumWidth: parent.width + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + font: Theme.tinyFont + color: Theme.light + opacity: 0.6 + + text: { + var dataDirs = platformUtilities.appDataDirs(); + if (dataDirs.length > 0) { + return (dataDirs.length > 1 ? 'QField app directories' : 'QField app directory') + '\n' + dataDirs.join('\n'); } + return ''; + } + } - QfButton { - id: linksButton - dropdown: true - Layout.fillWidth: true - icon.source: Theme.getThemeVectorIcon( 'ic_book_white_24dp' ) + QfButton { + id: sponsorshipButton + Layout.fillWidth: true + icon.source: Theme.getThemeVectorIcon('ic_sponsor_white_24dp') - text: qsTr( 'Documentation' ) + text: qsTr('Support QField') + onClicked: Qt.openUrlExternally("https://github.com/sponsors/opengisch") + } + QfButton { + id: linksButton + dropdown: true + Layout.fillWidth: true + icon.source: Theme.getThemeVectorIcon('ic_book_white_24dp') - onClicked: { - Qt.openUrlExternally("https://docs.qfield.org/") - } + text: qsTr('Documentation') - onDropdownClicked: { - linksMenu.popup(linksButton.width - linksMenu.width + 10, linksButton.y + 10) - } - } - } + onClicked: { + Qt.openUrlExternally("https://docs.qfield.org/"); + } - Menu { - id: linksMenu - title: qsTr( "Links Menu" ) - - width: { - var result = 0; - var padding = 0; - for (var i = 0; i < count; ++i) { - var item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.padding, padding); - } - return result + padding * 2; - } + onDropdownClicked: { + linksMenu.popup(linksButton.width - linksMenu.width + 10, linksButton.y + 10); + } + } + } + + Menu { + id: linksMenu + title: qsTr("Links Menu") + + width: { + var result = 0; + var padding = 0; + for (var i = 0; i < count; ++i) { + var item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.padding, padding); + } + return result + padding * 2; + } - MenuItem { - text: qsTr('Changelog') + MenuItem { + text: qsTr('Changelog') - font: Theme.defaultFont - height: 48 - leftPadding: Theme.menuItemLeftPadding - icon.source: Theme.getThemeVectorIcon( 'ic_speaker_white_24dp' ) + font: Theme.defaultFont + height: 48 + leftPadding: Theme.menuItemLeftPadding + icon.source: Theme.getThemeVectorIcon('ic_speaker_white_24dp') - onTriggered: { - changelogPopup.open() - } - } + onTriggered: { + changelogPopup.open(); + } } + } } diff --git a/src/qml/BadLayerItem.qml b/src/qml/BadLayerItem.qml index 20a4060c54..93ee0310bd 100644 --- a/src/qml/BadLayerItem.qml +++ b/src/qml/BadLayerItem.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 @@ -16,7 +15,7 @@ Page { height: mainWindow.height header: QfPageHeader { - title: qsTr( 'Unable to load some layers' ) + title: qsTr('Unable to load some layers') showBackButton: false showApplyButton: false @@ -38,67 +37,67 @@ Page { Layout.fillWidth: true Layout.fillHeight: false - text: qsTr( "The following layers could not be loaded, please review those and reconfigure the QGIS project." ) + text: qsTr("The following layers could not be loaded, please review those and reconfigure the QGIS project.") font: Theme.defaultFont color: Theme.mainTextColor wrapMode: Text.WordWrap } Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - color: Theme.controlBackgroundColor - border.color: Theme.controlBorderColor - border.width: 1 - - ListView { - id: table - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.StopAtBounds - clip: true - spacing: 2 - anchors.fill: parent - - model: BadLayerHandler { - project: qgisProject - - onBadLayersFound: { - badLayerPage.visible = true - } - } + Layout.fillWidth: true + Layout.fillHeight: true + color: Theme.controlBackgroundColor + border.color: Theme.controlBorderColor + border.width: 1 + + ListView { + id: table + flickableDirection: Flickable.VerticalFlick + boundsBehavior: Flickable.StopAtBounds + clip: true + spacing: 2 + anchors.fill: parent + + model: BadLayerHandler { + project: qgisProject + + onBadLayersFound: { + badLayerPage.visible = true; + } + } - delegate: Rectangle { - id: rectangle - width: parent ? parent.width : undefined - height: line.height - color: "transparent" - - Column { - id: line - width: parent.width - spacing: 0 - - Text { - id: name - width: rectangle.width - padding * 2 - padding: 5 - text: LayerName - font: Theme.strongTipFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - } - Text { - id: uri - width: rectangle.width - padding * 2 - padding: 5 - text: DataSource - font: Theme.tipFont - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - } - } + delegate: Rectangle { + id: rectangle + width: parent ? parent.width : undefined + height: line.height + color: "transparent" + + Column { + id: line + width: parent.width + spacing: 0 + + Text { + id: name + width: rectangle.width - padding * 2 + padding: 5 + text: LayerName + font: Theme.strongTipFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + } + Text { + id: uri + width: rectangle.width - padding * 2 + padding: 5 + text: DataSource + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap } + } } + } } Label { @@ -106,15 +105,15 @@ Page { Layout.fillHeight: false Layout.topMargin: 5 - text: qsTr( 'You may check the %1Portable Project%2 documentation page for more help.') - .arg( "" ) - .arg( "" ) + text: qsTr('You may check the %1Portable Project%2 documentation page for more help.').arg("").arg("") textFormat: Text.RichText font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap - onLinkActivated: (link) => { Qt.openUrlExternally(link) } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } } } } diff --git a/src/qml/BluetoothDeviceChooser.qml b/src/qml/BluetoothDeviceChooser.qml index 71cf8b5f8c..944a0db628 100644 --- a/src/qml/BluetoothDeviceChooser.qml +++ b/src/qml/BluetoothDeviceChooser.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 - import Theme 1.0 Item { @@ -22,8 +20,10 @@ Item { } function getSettings() { - return {'name': deviceName, - 'address': deviceAddress}; + return { + "name": deviceName, + "address": deviceAddress + }; } GridLayout { @@ -44,17 +44,16 @@ Item { text: qsTr('Scan for nearby devices') onClicked: { - bluetoothDeviceModel.startServiceDiscovery( false ) + bluetoothDeviceModel.startServiceDiscovery(false); } onPressAndHold: { - fullDiscoveryDialog.open() + fullDiscoveryDialog.open(); } enabled: bluetoothDeviceModel.scanningStatus !== BluetoothDeviceModel.Scanning opacity: enabled ? 1 : 0 } - BusyIndicator { id: busyIndicator anchors.centerIn: scanButton @@ -66,9 +65,7 @@ Item { Label { Layout.fillWidth: true - text: bluetoothDeviceComboBox.count > 0 - ? qsTr( "Select the Bluetooth device from the list below:" ) - : qsTr( "No Bluetooth devices detected, scan to populate nearby devices." ) + text: bluetoothDeviceComboBox.count > 0 ? qsTr("Select the Bluetooth device from the list below:") : qsTr("No Bluetooth devices detected, scan to populate nearby devices.") font: Theme.defaultFont wrapMode: Text.WordWrap @@ -104,58 +101,53 @@ Item { target: bluetoothDeviceModel function onModelReset() { - bluetoothDeviceComboBox.currentIndex = selectedBluetoothDevice + bluetoothDeviceComboBox.currentIndex = selectedBluetoothDevice; } function onLastErrorChanged(lastError) { - displayToast(qsTr('Scanning error: %1').arg(lastError), 'error') - console.log(lastError) + displayToast(qsTr('Scanning error: %1').arg(lastError), 'error'); + console.log(lastError); } function onScanningStatusChanged(scanningStatus) { - if( scanningStatus === BluetoothDeviceModel.Scanning ) - { - displayToast( qsTr('Scanning for paired devices') ) + if (scanningStatus === BluetoothDeviceModel.Scanning) { + displayToast(qsTr('Scanning for paired devices')); } - if( scanningStatus === BluetoothDeviceModel.Failed ) - { - displayToast( qsTr('Scanning failed: %1').arg( bluetoothDeviceModel.lastError ), 'error' ) + if (scanningStatus === BluetoothDeviceModel.Failed) { + displayToast(qsTr('Scanning failed: %1').arg(bluetoothDeviceModel.lastError), 'error'); } - if( scanningStatus === BluetoothDeviceModel.Succeeded ) - { - var message = qsTr('Scanning done') - if ( bluetoothDeviceModel.rowCount() > 1 ) - { - message += ': ' + qsTr( '%n device(s) found', '', bluetoothDeviceModel.rowCount() - 1 ) + if (scanningStatus === BluetoothDeviceModel.Succeeded) { + var message = qsTr('Scanning done'); + if (bluetoothDeviceModel.rowCount() > 1) { + message += ': ' + qsTr('%n device(s) found', '', bluetoothDeviceModel.rowCount() - 1); } - displayToast( message ) + displayToast(message); } - if( scanningStatus === BluetoothDeviceModel.Canceled ) - { - displayToast( qsTr('Scanning canceled') ) + if (scanningStatus === BluetoothDeviceModel.Canceled) { + displayToast(qsTr('Scanning canceled')); } } } } Label { - id: bluetoothDeviceName - Layout.fillWidth: true - visible: deviceAddress != '' - font: Theme.defaultFont - color: Theme.secondaryTextColor - text: qsTr('Bluetooth device name:') + '\n ' + deviceName - wrapMode: Text.WordWrap + id: bluetoothDeviceName + Layout.fillWidth: true + visible: deviceAddress != '' + font: Theme.defaultFont + color: Theme.secondaryTextColor + text: qsTr('Bluetooth device name:') + '\n ' + deviceName + wrapMode: Text.WordWrap } Label { - id: bluetoothDeviceAddress - Layout.fillWidth: true - visible: deviceAddress != '' - font: Theme.defaultFont - color: Theme.secondaryTextColor - text: qsTr('Bluetooth device address:') + '\n ' + deviceAddress - wrapMode: Text.WordWrap + id: bluetoothDeviceAddress + Layout.fillWidth: true + visible: deviceAddress != '' + font: Theme.defaultFont + color: Theme.secondaryTextColor + text: qsTr('Bluetooth device address:') + '\n ' + deviceAddress + wrapMode: Text.WordWrap } } @@ -167,24 +159,24 @@ Item { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Make a full service discovery" ) + title: qsTr("Make a full service discovery") Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( 'A full device scan can take longer. You really want to do it?\nCancel to make a minimal device scan instead.') + text: qsTr('A full device scan can take longer. You really want to do it?\nCancel to make a minimal device scan instead.') } standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - bluetoothDeviceModel.startServiceDiscovery( true ) - visible = false + bluetoothDeviceModel.startServiceDiscovery(true); + visible = false; } onRejected: { - bluetoothDeviceModel.startServiceDiscovery( false ) - visible = false + bluetoothDeviceModel.startServiceDiscovery(false); + visible = false; } } } diff --git a/src/qml/BookmarkHighlight.qml b/src/qml/BookmarkHighlight.qml index 4543e9ea4c..ed49b28a8a 100644 --- a/src/qml/BookmarkHighlight.qml +++ b/src/qml/BookmarkHighlight.qml @@ -1,8 +1,6 @@ import QtQuick 2.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Repeater { diff --git a/src/qml/BookmarkProperties.qml b/src/qml/BookmarkProperties.qml index d5469691c3..0a96bd5cd6 100644 --- a/src/qml/BookmarkProperties.qml +++ b/src/qml/BookmarkProperties.qml @@ -1,207 +1,202 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Popup { - id: bookmarkProperties + id: bookmarkProperties + + property string bookmarkId: '' + property string bookmarkName: '' + property string bookmarkGroup: '' + + width: Math.min(350, mainWindow.width - Theme.popupScreenEdgeMargin) + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + padding: 0 + + onAboutToShow: { + nameField.text = bookmarkName; + groupField.value = bookmarkGroup; + } + + function saveBookmark() { + bookmarkModel.updateBookmarkDetails(bookmarkProperties.bookmarkId, nameField.text, groupField.value); + } + + Page { + width: parent.width + padding: 10 + header: QfPageHeader { + id: pageHeader + title: qsTr("Bookmark Properties") + + showBackButton: false + showApplyButton: false + showCancelButton: true + backgroundFill: false + + onCancel: { + bookmarkProperties.close(); + } + } - property string bookmarkId: '' - property string bookmarkName: '' - property string bookmarkGroup: '' + ColumnLayout { + id: propertiesLayout + spacing: 4 + width: parent.width - width: Math.min(350, mainWindow.width - Theme.popupScreenEdgeMargin) - x: (parent.width - width) / 2 - y: (parent.height - height) / 2 - padding: 0 + Label { + Layout.fillWidth: true + text: qsTr('Name') + font: Theme.defaultFont + } - onAboutToShow: { - nameField.text = bookmarkName; - groupField.value = bookmarkGroup; - } + QfTextField { + id: nameField + Layout.fillWidth: true + font: Theme.defaultFont + text: '' - function saveBookmark() { - bookmarkModel.updateBookmarkDetails(bookmarkProperties.bookmarkId, nameField.text, groupField.value) - } + onTextChanged: { + saveBookmark(); + } + } + + Label { + Layout.fillWidth: true + text: qsTr('Color') + font: Theme.defaultFont + } - Page { - width: parent.width - padding: 10 - header: QfPageHeader { - id: pageHeader - title: qsTr( "Bookmark Properties" ) + RowLayout { + id: groupField + spacing: 8 + Layout.fillWidth: true - showBackButton: false - showApplyButton: false - showCancelButton: true - backgroundFill: false + property int iconSize: 32 + property string value: '' - onCancel: { - bookmarkProperties.close() + onValueChanged: { + saveBookmark(); + } + + Rectangle { + id: defaultColor + Layout.alignment: Qt.AlignVCenter + width: groupField.iconSize + height: groupField.iconSize + color: Theme.bookmarkDefault + border.width: 4 + border.color: groupField.value != 'orange' && groupField.value != 'red' && groupField.value != 'blue' ? Theme.mainTextColor : "transparent" + radius: 2 + + MouseArea { + anchors.fill: parent + onClicked: groupField.value = '' } } + Rectangle { + id: orangeColor + width: groupField.iconSize + height: groupField.iconSize + color: Theme.bookmarkOrange + border.width: 4 + border.color: groupField.value === 'orange' ? Theme.mainTextColor : "transparent" + radius: 2 + + MouseArea { + anchors.fill: parent + onClicked: groupField.value = 'orange' + } + } + Rectangle { + id: redColor + width: groupField.iconSize + height: groupField.iconSize + color: Theme.bookmarkRed + border.width: 4 + border.color: groupField.value === 'red' ? Theme.mainTextColor : "transparent" + radius: 2 + + MouseArea { + anchors.fill: parent + onClicked: groupField.value = 'red' + } + } + Rectangle { + id: blueColor + width: groupField.iconSize + height: groupField.iconSize + color: Theme.bookmarkBlue + border.width: 4 + border.color: groupField.value === 'blue' ? Theme.mainTextColor : "transparent" + radius: 2 + + MouseArea { + anchors.fill: parent + onClicked: groupField.value = 'blue' + } + } + Item { + Layout.fillWidth: true + } + } + + QfButton { + id: updateBookmarkButton + Layout.fillWidth: true + Layout.topMargin: 10 + text: qsTr('Copy bookmark details') + + onClicked: { + var point = bookmarkModel.getBookmarkPoint(bookmarkProperties.bookmarkId); + var crs = bookmarkModel.getBookmarkCrs(bookmarkProperties.bookmarkId); + var coordinates = StringUtils.pointInformation(point, crs); + platformUtilities.copyTextToClipboard(nameField.text + '\n' + coordinates); + displayToast(qsTr('Bookmark details copied to clipboard')); + } + } + + QfButton { + id: deleteBookmarkButton + Layout.fillWidth: true + bgcolor: 'transparent' + color: Theme.darkRed + text: qsTr('Remove bookmark') - ColumnLayout { - id: propertiesLayout - spacing: 4 - width: parent.width - - Label { - Layout.fillWidth: true - text: qsTr('Name') - font: Theme.defaultFont - } - - QfTextField { - id: nameField - Layout.fillWidth: true - font: Theme.defaultFont - text: '' - - onTextChanged: { - saveBookmark(); - } - } - - Label { - Layout.fillWidth: true - text: qsTr('Color') - font: Theme.defaultFont - } - - RowLayout { - id: groupField - spacing: 8 - Layout.fillWidth: true - - property int iconSize: 32 - property string value: '' - - onValueChanged: { - saveBookmark(); - } - - Rectangle { - id: defaultColor - Layout.alignment: Qt.AlignVCenter - width: groupField.iconSize - height: groupField.iconSize - color: Theme.bookmarkDefault - border.width: 4 - border.color: groupField.value != 'orange' && - groupField.value != 'red' && - groupField.value != 'blue' ? Theme.mainTextColor : "transparent" - radius: 2 - - MouseArea { - anchors.fill: parent - onClicked: groupField.value = ''; - } - } - Rectangle { - id: orangeColor - width: groupField.iconSize - height: groupField.iconSize - color: Theme.bookmarkOrange - border.width: 4 - border.color: groupField.value === 'orange' ? Theme.mainTextColor : "transparent" - radius: 2 - - MouseArea { - anchors.fill: parent - onClicked: groupField.value = 'orange'; - } - } - Rectangle { - id: redColor - width: groupField.iconSize - height: groupField.iconSize - color: Theme.bookmarkRed - border.width: 4 - border.color: groupField.value === 'red' ? Theme.mainTextColor : "transparent" - radius: 2 - - MouseArea { - anchors.fill: parent - onClicked: groupField.value = 'red'; - } - } - Rectangle { - id: blueColor - width: groupField.iconSize - height: groupField.iconSize - color: Theme.bookmarkBlue - border.width: 4 - border.color: groupField.value === 'blue' ? Theme.mainTextColor : "transparent" - radius: 2 - - MouseArea { - anchors.fill: parent - onClicked: groupField.value = 'blue'; - } - } - Item { - Layout.fillWidth: true - } - } - - QfButton { - id: updateBookmarkButton - Layout.fillWidth: true - Layout.topMargin: 10 - text: qsTr('Copy bookmark details') - - onClicked: { - var point = bookmarkModel.getBookmarkPoint(bookmarkProperties.bookmarkId) - var crs = bookmarkModel.getBookmarkCrs(bookmarkProperties.bookmarkId) - var coordinates = StringUtils.pointInformation(point, crs) - - platformUtilities.copyTextToClipboard(nameField.text + '\n' + coordinates) - displayToast(qsTr('Bookmark details copied to clipboard')); - } - } - - QfButton { - id: deleteBookmarkButton - Layout.fillWidth: true - bgcolor: 'transparent' - color: Theme.darkRed - text: qsTr('Remove bookmark') - - onClicked: { - removeBookmarkDialog.open(); - } - } + onClicked: { + removeBookmarkDialog.open(); } + } } + } - Dialog { - id: removeBookmarkDialog - parent: mainWindow.contentItem + Dialog { + id: removeBookmarkDialog + parent: mainWindow.contentItem - visible: false - modal: true - font: Theme.defaultFont + visible: false + modal: true + font: Theme.defaultFont - z: 10000 // 1000s are embedded feature forms, user a higher value to insure the dialog will always show above embedded feature forms - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + z: 10000 // 1000s are embedded feature forms, user a higher value to insure the dialog will always show above embedded feature forms + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Remove bookmark" ) - Label { - width: parent.width - wrapMode: Text.WordWrap - text: qsTr( "You are about to remove a bookmark, proceed?" ) - } + title: qsTr("Remove bookmark") + Label { + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("You are about to remove a bookmark, proceed?") + } - standardButtons: Dialog.Ok | Dialog.Cancel - onAccepted: { - bookmarkModel.removeBookmark(bookmarkProperties.bookmarkId); - bookmarkProperties.close(); - } + standardButtons: Dialog.Ok | Dialog.Cancel + onAccepted: { + bookmarkModel.removeBookmark(bookmarkProperties.bookmarkId); + bookmarkProperties.close(); } + } } diff --git a/src/qml/BookmarkRenderer.qml b/src/qml/BookmarkRenderer.qml index 783ed86489..5a2d2110ba 100644 --- a/src/qml/BookmarkRenderer.qml +++ b/src/qml/BookmarkRenderer.qml @@ -1,156 +1,153 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Item { - id: bookmarkRenderer + id: bookmarkRenderer + + property var bookmarkIndex: undefined + property string bookmarkId: '' + property string bookmarkName: '' + property string bookmarkGroup: '' + property bool bookmarkUser: false - property var bookmarkIndex: undefined - property string bookmarkId: '' - property string bookmarkName: '' - property string bookmarkGroup: '' - property bool bookmarkUser: false + property MapSettings mapSettings + property alias geometryWrapper: geometryWrapper - property MapSettings mapSettings - property alias geometryWrapper: geometryWrapper + QgsGeometryWrapper { + id: geometryWrapper + } - QgsGeometryWrapper { - id: geometryWrapper + Connections { + target: geometryWrapper + + function onQgsGeometryChanged() { + geometryComponent.sourceComponent = undefined; + if (geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point) { + geometryComponent.sourceComponent = pointHighlight; + } } + } - Connections { - target: geometryWrapper + Component { + id: pointHighlight - function onQgsGeometryChanged() { - geometryComponent.sourceComponent = undefined - if (geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point) { - geometryComponent.sourceComponent = pointHighlight - } + Repeater { + model: geometryWrapper.pointList() + + Item { + property CoordinateTransformer ct: CoordinateTransformer { + id: _ct + sourceCrs: geometryWrapper.crs + sourcePosition: modelData + destinationCrs: mapCanvas.mapSettings.destinationCrs + transformContext: qgisProject ? qgisProject.transformContext : CoordinateReferenceSystemUtils.emptyTransformContext() + } + + MapToScreen { + id: mapToScreenPosition + mapSettings: mapCanvas.mapSettings + mapPoint: _ct.projectedPosition } - } - Component { - id: pointHighlight - - Repeater { - model: geometryWrapper.pointList() - - Item { - property CoordinateTransformer ct: CoordinateTransformer { - id: _ct - sourceCrs: geometryWrapper.crs - sourcePosition: modelData - destinationCrs: mapCanvas.mapSettings.destinationCrs - transformContext: qgisProject ? qgisProject.transformContext : CoordinateReferenceSystemUtils.emptyTransformContext() - } - - MapToScreen { - id: mapToScreenPosition - mapSettings: mapCanvas.mapSettings - mapPoint: _ct.projectedPosition - } - - Shape { - id: bookmark - - x: mapToScreenPosition.screenPoint.x - width / 2 - y: mapToScreenPosition.screenPoint.y - height + 4 - - width: 36 - height: 40 - - ShapePath { - strokeWidth: 3 - strokeColor: "white" - strokeStyle: ShapePath.SolidLine - joinStyle: ShapePath.MiterJoin - fillColor: { - switch (bookmarkRenderer.bookmarkGroup) { - case 'red': - return Theme.bookmarkRed; - case 'orange': - return Theme.bookmarkOrange; - case 'blue': - return Theme.bookmarkBlue; - default: - return Theme.bookmarkDefault; - } - } - - startX: 6 - startY: 16 - PathArc { - x: 30 - y: 16 - radiusX: 12 - radiusY: 14 - } - PathArc { - x: 18 - y: 36 - radiusX: 36 - radiusY: 36 - } - PathArc{ - x: 6 - y: 16 - radiusX: 36 - radiusY: 36 - } - } - - Rectangle { - x: 13 - y: 9 - width: 10 - height: 10 - color: "white" - radius: 4 - } - - layer.enabled: true - layer.samples: 4 - layer.effect: QfDropShadow { - transparentBorder: true - radius: 8 - color: "#99000000" - horizontalOffset: 0 - verticalOffset: 0 - } - } - - MouseArea { - anchors.fill: bookmark - onClicked: { - displayToast(qsTr('Bookmark: %1').arg(bookmarkRenderer.bookmarkName)); - } - onDoubleClicked: { - bookmarkModel.setExtentFromBookmark(bookmarkModel.index(bookmarkRenderer.bookmarkIndex, 0)); - } - onPressAndHold: { - if (bookmarkRenderer.bookmarkUser) { - bookmarkProperties.bookmarkId = bookmarkRenderer.bookmarkId; - bookmarkProperties.bookmarkName = bookmarkRenderer.bookmarkName; - bookmarkProperties.bookmarkGroup = bookmarkRenderer.bookmarkGroup; - bookmarkProperties.open(); - } else { - displayToast(qsTr('Project bookmarks cannot be edited')) - } - } - } + Shape { + id: bookmark + + x: mapToScreenPosition.screenPoint.x - width / 2 + y: mapToScreenPosition.screenPoint.y - height + 4 + + width: 36 + height: 40 + + ShapePath { + strokeWidth: 3 + strokeColor: "white" + strokeStyle: ShapePath.SolidLine + joinStyle: ShapePath.MiterJoin + fillColor: { + switch (bookmarkRenderer.bookmarkGroup) { + case 'red': + return Theme.bookmarkRed; + case 'orange': + return Theme.bookmarkOrange; + case 'blue': + return Theme.bookmarkBlue; + default: + return Theme.bookmarkDefault; + } } + + startX: 6 + startY: 16 + PathArc { + x: 30 + y: 16 + radiusX: 12 + radiusY: 14 + } + PathArc { + x: 18 + y: 36 + radiusX: 36 + radiusY: 36 + } + PathArc { + x: 6 + y: 16 + radiusX: 36 + radiusY: 36 + } + } + + Rectangle { + x: 13 + y: 9 + width: 10 + height: 10 + color: "white" + radius: 4 + } + + layer.enabled: true + layer.samples: 4 + layer.effect: QfDropShadow { + transparentBorder: true + radius: 8 + color: "#99000000" + horizontalOffset: 0 + verticalOffset: 0 + } } - } - Loader { - id: geometryComponent - // the sourceComponent is updated with the connection on wrapper qgsGeometryChanged signal - // but it needs to be ready on first used - sourceComponent: geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point ? pointHighlight : undefined + MouseArea { + anchors.fill: bookmark + onClicked: { + displayToast(qsTr('Bookmark: %1').arg(bookmarkRenderer.bookmarkName)); + } + onDoubleClicked: { + bookmarkModel.setExtentFromBookmark(bookmarkModel.index(bookmarkRenderer.bookmarkIndex, 0)); + } + onPressAndHold: { + if (bookmarkRenderer.bookmarkUser) { + bookmarkProperties.bookmarkId = bookmarkRenderer.bookmarkId; + bookmarkProperties.bookmarkName = bookmarkRenderer.bookmarkName; + bookmarkProperties.bookmarkGroup = bookmarkRenderer.bookmarkGroup; + bookmarkProperties.open(); + } else { + displayToast(qsTr('Project bookmarks cannot be edited')); + } + } + } + } } + } + + Loader { + id: geometryComponent + // the sourceComponent is updated with the connection on wrapper qgsGeometryChanged signal + // but it needs to be ready on first used + sourceComponent: geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point ? pointHighlight : undefined + } } - diff --git a/src/qml/BrowserPanel.qml b/src/qml/BrowserPanel.qml index 6f465a1a9e..fa29ed3978 100644 --- a/src/qml/BrowserPanel.qml +++ b/src/qml/BrowserPanel.qml @@ -2,14 +2,13 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtWebView 1.14 - import org.qfield 1.0 import Theme 1.0 Popup { id: browserPanel - signal cancel() + signal cancel property var browserView: undefined property var browserCookies: [] @@ -31,9 +30,7 @@ Popup { anchors.fill: parent header: QfPageHeader { id: pageHeader - title: browserView && !browserView.loading && browserView.title !== '' - ? browserView.title - : qsTr("Browser") + title: browserView && !browserView.loading && browserView.title !== '' ? browserView.title : qsTr("Browser") showBackButton: browserPanel.fullscreen showApplyButton: false @@ -44,11 +41,11 @@ Popup { topMargin: browserPanel.fullscreen ? mainWindow.sceneTopMargin : 0 onBack: { - browserPanel.cancel() + browserPanel.cancel(); } onCancel: { - browserPanel.cancel() + browserPanel.cancel(); } } @@ -65,8 +62,7 @@ Popup { onAboutToShow: { // Reset tracked cookies - browserCookies = [] - + browserCookies = []; if (url != '') { if (browserView === undefined) { // avoid cost of WevView creation until needed @@ -84,9 +80,9 @@ Popup { onCookieAdded: (domain, name) => { browserPanel.browserCookies.push([domain, name]) } - }', browserContent) + }', browserContent); if (clearCookiesOnOpen) { - browserView.deleteAllCookies() + browserView.deleteAllCookies(); } } else { browserView = Qt.createQmlObject('import QtWebView 1.14 @@ -99,20 +95,19 @@ Popup { height = parent.height; opacity = 1 } } - }', browserContent) + }', browserContent); } } - browserView.anchors.fill = undefined - browserView.url = url - browserView.opacity = 0 + browserView.anchors.fill = undefined; + browserView.url = url; + browserView.opacity = 0; } - - clearCookiesOnOpen = false + clearCookiesOnOpen = false; } function deleteCookies() { - for(const [domain, name] of browserCookies) { - browserView.deleteCookie(domain, name) + for (const [domain, name] of browserCookies) { + browserView.deleteCookie(domain, name); } browserCookies = []; } diff --git a/src/qml/BusyOverlay.qml b/src/qml/BusyOverlay.qml index fc94584c16..c71f407b16 100644 --- a/src/qml/BusyOverlay.qml +++ b/src/qml/BusyOverlay.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import Theme 1.0 import org.qfield 1.0 @@ -18,35 +17,67 @@ Rectangle { state: "hidden" states: [ - State { - name: "hidden" - PropertyChanges { target: busyOverlay; opacity: 0 } - PropertyChanges { target: busyOverlay; visible: false } - }, - - State { - name: "visible" - PropertyChanges { target: busyOverlay; visible: true } - PropertyChanges { target: busyOverlay; opacity: 1 } - }] + State { + name: "hidden" + PropertyChanges { + target: busyOverlay + opacity: 0 + } + PropertyChanges { + target: busyOverlay + visible: false + } + }, + State { + name: "visible" + PropertyChanges { + target: busyOverlay + visible: true + } + PropertyChanges { + target: busyOverlay + opacity: 1 + } + } + ] transitions: [ - Transition { - from: "hidden" - to: "visible" - SequentialAnimation { - PropertyAnimation { target: busyOverlay; property: "visible"; duration: 0 } - ScriptAction { script: busyProgress.value = 0.0; } - NumberAnimation { target: busyOverlay; easing.type: Easing.InOutQuad; properties: "opacity"; duration: 250 } - } - }, - Transition { - from: "visible" - to: "hidden" - SequentialAnimation { - PropertyAnimation { target: busyOverlay; easing.type: Easing.InOutQuad; property: "opacity"; duration: 250 } - PropertyAnimation { target: busyOverlay; property: "visible"; duration: 0 } - } + Transition { + from: "hidden" + to: "visible" + SequentialAnimation { + PropertyAnimation { + target: busyOverlay + property: "visible" + duration: 0 + } + ScriptAction { + script: busyProgress.value = 0.0 + } + NumberAnimation { + target: busyOverlay + easing.type: Easing.InOutQuad + properties: "opacity" + duration: 250 + } } + }, + Transition { + from: "visible" + to: "hidden" + SequentialAnimation { + PropertyAnimation { + target: busyOverlay + easing.type: Easing.InOutQuad + property: "opacity" + duration: 250 + } + PropertyAnimation { + target: busyOverlay + property: "visible" + duration: 0 + } + } + } ] BusyIndicator { @@ -69,7 +100,7 @@ Rectangle { to: 1.0 } - Rectangle{ + Rectangle { id: busyMessageShield anchors.top: busyIndicator.bottom anchors.topMargin: 10 diff --git a/src/qml/Changelog.qml b/src/qml/Changelog.qml index eadaae68fc..817cb6a96f 100644 --- a/src/qml/Changelog.qml +++ b/src/qml/Changelog.qml @@ -1,148 +1,144 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import Theme 1.0 import org.qfield 1.0 Popup { - id: changelogPopup - - parent: mainWindow.contentItem - x: Theme.popupScreenEdgeMargin - y: Theme.popupScreenEdgeMargin - width: parent.width - Theme.popupScreenEdgeMargin * 2 - height: parent.height - Theme.popupScreenEdgeMargin * 2 - padding: 0 - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - focus: visible - - Page { - focus: true - anchors.fill: parent - - header: QfPageHeader { - title: qsTr("What's new in QField") - - showApplyButton: false - showCancelButton: false - showBackButton: true - - onBack: { - changelogPopup.close() - } - } - - ColumnLayout { - anchors.fill: parent - anchors.margins: 10 - - Flickable { - id: changelogFlickable - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: 10 - Layout.bottomMargin: 10 - flickableDirection: Flickable.VerticalFlick - interactive: true - contentWidth: parent.width; - contentHeight: changelogGrid.height - clip: true - - GridLayout { - id: changelogGrid - - anchors.left: parent.left - anchors.right: parent.right - - columns: 1 - - Text { - id: changelogBody - Layout.fillWidth: true - Layout.fillHeight: true - Layout.minimumHeight: contentHeight - Layout.maximumHeight: contentHeight - visible: changelogContents.status != ChangelogContents.LoadingStatus - - color: Theme.mainTextColor - font: Theme.tipFont - - fontSizeMode: Text.VerticalFit - textFormat: Text.MarkdownText - wrapMode: Text.WordWrap - - text: { - switch ( changelogContents.status ) { - case ChangelogContents.IdleStatus: - case ChangelogContents.LoadingStatus: - return '' - case ChangelogContents.SuccessStatus: - return changelogContents.markdown - case ChangelogContents.ErrorStatus: - return qsTr( 'Error while fetching changelog, try again later.' ) - } - } - - onLinkActivated: (link) => { Qt.openUrlExternally(link) } - } - - BusyIndicator { - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - - visible: changelogContents.status == ChangelogContents.LoadingStatus - running: visible - } - } - } - - QfButton { - id: sponsorshipButton - Layout.fillWidth: true - icon.source: Theme.getThemeVectorIcon( 'ic_sponsor_white_24dp' ) - - text: qsTr( 'Support QField') - onClicked: Qt.openUrlExternally("https://github.com/sponsors/opengisch") - } - } + id: changelogPopup + + parent: mainWindow.contentItem + x: Theme.popupScreenEdgeMargin + y: Theme.popupScreenEdgeMargin + width: parent.width - Theme.popupScreenEdgeMargin * 2 + height: parent.height - Theme.popupScreenEdgeMargin * 2 + padding: 0 + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + focus: visible + + Page { + focus: true + anchors.fill: parent + + header: QfPageHeader { + title: qsTr("What's new in QField") + + showApplyButton: false + showCancelButton: false + showBackButton: true + + onBack: { + changelogPopup.close(); + } } - ChangelogContents { - id: changelogContents - onMarkdownChanged: { - if ( changelogContents.markdown ) { - settings.setValue( "/QField/isLoadingChangelog", false ) - settings.remove( "/QField/isCrashingSslDevice" ) + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + + Flickable { + id: changelogFlickable + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: 10 + Layout.bottomMargin: 10 + flickableDirection: Flickable.VerticalFlick + interactive: true + contentWidth: parent.width + contentHeight: changelogGrid.height + clip: true + + GridLayout { + id: changelogGrid + + anchors.left: parent.left + anchors.right: parent.right + + columns: 1 + + Text { + id: changelogBody + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: contentHeight + Layout.maximumHeight: contentHeight + visible: changelogContents.status != ChangelogContents.LoadingStatus + + color: Theme.mainTextColor + font: Theme.tipFont + + fontSizeMode: Text.VerticalFit + textFormat: Text.MarkdownText + wrapMode: Text.WordWrap + + text: { + switch (changelogContents.status) { + case ChangelogContents.IdleStatus: + case ChangelogContents.LoadingStatus: + return ''; + case ChangelogContents.SuccessStatus: + return changelogContents.markdown; + case ChangelogContents.ErrorStatus: + return qsTr('Error while fetching changelog, try again later.'); + } } - } - } - onClosed: { - settings.setValue( "/QField/ChangelogVersion", appVersion ) - changelogFlickable.contentY = 0 - } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } + } - onOpened: { - if ( settings.valueBool( "/QField/isLoadingChangelog", false ) ) { - settings.setValue( "/QField/isCrashingSslDevice", true ) - } else { - settings.remove( "/QField/isCrashingSslDevice" ) - } + BusyIndicator { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - if ( settings.valueBool( "/QField/isCrashingSslDevice", false ) === true ) { - changelogBody.text = qsTr( "Check the latest QField changes on " ) - + ' ' + qsTr( 'QField releases page' ) + '.' - return + visible: changelogContents.status == ChangelogContents.LoadingStatus + running: visible + } } + } - if ( changelogContents.status === ChangelogContents.SuccessStatus || changelogContents.status === ChangelogContents.LoadingStatus ) - return + QfButton { + id: sponsorshipButton + Layout.fillWidth: true + icon.source: Theme.getThemeVectorIcon('ic_sponsor_white_24dp') - settings.remove( "/QField/isLoadingChangelog" ) - settings.setValue( "/QField/isLoadingChangelog", true ) - settings.sync() - - changelogContents.request() + text: qsTr('Support QField') + onClicked: Qt.openUrlExternally("https://github.com/sponsors/opengisch") + } + } + } + + ChangelogContents { + id: changelogContents + onMarkdownChanged: { + if (changelogContents.markdown) { + settings.setValue("/QField/isLoadingChangelog", false); + settings.remove("/QField/isCrashingSslDevice"); + } + } + } + + onClosed: { + settings.setValue("/QField/ChangelogVersion", appVersion); + changelogFlickable.contentY = 0; + } + + onOpened: { + if (settings.valueBool("/QField/isLoadingChangelog", false)) { + settings.setValue("/QField/isCrashingSslDevice", true); + } else { + settings.remove("/QField/isCrashingSslDevice"); + } + if (settings.valueBool("/QField/isCrashingSslDevice", false) === true) { + changelogBody.text = qsTr("Check the latest QField changes on ") + ' ' + qsTr('QField releases page') + '.'; + return; } + if (changelogContents.status === ChangelogContents.SuccessStatus || changelogContents.status === ChangelogContents.LoadingStatus) + return; + settings.remove("/QField/isLoadingChangelog"); + settings.setValue("/QField/isLoadingChangelog", true); + settings.sync(); + changelogContents.request(); + } } diff --git a/src/qml/CodeReader.qml b/src/qml/CodeReader.qml index 5426ce6f6d..02aae8b035 100644 --- a/src/qml/CodeReader.qml +++ b/src/qml/CodeReader.qml @@ -4,13 +4,11 @@ import QtQuick.Layouts import QtQuick.Shapes import QtMultimedia import QtCore - import org.qfield 1.0 - import Theme 1.0 Popup { - id : codeReader + id: codeReader signal decoded(var string) @@ -30,26 +28,25 @@ Popup { dim: true onAboutToShow: { - openedOnce = true + openedOnce = true; // when NFC is not accessible, make sure the only option, QR, is active if (!withNfc && !settings.cameraActive) { - settings.cameraActive = true + settings.cameraActive = true; } - decodedString = '' - barcodeDecoder.clearDecodedString() - + decodedString = ''; + barcodeDecoder.clearDecodedString(); if (cameraPermission.status === Qt.PermissionStatus.Undetermined) { - cameraPermission.request() + cameraPermission.request(); } } onOpened: { - contentItem.forceActiveFocus() + contentItem.forceActiveFocus(); } onAboutToHide: { if (cameraLoader.active) { - cameraLoader.item.camera.torchMode = Camera.TorchOff + cameraLoader.item.camera.torchMode = Camera.TorchOff; } } @@ -68,7 +65,7 @@ Popup { onDecodedStringChanged: { if (decodedString !== '') { - codeReader.decodedString = decodedString + codeReader.decodedString = decodedString; decodedFlashAnimation.start(); } } @@ -85,8 +82,8 @@ Popup { onReadStringChanged: { if (readString !== '') { - displayToast(qsTr('NFC text tag detected')) - codeReader.decodedString = readString + displayToast(qsTr('NFC text tag detected')); + codeReader.decodedString = readString; decodedFlashAnimation.start(); } } @@ -125,7 +122,7 @@ Popup { id: closeButton Layout.rightMargin: 10 Layout.alignment: Qt.AlignVCenter - iconSource: Theme.getThemeIcon( 'ic_close_black_24dp' ) + iconSource: Theme.getThemeIcon('ic_close_black_24dp') iconColor: Theme.mainTextColor bgcolor: "transparent" @@ -160,14 +157,14 @@ Popup { SequentialAnimation { NumberAnimation { - target: nearfieldFeedback + target: nearfieldFeedback property: "width" to: 120 + (Math.min(visualFeedback.width, visualFeedback.height) - 120) duration: 2000 easing.type: Easing.InOutQuad } NumberAnimation { - target: nearfieldFeedback + target: nearfieldFeedback property: "width" to: 120 duration: 2000 @@ -213,7 +210,7 @@ Popup { } onLoaded: { - barcodeDecoder.videoSink = item.sink + barcodeDecoder.videoSink = item.sink; } } @@ -225,8 +222,18 @@ Popup { color: "transparent" SequentialAnimation { id: decodedFlashAnimation - PropertyAnimation { target: decodedFlash; property: "color"; to: "white"; duration: 0 } - PropertyAnimation { target: decodedFlash; property: "color"; to: "transparent"; duration: 500 } + PropertyAnimation { + target: decodedFlash + property: "color" + to: "white" + duration: 0 + } + PropertyAnimation { + target: decodedFlash + property: "color" + to: "transparent" + duration: 500 + } } } @@ -244,14 +251,46 @@ Popup { startX: 5 startY: 10 - PathArc { x: 10; y: 5; radiusX: 5; radiusY: 5 } - PathLine { x: frame.width - 10; y: 5; } - PathArc { x: frame.width - 5; y: 10; radiusX: 5; radiusY: 5 } - PathLine { x: frame.width - 5; y: frame.height - 10; } - PathArc { x: frame.width - 10; y: frame.height - 5; radiusX: 5; radiusY: 5 } - PathLine { x: 10; y: frame.height - 5; } - PathArc { x: 5; y: frame.height - 10; radiusX: 5; radiusY: 5 } - PathLine { x: 5; y: 10 } + PathArc { + x: 10 + y: 5 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: frame.width - 10 + y: 5 + } + PathArc { + x: frame.width - 5 + y: 10 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: frame.width - 5 + y: frame.height - 10 + } + PathArc { + x: frame.width - 10 + y: frame.height - 5 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: 10 + y: frame.height - 5 + } + PathArc { + x: 5 + y: frame.height - 10 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: 5 + y: 10 + } } } @@ -269,21 +308,74 @@ Popup { startX: 20 startY: 60 - PathLine { x: 20; y: 25 } - PathArc { x: 25; y: 20; radiusX: 5; radiusY: 5 } - PathLine { x: 60; y: 20 } - PathMove { x: aim.width - 60; y: 20 } - PathLine { x: aim.width - 25; y: 20 } - PathArc { x: aim.width - 20; y: 25; radiusX: 5; radiusY: 5; } - PathLine { x: aim.width - 20; y: 60 } - PathMove { x: aim.width - 20; y: aim.height - 60 } - PathLine { x: aim.width - 20; y: aim.height - 25 } - PathArc { x: aim.width - 25; y: aim.height - 20; radiusX: 5; radiusY: 5 } - PathLine { x: aim.width - 60; y: aim.height - 20 } - PathMove { x: 60; y: aim.height - 20 } - PathLine { x: 25; y: aim.height - 20 } - PathArc { x: 20; y: aim.height - 25; radiusX: 5; radiusY: 5 } - PathLine { x: 20; y: aim.height - 60; } + PathLine { + x: 20 + y: 25 + } + PathArc { + x: 25 + y: 20 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: 60 + y: 20 + } + PathMove { + x: aim.width - 60 + y: 20 + } + PathLine { + x: aim.width - 25 + y: 20 + } + PathArc { + x: aim.width - 20 + y: 25 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: aim.width - 20 + y: 60 + } + PathMove { + x: aim.width - 20 + y: aim.height - 60 + } + PathLine { + x: aim.width - 20 + y: aim.height - 25 + } + PathArc { + x: aim.width - 25 + y: aim.height - 20 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: aim.width - 60 + y: aim.height - 20 + } + PathMove { + x: 60 + y: aim.height - 20 + } + PathLine { + x: 25 + y: aim.height - 20 + } + PathArc { + x: 20 + y: aim.height - 25 + radiusX: 5 + radiusY: 5 + } + PathLine { + x: 20 + y: aim.height - 60 + } } } @@ -293,12 +385,12 @@ Popup { anchors.bottomMargin: 20 anchors.horizontalCenter: parent.horizontalCenter round: true - iconSource: Theme.getThemeVectorIcon( 'ic_flashlight_white_48dp' ) + iconSource: Theme.getThemeVectorIcon('ic_flashlight_white_48dp') iconColor: "white" bgcolor: Theme.darkGraySemiOpaque visible: settings.cameraActive && cameraLoader.active && cameraLoader.item.camera.isTorchModeSupported(Camera.TorchOn) - state: cameraLoader.active && cameraLoader.item.camera.torchMode === Camera.TorchOn ? "On" : "Off" + state: cameraLoader.active && cameraLoader.item.camera.torchMode === Camera.TorchOn ? "On" : "Off" states: [ State { name: "Off" @@ -308,7 +400,6 @@ Popup { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -321,9 +412,9 @@ Popup { onClicked: { if (cameraLoader.item.camera.torchMode === Camera.TorchOff) { - cameraLoader.item.camera.torchMode = Camera.TorchOn + cameraLoader.item.camera.torchMode = Camera.TorchOn; } else { - cameraLoader.item.camera.torchMode = Camera.TorchOff + cameraLoader.item.camera.torchMode = Camera.TorchOff; } } } @@ -335,7 +426,7 @@ Popup { anchors.right: flashlightButton.left anchors.rightMargin: 10 round: true - iconSource: Theme.getThemeVectorIcon( 'ic_qr_code_black_24dp' ) + iconSource: Theme.getThemeVectorIcon('ic_qr_code_black_24dp') iconColor: "white" bgcolor: Theme.darkGraySemiOpaque @@ -349,7 +440,6 @@ Popup { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -372,7 +462,7 @@ Popup { anchors.left: flashlightButton.right anchors.leftMargin: 10 round: true - iconSource: Theme.getThemeVectorIcon( 'ic_nfc_code_black_24dp' ) + iconSource: Theme.getThemeVectorIcon('ic_nfc_code_black_24dp') iconColor: "white" bgcolor: Theme.darkGraySemiOpaque @@ -386,7 +476,6 @@ Popup { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -410,9 +499,7 @@ Popup { id: decodedText Layout.fillWidth: true - text: codeReader.decodedString !== '' - ? codeReader.decodedString - : qsTr( 'Center your device on a code') + text: codeReader.decodedString !== '' ? codeReader.decodedString : qsTr('Center your device on a code') font: Theme.tipFont color: Theme.mainTextColor horizontalAlignment: Text.AlignLeft @@ -425,17 +512,17 @@ Popup { enabled: codeReader.decodedString !== '' opacity: enabled ? 1 : 0.2 Layout.alignment: Qt.AlignVCenter - iconSource: Theme.getThemeIcon( 'ic_check_black_48dp' ) + iconSource: Theme.getThemeIcon('ic_check_black_48dp') iconColor: enabled ? "white" : Theme.mainTextColor bgcolor: enabled ? Theme.mainColor : "transparent" round: true onClicked: { if (codeReader.barcodeRequestedItem != undefined) { - codeReader.barcodeRequestedItem.requestedBarcodeReceived(codeReader.decodedString) - codeReader.barcodeRequestedItem = undefined; + codeReader.barcodeRequestedItem.requestedBarcodeReceived(codeReader.decodedString); + codeReader.barcodeRequestedItem = undefined; } else { - codeReader.decoded(codeReader.decodedString); + codeReader.decoded(codeReader.decodedString); } codeReader.close(); } diff --git a/src/qml/ConfirmationToolbar.qml b/src/qml/ConfirmationToolbar.qml index 0afcf8cce5..f463cd02c2 100644 --- a/src/qml/ConfirmationToolbar.qml +++ b/src/qml/ConfirmationToolbar.qml @@ -1,41 +1,40 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 VisibilityFadingRow { - id: confirmationToolbar + id: confirmationToolbar - spacing: 4 + spacing: 4 - /* This signal is emitted when the digitized geometry has been confirmed. + /* This signal is emitted when the digitized geometry has been confirmed. * The correspoding handler is \c onConfirmed. */ - signal confirm - /* This signal is emitted when the user cancels geometry digitizing. + signal confirm + /* This signal is emitted when the user cancels geometry digitizing. * The correspoding handler is \c onCancel. */ - signal cancel - - QfToolButton { - id: cancelButton - iconSource: Theme.getThemeIcon( "ic_clear_white_24dp" ) - visible: true - round: true - bgcolor: Theme.darkRed - - onClicked: cancel() - } - - QfToolButton { - id: confirmButton - iconSource: Theme.getThemeIcon( "ic_check_white_48dp" ) - visible: true - round: true - bgcolor: Theme.mainColor - - onClicked: confirm() - } + signal cancel + + QfToolButton { + id: cancelButton + iconSource: Theme.getThemeIcon("ic_clear_white_24dp") + visible: true + round: true + bgcolor: Theme.darkRed + + onClicked: cancel() + } + + QfToolButton { + id: confirmButton + iconSource: Theme.getThemeIcon("ic_check_white_48dp") + visible: true + round: true + bgcolor: Theme.mainColor + + onClicked: confirm() + } } diff --git a/src/qml/CoordinateLocator.qml b/src/qml/CoordinateLocator.qml index 09518741ba..74ea8787d4 100644 --- a/src/qml/CoordinateLocator.qml +++ b/src/qml/CoordinateLocator.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -43,12 +42,7 @@ Item { // the map canvas extent changes (user pans/zooms) and the calculation of the display position is retriggered readonly property point displayPosition: { // this property gets initially evaluated before the `currentCoordinate` - const coordinate = currentCoordinate - ? currentCoordinate - : !!overrideLocation - ? overrideLocation - : snappingUtils.snappedCoordinate; - + const coordinate = currentCoordinate ? currentCoordinate : !!overrideLocation ? overrideLocation : snappingUtils.snappedCoordinate; return !!mapSettings.visibleExtent && coordinate !== undefined ? mapSettings.coordinateToScreen(coordinate) : Qt.point(); } @@ -65,35 +59,18 @@ Item { mapSettings: locator.mapSettings inputCoordinate: { // Get the current crosshair location in screen coordinates. If `undefined`, then we use the center of the screen as input point. - const location = sourceLocation === undefined - ? Qt.point(locator.width / 2, locator.height / 2) - : sourceLocation; - + const location = sourceLocation === undefined ? Qt.point(locator.width / 2, locator.height / 2) : sourceLocation; if (snapToCommonAngleButton.isSnapToCommonAngleEnabled) { - locator.commonAngleInDegrees = getCommonAngleInDegrees( - location, - locator.rubberbandModel, - snapToCommonAngleButton.snapToCommonAngleDegrees, - snapToCommonAngleButton.isSnapToCommonAngleRelative, - ); - + locator.commonAngleInDegrees = getCommonAngleInDegrees(location, locator.rubberbandModel, snapToCommonAngleButton.snapToCommonAngleDegrees, snapToCommonAngleButton.isSnapToCommonAngleRelative); const coords = calculateSnapToAngleLineEndCoords(snappedPoint, locator.commonAngleInDegrees, snapToCommonAngleButton.isSnapToCommonAngleRelative, 1000); - snapToCommonAngleLines.endCoordX = coords.x || 0; snapToCommonAngleLines.endCoordY = coords.y || 0; - - return snapPointToCommonAngle( - location, - locator.rubberbandModel, - locator.commonAngleInDegrees, - snapToCommonAngleButton.isSnapToCommonAngleRelative, - ); + return snapPointToCommonAngle(location, locator.rubberbandModel, locator.commonAngleInDegrees, snapToCommonAngleButton.isSnapToCommonAngleRelative); } else { locator.commonAngleInDegrees = null; snapToCommonAngleLines.endCoordX = 0; snapToCommonAngleLines.endCoordY = 0; } - return location; } config: qgisProject ? qgisProject.snappingConfig : snappingUtils.emptySnappingConfig() @@ -102,15 +79,12 @@ Item { property point snappedPoint onSnappingResultChanged: { - if ( snappingResult.isValid ) - { - snappedCoordinate = snappingResult.point - snappedPoint = mapSettings.coordinateToScreen( snappedCoordinate ) - } - else - { - snappedPoint = inputCoordinate - snappedCoordinate = mapSettings.screenToCoordinate( snappedPoint ) + if (snappingResult.isValid) { + snappedCoordinate = snappingResult.point; + snappedPoint = mapSettings.coordinateToScreen(snappedCoordinate); + } else { + snappedPoint = inputCoordinate; + snappedCoordinate = mapSettings.screenToCoordinate(snappedPoint); } } } @@ -137,20 +111,17 @@ Item { anchors.left: parent.left anchors.leftMargin: 1.2 height: parent.height - 2.4 - width: (positioningSettings.averagedPositioning - ? Math.min(parent.width,(parent.width * (averagedPositionCount / positioningSettings.averagedPositioningMinimumCount))) - : parent.width) - 2.4 - color: positioningSettings.accuracyIndicator - ? !positionSource.positionInformation - || !positionSource.positionInformation.haccValid - || positionSource.positionInformation.hacc > positioningSettings.accuracyBad - ? Theme.accuracyBad - : positionSource.positionInformation.hacc > positioningSettings.accuracyExcellent - ? Theme.accuracyTolerated - : Theme.accuracyExcellent - : Theme.positionColor - - transitions: [ Transition { NumberAnimation { property: "width"; duration: 200 } } ] + width: (positioningSettings.averagedPositioning ? Math.min(parent.width, (parent.width * (averagedPositionCount / positioningSettings.averagedPositioningMinimumCount))) : parent.width) - 2.4 + color: positioningSettings.accuracyIndicator ? !positionSource.positionInformation || !positionSource.positionInformation.haccValid || positionSource.positionInformation.hacc > positioningSettings.accuracyBad ? Theme.accuracyBad : positionSource.positionInformation.hacc > positioningSettings.accuracyExcellent ? Theme.accuracyTolerated : Theme.accuracyExcellent : Theme.positionColor + + transitions: [ + Transition { + NumberAnimation { + property: "width" + duration: 200 + } + } + ] } Text { @@ -177,18 +148,24 @@ Item { x: displayPosition.x - halfWidth y: displayPosition.y - halfWidth - Behavior on x { + Behavior on x { enabled: !overrideLocation && !sourceLocation // It looks strange if the GPS position indicator and the crosshair are not synchronized - NumberAnimation { duration: 100 } + NumberAnimation { + duration: 100 + } } - Behavior on y { + Behavior on y { enabled: !overrideLocation && !sourceLocation - NumberAnimation { duration: 100 } + NumberAnimation { + duration: 100 + } } - Behavior on width { - SmoothedAnimation { duration: 2000 } + Behavior on width { + SmoothedAnimation { + duration: 2000 + } } ShapePath { @@ -205,36 +182,52 @@ Item { fillColor: "transparent" PathAngleArc { - centerX: crosshairCircle.halfWidth; centerY: crosshairCircle.halfWidth - radiusX: crosshairCircle.halfWidth; radiusY: crosshairCircle.halfWidth - startAngle: 0 + crosshairCircle.arcSpacing; sweepAngle: 90 - crosshairCircle.arcSpacing * 2 + centerX: crosshairCircle.halfWidth + centerY: crosshairCircle.halfWidth + radiusX: crosshairCircle.halfWidth + radiusY: crosshairCircle.halfWidth + startAngle: 0 + crosshairCircle.arcSpacing + sweepAngle: 90 - crosshairCircle.arcSpacing * 2 } PathAngleArc { - centerX: crosshairCircle.halfWidth; centerY: crosshairCircle.halfWidth - radiusX: crosshairCircle.halfWidth; radiusY: crosshairCircle.halfWidth - startAngle: 90 + crosshairCircle.arcSpacing; sweepAngle: 90 - crosshairCircle.arcSpacing * 2 + centerX: crosshairCircle.halfWidth + centerY: crosshairCircle.halfWidth + radiusX: crosshairCircle.halfWidth + radiusY: crosshairCircle.halfWidth + startAngle: 90 + crosshairCircle.arcSpacing + sweepAngle: 90 - crosshairCircle.arcSpacing * 2 } PathAngleArc { - centerX: crosshairCircle.halfWidth; centerY: crosshairCircle.halfWidth - radiusX: crosshairCircle.halfWidth; radiusY: crosshairCircle.halfWidth - startAngle: 180 + crosshairCircle.arcSpacing; sweepAngle: 90 - crosshairCircle.arcSpacing * 2 + centerX: crosshairCircle.halfWidth + centerY: crosshairCircle.halfWidth + radiusX: crosshairCircle.halfWidth + radiusY: crosshairCircle.halfWidth + startAngle: 180 + crosshairCircle.arcSpacing + sweepAngle: 90 - crosshairCircle.arcSpacing * 2 } PathAngleArc { - centerX: crosshairCircle.halfWidth; centerY: crosshairCircle.halfWidth - radiusX: crosshairCircle.halfWidth; radiusY: crosshairCircle.halfWidth - startAngle: 270 + crosshairCircle.arcSpacing; sweepAngle: 90 - crosshairCircle.arcSpacing * 2 + centerX: crosshairCircle.halfWidth + centerY: crosshairCircle.halfWidth + radiusX: crosshairCircle.halfWidth + radiusY: crosshairCircle.halfWidth + startAngle: 270 + crosshairCircle.arcSpacing + sweepAngle: 90 - crosshairCircle.arcSpacing * 2 } PathMove { - x: crosshairCircle.halfWidth; y: crosshairCircle.halfWidth - 8 + x: crosshairCircle.halfWidth + y: crosshairCircle.halfWidth - 8 } PathLine { - x: crosshairCircle.halfWidth; y: crosshairCircle.halfWidth + 8 + x: crosshairCircle.halfWidth + y: crosshairCircle.halfWidth + 8 } PathMove { - x: crosshairCircle.halfWidth - 8; y: crosshairCircle.halfWidth + x: crosshairCircle.halfWidth - 8 + y: crosshairCircle.halfWidth } PathLine { - x: crosshairCircle.halfWidth + 8; y: crosshairCircle.halfWidth + x: crosshairCircle.halfWidth + 8 + y: crosshairCircle.halfWidth } } } @@ -245,7 +238,7 @@ Item { property double endCoordX: 0 property double endCoordY: 0 - visible: !!locator.commonAngleInDegrees || ( endCoordX !== 0 && endCoordY !== 0 ) + visible: !!locator.commonAngleInDegrees || (endCoordX !== 0 && endCoordY !== 0) width: parent.width height: parent.height anchors.centerIn: parent @@ -258,10 +251,14 @@ Item { strokeWidth: 4 strokeColor: "#fff" strokeStyle: ShapePath.DashLine - dashPattern: [ 5, 3 ] - startX: snappedPoint.x; startY: snappedPoint.y + dashPattern: [5, 3] + startX: snappedPoint.x + startY: snappedPoint.y - PathLine { x: snapToCommonAngleLines.endCoordX; y: snapToCommonAngleLines.endCoordY } + PathLine { + x: snapToCommonAngleLines.endCoordX + y: snapToCommonAngleLines.endCoordY + } } // inner line @@ -270,9 +267,13 @@ Item { strokeColor: "#000" strokeStyle: ShapePath.DashLine dashPattern: outerLine.dashPattern.map(v => v * 2) - startX: snappedPoint.x; startY: snappedPoint.y + startX: snappedPoint.x + startY: snappedPoint.y - PathLine { x: snapToCommonAngleLines.endCoordX; y: snapToCommonAngleLines.endCoordY } + PathLine { + x: snapToCommonAngleLines.endCoordX + y: snapToCommonAngleLines.endCoordY + } } } @@ -300,20 +301,19 @@ Item { } Component.onCompleted: { - crosshairPathBuffer.pathElements = crosshairPath.pathElements + crosshairPathBuffer.pathElements = crosshairPath.pathElements; } Connections { target: snappingUtils function onSnappingResultChanged() { - crosshairCircle.isSnapped = overrideLocation == undefined && snappingUtils.snappingResult.isValid + crosshairCircle.isSnapped = overrideLocation == undefined && snappingUtils.snappingResult.isValid; } } - function flash() - { - flashAnimation.start() + function flash() { + flashAnimation.start(); } /** @@ -329,7 +329,6 @@ Item { if (!rubberbandModel) { return; } - const MINIMAL_PIXEL_DISTANCE_TRESHOLD = 20; const SOFT_CONSTRAINT_TOLERANCE_DEGREES = 20; const SOFT_CONSTRAINT_TOLERANCE_PIXEL = 40; @@ -340,27 +339,19 @@ Item { if (rubberbandPointsCount < 2) { return; } - const distanceFromLastPoint = Math.sqrt((currentPoint.x - previousPoint.x) ** 2 + (currentPoint.y - previousPoint.y) ** 2); if (distanceFromLastPoint < MINIMAL_PIXEL_DISTANCE_TRESHOLD) { return; } - const commonAngle = commonAngleStepDeg * Math.PI / 180; // see if soft common angle constraint should be performed // only if not in HardLock mode - let softAngle = Math.atan2( - currentPoint.y - previousPoint.y, - currentPoint.x - previousPoint.x - ); + let softAngle = Math.atan2(currentPoint.y - previousPoint.y, currentPoint.x - previousPoint.x); let deltaAngle = 0; if (isRelativeAngle && rubberbandPointsCount >= 3) { // compute the angle relative to the last segment (0° is aligned with last segment) const penultimatePoint = mapCanvas.mapSettings.coordinateToScreen(rubberbandModel.penultimateCoordinate); - deltaAngle = Math.atan2( - previousPoint.y - penultimatePoint.y, - previousPoint.x - penultimatePoint.x - ); + deltaAngle = Math.atan2(previousPoint.y - penultimatePoint.y, previousPoint.x - penultimatePoint.x); softAngle -= deltaAngle; } const quo = Math.round(softAngle / commonAngle); @@ -369,10 +360,7 @@ Item { softAngle = quo * commonAngle; // http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html // use the direction vector (cos(a),sin(a)) from previous point. |x2-x1|=1 since sin2+cos2=1 - const dist = Math.abs( - Math.cos(softAngle + deltaAngle) * (previousPoint.y - currentPoint.y) - - Math.sin(softAngle + deltaAngle) * (previousPoint.x - currentPoint.x) - ); + const dist = Math.abs(Math.cos(softAngle + deltaAngle) * (previousPoint.y - currentPoint.y) - Math.sin(softAngle + deltaAngle) * (previousPoint.x - currentPoint.x)); if (dist < SOFT_CONSTRAINT_TOLERANCE_PIXEL) { return 180.0 / Math.PI * softAngle; } @@ -397,28 +385,20 @@ Item { if (commonAngleDegrees == null) { return currentPoint; } - let angleValue = commonAngleDegrees * Math.PI / 180; const returnPoint = currentPoint; const previousPoint = mapCanvas.mapSettings.coordinateToScreen(rubberbandModel.lastCoordinate); const rubberbandPointsCount = rubberbandModel.vertexCount; - if (isRelativeAngle && rubberbandPointsCount >= 3) { // compute the angle relative to the last segment (0° is aligned with last segment) const penultimatePoint = mapCanvas.mapSettings.coordinateToScreen(rubberbandModel.penultimateCoordinate); - angleValue += Math.atan2( - previousPoint.y - penultimatePoint.y, - previousPoint.x - penultimatePoint.x, - ) + angleValue += Math.atan2(previousPoint.y - penultimatePoint.y, previousPoint.x - penultimatePoint.x); } - const cosa = Math.cos(angleValue); const sina = Math.sin(angleValue); const v = (currentPoint.x - previousPoint.x) * cosa + (currentPoint.y - previousPoint.y) * sina; - returnPoint.x = (previousPoint.x + cosa * v); returnPoint.y = (previousPoint.y + sina * v); - return returnPoint; } @@ -430,37 +410,30 @@ Item { * @param {number} screenSize - size of the screen. Used to make sure the end of the line is outside the screen. */ function calculateSnapToAngleLineEndCoords(currentPoint, angleDegrees, isRelativeAngle, screenSize) { - if ( rubberbandModel == null ) { + if (rubberbandModel == null) { return {}; } - const rubberbandPointsCount = rubberbandModel.vertexCount; // if the angle is null or undefined, return empty coordinate map if (angleDegrees == null) { return {}; } - - let deltaAngle = 0 + let deltaAngle = 0; if (isRelativeAngle && rubberbandPointsCount >= 3) { // compute the angle relative to the last segment (0° is aligned with last segment) const previousPoint = mapCanvas.mapSettings.coordinateToScreen(rubberbandModel.lastCoordinate); const penultimatePoint = mapCanvas.mapSettings.coordinateToScreen(rubberbandModel.penultimateCoordinate); - deltaAngle = Math.atan2( - previousPoint.y - penultimatePoint.y, - previousPoint.x - penultimatePoint.x - ); + deltaAngle = Math.atan2(previousPoint.y - penultimatePoint.y, previousPoint.x - penultimatePoint.x); } - const x1 = currentPoint.x; const y1 = currentPoint.y; const angleRadians = angleDegrees * Math.PI / 180 + deltaAngle; const x2 = x1 + screenSize * Math.cos(angleRadians); const y2 = y1 + screenSize * Math.sin(angleRadians); - return { - x: x2, - y: y2 + "x": x2, + "y": y2 }; } } diff --git a/src/qml/DashBoard.qml b/src/qml/DashBoard.qml index 0c9b23de54..15fff9086d 100644 --- a/src/qml/DashBoard.qml +++ b/src/qml/DashBoard.qml @@ -2,7 +2,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -23,15 +22,15 @@ Drawer { Component.onCompleted: { if (Material.roundedScale) { - Material.roundedScale = Material.NotRounded + Material.roundedScale = Material.NotRounded; } } onOpened: { - contentItem.forceActiveFocus() + contentItem.forceActiveFocus(); } - width: Math.min( 300, mainWindow.width) + width: Math.min(300, mainWindow.width) height: parent.height edge: Qt.LeftEdge dragMargin: 10 @@ -48,7 +47,7 @@ Drawer { onActiveLayerChanged: { if (activeLayer && activeLayer.readOnly && stateMachine.state == "digitize") - displayToast(qsTr("The layer %1 is read only.").arg(activeLayer.name)) + displayToast(qsTr("The layer %1 is read only.").arg(activeLayer.name)); } Connections { @@ -56,10 +55,9 @@ Drawer { function onStateChanged() { if (stateMachine.state === "measure") { - return + return; } - - modeSwitch.checked = stateMachine.state === "digitize" + modeSwitch.checked = stateMachine.state === "digitize"; } } @@ -85,7 +83,7 @@ Drawer { QfToolButton { id: closeButton anchors.verticalCenter: parent.verticalCenter - iconSource: Theme.getThemeVectorIcon( 'ic_arrow_left_white_24dp' ) + iconSource: Theme.getThemeVectorIcon('ic_arrow_left_white_24dp') bgcolor: "transparent" onClicked: close() } @@ -93,7 +91,7 @@ Drawer { QfToolButton { id: settingsButton anchors.verticalCenter: parent.verticalCenter - iconSource: Theme.getThemeVectorIcon( 'ic_settings_white_24dp' ) + iconSource: Theme.getThemeVectorIcon('ic_settings_white_24dp') bgcolor: "transparent" onClicked: showMenu() } @@ -102,28 +100,29 @@ Drawer { id: cloudButton anchors.verticalCenter: parent.verticalCenter iconSource: { - if ( cloudConnection.status === QFieldCloudConnection.LoggedIn ){ - switch(cloudProjectsModel.currentProjectData.Status ) { - case QFieldCloudProjectsModel.Downloading: - switch ( cloudProjectsModel.currentProjectData.PackagingStatus ) { - case QFieldCloudProjectsModel.PackagingFinishedStatus: - return Theme.getThemeVectorIcon('ic_cloud_download_24dp'); - default: - return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); - } - case QFieldCloudProjectsModel.Uploading: - switch ( cloudProjectsModel.currentProjectData.UploadDeltaStatus ) { - case QFieldCloudProjectsModel.DeltaFileLocalStatus: - return Theme.getThemeVectorIcon('ic_cloud_upload_24dp'); - default: - return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); - } - case QFieldCloudProjectsModel.Idle: - return cloudProjectsModel.currentProjectData.ProjectFileOutdated ? Theme.getThemeVectorIcon('ic_cloud_attention_24dp') : Theme.getThemeVectorIcon('ic_cloud_active_24dp'); - default: Theme.getThemeVectorIcon( 'ic_cloud_24dp' ); + if (cloudConnection.status === QFieldCloudConnection.LoggedIn) { + switch (cloudProjectsModel.currentProjectData.Status) { + case QFieldCloudProjectsModel.Downloading: + switch (cloudProjectsModel.currentProjectData.PackagingStatus) { + case QFieldCloudProjectsModel.PackagingFinishedStatus: + return Theme.getThemeVectorIcon('ic_cloud_download_24dp'); + default: + return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); + } + case QFieldCloudProjectsModel.Uploading: + switch (cloudProjectsModel.currentProjectData.UploadDeltaStatus) { + case QFieldCloudProjectsModel.DeltaFileLocalStatus: + return Theme.getThemeVectorIcon('ic_cloud_upload_24dp'); + default: + return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); + } + case QFieldCloudProjectsModel.Idle: + return cloudProjectsModel.currentProjectData.ProjectFileOutdated ? Theme.getThemeVectorIcon('ic_cloud_attention_24dp') : Theme.getThemeVectorIcon('ic_cloud_active_24dp'); + default: + Theme.getThemeVectorIcon('ic_cloud_24dp'); } } else { - return Theme.getThemeVectorIcon( 'ic_cloud_24dp' ); + return Theme.getThemeVectorIcon('ic_cloud_24dp'); } } bgcolor: "transparent" @@ -136,32 +135,27 @@ Drawer { if (featureForm.visible) { featureForm.hide(); } - showCloudMenu() + showCloudMenu(); } - bottomRightIndicatorText: cloudProjectsModel.layerObserver.deltaFileWrapper.count > 0 - ? cloudProjectsModel.layerObserver.deltaFileWrapper.count - : cloudProjectsModel.layerObserver.deltaFileWrapper.count >= 10 - ? '+' - : '' + bottomRightIndicatorText: cloudProjectsModel.layerObserver.deltaFileWrapper.count > 0 ? cloudProjectsModel.layerObserver.deltaFileWrapper.count : cloudProjectsModel.layerObserver.deltaFileWrapper.count >= 10 ? '+' : '' SequentialAnimation { OpacityAnimator { - from: 1 - to: 0.2 - duration: 2000 - target: cloudButton + from: 1 + to: 0.2 + duration: 2000 + target: cloudButton } OpacityAnimator { - from: 0.2 - to: 1 - duration: 2000 - target: cloudButton + from: 0.2 + to: 1 + duration: 2000 + target: cloudButton } - running: cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading || - cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading + running: cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading loops: Animation.Infinite onStopped: { - cloudButton.opacity = 1 + cloudButton.opacity = 1; } } } @@ -171,7 +165,7 @@ Drawer { id: modeSwitch visible: projectInfo.insertRights height: 56 - width: ( 56 + 36 ) + width: (56 + 36) anchors.right: parent.right anchors.verticalCenter: buttonsRow.verticalCenter indicator: Rectangle { @@ -179,7 +173,7 @@ Drawer { implicitWidth: 36 * 2 x: modeSwitch.leftPadding radius: 4 - color: "#66212121" + color: "#66212121" border.color: "#44FFFFFF" anchors.verticalCenter: parent.verticalCenter Image { @@ -188,7 +182,7 @@ Drawer { anchors.left: parent.left anchors.leftMargin: 4 anchors.verticalCenter: parent.verticalCenter - source: Theme.getThemeVectorIcon( 'ic_map_white_24dp' ) + source: Theme.getThemeVectorIcon('ic_map_white_24dp') sourceSize.width: parent.height * screen.devicePixelRatio sourceSize.height: parent.width * screen.devicePixelRatio opacity: 0.4 @@ -199,7 +193,7 @@ Drawer { anchors.right: parent.right anchors.rightMargin: 4 anchors.verticalCenter: parent.verticalCenter - source: Theme.getThemeVectorIcon( 'ic_create_white_24dp' ) + source: Theme.getThemeVectorIcon('ic_create_white_24dp') sourceSize.width: parent.height * screen.devicePixelRatio sourceSize.height: parent.width * screen.devicePixelRatio opacity: 0.4 @@ -209,17 +203,17 @@ Drawer { width: 36 height: 36 radius: 4 - color: Theme.mainColor + color: Theme.mainColor border.color: "white" Image { width: 28 height: 28 anchors.centerIn: parent - source: modeSwitch.checked ? Theme.getThemeVectorIcon( 'ic_create_white_24dp' ) : Theme.getThemeVectorIcon( 'ic_map_white_24dp' ) + source: modeSwitch.checked ? Theme.getThemeVectorIcon('ic_create_white_24dp') : Theme.getThemeVectorIcon('ic_map_white_24dp') sourceSize.width: parent.height * screen.devicePixelRatio sourceSize.height: parent.width * screen.devicePixelRatio } - Behavior on x { + Behavior on x { PropertyAnimation { duration: 100 easing.type: Easing.OutQuart @@ -229,14 +223,14 @@ Drawer { } onPositionChanged: { - if ( checked ) { - changeMode( "digitize" ) + if (checked) { + changeMode("digitize"); } else { - if ( digitizingToolbar.rubberbandModel && digitizingToolbar.rubberbandModel.vertexCount > 1 ) { - displayToast( qsTr( "Finish or dimiss the digitizing feature before toggling to browse mode" ) ) - checked = ! checked + if (digitizingToolbar.rubberbandModel && digitizingToolbar.rubberbandModel.vertexCount > 1) { + displayToast(qsTr("Finish or dimiss the digitizing feature before toggling to browse mode")); + checked = !checked; } else { - changeMode( "browse" ) + changeMode("browse"); } } } @@ -244,9 +238,8 @@ Drawer { } GroupBox { - Layout.fillWidth: true - id: mapThemeContainer + Layout.fillWidth: true title: qsTr("Map Theme") leftPadding: 10 rightPadding: 10 @@ -256,118 +249,117 @@ Drawer { property bool isLoading: false label: Label { - x: parent.leftPadding - y: 2 - width: parent.availableWidth - text: parent.title - color: Theme.mainColor - font: Theme.strongTipFont - elide: Text.ElideRight + x: parent.leftPadding + y: 2 + width: parent.availableWidth + text: parent.title + color: Theme.mainColor + font: Theme.strongTipFont + elide: Text.ElideRight } background: Rectangle { - y: parent.height - 1 - width: parent.width - height: 1 - color: Theme.mainColor + y: parent.height - 1 + width: parent.width + height: 1 + color: Theme.mainColor } RowLayout { - width: parent.width - ComboBox { - id: mapThemeComboBox - Layout.fillWidth: true - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - Connections { - target: iface - - function onLoadProjectTriggered() { - mapThemeContainer.isLoading = true - } - - function onLoadProjectEnded() { - var themes = qgisProject.mapThemeCollection.mapThemes - mapThemeComboBox.model = themes - mapThemeComboBox.enabled = themes.length > 1 - mapThemeComboBox.opacity = themes.length > 1 ? 1 : 0.25 - mapThemeContainer.visible = themes.length > 1 || flatLayerTree.isTemporal - flatLayerTree.updateCurrentMapTheme() - mapThemeComboBox.currentIndex = flatLayerTree.mapTheme != '' ? mapThemeComboBox.find( flatLayerTree.mapTheme ) : -1 - mapThemeContainer.isLoading = false - } - } + width: parent.width + ComboBox { + id: mapThemeComboBox + Layout.fillWidth: true + font: Theme.defaultFont - Connections { - target: flatLayerTree + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin - function onMapThemeChanged() { - if (!mapThemeContainer.isLoading && mapThemeComboBox.currentText != flatLayerTree.mapTheme) { - mapThemeContainer.isLoading = true - mapThemeComboBox.currentIndex = flatLayerTree.mapTheme != '' ? mapThemeComboBox.find( flatLayerTree.mapTheme ) : -1 - mapThemeContainer.isLoading = false - } - } - } + Connections { + target: iface - onCurrentTextChanged: { - if ( !mapThemeContainer.isLoading && qgisProject.mapThemeCollection.mapThemes.length > 1 ) { - flatLayerTree.mapTheme = mapThemeComboBox.currentText - } - } + function onLoadProjectTriggered() { + mapThemeContainer.isLoading = true; + } - delegate: ItemDelegate { - width: mapThemeComboBox.width - height: 36 - text: modelData - font.weight: mapThemeComboBox.currentIndex === index ? Font.DemiBold : Font.Normal - font.pointSize: Theme.tipFont.pointSize - highlighted: mapThemeComboBox.highlightedIndex == index - } + function onLoadProjectEnded() { + var themes = qgisProject.mapThemeCollection.mapThemes; + mapThemeComboBox.model = themes; + mapThemeComboBox.enabled = themes.length > 1; + mapThemeComboBox.opacity = themes.length > 1 ? 1 : 0.25; + mapThemeContainer.visible = themes.length > 1 || flatLayerTree.isTemporal; + flatLayerTree.updateCurrentMapTheme(); + mapThemeComboBox.currentIndex = flatLayerTree.mapTheme != '' ? mapThemeComboBox.find(flatLayerTree.mapTheme) : -1; + mapThemeContainer.isLoading = false; + } + } - contentItem: Text { - height: 36 - leftPadding: 8 - text: mapThemeComboBox.displayText - font: Theme.tipFont - color: Theme.mainTextColor - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } + Connections { + target: flatLayerTree - background: Item { - implicitWidth: 120 - implicitHeight: 36 - - Rectangle { - anchors.fill: parent - id: backgroundRect - border.color: mapThemeComboBox.pressed ? "#17a81a" : Theme.mainColor - border.width: mapThemeComboBox.visualFocus ? 2 : 1 - color: "transparent" - radius: 2 - } + function onMapThemeChanged() { + if (!mapThemeContainer.isLoading && mapThemeComboBox.currentText != flatLayerTree.mapTheme) { + mapThemeContainer.isLoading = true; + mapThemeComboBox.currentIndex = flatLayerTree.mapTheme != '' ? mapThemeComboBox.find(flatLayerTree.mapTheme) : -1; + mapThemeContainer.isLoading = false; } + } } - QfToolButton { - id: temporalButton - Layout.alignment: Qt.AlignVCenter - visible: flatLayerTree.isTemporal - iconSource: Theme.getThemeVectorIcon( 'ic_temporal_black_24dp' ) - iconColor: mapSettings.isTemporal ? Theme.mainColor : Theme.mainTextColor - bgcolor: "transparent" - onClicked: temporalProperties.open(); + onCurrentTextChanged: { + if (!mapThemeContainer.isLoading && qgisProject.mapThemeCollection.mapThemes.length > 1) { + flatLayerTree.mapTheme = mapThemeComboBox.currentText; + } + } + + delegate: ItemDelegate { + width: mapThemeComboBox.width + height: 36 + text: modelData + font.weight: mapThemeComboBox.currentIndex === index ? Font.DemiBold : Font.Normal + font.pointSize: Theme.tipFont.pointSize + highlighted: mapThemeComboBox.highlightedIndex == index + } + + contentItem: Text { + height: 36 + leftPadding: 8 + text: mapThemeComboBox.displayText + font: Theme.tipFont + color: Theme.mainTextColor + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Item { + implicitWidth: 120 + implicitHeight: 36 + + Rectangle { + id: backgroundRect + anchors.fill: parent + border.color: mapThemeComboBox.pressed ? "#17a81a" : Theme.mainColor + border.width: mapThemeComboBox.visualFocus ? 2 : 1 + color: "transparent" + radius: 2 + } } + } + + QfToolButton { + id: temporalButton + Layout.alignment: Qt.AlignVCenter + visible: flatLayerTree.isTemporal + iconSource: Theme.getThemeVectorIcon('ic_temporal_black_24dp') + iconColor: mapSettings.isTemporal ? Theme.mainColor : Theme.mainTextColor + bgcolor: "transparent" + onClicked: temporalProperties.open() + } } } - Rectangle { Layout.fillWidth: true Layout.fillHeight: true @@ -382,10 +374,10 @@ Drawer { } TemporalProperties { - id: temporalProperties - mapSettings: dashBoard.mapSettings; - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - parent: mainWindow.contentItem + id: temporalProperties + mapSettings: dashBoard.mapSettings + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + parent: mainWindow.contentItem } } diff --git a/src/qml/DigitizingToolbar.qml b/src/qml/DigitizingToolbar.qml index bfbc703ecb..ee8fd37da9 100644 --- a/src/qml/DigitizingToolbar.qml +++ b/src/qml/DigitizingToolbar.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -38,38 +37,27 @@ VisibilityFadingRow { signal vertexCountChanged Connections { - target: rubberbandModel - - function onVertexCountChanged() { - var extraVertexNeed = coordinateLocator && coordinateLocator.positionLocked - && positioningSettings.averagedPositioning - && positioningSettings.averagedPositioningMinimumCount > 1 - ? 1 - : 0 - - // set geometry valid - if (Number( rubberbandModel ? rubberbandModel.geometryType : 0 ) === 0) - { - geometryValid = false - } - else if (Number( rubberbandModel.geometryType ) === 1) - { - // Line: at least 2 points - geometryValid = rubberbandModel.vertexCount > 1 + extraVertexNeed - } - else if (Number( rubberbandModel.geometryType ) === 2) - { - // Polygon: at least 3 points - geometryValid = rubberbandModel.vertexCount > 2 + extraVertexNeed - } - else - { - geometryValid = false - } - - // emit the signal of digitizingToolbar - vertexCountChanged() + target: rubberbandModel + + function onVertexCountChanged() { + var extraVertexNeed = coordinateLocator && coordinateLocator.positionLocked && positioningSettings.averagedPositioning && positioningSettings.averagedPositioningMinimumCount > 1 ? 1 : 0; + + // set geometry valid + if (Number(rubberbandModel ? rubberbandModel.geometryType : 0) === 0) { + geometryValid = false; + } else if (Number(rubberbandModel.geometryType) === 1) { + // Line: at least 2 points + geometryValid = rubberbandModel.vertexCount > 1 + extraVertexNeed; + } else if (Number(rubberbandModel.geometryType) === 2) { + // Polygon: at least 3 points + geometryValid = rubberbandModel.vertexCount > 2 + extraVertexNeed; + } else { + geometryValid = false; } + + // emit the signal of digitizingToolbar + vertexCountChanged(); + } } DigitizingLogger { @@ -87,18 +75,18 @@ VisibilityFadingRow { QfToolButton { id: cancelButton - iconSource: Theme.getThemeIcon( "ic_clear_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_clear_white_24dp") visible: rubberbandModel && rubberbandModel.vertexCount > 1 round: true bgcolor: Theme.darkRed onClicked: { - homeButton.waitingForDigitizingFinish = false + homeButton.waitingForDigitizingFinish = false; if (stateMachine.state !== "measure") { cancelDialog.open(); } else { digitizingLogger.clearCoordinates(); - rubberbandModel.reset() + rubberbandModel.reset(); cancel(); } } @@ -107,24 +95,21 @@ VisibilityFadingRow { QfToolButton { id: confirmButton iconSource: { - Theme.getThemeIcon( "ic_check_white_48dp" ) + Theme.getThemeIcon("ic_check_white_48dp"); } visible: { - if (!showConfirmButton) - { - false - } - else - { - geometryValid + if (!showConfirmButton) { + false; + } else { + geometryValid; } } round: true bgcolor: Theme.mainColor onClicked: { - homeButton.waitingForDigitizingFinish = false - confirm() + homeButton.waitingForDigitizingFinish = false; + confirm(); } } @@ -136,29 +121,29 @@ VisibilityFadingRow { onTriggered: { if (!rubberbandModel || rubberbandModel.vertexCount == 0) stop(); - - removeVertex() - if (interval > 100) interval = interval * 0.8; + removeVertex(); + if (interval > 100) + interval = interval * 0.8; } } QfToolButton { id: removeVertexButton - iconSource: Theme.getThemeIcon( "ic_remove_vertex_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_remove_vertex_white_24dp") visible: rubberbandModel && rubberbandModel.vertexCount > 1 round: true bgcolor: Theme.darkGray onPressed: { - removeVertex() - removeVertexTimer.interval = 700 - removeVertexTimer.restart() + removeVertex(); + removeVertexTimer.interval = 700; + removeVertexTimer.restart(); } onReleased: { - removeVertexTimer.stop() + removeVertexTimer.stop(); } onCanceled: { - removeVertexTimer.stop() + removeVertexTimer.stop(); } } @@ -167,18 +152,17 @@ VisibilityFadingRow { round: true enabled: !screenHovering bgcolor: { - if (!enabled) { - Theme.darkGraySemiOpaque - } else if (!showConfirmButton) { - Theme.darkGray - } else if (Number( rubberbandModel ? rubberbandModel.geometryType : 0 ) === Qgis.GeometryType.Point || - Number( rubberbandModel.geometryType ) === Qgis.GeometryType.Null) { - Theme.mainColor - } else { - Theme.darkGray - } + if (!enabled) { + Theme.darkGraySemiOpaque; + } else if (!showConfirmButton) { + Theme.darkGray; + } else if (Number(rubberbandModel ? rubberbandModel.geometryType : 0) === Qgis.GeometryType.Point || Number(rubberbandModel.geometryType) === Qgis.GeometryType.Null) { + Theme.mainColor; + } else { + Theme.darkGray; + } } - iconSource: Theme.getThemeIcon( "ic_add_vertex_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_add_vertex_white_24dp") iconColor: enabled ? "white" : Theme.darkGraySemiOpaque property bool lastAdditionAveraged: false @@ -189,11 +173,9 @@ VisibilityFadingRow { target: positionSource function onAveragedPositionCountChanged() { - if (addVertexButton.averagedPositionAutoRelease && positionSource.averagedPosition - && positionSource.averagedPositionCount >= positioningSettings.averagedPositioningMinimumCount - && positioningSettings.averagedPositioningAutomaticStop) { + if (addVertexButton.averagedPositionAutoRelease && positionSource.averagedPosition && positionSource.averagedPositionCount >= positioningSettings.averagedPositioningMinimumCount && positioningSettings.averagedPositioningAutomaticStop) { addVertexButton.averagedPositionPressAndHeld = true; - addVertexButton.released() + addVertexButton.released(); } } } @@ -214,25 +196,20 @@ VisibilityFadingRow { } averagedPositionPressAndHeld = false; averagedPositionAutoRelease = false; - if (coordinateLocator && coordinateLocator.positionLocked) { - if (positioningSettings.averagedPositioning && - positioningSettings.averagedPositioningMinimumCount > positionSource.averagedPositionCount) { - displayToast( qsTr( "The collected positions count does not meet the requirement" ), 'warning' ) + if (positioningSettings.averagedPositioning && positioningSettings.averagedPositioningMinimumCount > positionSource.averagedPositionCount) { + displayToast(qsTr("The collected positions count does not meet the requirement"), 'warning'); positionSource.averagedPosition = false; return; } - if (!checkAccuracyRequirement()) { positionSource.averagedPosition = false; return; } - - lastAdditionAveraged = true - addVertex() - if (Number(rubberbandModel.geometryType) === Qgis.GeometryType.Point || - Number(rubberbandModel.geometryType) === Qgis.GeometryType.Null) { - confirm() + lastAdditionAveraged = true; + addVertex(); + if (Number(rubberbandModel.geometryType) === Qgis.GeometryType.Point || Number(rubberbandModel.geometryType) === Qgis.GeometryType.Null) { + confirm(); } positionSource.averagedPosition = false; } @@ -248,27 +225,21 @@ VisibilityFadingRow { if (!checkAccuracyRequirement()) { return; } - - if (coordinateLocator && coordinateLocator.positionLocked && - positioningSettings.averagedPositioning && - (positioningSettings.averagedPositioningMinimumCount > 1 - || !positioningSettings.averagedPositioningAutomaticStop)) { + if (coordinateLocator && coordinateLocator.positionLocked && positioningSettings.averagedPositioning && (positioningSettings.averagedPositioningMinimumCount > 1 || !positioningSettings.averagedPositioningAutomaticStop)) { if (!positionSource.averagedPosition) { averagedPositionAutoRelease = true; positionSource.averagedPosition = true; } else { addVertexButton.averagedPositionPressAndHeld = true; - addVertexButton.released() + addVertexButton.released(); } return; } - - lastAdditionAveraged = false - if (Number(rubberbandModel.geometryType) === Qgis.GeometryType.Point || - Number(rubberbandModel.geometryType) === Qgis.GeometryType.Null) { - confirm() + lastAdditionAveraged = false; + if (Number(rubberbandModel.geometryType) === Qgis.GeometryType.Point || Number(rubberbandModel.geometryType) === Qgis.GeometryType.Null) { + confirm(); } else { - addVertex() + addVertex(); } } } @@ -281,20 +252,20 @@ VisibilityFadingRow { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Cancel digitizing" ) + title: qsTr("Cancel digitizing") Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( "Should the digitized geometry be discarded?" ) + text: qsTr("Should the digitized geometry be discarded?") } standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { digitizingLogger.clearCoordinates(); - rubberbandModel.reset() + rubberbandModel.reset(); cancel(); visible = false; } @@ -304,13 +275,9 @@ VisibilityFadingRow { } function checkAccuracyRequirement() { - if (coordinateLocator && coordinateLocator.positionLocked && - positioningSettings.accuracyIndicator && positioningSettings.accuracyRequirement) { - if (positioningSettings.accuracyBad > 0 && - (!coordinateLocator.positionInformation || - !coordinateLocator.positionInformation.haccValid || - coordinateLocator.positionInformation.hacc >= positioningSettings.accuracyBad)) { - displayToast( qsTr( "Position accuracy doesn't meet the minimum requirement, vertex not added" ), 'warning' ) + if (coordinateLocator && coordinateLocator.positionLocked && positioningSettings.accuracyIndicator && positioningSettings.accuracyRequirement) { + if (positioningSettings.accuracyBad > 0 && (!coordinateLocator.positionInformation || !coordinateLocator.positionInformation.haccValid || coordinateLocator.positionInformation.hacc >= positioningSettings.accuracyBad)) { + displayToast(qsTr("Position accuracy doesn't meet the minimum requirement, vertex not added"), 'warning'); return false; } } @@ -318,30 +285,28 @@ VisibilityFadingRow { } function triggerAddVertex() { - addVertexButton.clicked() + addVertexButton.clicked(); } function addVertex() { - digitizingLogger.addCoordinate( coordinateLocator.currentCoordinate ) - coordinateLocator.flash() - - rubberbandModel.addVertex() + digitizingLogger.addCoordinate(coordinateLocator.currentCoordinate); + coordinateLocator.flash(); + rubberbandModel.addVertex(); } function removeVertex() { digitizingLogger.removeLastCoordinate(); - rubberbandModel.removeVertex() - mapSettings.setCenter( rubberbandModel.currentCoordinate, true ) + rubberbandModel.removeVertex(); + mapSettings.setCenter(rubberbandModel.currentCoordinate, true); } function confirm() { - rubberbandModel.frozen = true - if (addVertexButton.lastAdditionAveraged) { - rubberbandModel.removeVertex(); - } else { - digitizingLogger.addCoordinate( coordinateLocator.currentCoordinate ) - } - - confirmed() + rubberbandModel.frozen = true; + if (addVertexButton.lastAdditionAveraged) { + rubberbandModel.removeVertex(); + } else { + digitizingLogger.addCoordinate(coordinateLocator.currentCoordinate); + } + confirmed(); } } diff --git a/src/qml/ElevationProfile.qml b/src/qml/ElevationProfile.qml index bbe9ef2c22..4e14d6460a 100644 --- a/src/qml/ElevationProfile.qml +++ b/src/qml/ElevationProfile.qml @@ -1,10 +1,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQml 2.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Rectangle { @@ -58,25 +56,45 @@ Rectangle { visible: opacity > 0 states: [ - State { name: 'on' - PropertyChanges { target: busyIndicator; opacity: 1.0 }}, - State { name: 'off' - PropertyChanges { target: busyIndicator; opacity: 0.0 }} + State { + name: 'on' + PropertyChanges { + target: busyIndicator + opacity: 1.0 + } + }, + State { + name: 'off' + PropertyChanges { + target: busyIndicator + opacity: 0.0 + } + } ] transitions: [ Transition { from: "off" to: "on" SequentialAnimation { - NumberAnimation { target: busyIndicator; property: 'opacity'; duration: 100; } + NumberAnimation { + target: busyIndicator + property: 'opacity' + duration: 100 + } } }, Transition { from: "on" to: "off" SequentialAnimation { - PauseAnimation { duration: 100 } - NumberAnimation { target: busyIndicator; property: 'opacity'; duration: 200; } + PauseAnimation { + duration: 100 + } + NumberAnimation { + target: busyIndicator + property: 'opacity' + duration: 200 + } } } ] @@ -91,9 +109,7 @@ Rectangle { font: Theme.tinyFont horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap - text: elevationProfileCanvas.isRendering - ? qsTr('Rendering elevation profile…') - : qsTr('Digitize a path to render the elevation profile') + text: elevationProfileCanvas.isRendering ? qsTr('Rendering elevation profile…') : qsTr('Digitize a path to render the elevation profile') style: Text.Outline styleColor: Theme.mainBackgroundColorSemiOpaque } diff --git a/src/qml/EmbeddedFeatureForm.qml b/src/qml/EmbeddedFeatureForm.qml index c5b0741430..915e6c2a8f 100644 --- a/src/qml/EmbeddedFeatureForm.qml +++ b/src/qml/EmbeddedFeatureForm.qml @@ -1,116 +1,114 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import org.qfield 1.0 - import Theme 1.0 Popup { - id: formPopup - - property alias state: form.state - property alias embeddedLevel: form.embeddedLevel - property alias currentLayer: formFeatureModel.currentLayer - property alias linkedRelation: formFeatureModel.linkedRelation - property alias linkedRelationOrderingField: formFeatureModel.linkedRelationOrderingField - property alias linkedParentFeature: formFeatureModel.linkedParentFeature - property alias feature: formFeatureModel.feature - property alias attributeFormModel: formAttributeFormModel - property alias digitizingToolbar: form.digitizingToolbar - property alias codeReader: form.codeReader - - Connections { - target: digitizingToolbar - - property bool wasVisible: false - function onGeometryRequestedChanged() { - if ( digitizingToolbar.geometryRequested && formPopup.visible ) { - wasVisible = true - formPopup.visible = false - } else if ( !digitizingToolbar.geometryRequested && wasVisible ) { - wasVisible = false - formPopup.visible = true - } - } + id: formPopup + + property alias state: form.state + property alias embeddedLevel: form.embeddedLevel + property alias currentLayer: formFeatureModel.currentLayer + property alias linkedRelation: formFeatureModel.linkedRelation + property alias linkedRelationOrderingField: formFeatureModel.linkedRelationOrderingField + property alias linkedParentFeature: formFeatureModel.linkedParentFeature + property alias feature: formFeatureModel.feature + property alias attributeFormModel: formAttributeFormModel + property alias digitizingToolbar: form.digitizingToolbar + property alias codeReader: form.codeReader + + Connections { + target: digitizingToolbar + + property bool wasVisible: false + function onGeometryRequestedChanged() { + if (digitizingToolbar.geometryRequested && formPopup.visible) { + wasVisible = true; + formPopup.visible = false; + } else if (!digitizingToolbar.geometryRequested && wasVisible) { + wasVisible = false; + formPopup.visible = true; + } } + } - onAboutToShow: { - if (state === 'Add') { - form.featureCreated = false; - formFeatureModel.resetAttributes(); - } + onAboutToShow: { + if (state === 'Add') { + form.featureCreated = false; + formFeatureModel.resetAttributes(); } + } + + signal featureSaved(int id) + signal featureCancelled + + parent: mainWindow.contentItem + closePolicy: Popup.NoAutoClose // prevent accidental feature addition and editing + + x: Theme.popupScreenEdgeMargin / 2 + y: Theme.popupScreenEdgeMargin + z: 1000 + embeddedLevel + + padding: 0 + width: parent.width - Theme.popupScreenEdgeMargin + height: parent.height - Theme.popupScreenEdgeMargin * 2 + modal: true + + FeatureForm { + id: form + property bool isSaved: false + + model: AttributeFormModel { + id: formAttributeFormModel + featureModel: FeatureModel { + id: formFeatureModel + project: qgisProject + positionInformation: coordinateLocator.positionInformation + positionLocked: coordinateLocator.overrideLocation !== undefined + topSnappingResult: coordinateLocator.topSnappingResult + cloudUserInformation: projectInfo.cloudUserInformation + } + } + + focus: true - signal featureSaved(int id) - signal featureCancelled - - parent: mainWindow.contentItem - closePolicy: Popup.NoAutoClose // prevent accidental feature addition and editing - - x: Theme.popupScreenEdgeMargin / 2 - y: Theme.popupScreenEdgeMargin - z: 1000 + embeddedLevel - - padding: 0 - width: parent.width - Theme.popupScreenEdgeMargin - height: parent.height - Theme.popupScreenEdgeMargin * 2 - modal: true - - FeatureForm { - id: form - property bool isSaved: false - - model: AttributeFormModel { - id: formAttributeFormModel - featureModel: FeatureModel { - id: formFeatureModel - project: qgisProject - positionInformation: coordinateLocator.positionInformation - positionLocked: coordinateLocator.overrideLocation !== undefined - topSnappingResult: coordinateLocator.topSnappingResult - cloudUserInformation: projectInfo.cloudUserInformation - } - } - - focus: true - - embedded: true - toolbarVisible: true - - anchors.fill: parent - - onConfirmed: { - formPopup.featureSaved(formFeatureModel.feature.id) - closePopup() - } - - onCancelled: { - formPopup.featureCancelled() - closePopup() - } - - function closePopup() { - if (formPopup.opened) { - isSaved = true - formPopup.close() - } else { - isSaved = false - } - } + embedded: true + toolbarVisible: true + + anchors.fill: parent + + onConfirmed: { + formPopup.featureSaved(formFeatureModel.feature.id); + closePopup(); } - onClosed: { - if (!form.isSaved) { - form.confirm() - digitizingToolbar.digitizingLogger.writeCoordinates(); - } else { - form.isSaved = false - digitizingToolbar.digitizingLogger.clearCoordinates(); - } + onCancelled: { + formPopup.featureCancelled(); + closePopup(); } - function applyGeometry(geometry) { - formFeatureModel.geometry = geometry; - formFeatureModel.applyGeometry(); + function closePopup() { + if (formPopup.opened) { + isSaved = true; + formPopup.close(); + } else { + isSaved = false; + } } + } + + onClosed: { + if (!form.isSaved) { + form.confirm(); + digitizingToolbar.digitizingLogger.writeCoordinates(); + } else { + form.isSaved = false; + digitizingToolbar.digitizingLogger.clearCoordinates(); + } + } + + function applyGeometry(geometry) { + formFeatureModel.geometry = geometry; + formFeatureModel.applyGeometry(); + } } diff --git a/src/qml/FeatureForm.qml b/src/qml/FeatureForm.qml index 0d8e02d44b..289d0b8a30 100644 --- a/src/qml/FeatureForm.qml +++ b/src/qml/FeatureForm.qml @@ -6,7 +6,6 @@ import QtQml.Models 2.14 import QtQml 2.14 import QtCharts 2.14 // Not actually used here but added so the android deploy script adds the relevant package import QtWebView 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -43,7 +42,7 @@ Page { if (!qfieldSettings.autoSave) { cancelDialog.open(); } else { - cancel() + cancel(); } } @@ -95,7 +94,7 @@ Page { height: 48 onClicked: { - tabRow.currentIndex = index + tabRow.currentIndex = index; } background: Rectangle { @@ -184,9 +183,7 @@ Page { Repeater { // Note: digitizing a child geometry will temporarily hide the feature form, // we need to preserve items so signal connections are kept alive - model: form.model.hasTabs - ? contentModel - : form.model + model: form.model.hasTabs ? contentModel : form.model delegate: fieldItem } } @@ -215,9 +212,7 @@ Page { font.bold: true topPadding: 10 bottomPadding: 5 - opacity: form.state === 'ReadOnly' || embedded && EditorWidget === 'RelationEditor' - ? 0.45 - : 1 + opacity: form.state === 'ReadOnly' || embedded && EditorWidget === 'RelationEditor' ? 0.45 : 1 color: labelOverrideColor !== undefined && labelOverrideColor ? labelColor : Theme.mainTextColor } @@ -235,7 +230,9 @@ Page { opacity: textLabel.opacity color: Theme.mainTextColor linkColor: Theme.mainColor - onLinkActivated: (link) => { Qt.openUrlExternally(link) } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } } } } @@ -260,9 +257,7 @@ Page { font.bold: true topPadding: 10 bottomPadding: 5 - opacity: form.state === 'ReadOnly' || embedded && EditorWidget === 'RelationEditor' - ? 0.45 - : 1 + opacity: form.state === 'ReadOnly' || embedded && EditorWidget === 'RelationEditor' ? 0.45 : 1 color: labelOverrideColor !== undefined && labelOverrideColor ? labelColor : Theme.mainTextColor } @@ -271,7 +266,7 @@ Page { property string code: containerCode onCodeChanged: { - var obj = Qt.createQmlObject(code,qmlItem,'qmlContent'); + var obj = Qt.createQmlObject(code, qmlItem, 'qmlContent'); } height: childrenRect.height @@ -308,9 +303,7 @@ Page { font.bold: true topPadding: 10 bottomPadding: 5 - opacity: form.state === 'ReadOnly' || embedded && EditorWidget === 'RelationEditor' - ? 0.45 - : 1 + opacity: form.state === 'ReadOnly' || embedded && EditorWidget === 'RelationEditor' ? 0.45 : 1 color: labelOverrideColor !== undefined && labelOverrideColor ? labelColor : Theme.mainTextColor } @@ -343,8 +336,7 @@ Page { }); } } - }' - , htmlContent); + }', htmlContent); } htmlItem.loadHtml(htmlCode); } @@ -382,7 +374,7 @@ Page { function onModelReset() { if (containerGroupIndex !== undefined && innerContainer.visible) { - innerSubModel.rootIndex = form.model.mapFromSource(containerGroupIndex) + innerSubModel.rootIndex = form.model.mapFromSource(containerGroupIndex); } } } @@ -393,7 +385,8 @@ Page { Component { id: dummyContainer - Item {} + Item { + } } /** @@ -403,11 +396,7 @@ Page { id: fieldItem Item { - width: parent && parent.width > 0 - ? parent.width / ColumnCount > 200 - ? parent.width / ColumnCount - : parent.width - : form.width + width: parent && parent.width > 0 ? parent.width / ColumnCount > 200 ? parent.width / ColumnCount : parent.width : form.width height: fieldGroupTitle.height + fieldContent.childrenRect.height Rectangle { @@ -463,23 +452,14 @@ Page { property var labelOverrideColor: LabelOverrideColor property var labelColor: LabelColor - active: (Type === 'container' && GroupIndex !== undefined && GroupIndex.valid) || - ((Type === 'text' || Type === 'html' || Type === 'qml') && form.model.featureModel.modelMode != FeatureModel.MultiFeatureModel) + active: (Type === 'container' && GroupIndex !== undefined && GroupIndex.valid) || ((Type === 'text' || Type === 'html' || Type === 'qml') && form.model.featureModel.modelMode != FeatureModel.MultiFeatureModel) height: active ? item.childrenRect.height : 0 anchors { left: parent.left right: parent.right } - sourceComponent: Type === 'container' && GroupIndex !== undefined && GroupIndex.valid - ? innerContainer - : Type === 'qml' - ? qmlContainer - : Type === 'html' - ? htmlContainer - : Type === 'text' - ? textContainer - : dummyContainer + sourceComponent: Type === 'container' && GroupIndex !== undefined && GroupIndex.valid ? innerContainer : Type === 'qml' ? qmlContainer : Type === 'html' ? htmlContainer : Type === 'text' ? textContainer : dummyContainer } Item { @@ -508,9 +488,7 @@ Page { font.strikeout: LabelOverrideFont ? LabelFont.strikeout : false topPadding: 10 bottomPadding: 5 - opacity: (form.state === 'ReadOnly' || !AttributeEditable) || embedded && EditorWidget === 'RelationEditor' - ? 0.45 - : 1 + opacity: (form.state === 'ReadOnly' || !AttributeEditable) || embedded && EditorWidget === 'RelationEditor' ? 0.45 : 1 color: LabelOverrideColor ? LabelColor : Theme.mainTextColor } @@ -522,11 +500,10 @@ Page { top: fieldLabel.bottom } - font.pointSize: fieldLabel.font.pointSize/3*2 + font.pointSize: fieldLabel.font.pointSize / 3 * 2 text: { - if ( ConstraintHardValid && ConstraintSoftValid ) + if (ConstraintHardValid && ConstraintSoftValid) return ''; - return ConstraintDescription || ''; } height: !ConstraintHardValid || !ConstraintSoftValid ? undefined : 0 @@ -538,12 +515,19 @@ Page { Item { id: placeholder height: attributeEditorLoader.childrenRect.height - anchors { left: parent.left; right: menuButton.left; top: constraintDescriptionLabel.bottom; } + anchors { + left: parent.left + right: menuButton.left + top: constraintDescriptionLabel.bottom + } Loader { id: attributeEditorLoader - anchors { left: parent.left; right: parent.right } + anchors { + left: parent.left + right: parent.right + } //disable widget if it's: // - not activated in multi edit mode @@ -552,11 +536,9 @@ Page { // - a relation in multi edit mode property bool isAdding: form.state === 'Add' property bool isEditing: form.state === 'Edit' - property bool isEnabled: !!AttributeEditable - && form.state !== 'ReadOnly' - && !( Type === 'relation' && form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel ) + property bool isEnabled: !!AttributeEditable && form.state !== 'ReadOnly' && !(Type === 'relation' && form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel) property var value: AttributeValue - property var config: ( EditorWidgetConfig || {} ) + property var config: (EditorWidgetConfig || {}) property var widget: EditorWidget property var relationEditorWidget: RelationEditorWidget property var relationEditorWidgetConfig: RelationEditorWidgetConfig @@ -576,10 +558,10 @@ Page { active: widget !== 'Hidden' source: { - if ( widget === 'RelationEditor' ) { - return 'editorwidgets/relationeditors/' + ( RelationEditorWidget || 'relation_editor' ) + '.qml' + if (widget === 'RelationEditor') { + return 'editorwidgets/relationeditors/' + (RelationEditorWidget || 'relation_editor') + '.qml'; } - return 'editorwidgets/' + ( widget || 'TextEdit' ) + '.qml' + return 'editorwidgets/' + (widget || 'TextEdit') + '.qml'; } onLoaded: { @@ -587,10 +569,8 @@ Page { } onStatusChanged: { - if ( attributeEditorLoader.status === Loader.Error ) { - source = ( widget === 'RelationEditor' ) - ? 'editorwidgets/relationeditors/relation_editor.qml' - : 'editorwidgets/TextEdit.qml' + if (attributeEditorLoader.status === Loader.Error) { + source = (widget === 'RelationEditor') ? 'editorwidgets/relationeditors/relation_editor.qml' : 'editorwidgets/TextEdit.qml'; } } } @@ -600,15 +580,15 @@ Page { function onAboutToSave() { // it may not be implemented - if ( attributeEditorLoader.item.pushChanges ) { - attributeEditorLoader.item.pushChanges( form.model.featureModel.feature ) + if (attributeEditorLoader.item.pushChanges) { + attributeEditorLoader.item.pushChanges(form.model.featureModel.feature); } } function onValueChanged(field, oldValue, newValue) { // it may not be implemented - if ( attributeEditorLoader.item.siblingValueChanged ) { - attributeEditorLoader.item.siblingValueChanged( field, form.model.featureModel.feature ) + if (attributeEditorLoader.item.siblingValueChanged) { + attributeEditorLoader.item.siblingValueChanged(field, form.model.featureModel.feature); } } } @@ -618,39 +598,38 @@ Page { function onValueChangeRequested(value, isNull) { //do not compare AttributeValue and value with strict comparison operators - if( ( AttributeValue != value || ( AttributeValue !== undefined && isNull ) ) && !( AttributeValue === undefined && isNull ) ) - { - var oldValue = AttributeValue - AttributeValue = isNull ? undefined : value - - valueChanged(Field, oldValue, AttributeValue) - - if ( !AttributeAllowEdit && form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel ) { + if ((AttributeValue != value || (AttributeValue !== undefined && isNull)) && !(AttributeValue === undefined && isNull)) { + var oldValue = AttributeValue; + AttributeValue = isNull ? undefined : value; + valueChanged(Field, oldValue, AttributeValue); + if (!AttributeAllowEdit && form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel) { AttributeAllowEdit = true; } - - if ( qfieldSettings.autoSave && !setupOnly && !master.ignoreChanges ) { + if (qfieldSettings.autoSave && !setupOnly && !master.ignoreChanges) { // indirect action, no need to check for success and display a toast, the log is enough - save() + save(); } } } function onRequestGeometry(item, layer) { - form.digitizingToolbar.geometryRequested = true - form.digitizingToolbar.geometryRequestedItem = item - form.digitizingToolbar.geometryRequestedLayer = layer + form.digitizingToolbar.geometryRequested = true; + form.digitizingToolbar.geometryRequestedItem = item; + form.digitizingToolbar.geometryRequestedLayer = layer; } function onRequestBarcode(item) { - form.codeReader.barcodeRequestedItem = item - form.codeReader.open() + form.codeReader.barcodeRequestedItem = item; + form.codeReader.open(); } } } QfToolButton { id: menuButton - anchors { right: rememberButton.left; top: constraintDescriptionLabel.bottom; } + anchors { + right: rememberButton.left + top: constraintDescriptionLabel.bottom + } visible: attributeEditorLoader.isEnabled && attributeEditorLoader.item.hasMenu enabled: visible @@ -661,7 +640,7 @@ Page { bgcolor: "transparent" onClicked: { - attributeEditorLoader.item.menu.popup(menuButton.x, menuButton.y) + attributeEditorLoader.item.menu.popup(menuButton.x, menuButton.y); } } @@ -682,30 +661,34 @@ Page { } onClicked: { - RememberValue = !RememberValue + RememberValue = !RememberValue; if (RememberValue) { - displayToast(qsTr("The last entered value for this field will be remembered and reused when creating new features")) + displayToast(qsTr("The last entered value for this field will be remembered and reused when creating new features")); } else { - displayToast(qsTr("The last entered value for this field will not be reused when creating new features")) + displayToast(qsTr("The last entered value for this field will not be reused when creating new features")); } - projectInfo.saveLayerRememberedFields(form.model.featureModel.currentLayer) + projectInfo.saveLayerRememberedFields(form.model.featureModel.currentLayer); } } Label { id: multiEditAttributeLabel - text: (AttributeAllowEdit ? qsTr( "Value applied" ) : qsTr( "Value skipped" ) ) + qsTr( " (click to toggle)" ) + text: (AttributeAllowEdit ? qsTr("Value applied") : qsTr("Value skipped")) + qsTr(" (click to toggle)") visible: form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel && Type !== 'relation' height: form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel ? undefined : 0 bottomPadding: form.model.featureModel.modelMode == FeatureModel.MultiFeatureModel ? 15 : 0 - anchors { left: parent.left; top: placeholder.bottom; rightMargin: 10; } + anchors { + left: parent.left + top: placeholder.bottom + rightMargin: 10 + } font: Theme.tipFont color: AttributeAllowEdit ? Theme.mainColor : Theme.secondaryTextColor MouseArea { anchors.fill: parent onClicked: { - AttributeAllowEdit = !AttributeAllowEdit + AttributeAllowEdit = !AttributeAllowEdit; } } } @@ -716,71 +699,59 @@ Page { function confirm() { //if this is not handled before (e.g. when this is called because the drawer is closed by tipping on the map) - if ( !model.constraintsHardValid ) - { - displayToast( qsTr( 'Constraints not valid'), 'warning' ) - cancel() - return + if (!model.constraintsHardValid) { + displayToast(qsTr('Constraints not valid'), 'warning'); + cancel(); + return; + } else if (!model.constraintsSoftValid) { + displayToast(qsTr('Note: soft constraints were not met')); } - else if ( !model.constraintsSoftValid ) - { - displayToast( qsTr( 'Note: soft constraints were not met') ) + parent.focus = true; + if (setupOnly) { + temporaryStored(); + return; } - - parent.focus = true - - if( setupOnly ) { - temporaryStored() - return - } - - if ( !save() ) { - displayToast( qsTr( 'Unable to save changes'), 'error' ) - featureCreated = false - return + if (!save()) { + displayToast(qsTr('Unable to save changes'), 'error'); + featureCreated = false; + return; } - - state = 'Edit' - featureCreated = false - - confirmed() + state = 'Edit'; + featureCreated = false; + confirmed(); } function save() { - if( !model.constraintsHardValid ) { - return false + if (!model.constraintsHardValid) { + return false; } - - aboutToSave() - + aboutToSave(); master.ignoreChanges = true; - var isSuccess = false; - if( form.state === 'Add' && !featureCreated ) { - isSuccess = model.create() - featureCreated = isSuccess + if (form.state === 'Add' && !featureCreated) { + isSuccess = model.create(); + featureCreated = isSuccess; } else { - isSuccess = model.save() + isSuccess = model.save(); } - master.ignoreChanges = false; - return isSuccess + return isSuccess; } function cancel() { - if( form.state === 'Add' && featureCreated ) { + if (form.state === 'Add' && featureCreated) { // indirect action, no need to check for success and display a toast, the log is enough - model.deleteFeature() + model.deleteFeature(); } - cancelled() - featureCreated = false + cancelled(); + featureCreated = false; } Connections { target: Qt.inputMethod function onVisibleChanged() { - Qt.inputMethod.commit() + Qt.inputMethod.commit(); } } @@ -796,7 +767,7 @@ Page { } background: Rectangle { - color: !model.constraintsHardValid ? Theme.errorColor : !model.constraintsSoftValid ? Theme.warningColor : Theme.mainColor + color: !model.constraintsHardValid ? Theme.errorColor : !model.constraintsSoftValid ? Theme.warningColor : Theme.mainColor } RowLayout { @@ -809,22 +780,22 @@ Page { Layout.alignment: Qt.AlignTop | Qt.AlignLeft - visible: ( form.state === 'Add' || form.state === 'Edit' ) + visible: (form.state === 'Add' || form.state === 'Edit') width: 48 height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_check_white_48dp" ) + iconSource: Theme.getThemeIcon("ic_check_white_48dp") opacity: typeof featureFormList !== "undefined" ? featureFormList.model.constraintsHardValid ? 1.0 : 0.3 : 1.0 onClicked: { - if( model.constraintsHardValid ) { - if ( !model.constraintsSoftValid ) { - displayToast( qsTr('Note: soft constraints were not met') ) + if (model.constraintsHardValid) { + if (!model.constraintsSoftValid) { + displayToast(qsTr('Note: soft constraints were not met')); } - confirm() + confirm(); } else { - displayToast( qsTr('Constraints not valid'), 'warning' ) + displayToast(qsTr('Constraints not valid'), 'warning'); } } } @@ -837,19 +808,17 @@ Page { font: Theme.strongFont color: Theme.light - text: - { - var currentLayer = model.featureModel.currentLayer - var layerName = 'N/A' + text: { + var currentLayer = model.featureModel.currentLayer; + var layerName = 'N/A'; if (currentLayer != null) - layerName = currentLayer.name - - if ( form.state === 'Add' ) - qsTr( 'Add feature on %1' ).arg(layerName ) - else if ( form.state === 'Edit' ) - qsTr( 'Edit feature on %1' ).arg(layerName) + layerName = currentLayer.name; + if (form.state === 'Add') + qsTr('Add feature on %1').arg(layerName); + else if (form.state === 'Edit') + qsTr('Edit feature on %1').arg(layerName); else - qsTr( 'View feature on %1' ).arg(layerName) + qsTr('View feature on %1').arg(layerName); } fontSizeMode: Text.Fit @@ -869,12 +838,12 @@ Page { clip: true visible: !setupOnly - iconSource: form.state === 'Add' ? Theme.getThemeIcon( 'ic_delete_forever_white_24dp' ) : Theme.getThemeIcon( 'ic_close_white_24dp' ) + iconSource: form.state === 'Add' ? Theme.getThemeIcon('ic_delete_forever_white_24dp') : Theme.getThemeIcon('ic_close_white_24dp') onClicked: { - Qt.inputMethod.hide() + Qt.inputMethod.hide(); if ((form.state === 'Add' || form.state === 'Edit')) { - form.requestCancel() + form.requestCancel(); } else { cancel(); } @@ -892,21 +861,19 @@ Page { font: Theme.defaultFont z: 10000 // 1000s are embedded feature forms, user a higher value to insure the dialog will always show above embedded feature forms - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Cancel editing" ) + title: qsTr("Cancel editing") Label { width: parent.width wrapMode: Text.WordWrap - text: form.state === 'Add' - ? qsTr( "You are about to dismiss the new feature, proceed?" ) - : qsTr( "You are about to leave editing state, any changes will be lost. Proceed?" ) + text: form.state === 'Add' ? qsTr("You are about to dismiss the new feature, proceed?") : qsTr("You are about to leave editing state, any changes will be lost. Proceed?") } standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - form.cancel() + form.cancel(); } } } diff --git a/src/qml/FeatureListForm.qml b/src/qml/FeatureListForm.qml index e3d9cd24a3..57bca5bd55 100644 --- a/src/qml/FeatureListForm.qml +++ b/src/qml/FeatureListForm.qml @@ -14,13 +14,11 @@ * (at your option) any later version. * * * ***************************************************************************/ - import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -47,8 +45,7 @@ Rectangle { property bool fullScreenView: qfieldSettings.fullScreenIdentifyView property bool isVertical: parent.width < parent.height || parent.width < 300 - property bool canvasOperationRequested: digitizingToolbar.geometryRequested || - moveFeaturesToolbar.moveFeaturesRequested + property bool canvasOperationRequested: digitizingToolbar.geometryRequested || moveFeaturesToolbar.moveFeaturesRequested signal showMessage(string message) signal editGeometry @@ -58,40 +55,27 @@ Rectangle { } width: { - if ( props.isVisible || featureForm.canvasOperationRequested ) - { - if (fullScreenView || parent.width < parent.height || parent.width < 300) - { - parent.width - } - else - { - Math.min(Math.max(200, parent.width / 2.25), parent.width) - } - } - else - { - - 0 + if (props.isVisible || featureForm.canvasOperationRequested) { + if (fullScreenView || parent.width < parent.height || parent.width < 300) { + parent.width; + } else { + Math.min(Math.max(200, parent.width / 2.25), parent.width); } + } else { + 0; + } } height: { - if ( props.isVisible || featureForm.canvasOperationRequested ) - { - if (fullScreenView || parent.width > parent.height) - { - parent.height - } - else - { - isVertical = true - Math.min(Math.max( 200, parent.height / 2 ), parent.height) - } - } - else - { - 0 - } + if (props.isVisible || featureForm.canvasOperationRequested) { + if (fullScreenView || parent.width > parent.height) { + parent.height; + } else { + isVertical = true; + Math.min(Math.max(200, parent.height / 2), parent.height); + } + } else { + 0; + } } anchors.bottomMargin: featureForm.canvasOperationRequested ? featureForm.height : 0 @@ -106,10 +90,10 @@ Rectangle { name: "Hidden" StateChangeScript { script: { - hide() - if( featureFormList.state === "Edit" ){ + hide(); + if (featureFormList.state === "Edit") { //e.g. tip on the canvas during an edit - featureFormList.confirm() + featureFormList.confirm(); } } } @@ -139,13 +123,13 @@ Rectangle { } StateChangeScript { script: { - show() - locatorItem.state = "off" - if( featureFormList.state === "Edit" ){ + show(); + locatorItem.state = "off"; + if (featureFormList.state === "Edit") { ///e.g. tip on the canvas during an edit - featureFormList.confirm() + featureFormList.confirm(); } - featureListToolBar.title = qsTr('Features') + featureListToolBar.title = qsTr('Features'); } } }, @@ -167,7 +151,6 @@ Rectangle { PropertyChanges { target: featureFormList state: "ReadOnly" - } }, /* Shows an editable form for the currently selected feature */ @@ -211,7 +194,7 @@ Rectangle { } StateChangeScript { script: { - featureListToolBar.title = qsTr('Processing Algorithms') + featureListToolBar.title = qsTr('Processing Algorithms'); } } }, @@ -231,8 +214,8 @@ Rectangle { } StateChangeScript { script: { - featureListToolBar.title = processingAlgorithmForm.algorithmDisplayName - featureListToolBar.title = processingAlgorithmForm.algorithmDisplayName + featureListToolBar.title = processingAlgorithmForm.algorithmDisplayName; + featureListToolBar.title = processingAlgorithmForm.algorithmDisplayName; } } } @@ -284,7 +267,10 @@ Rectangle { color: Theme.controlBorderColor Text { - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } font.bold: true font.pointSize: Theme.resultFont.pointSize color: Theme.mainTextColor @@ -297,26 +283,30 @@ Rectangle { id: itemBackground anchors { left: parent ? parent.left : undefined - right: parent ? parent.right: undefined + right: parent ? parent.right : undefined } focus: true - height: Math.max( 48, featureText.height ) + height: Math.max(48, featureText.height) color: "transparent" Ripple { - clip: true - width: parent.width - height: parent.height - pressed: mouseArea.pressed - anchor: itemBackground - active: mouseArea.pressed - color: Material.rippleColor + clip: true + width: parent.width + height: parent.height + pressed: mouseArea.pressed + anchor: itemBackground + active: mouseArea.pressed + color: Material.rippleColor } CheckBox { - anchors { leftMargin: 5; left: parent.left; verticalCenter: parent.verticalCenter } - checked: featureSelected - visible: featureForm.multiSelection + anchors { + leftMargin: 5 + left: parent.left + verticalCenter: parent.verticalCenter + } + checked: featureSelected + visible: featureForm.multiSelection } Text { @@ -338,7 +328,7 @@ Rectangle { width: 6 color: featureForm.selectionColor opacity: index == featureForm.selection.focusedItem && featureForm.selection.model.selectedCount == 0 ? 1 : 0 - Behavior on opacity { + Behavior on opacity { PropertyAnimation { easing.type: Easing.OutQuart } @@ -350,30 +340,27 @@ Rectangle { anchors.fill: parent onClicked: { - if ( featureForm.multiSelection ) { - featureForm.selection.toggleSelectedItem( index ); - if ( featureForm.selection.model.selectedCount == 0 ) { - featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel - featureForm.multiSelection = false; - } - featureForm.selection.focusedItem = featureForm.selection.model.selectedCount > 0 ? index : -1; + if (featureForm.multiSelection) { + featureForm.selection.toggleSelectedItem(index); + if (featureForm.selection.model.selectedCount == 0) { + featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel; + featureForm.multiSelection = false; + } + featureForm.selection.focusedItem = featureForm.selection.model.selectedCount > 0 ? index : -1; } else { - featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel - featureForm.state = "FeatureForm" - featureForm.selection.focusedItem = index + featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel; + featureForm.state = "FeatureForm"; + featureForm.selection.focusedItem = index; featureForm.multiSelection = false; } - - featureFormList.model.applyFeatureModel() + featureFormList.model.applyFeatureModel(); } - onPressAndHold: - { - featureFormList.model.featureModel.modelMode = FeatureModel.MultiFeatureModel - featureForm.selection.focusedItem = index - featureForm.selection.toggleSelectedItem( index ); + onPressAndHold: { + featureFormList.model.featureModel.modelMode = FeatureModel.MultiFeatureModel; + featureForm.selection.focusedItem = index; + featureForm.selection.toggleSelectedItem(index); featureForm.multiSelection = true; - } } @@ -394,7 +381,7 @@ Rectangle { width: parent.width } - Behavior on height { + Behavior on height { PropertyAnimation { easing.type: Easing.OutQuart } @@ -430,11 +417,11 @@ Rectangle { focus: true onCancelled: { - featureForm.selection.focusedItemChanged() - featureFormList.model.featureModel.reset() - featureForm.state = featureForm.selection.model.selectedCount > 0 ? "FeatureList" : "FeatureForm" + featureForm.selection.focusedItemChanged(); + featureFormList.model.featureModel.reset(); + featureForm.state = featureForm.selection.model.selectedCount > 0 ? "FeatureList" : "FeatureForm"; if (!qfieldSettings.autoSave) { - displayToast( qsTr( "Changes discarded" ), 'warning' ) + displayToast(qsTr("Changes discarded"), 'warning'); } } } @@ -453,9 +440,9 @@ Rectangle { property bool shown: false visible: shown - onAlgorithmSelected: (id) => { - processingAlgorithm.id = id - featureForm.state = "ProcessingAlgorithmForm" + onAlgorithmSelected: id => { + processingAlgorithm.id = id; + featureForm.state = "ProcessingAlgorithmForm"; } } @@ -500,45 +487,45 @@ Rectangle { mapSettings: featureForm.mapSettings onFeatureFormStateRequested: { - featureForm.state = "FeatureForm" + featureForm.state = "FeatureForm"; } } onBackClicked: { - featureForm.focus = true; - if ( featureForm.state != "FeatureList" ) { - featureForm.state = "FeatureList"; - } else { - featureForm.state = "Hidden"; - } + featureForm.focus = true; + if (featureForm.state != "FeatureList") { + featureForm.state = "FeatureList"; + } else { + featureForm.state = "Hidden"; + } } onStatusIndicatorClicked: { - featureForm.state = "FeatureList" + featureForm.state = "FeatureList"; } - onStatusIndicatorSwiped: (direction) => { + onStatusIndicatorSwiped: direction => { if (isVertical) { if (direction === 'up') { - fullScreenView = true + fullScreenView = true; } else if (direction === 'down') { - if ( fullScreenView ) { - fullScreenView = false + if (fullScreenView) { + fullScreenView = false; } else { if (featureForm.state != 'FeatureFormEdit') { - featureForm.state = 'Hidden' + featureForm.state = 'Hidden'; } } } } else { if (direction === 'left') { - fullScreenView = true + fullScreenView = true; } else if (direction === 'right') { - if ( fullScreenView ) { - fullScreenView = false + if (fullScreenView) { + fullScreenView = false; } else { if (featureForm.state != 'FeatureFormEdit') { - featureForm.state = 'Hidden' + featureForm.state = 'Hidden'; } } } @@ -546,252 +533,228 @@ Rectangle { } onEditAttributesButtonClicked: { - if( trackingModel.featureInTracking(selection.focusedLayer, selection.focusedFeature.id) ) - { - displayToast( qsTr( "Stop tracking this feature to edit attributes" ) ) - } - else - { - featureForm.state = "FeatureFormEdit" - } + if (trackingModel.featureInTracking(selection.focusedLayer, selection.focusedFeature.id)) { + displayToast(qsTr("Stop tracking this feature to edit attributes")); + } else { + featureForm.state = "FeatureFormEdit"; + } } onEditGeometryButtonClicked: { - if( trackingModel.featureInTracking(selection.focusedLayer, selection.focusedFeature.id) ) - { - displayToast( qsTr( "Stop tracking this feature to edit geometry" ) ) - } - else - { - editGeometry() - } + if (trackingModel.featureInTracking(selection.focusedLayer, selection.focusedFeature.id)) { + displayToast(qsTr("Stop tracking this feature to edit geometry")); + } else { + editGeometry(); + } } onSave: { - featureFormList.confirm() - featureForm.state = featureForm.selection.model.selectedCount > 0 ? "FeatureList" : "FeatureForm" - displayToast( qsTr( "Changes saved" ) ) + featureFormList.confirm(); + featureForm.state = featureForm.selection.model.selectedCount > 0 ? "FeatureList" : "FeatureForm"; + displayToast(qsTr("Changes saved")); } onCancel: { - featureForm.requestCancel(); + featureForm.requestCancel(); } onDestinationClicked: { - navigation.setDestinationFeature(featureForm.selection.focusedFeature,featureForm.selection.focusedLayer) + navigation.setDestinationFeature(featureForm.selection.focusedFeature, featureForm.selection.focusedLayer); featureForm.state = "Hidden"; } onMoveClicked: { - if (featureForm.selection.focusedItem !== -1) { - featureForm.state = "FeatureList" - featureForm.multiSelection = true - featureForm.selection.model.toggleSelectedItem(featureForm.selection.focusedItem) - moveFeaturesToolbar.initializeMoveFeatures() - } + if (featureForm.selection.focusedItem !== -1) { + featureForm.state = "FeatureList"; + featureForm.multiSelection = true; + featureForm.selection.model.toggleSelectedItem(featureForm.selection.focusedItem); + moveFeaturesToolbar.initializeMoveFeatures(); + } } onDuplicateClicked: { - if (featureForm.selection.model.duplicateFeature(featureForm.selection.focusedLayer,featureForm.selection.focusedFeature)) { - displayToast( qsTr( "Successfully duplicated feature" ) ) - - featureForm.selection.focusedItem = -1 - featureForm.state = "FeatureList" - featureForm.multiSelection = true - - moveFeaturesToolbar.initializeMoveFeatures() - } + if (featureForm.selection.model.duplicateFeature(featureForm.selection.focusedLayer, featureForm.selection.focusedFeature)) { + displayToast(qsTr("Successfully duplicated feature")); + featureForm.selection.focusedItem = -1; + featureForm.state = "FeatureList"; + featureForm.multiSelection = true; + moveFeaturesToolbar.initializeMoveFeatures(); + } } onTransferClicked: { - transferDialog.show() + transferDialog.show(); } onDeleteClicked: { - var selectedFeatures = featureForm.selection.model.selectedFeatures - var selectedFeature = selectedFeatures && selectedFeatures.length > 0 ? selectedFeatures[0] : null - - if( - selectedFeature - && featureForm.selection.focusedLayer - && trackingModel.featureInTracking(featureForm.selection.focusedLayer, selectedFeature) - ) - { - displayToast( qsTr( "A number of features are being tracked, stop tracking to delete those" ) ) - } - else - { - deleteDialog.show() - } + var selectedFeatures = featureForm.selection.model.selectedFeatures; + var selectedFeature = selectedFeatures && selectedFeatures.length > 0 ? selectedFeatures[0] : null; + if (selectedFeature && featureForm.selection.focusedLayer && trackingModel.featureInTracking(featureForm.selection.focusedLayer, selectedFeature)) { + displayToast(qsTr("A number of features are being tracked, stop tracking to delete those")); + } else { + deleteDialog.show(); + } } onToggleMultiSelection: { - featureForm.selection.focusedItem = -1; - if ( featureForm.multiSelection ) { - if (featureForm.state == "ProcessingAlgorithmsList" || featureForm.state == "ProcessingAlgorithmForm") { - featureForm.state = "FeatureList" - } - - featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel - featureFormList.model.applyFeatureModel() - featureForm.selection.model.clearSelection(); - } else { - featureFormList.model.featureModel.modelMode = FeatureModel.MultiFeatureModel + featureForm.selection.focusedItem = -1; + if (featureForm.multiSelection) { + if (featureForm.state == "ProcessingAlgorithmsList" || featureForm.state == "ProcessingAlgorithmForm") { + featureForm.state = "FeatureList"; } - featureForm.multiSelection = !featureForm.multiSelection; - featureForm.focus = true; + featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel; + featureFormList.model.applyFeatureModel(); + featureForm.selection.model.clearSelection(); + } else { + featureFormList.model.featureModel.modelMode = FeatureModel.MultiFeatureModel; + } + featureForm.multiSelection = !featureForm.multiSelection; + featureForm.focus = true; } onMultiEditClicked: { - if (featureForm.selection.focusedItem == -1) { - // focus on the first selected item to grab its layer - featureForm.selection.focusedItem = 0; - } - featureForm.state = "FeatureFormEdit" + if (featureForm.selection.focusedItem == -1) { + // focus on the first selected item to grab its layer + featureForm.selection.focusedItem = 0; + } + featureForm.state = "FeatureFormEdit"; } onMultiMergeClicked: { - if( trackingModel.featureInTracking(featureForm.selection.focusedLayer, featureForm.selection.model.selectedFeatures) ) - { - displayToast( qsTr( "A number of features are being tracked, stop tracking to merge those" ) ) - } - else - { - mergeDialog.show() - } + if (trackingModel.featureInTracking(featureForm.selection.focusedLayer, featureForm.selection.model.selectedFeatures)) { + displayToast(qsTr("A number of features are being tracked, stop tracking to merge those")); + } else { + mergeDialog.show(); + } } onMultiMoveClicked: { - moveFeaturesToolbar.initializeMoveFeatures() + moveFeaturesToolbar.initializeMoveFeatures(); } onMultiProcessingClicked: { - featureForm.state = "ProcessingAlgorithmsList" + featureForm.state = "ProcessingAlgorithmsList"; } onProcessingRunClicked: { - processingAlgorithm.run() - featureForm.state = "FeatureList" + processingAlgorithm.run(); + featureForm.state = "FeatureList"; } CoordinateTransformer { - id: moveFeaturesTransformer - sourceCrs: mapCanvas.mapSettings.destinationCrs - destinationCrs: featureForm.selection.model.selectedLayer ? featureForm.selection.model.selectedLayer.crs : mapCanvas.mapSettings.destinationCrs + id: moveFeaturesTransformer + sourceCrs: mapCanvas.mapSettings.destinationCrs + destinationCrs: featureForm.selection.model.selectedLayer ? featureForm.selection.model.selectedLayer.crs : mapCanvas.mapSettings.destinationCrs } Connections { - target: moveFeaturesToolbar - - function onMoveConfirmed() { - moveFeaturesTransformer.sourcePosition = moveFeaturesToolbar.endPoint - var translateX = moveFeaturesTransformer.projectedPosition.x - var translateY = moveFeaturesTransformer.projectedPosition.y - moveFeaturesTransformer.sourcePosition = moveFeaturesToolbar.startPoint - translateX -= moveFeaturesTransformer.projectedPosition.x - translateY -= moveFeaturesTransformer.projectedPosition.y - featureForm.model.moveSelection(translateX, translateY) - } + target: moveFeaturesToolbar + + function onMoveConfirmed() { + moveFeaturesTransformer.sourcePosition = moveFeaturesToolbar.endPoint; + var translateX = moveFeaturesTransformer.projectedPosition.x; + var translateY = moveFeaturesTransformer.projectedPosition.y; + moveFeaturesTransformer.sourcePosition = moveFeaturesToolbar.startPoint; + translateX -= moveFeaturesTransformer.projectedPosition.x; + translateY -= moveFeaturesTransformer.projectedPosition.y; + featureForm.model.moveSelection(translateX, translateY); + } } onMultiDuplicateClicked: { - if (featureForm.multiSelection) { - if (featureForm.model.duplicateSelection()) { - displayToast( qsTr( "Successfully duplicated selected features, list updated to show newly-created features" ) ) - moveFeaturesToolbar.initializeMoveFeatures() - } + if (featureForm.multiSelection) { + if (featureForm.model.duplicateSelection()) { + displayToast(qsTr("Successfully duplicated selected features, list updated to show newly-created features")); + moveFeaturesToolbar.initializeMoveFeatures(); } + } } onMultiDeleteClicked: { - if( trackingModel.featuresInTracking(featureForm.selection.focusedLayer, featureForm.selection.model.selectedFeatures) ) - { - displayToast( qsTr( "A number of features are being tracked, stop tracking to delete those" ) ) - } - else - { - deleteDialog.show() - } + if (trackingModel.featuresInTracking(featureForm.selection.focusedLayer, featureForm.selection.model.selectedFeatures)) { + displayToast(qsTr("A number of features are being tracked, stop tracking to delete those")); + } else { + deleteDialog.show(); + } } } - Keys.onReleased: (event) => { - if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - // if visible overlays (such as embedded feature forms) are present, don't take over - if (Overlay.overlay && Overlay.overlay.visibleChildren.length > 1 || (Overlay.overlay.visibleChildren.length === 1 && !toast.visible)) - return; - - if (state != "FeatureList") { - if (featureListToolBar.state === "Edit") { - featureFormList.requestCancel(); - } else { - state = "FeatureList"; - } - } else { - if (featureForm.multiSelection) { - featureForm.selection.model.clearSelection(); - featureForm.selection.focusedItem = -1 - featureForm.multiSelection = false; - } else { - state = "Hidden"; - } - } - event.accepted = true; + Keys.onReleased: event => { + if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { + // if visible overlays (such as embedded feature forms) are present, don't take over + if (Overlay.overlay && Overlay.overlay.visibleChildren.length > 1 || (Overlay.overlay.visibleChildren.length === 1 && !toast.visible)) + return; + if (state != "FeatureList") { + if (featureListToolBar.state === "Edit") { + featureFormList.requestCancel(); + } else { + state = "FeatureList"; + } + } else { + if (featureForm.multiSelection) { + featureForm.selection.model.clearSelection(); + featureForm.selection.focusedItem = -1; + featureForm.multiSelection = false; + } else { + state = "Hidden"; + } } + event.accepted = true; + } } - Behavior on width { + Behavior on width { PropertyAnimation { duration: parent.width > parent.height ? 250 : 0 easing.type: Easing.OutQuart onRunningChanged: { - if ( running ) - mapCanvasMap.freeze('formresize') + if (running) + mapCanvasMap.freeze('formresize'); else - mapCanvasMap.unfreeze('formresize') + mapCanvasMap.unfreeze('formresize'); } } } - Behavior on height { + Behavior on height { PropertyAnimation { duration: parent.width < parent.height ? 250 : 0 easing.type: Easing.OutQuart onRunningChanged: { - if ( running ) - mapCanvasMap.freeze('formresize') + if (running) + mapCanvasMap.freeze('formresize'); else - mapCanvasMap.unfreeze('formresize') + mapCanvasMap.unfreeze('formresize'); } } } - Behavior on anchors.rightMargin { + Behavior on anchors.rightMargin { PropertyAnimation { duration: 250 easing.type: Easing.OutQuart onRunningChanged: { - if ( running ) - mapCanvasMap.freeze('formresize') + if (running) + mapCanvasMap.freeze('formresize'); else - mapCanvasMap.unfreeze('formresize') + mapCanvasMap.unfreeze('formresize'); } } } - Behavior on anchors.bottomMargin { + Behavior on anchors.bottomMargin { PropertyAnimation { duration: 250 easing.type: Easing.OutQuart onRunningChanged: { - if ( running ) - mapCanvasMap.freeze('formresize') + if (running) + mapCanvasMap.freeze('formresize'); else - mapCanvasMap.unfreeze('formresize') + mapCanvasMap.unfreeze('formresize'); } } } @@ -800,48 +763,43 @@ Rectangle { target: globalFeaturesList.model function onRowsInserted(parent, first, VectorLayerStatic) { - if ( model.rowCount() > 0 ) { - state = "FeatureList" + if (model.rowCount() > 0) { + state = "FeatureList"; } else { - showMessage( qsTr('No feature at this position') ) - state = "Hidden" + showMessage(qsTr('No feature at this position')); + state = "Hidden"; } } function onCountChanged() { - if ( model.rowCount() === 0 ) { - state = "Hidden" + if (model.rowCount() === 0) { + state = "Hidden"; } } function onModelReset() { - if ( model.rowCount() > 0 ) { - state = "FeatureList" + if (model.rowCount() > 0) { + state = "FeatureList"; } else { - state = "Hidden" + state = "Hidden"; } } } - function show() - { - props.isVisible = true - focus = true + function show() { + props.isVisible = true; + focus = true; } - function hide() - { + function hide() { props.isVisible = false; focus = false; - fullScreenView = qfieldSettings.fullScreenIdentifyView; - - if ( !featureForm.canvasOperationRequested ) - { + if (!featureForm.canvasOperationRequested) { featureForm.multiSelection = false; featureFormList.model.featureModel.modelMode = FeatureModel.SingleFeatureModel; featureForm.selection.clear(); - if ( featureForm.selection.model ) { + if (featureForm.selection.model) { featureForm.selection.model.clearSelection(); } model.clear(); @@ -860,43 +818,40 @@ Rectangle { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Merge feature(s)" ) + title: qsTr("Merge feature(s)") Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( "Should the %n feature(s) selected really be merge?\n\nThe features geometries will be combined into feature '%1', which will keep its attributes.", "0", mergeDialog.selectedCount ).arg( mergeDialog.featureDisplayName ) + text: qsTr("Should the %n feature(s) selected really be merge?\n\nThe features geometries will be combined into feature '%1', which will keep its attributes.", "0", mergeDialog.selectedCount).arg(mergeDialog.featureDisplayName) } standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - if ( isMerged ) { + if (isMerged) { return; } - - isMerged = featureForm.model.mergeSelection() - - if ( isMerged ) { - displayToast( qsTr( "Successfully merged %n feature(s)", "", selectedCount ) ); + isMerged = featureForm.model.mergeSelection(); + if (isMerged) { + displayToast(qsTr("Successfully merged %n feature(s)", "", selectedCount)); } else { - displayToast( qsTr( "Failed to merge %n feature(s)", "", selectedCount ), 'warning' ); + displayToast(qsTr("Failed to merge %n feature(s)", "", selectedCount), 'warning'); } - - visible = false + visible = false; featureForm.focus = true; } onRejected: { - visible = false + visible = false; featureForm.focus = true; } function show() { - this.isMerged = false; - this.selectedCount = featureForm.model.selectedCount; - this.featureDisplayName = FeatureUtils.displayName(featureForm.selection.focusedLayer,featureForm.model.selectedFeatures[0]) - this.open(); + this.isMerged = false; + this.selectedCount = featureForm.model.selectedCount; + this.featureDisplayName = FeatureUtils.displayName(featureForm.selection.focusedLayer, featureForm.model.selectedFeatures[0]); + this.open(); } } @@ -908,10 +863,10 @@ Rectangle { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Transfer Feature Attributes" ) + title: qsTr("Transfer Feature Attributes") Column { width: childrenRect.width @@ -948,23 +903,23 @@ Rectangle { standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - let feature = transferFeatureListModel.getFeatureById(transferComboBox.currentValue) + let feature = transferFeatureListModel.getFeatureById(transferComboBox.currentValue); if (featureFormList.model.featureModel.updateAttributesFromFeature(feature)) { - featureFormList.model.featureModel.save() - mainWindow.displayToast(qsTr('Feature attributes transferred')) + featureFormList.model.featureModel.save(); + mainWindow.displayToast(qsTr('Feature attributes transferred')); } else { - mainWindow.displayToast(qsTr('No feature attributes were transferred')) + mainWindow.displayToast(qsTr('No feature attributes were transferred')); } - transferFeatureListModel.currentLayer = null + transferFeatureListModel.currentLayer = null; } onRejected: { - transferFeatureListModel.currentLayer = null + transferFeatureListModel.currentLayer = null; } function show() { - transferFeatureListModel.displayValueField = featureFormList.model.featureModel.currentLayer.displayExpression - transferFeatureListModel.currentLayer = featureFormList.model.featureModel.currentLayer + transferFeatureListModel.displayValueField = featureFormList.model.featureModel.currentLayer.displayExpression; + transferFeatureListModel.currentLayer = featureFormList.model.featureModel.currentLayer; this.open(); } } @@ -980,52 +935,49 @@ Rectangle { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Delete feature(s)" ) + title: qsTr("Delete feature(s)") Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( "Should the %n feature(s) selected really be deleted?", "0", deleteDialog.selectedCount ) + text: qsTr("Should the %n feature(s) selected really be deleted?", "0", deleteDialog.selectedCount) } standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - if ( isDeleted ) { + if (isDeleted) { return; } - - if ( featureForm.multiSelection ) { - isDeleted = featureForm.model.deleteSelection() + if (featureForm.multiSelection) { + isDeleted = featureForm.model.deleteSelection(); } else { - isDeleted = featureForm.selection.model.deleteFeature(featureForm.selection.focusedLayer,featureForm.selection.focusedFeature.id) + isDeleted = featureForm.selection.model.deleteFeature(featureForm.selection.focusedLayer, featureForm.selection.focusedFeature.id); } - - if ( isDeleted ) { - displayToast( qsTr( "Successfully deleted %n feature(s)", "", selectedCount ) ); - if ( !featureForm.multiSelection ) { - featureForm.selection.focusedItem = -1 - featureForm.state = "FeatureList" + if (isDeleted) { + displayToast(qsTr("Successfully deleted %n feature(s)", "", selectedCount)); + if (!featureForm.multiSelection) { + featureForm.selection.focusedItem = -1; + featureForm.state = "FeatureList"; } - if ( featureForm.selection.model.count === 0 ) + if (featureForm.selection.model.count === 0) featureForm.state = "Hidden"; } else { - displayToast( qsTr( "Failed to delete %n feature(s)", "", selectedCount ), 'error' ); + displayToast(qsTr("Failed to delete %n feature(s)", "", selectedCount), 'error'); } - - visible = false + visible = false; featureForm.focus = true; } onRejected: { - visible = false + visible = false; featureForm.focus = true; } function show() { - this.isDeleted = false; - this.selectedCount = featureForm.multiSelection ? featureForm.model.selectedCount : 1; - this.open(); + this.isDeleted = false; + this.selectedCount = featureForm.multiSelection ? featureForm.model.selectedCount : 1; + this.open(); } } @@ -1035,14 +987,14 @@ Rectangle { target: qgisProject function onLayersWillBeRemoved(layerIds) { - if( state != "FeatureList" ) { - if( featureListToolBar.state === "Edit"){ - featureForm.state = "FeatureForm" - displayToast( qsTr( "Changes discarded" ), 'warning' ) - } - state = "FeatureList" + if (state != "FeatureList") { + if (featureListToolBar.state === "Edit") { + featureForm.state = "FeatureForm"; + displayToast(qsTr("Changes discarded"), 'warning'); } - state = "Hidden" + state = "FeatureList"; + } + state = "Hidden"; } } } diff --git a/src/qml/FeatureListSelectionHighlight.qml b/src/qml/FeatureListSelectionHighlight.qml index d9d5bc332d..bffa80b510 100644 --- a/src/qml/FeatureListSelectionHighlight.qml +++ b/src/qml/FeatureListSelectionHighlight.qml @@ -1,5 +1,4 @@ import QtQuick 2.14 - import org.qgis 1.0 import org.qfield 1.0 @@ -21,13 +20,13 @@ Repeater { geometryWrapper.qgsGeometry: model.geometry geometryWrapper.crs: model.crs - visible: featureListSelectionHighlight.visible && ( !showSelectedOnly || model.featureSelected ) + visible: featureListSelectionHighlight.visible && (!showSelectedOnly || model.featureSelected) color: model.featureSelected ? featureListSelectionHighlight.selectedColor : selectionModel.model.selectedCount === 0 && selectionModel && model.index === selectionModel.focusedItem ? featureListSelectionHighlight.focusedColor : featureListSelectionHighlight.color z: model.index === selectionModel.focusedItem ? 1 : 0 transform: Translate { - x: featureListSelectionHighlight.translateX - y: -featureListSelectionHighlight.translateY + x: featureListSelectionHighlight.translateX + y: -featureListSelectionHighlight.translateY } } } diff --git a/src/qml/GeometryEditorsToolbar.qml b/src/qml/GeometryEditorsToolbar.qml index 96a835266c..fe6c308dc6 100644 --- a/src/qml/GeometryEditorsToolbar.qml +++ b/src/qml/GeometryEditorsToolbar.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQml.Models 2.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 /** @@ -24,7 +22,6 @@ It can optionally implement the functions: * canvasLongPressed(point) These functions must return true if they catch the event */ - VisibilityFadingRow { id: geometryEditorsToolbar @@ -45,63 +42,62 @@ VisibilityFadingRow { } Component.onCompleted: { - editors.addEditor(qsTr("Vertex Tool"), "ic_vertex_tool_white_24dp", "geometryeditors/VertexEditor.qml") - editors.addEditor(qsTr("Split Tool"), "ic_split_tool_white_24dp", "geometryeditors/SplitFeature.qml", GeometryEditorsModelSingleton.Line | GeometryEditorsModelSingleton.Polygon) - editors.addEditor(qsTr("Reshape Tool"), "ic_reshape_tool_white_24dp", "geometryeditors/Reshape.qml", GeometryEditorsModelSingleton.Line | GeometryEditorsModelSingleton.Polygon) - editors.addEditor(qsTr("Erase Tool"), "ic_erase_tool_white_24dp", "geometryeditors/Erase.qml", GeometryEditorsModelSingleton.Line | GeometryEditorsModelSingleton.Polygon) - editors.addEditor(qsTr("Fill Ring Tool"), "ic_ring_tool_white_24dp", "geometryeditors/FillRing.qml", GeometryEditorsModelSingleton.Polygon) + editors.addEditor(qsTr("Vertex Tool"), "ic_vertex_tool_white_24dp", "geometryeditors/VertexEditor.qml"); + editors.addEditor(qsTr("Split Tool"), "ic_split_tool_white_24dp", "geometryeditors/SplitFeature.qml", GeometryEditorsModelSingleton.Line | GeometryEditorsModelSingleton.Polygon); + editors.addEditor(qsTr("Reshape Tool"), "ic_reshape_tool_white_24dp", "geometryeditors/Reshape.qml", GeometryEditorsModelSingleton.Line | GeometryEditorsModelSingleton.Polygon); + editors.addEditor(qsTr("Erase Tool"), "ic_erase_tool_white_24dp", "geometryeditors/Erase.qml", GeometryEditorsModelSingleton.Line | GeometryEditorsModelSingleton.Polygon); + editors.addEditor(qsTr("Fill Ring Tool"), "ic_ring_tool_white_24dp", "geometryeditors/FillRing.qml", GeometryEditorsModelSingleton.Polygon); } function init() { - var lastUsed = settings.value("/QField/GeometryEditorLastUsed", -1) - if (lastUsed >= 0 && lastUsed < editors.rowCount()) - { - selectorRow.stateVisible = false - var toolbarQml = editors.data(editors.index(lastUsed, 0), GeometryEditorsModelSingleton.ToolbarRole) - var iconPath = editors.data(editors.index(lastUsed, 0), GeometryEditorsModelSingleton.IconPathRole) - var name = editors.data(editors.index(lastUsed, 0), GeometryEditorsModelSingleton.NameRole) - geometryEditorsToolbar.image = Theme.getThemeVectorIcon(iconPath) - toolbarRow.load(toolbarQml, iconPath, name) + var lastUsed = settings.value("/QField/GeometryEditorLastUsed", -1); + if (lastUsed >= 0 && lastUsed < editors.rowCount()) { + selectorRow.stateVisible = false; + var toolbarQml = editors.data(editors.index(lastUsed, 0), GeometryEditorsModelSingleton.ToolbarRole); + var iconPath = editors.data(editors.index(lastUsed, 0), GeometryEditorsModelSingleton.IconPathRole); + var name = editors.data(editors.index(lastUsed, 0), GeometryEditorsModelSingleton.NameRole); + geometryEditorsToolbar.image = Theme.getThemeVectorIcon(iconPath); + toolbarRow.load(toolbarQml, iconPath, name); } } function cancelEditors() { if (toolbarRow.item) { - toolbarRow.item.cancel() + toolbarRow.item.cancel(); } - featureModel.vertexModel.clear() + featureModel.vertexModel.clear(); } // returns true if handled function canvasClicked(point, type) { - if ( toolbarRow.item && toolbarRow.visible ) - return toolbarRow.item.canvasClicked(point, type) + if (toolbarRow.item && toolbarRow.visible) + return toolbarRow.item.canvasClicked(point, type); else - return false + return false; } // returns true if handled function canvasLongPressed(point, type) { - if ( toolbarRow.item && toolbarRow.visible ) - return toolbarRow.item.canvasLongPressed(point, type) + if (toolbarRow.item && toolbarRow.visible) + return toolbarRow.item.canvasLongPressed(point, type); else - return false + return false; } // returns true if handled or not defined function canvasFreehandBegin() { - if ( toolbarRow.item && toolbarRow.visible) - return toolbarRow.item.canvasFreehandBegin ? toolbarRow.item.canvasFreehandBegin() : true + if (toolbarRow.item && toolbarRow.visible) + return toolbarRow.item.canvasFreehandBegin ? toolbarRow.item.canvasFreehandBegin() : true; else - return false + return false; } // returns true if handled or not defined function canvasFreehandEnd() { - if ( toolbarRow.item && toolbarRow.visible) - return toolbarRow.item.canvasFreehandEnd ? toolbarRow.item.canvasFreehandEnd() : true + if (toolbarRow.item && toolbarRow.visible) + return toolbarRow.item.canvasFreehandEnd ? toolbarRow.item.canvasFreehandEnd() : true; else - return false + return false; } VisibilityFadingRow { @@ -120,14 +116,12 @@ VisibilityFadingRow { onClicked: { // close current tool if (toolbarRow.item) { - toolbarRow.item.cancel() + toolbarRow.item.cancel(); } - - selectorRow.stateVisible = false - geometryEditorsToolbar.image = Theme.getThemeVectorIcon(iconPath) - toolbarRow.load(toolbar, iconPath, name) - - settings.setValue("/QField/GeometryEditorLastUsed", index) + selectorRow.stateVisible = false; + geometryEditorsToolbar.image = Theme.getThemeVectorIcon(iconPath); + toolbarRow.load(toolbar, iconPath, name); + settings.setValue("/QField/GeometryEditorLastUsed", index); } } } @@ -138,35 +132,34 @@ VisibilityFadingRow { width: item && item.stateVisible ? item.implicitWidth : 0 - function load(qmlSource, iconPath, name){ - source = qmlSource - item.init(geometryEditorsToolbar.featureModel, geometryEditorsToolbar.mapSettings, geometryEditorsToolbar.editorRubberbandModel, geometryEditorsToolbar.editorRenderer) - if (toolbarRow.item.screenHovering !== undefined) - toolbarRow.item.screenHovering = geometryEditorsToolbar.screenHovering - if (toolbarRow.item.vertexRubberbandVisible !== undefined) - vertexRubberband.isVisible = toolbarRow.item.vertexRubberbandVisible - else - vertexRubberband.isVisible = false - - toolbarRow.item.stateVisible = true - displayToast(name) + function load(qmlSource, iconPath, name) { + source = qmlSource; + item.init(geometryEditorsToolbar.featureModel, geometryEditorsToolbar.mapSettings, geometryEditorsToolbar.editorRubberbandModel, geometryEditorsToolbar.editorRenderer); + if (toolbarRow.item.screenHovering !== undefined) + toolbarRow.item.screenHovering = geometryEditorsToolbar.screenHovering; + if (toolbarRow.item.vertexRubberbandVisible !== undefined) + vertexRubberband.isVisible = toolbarRow.item.vertexRubberbandVisible; + else + vertexRubberband.isVisible = false; + toolbarRow.item.stateVisible = true; + displayToast(name); } onSourceChanged: { - geometryEditorsToolbar.editorChanged() + geometryEditorsToolbar.editorChanged(); } } onScreenHoveringChanged: { if (toolbarRow.item && toolbarRow.item.screenHovering !== undefined) - toolbarRow.item.screenHovering = geometryEditorsToolbar.screenHovering + toolbarRow.item.screenHovering = geometryEditorsToolbar.screenHovering; } Connections { target: toolbarRow.item function onFinished() { - featureModel.vertexModel.clear() + featureModel.vertexModel.clear(); } } @@ -174,15 +167,15 @@ VisibilityFadingRow { id: activeToolButton iconSource: Theme.getThemeIcon("more_horiz") round: true - visible: !selectorRow.stateVisible && !( toolbarRow.item && toolbarRow.item.stateVisible && toolbarRow.item.blocking ) + visible: !selectorRow.stateVisible && !(toolbarRow.item && toolbarRow.item.stateVisible && toolbarRow.item.blocking) bgcolor: Theme.mainColor onClicked: { - toolbarRow.item.cancel() - toolbarRow.source = '' - vertexRubberband.isVisible = false - selectorRow.stateVisible = true - image = Theme.getThemeIcon("ic_edit_geometry_white") - settings.setValue("/QField/GeometryEditorLastUsed", -1) + toolbarRow.item.cancel(); + toolbarRow.source = ''; + vertexRubberband.isVisible = false; + selectorRow.stateVisible = true; + image = Theme.getThemeIcon("ic_edit_geometry_white"); + settings.setValue("/QField/GeometryEditorLastUsed", -1); } } } diff --git a/src/qml/GeometryHighlighter.qml b/src/qml/GeometryHighlighter.qml index 8107d380a8..5901e27d75 100644 --- a/src/qml/GeometryHighlighter.qml +++ b/src/qml/GeometryHighlighter.qml @@ -1,5 +1,4 @@ import QtQuick 2.14 - import org.qfield 1.0 Item { @@ -15,20 +14,20 @@ Item { alwaysRunToEnd: true OpacityAnimator { - target: geometryHighlighter; - from: 1; - to: 0; + target: geometryHighlighter + from: 1 + to: 0 duration: 500 } OpacityAnimator { - target: geometryHighlighter; - from: 0; - to: 1; + target: geometryHighlighter + from: 0 + to: 1 duration: 500 } onFinished: { - geometryHighlighter.geometryWrapper.clear() + geometryHighlighter.geometryWrapper.clear(); } } @@ -41,7 +40,7 @@ Item { target: geometryRenderer.geometryWrapper function onQgsGeometryChanged() { - timer.restart() + timer.restart(); } } } diff --git a/src/qml/GeometryRenderer.qml b/src/qml/GeometryRenderer.qml index da26e0cead..3f2c24143a 100644 --- a/src/qml/GeometryRenderer.qml +++ b/src/qml/GeometryRenderer.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 - import org.qgis 1.0 import org.qfield 1.0 - Item { id: geometryRenderer property MapSettings mapSettings @@ -21,13 +19,11 @@ Item { target: geometryWrapper function onQgsGeometryChanged() { - geometryComponent.sourceComponent = undefined + geometryComponent.sourceComponent = undefined; if (geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point) { - geometryComponent.sourceComponent = pointHighlight - } - else - { - geometryComponent.sourceComponent = linePolygonHighlight + geometryComponent.sourceComponent = pointHighlight; + } else { + geometryComponent.sourceComponent = linePolygonHighlight; } } } @@ -66,8 +62,8 @@ Item { mapPoint: _ct.projectedPosition } - x: mapToScreenPosition.screenPoint.x - width/2 - y: mapToScreenPosition.screenPoint.y - width/2 + x: mapToScreenPosition.screenPoint.x - width / 2 + y: mapToScreenPosition.screenPoint.y - width / 2 color: Qt.hsla(geometryRenderer.color.hslHue, geometryRenderer.color.hslSaturation, geometryRenderer.color.hslLightness, 0.5) width: geometryRenderer.pointSize diff --git a/src/qml/InformationDrawer.qml b/src/qml/InformationDrawer.qml index cd47e81228..fb965e26bf 100644 --- a/src/qml/InformationDrawer.qml +++ b/src/qml/InformationDrawer.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import org.qfield 1.0 import Theme 1.0 @@ -13,7 +12,7 @@ Item { width: parent.width height: mainContent.height + (mainContent.height > 0 ? 5 : 0) + mainWindow.sceneBottomMargin - Behavior on height { + Behavior on height { PropertyAnimation { easing.type: Easing.OutQuart } @@ -33,12 +32,7 @@ Item { property alias positioningPreciseView: positioningPreciseView property PositioningSettings positioningSettings property Positioning positionSource - property bool positioningPreciseEnabled: !elevationProfile.visible - && !isNaN(navigation.distance) - && navigation.isActive - && (positioningSettings.alwaysShowPreciseView - || ( positioningPreciseView.hasAcceptableAccuracy - && positioningPreciseView.projectDistance < positioningPreciseView.precision )) + property bool positioningPreciseEnabled: !elevationProfile.visible && !isNaN(navigation.distance) && navigation.isActive && (positioningSettings.alwaysShowPreciseView || (positioningPreciseView.hasAcceptableAccuracy && positioningPreciseView.projectDistance < positioningPreciseView.precision)) // ElevationProfile property alias elevationProfile: elevationProfile diff --git a/src/qml/LayerLoginDialog.qml b/src/qml/LayerLoginDialog.qml index b8c9ae68ea..1bc556a14d 100644 --- a/src/qml/LayerLoginDialog.qml +++ b/src/qml/LayerLoginDialog.qml @@ -1,13 +1,12 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 Page { signal enter(string usr, string pw) - signal cancel() + signal cancel property string credentialTitle property var inCancelation @@ -18,7 +17,7 @@ Page { showApplyButton: false showCancelButton: true onCancel: { - parent.cancel() + parent.cancel(); } } @@ -113,10 +112,10 @@ Page { inputMethodHints: Qt.ImhHiddenText | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase horizontalAlignment: Text.AlignHCenter onReturnPressed: { - _processAuth() + _processAuth(); } Keys.onEnterPressed: { - _processAuth() + _processAuth(); } } @@ -143,13 +142,13 @@ Page { onVisibleChanged: { if (visible) { - username.forceActiveFocus() + username.forceActiveFocus(); } } function _processAuth() { - enter(username.text, password.text) - username.text = '' - password.text = '' + enter(username.text, password.text); + username.text = ''; + password.text = ''; } } diff --git a/src/qml/LayerTreeItemProperties.qml b/src/qml/LayerTreeItemProperties.qml index a138018cab..113c4e9afd 100644 --- a/src/qml/LayerTreeItemProperties.qml +++ b/src/qml/LayerTreeItemProperties.qml @@ -1,10 +1,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Popup { @@ -30,34 +28,27 @@ Popup { padding: 0 onClosed: { - index = undefined + index = undefined; } onIndexChanged: { if (index === undefined) - return - - updateTitle() - updateCredits() - - itemVisibleCheckBox.checked = layerTree.data(index, FlatLayerTreeModel.Visible) - itemLabelsVisibleCheckBox.checked = layerTree.data(index, FlatLayerTreeModel.LabelsVisible) - - expandCheckBox.text = layerTree.data( index, FlatLayerTreeModel.Type ) === 'group' ? qsTr('Expand group') : qsTr('Expand legend item') - expandCheckBox.checked = !layerTree.data(index, FlatLayerTreeModel.IsCollapsed) - - reloadDataButtonVisible = layerTree.data(index, FlatLayerTreeModel.CanReloadData) - zoomToButtonVisible = layerTree.data(index, FlatLayerTreeModel.HasSpatialExtent) - showFeaturesListButtonVisible = isShowFeaturesListButtonVisible() - showVisibleFeaturesListDropdownVisible = isShowVisibleFeaturesListDropdownVisible() - - trackingButtonVisible = isTrackingButtonVisible() - trackingButtonText = trackingModel.layerInTracking(layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer)) - ? qsTr('Stop tracking') - : qsTr('Setup tracking') + return; + updateTitle(); + updateCredits(); + itemVisibleCheckBox.checked = layerTree.data(index, FlatLayerTreeModel.Visible); + itemLabelsVisibleCheckBox.checked = layerTree.data(index, FlatLayerTreeModel.LabelsVisible); + expandCheckBox.text = layerTree.data(index, FlatLayerTreeModel.Type) === 'group' ? qsTr('Expand group') : qsTr('Expand legend item'); + expandCheckBox.checked = !layerTree.data(index, FlatLayerTreeModel.IsCollapsed); + reloadDataButtonVisible = layerTree.data(index, FlatLayerTreeModel.CanReloadData); + zoomToButtonVisible = layerTree.data(index, FlatLayerTreeModel.HasSpatialExtent); + showFeaturesListButtonVisible = isShowFeaturesListButtonVisible(); + showVisibleFeaturesListDropdownVisible = isShowVisibleFeaturesListDropdownVisible(); + trackingButtonVisible = isTrackingButtonVisible(); + trackingButtonText = trackingModel.layerInTracking(layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer)) ? qsTr('Stop tracking') : qsTr('Setup tracking'); // the layer tree model returns -1 for items that do not support the opacity setting - opacitySliderVisible = layerTree.data(index, FlatLayerTreeModel.Opacity) > -1 + opacitySliderVisible = layerTree.data(index, FlatLayerTreeModel.Opacity) > -1; } Page { @@ -85,14 +76,14 @@ Popup { visible: reloadDataButtonVisible bgcolor: "transparent" - iconSource: Theme.getThemeVectorIcon( 'refresh_24dp' ) + iconSource: Theme.getThemeVectorIcon('refresh_24dp') iconColor: Theme.mainTextColor onClicked: { - layerTree.data(index, FlatLayerTreeModel.MapLayerPointer).reload() - close() - dashBoard.visible = false - displayToast(qsTr('Reload of layer %1 triggered').arg(layerTree.data(index, Qt.DisplayName))) + layerTree.data(index, FlatLayerTreeModel.MapLayerPointer).reload(); + close(); + dashBoard.visible = false; + displayToast(qsTr('Reload of layer %1 triggered').arg(layerTree.data(index, Qt.DisplayName))); } } } @@ -124,7 +115,7 @@ Popup { wrapMode: Text.WordWrap textFormat: Text.RichText - text: qsTr('This layer is invalid. This might be due to a network issue, a missing file or a misconfiguration of the project.') + text: qsTr('This layer is invalid. This might be due to a network issue, a missing file or a misconfiguration of the project.') font: Theme.tipFont color: Theme.errorColor } @@ -140,7 +131,7 @@ Popup { onClicked: { layerTree.setData(index, checkState === Qt.Unchecked, FlatLayerTreeModel.IsCollapsed); - close() + close(); } } @@ -181,7 +172,7 @@ Popup { onClicked: { layerTree.setData(index, checkState === Qt.Checked, FlatLayerTreeModel.LabelsVisible); - projectInfo.saveLayerStyle(layerTree.data(index, FlatLayerTreeModel.MapLayerPointer)) + projectInfo.saveLayerStyle(layerTree.data(index, FlatLayerTreeModel.MapLayerPointer)); close(); } } @@ -191,7 +182,7 @@ Popup { Layout.fillWidth: true Layout.topMargin: 4 - Layout.bottomMargin:4 + Layout.bottomMargin: 4 spacing: 4 visible: opacitySliderVisible @@ -221,9 +212,8 @@ Popup { } QfSlider { - Layout.fillWidth: true - id: slider + Layout.fillWidth: true value: index !== undefined ? layerTree.data(index, FlatLayerTreeModel.Opacity) * 100 : 0 from: 0 to: 100 @@ -232,8 +222,8 @@ Popup { height: 40 onMoved: function () { - layerTree.setData(index, value / 100, FlatLayerTreeModel.Opacity) - projectInfo.saveLayerStyle(layerTree.data(index, FlatLayerTreeModel.MapLayerPointer)) + layerTree.setData(index, value / 100, FlatLayerTreeModel.Opacity); + projectInfo.saveLayerStyle(layerTree.data(index, FlatLayerTreeModel.MapLayerPointer)); } } } @@ -243,18 +233,14 @@ Popup { id: zoomToButton Layout.fillWidth: true Layout.topMargin: 5 - text: index ? layerTree.data( index, FlatLayerTreeModel.Type ) === 'group' - ? qsTr('Zoom to group') - : layerTree.data( index, FlatLayerTreeModel.Type ) === 'legend' - ? qsTr('Zoom to parent layer') - : qsTr('Zoom to layer') : '' + text: index ? layerTree.data(index, FlatLayerTreeModel.Type) === 'group' ? qsTr('Zoom to group') : layerTree.data(index, FlatLayerTreeModel.Type) === 'legend' ? qsTr('Zoom to parent layer') : qsTr('Zoom to layer') : '' visible: zoomToButtonVisible - icon.source: Theme.getThemeVectorIcon( 'zoom_out_map_24dp' ) + icon.source: Theme.getThemeVectorIcon('zoom_out_map_24dp') onClicked: { mapCanvas.mapSettings.extent = layerTree.nodeExtent(index, mapCanvas.mapSettings); - close() - dashBoard.visible = false + close(); + dashBoard.visible = false; } } @@ -265,26 +251,25 @@ Popup { dropdown: showVisibleFeaturesListDropdownVisible text: qsTr('Show features list') visible: showFeaturesListButtonVisible - icon.source: Theme.getThemeVectorIcon( 'ic_list_black_24dp' ) + icon.source: Theme.getThemeVectorIcon('ic_list_black_24dp') onClicked: { - if ( parseInt(layerTree.data(index, FlatLayerTreeModel.FeatureCount)) === 0 ) { - displayToast( qsTr( "The layer has no features" ) ) + if (parseInt(layerTree.data(index, FlatLayerTreeModel.FeatureCount)) === 0) { + displayToast(qsTr("The layer has no features")); } else { - var vl = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer) - var filter = layerTree.data(index, FlatLayerTreeModel.FilterExpression) - featureForm.model.setFeatures(vl, filter) + var vl = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer); + var filter = layerTree.data(index, FlatLayerTreeModel.FilterExpression); + featureForm.model.setFeatures(vl, filter); if (layerTree.data(index, FlatLayerTreeModel.HasSpatialExtent)) { - mapCanvas.mapSettings.extent = layerTree.nodeExtent(index, mapCanvas.mapSettings) + mapCanvas.mapSettings.extent = layerTree.nodeExtent(index, mapCanvas.mapSettings); } } - - close() - dashBoard.visible = false + close(); + dashBoard.visible = false; } onDropdownClicked: { - showFeaturesMenu.popup(showFeaturesList.width - showFeaturesMenu.width + 10, showFeaturesList.y + 10) + showFeaturesMenu.popup(showFeaturesList.width - showFeaturesMenu.width + 10, showFeaturesList.y + 10); } } @@ -294,32 +279,31 @@ Popup { Layout.topMargin: 5 text: trackingButtonText visible: trackingButtonVisible - icon.source: Theme.getThemeVectorIcon( 'directions_walk_24dp' ) + icon.source: Theme.getThemeVectorIcon('directions_walk_24dp') onClicked: { - var layer = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer) - close() - + var layer = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer); + close(); if (trackingModel.layerInTracking(layer)) { trackingModel.stopTracker(layer); - displayToast(qsTr('Track on layer %1 stopped').arg(layer.name)) + displayToast(qsTr('Track on layer %1 stopped').arg(layer.name)); } else { var tracker; - var idx = projectInfo.restoreTracker(layer) + var idx = projectInfo.restoreTracker(layer); if (idx.valid) { - tracker = trackings.itemAt(idx.row).tracker + tracker = trackings.itemAt(idx.row).tracker; } else { - idx = trackingModel.createTracker(layer) - tracker = trackings.itemAt(idx.row).tracker - tracker.visible = itemVisibleCheckBox.checked - tracker.minimumDistance = positioningSettings.trackerMinimumDistanceConstraint ? positioningSettings.trackerMinimumDistance : 0 - tracker.timeInterval = positioningSettings.trackerTimeIntervalConstraint ? positioningSettings.trackerTimeInterval : 0 - tracker.maximumDistance = positioningSettings.trackerErroneousDistanceSafeguard ? positioningSettings.trackerErroneousDistance : 0 - tracker.sensorCapture = positioningSettings.trackerSensorCaptureConstraint - tracker.conjunction = positioningSettings.trackerMeetAllConstraints - tracker.measureType = positioningSettings.trackerMeasureType + idx = trackingModel.createTracker(layer); + tracker = trackings.itemAt(idx.row).tracker; + tracker.visible = itemVisibleCheckBox.checked; + tracker.minimumDistance = positioningSettings.trackerMinimumDistanceConstraint ? positioningSettings.trackerMinimumDistance : 0; + tracker.timeInterval = positioningSettings.trackerTimeIntervalConstraint ? positioningSettings.trackerTimeInterval : 0; + tracker.maximumDistance = positioningSettings.trackerErroneousDistanceSafeguard ? positioningSettings.trackerErroneousDistance : 0; + tracker.sensorCapture = positioningSettings.trackerSensorCaptureConstraint; + tracker.conjunction = positioningSettings.trackerMeetAllConstraints; + tracker.measureType = positioningSettings.trackerMeasureType; } - trackingModel.requestTrackingSetup(layer) + trackingModel.requestTrackingSetup(layer); } } } @@ -346,10 +330,10 @@ Popup { MouseArea { anchors.fill: parent onClicked: { - if ( lockText.isReadOnly ) - displayToast(qsTr('This layer is configured as "Read-Only" which disables adding, deleting and editing features.')) + if (lockText.isReadOnly) + displayToast(qsTr('This layer is configured as "Read-Only" which disables adding, deleting and editing features.')); else - displayToast(qsTr('This layer is configured as "Lock Geometries" which disables adding and deleting features, as well as modifying the geometries of existing features.')) + displayToast(qsTr('This layer is configured as "Lock Geometries" which disables adding and deleting features, as well as modifying the geometries of existing features.')); } } } @@ -365,7 +349,9 @@ Popup { font.italic: true color: Theme.secondaryTextColor - onLinkActivated: (link) => { Qt.openUrlExternally(link) } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } } } } @@ -373,7 +359,7 @@ Popup { Menu { id: showFeaturesMenu - title: qsTr( "Show Features Menu" ) + title: qsTr("Show Features Menu") width: { var result = 0; @@ -394,16 +380,15 @@ Popup { leftPadding: Theme.menuItemLeftPadding onTriggered: { - if ( parseInt(layerTree.data(index, FlatLayerTreeModel.FeatureCount)) === 0 ) { - displayToast( qsTr( "The layer has no features" ) ) + if (parseInt(layerTree.data(index, FlatLayerTreeModel.FeatureCount)) === 0) { + displayToast(qsTr("The layer has no features")); } else { - var vl = layerTree.data( index, FlatLayerTreeModel.VectorLayerPointer ) - var filter = layerTree.data(index, FlatLayerTreeModel.FilterExpression) - featureForm.model.setFeatures( vl, filter, mapCanvas.mapSettings.visibleExtent ) + var vl = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer); + var filter = layerTree.data(index, FlatLayerTreeModel.FilterExpression); + featureForm.model.setFeatures(vl, filter, mapCanvas.mapSettings.visibleExtent); } - - close() - dashBoard.visible = false + close(); + dashBoard.visible = false; } } } @@ -414,7 +399,6 @@ Popup { function onDataChanged(topleft, bottomright, roles) { if (index === undefined) return; - if (roles.includes(FlatLayerTreeModel.FeatureCount)) { updateTitle(); } @@ -423,55 +407,47 @@ Popup { function updateTitle() { if (index === undefined) - return - - var title = layerTree.data(index, Qt.Name) - var type = layerTree.data(index, FlatLayerTreeModel.Type) - var vl = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer) + return; + var title = layerTree.data(index, Qt.Name); + var type = layerTree.data(index, FlatLayerTreeModel.Type); + var vl = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer); if (vl) { if (type === 'legend') { - title += ' (' + vl.name + ')' + title += ' (' + vl.name + ')'; } else if (type === 'layer' && layerTree.data(index, FlatLayerTreeModel.IsValid)) { - var count = layerTree.data(index, FlatLayerTreeModel.FeatureCount) + var count = layerTree.data(index, FlatLayerTreeModel.FeatureCount); if (count !== undefined && count >= 0) { - var countSuffix = ' [' + count + ']' - - if (!title.endsWith(countSuffix)) - title += countSuffix + var countSuffix = ' [' + count + ']'; + if (!title.endsWith(countSuffix)) + title += countSuffix; } } } - titleLabel.text = title + titleLabel.text = title; } function updateCredits() { - var credits = '' + var credits = ''; if (index !== undefined) { - credits = StringUtils.insertLinks(layerTree.data(index, FlatLayerTreeModel.Credits)) + credits = StringUtils.insertLinks(layerTree.data(index, FlatLayerTreeModel.Credits)); } else { - credits = '' + credits = ''; } - - creditsText.text = credits - creditsText.visible = credits !== '' + creditsText.text = credits; + creditsText.visible = credits !== ''; } function isTrackingButtonVisible() { - if ( !index ) - return false - - return layerTree.data( index, FlatLayerTreeModel.Type ) === 'layer' - && !layerTree.data( index, FlatLayerTreeModel.ReadOnly ) - && layerTree.data( index, FlatLayerTreeModel.Trackable ) + if (!index) + return false; + return layerTree.data(index, FlatLayerTreeModel.Type) === 'layer' && !layerTree.data(index, FlatLayerTreeModel.ReadOnly) && layerTree.data(index, FlatLayerTreeModel.Trackable); } function isShowFeaturesListButtonVisible() { - return layerTree.data( index, FlatLayerTreeModel.IsValid ) - && layerTree.data( index, FlatLayerTreeModel.LayerType ) === 'vectorlayer' + return layerTree.data(index, FlatLayerTreeModel.IsValid) && layerTree.data(index, FlatLayerTreeModel.LayerType) === 'vectorlayer'; } function isShowVisibleFeaturesListDropdownVisible() { - return isShowFeaturesListButtonVisible() - && layerTree.data(index, FlatLayerTreeModel.HasSpatialExtent) + return isShowFeaturesListButtonVisible() && layerTree.data(index, FlatLayerTreeModel.HasSpatialExtent); } } diff --git a/src/qml/Legend.qml b/src/qml/Legend.qml index d50ce193f2..b7244e96a8 100644 --- a/src/qml/Legend.qml +++ b/src/qml/Legend.qml @@ -3,7 +3,6 @@ import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -23,16 +22,15 @@ ListView { spacing: 0 function openProperties(index) { - itemProperties.index = legend.model.index(index, 0) - itemProperties.open() - itemProperties.forceActiveFocus() + itemProperties.index = legend.model.index(index, 0); + itemProperties.open(); + itemProperties.forceActiveFocus(); } delegate: Rectangle { + id: rectangle property int itemPadding: 30 * TreeLevel property bool isSelectedLayer: Type === "layer" && VectorLayerPointer && VectorLayerPointer == activeLayer - - id: rectangle width: parent ? parent.width : undefined height: line.height + 7 color: isSelectedLayer ? Theme.mainColor : "transparent" @@ -42,30 +40,28 @@ ListView { anchors.fill: parent enabled: (allowActiveLayerChange || (projectInfo.activeLayer != VectorLayerPointer)) acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: (mouse) => { + onClicked: mouse => { if (!allowActiveLayerChange) - return - + return; if (ReadOnly || GeometryLocked) - return - + return; if (VectorLayerPointer && VectorLayerPointer.isValid) { - activeLayer = VectorLayerPointer - projectInfo.activeLayer = VectorLayerPointer + activeLayer = VectorLayerPointer; + projectInfo.activeLayer = VectorLayerPointer; } } onDoubleClicked: { - openProperties(index) + openProperties(index); } onPressAndHold: { - openProperties(index) + openProperties(index); } - onReleased: (mouse) => { + onReleased: mouse => { if (mouse.button === Qt.RightButton) { - pressAndHold(mouse) + pressAndHold(mouse); } } } @@ -111,7 +107,7 @@ ListView { visible: HasChildren rotation: !IsCollapsed ? 90 : 0 - Behavior on rotation { + Behavior on rotation { NumberAnimation { duration: 100 } @@ -119,8 +115,8 @@ ListView { onClicked: { if (HasChildren) { - IsCollapsed = !IsCollapsed - projectInfo.saveLayerTreeState() + IsCollapsed = !IsCollapsed; + projectInfo.saveLayerTreeState(); } } } @@ -156,9 +152,9 @@ ListView { visible: HasSpatialExtent enabled: (allowActiveLayerChange || (projectInfo.activeLayer != VectorLayerPointer)) onClicked: { - layerTree.setData(legend.model.index(index, 0), !Visible, FlatLayerTreeModel.Visible) - flatLayerTree.mapTheme = '' - projectInfo.saveLayerTreeState() + layerTree.setData(legend.model.index(index, 0), !Visible, FlatLayerTreeModel.Visible); + flatLayerTree.mapTheme = ''; + projectInfo.saveLayerTreeState(); } } } @@ -177,34 +173,33 @@ ListView { mipmap: true source: { if (!legend.isVisible) - return '' - + return ''; if (LegendImage != '') { - return "image://legend/" + LegendImage + return "image://legend/" + LegendImage; } else if (LayerType == "vectorlayer") { switch (VectorLayerPointer.geometryType()) { case Qgis.GeometryType.Point: - return Theme.getThemeVectorIcon('ic_vectorlayer_point_18dp') + return Theme.getThemeVectorIcon('ic_vectorlayer_point_18dp'); case Qgis.GeometryType.Line: - return Theme.getThemeVectorIcon('ic_vectorlayer_line_18dp') + return Theme.getThemeVectorIcon('ic_vectorlayer_line_18dp'); case Qgis.GeometryType.Polygon: - return Theme.getThemeVectorIcon('ic_vectorlayer_polygon_18dp') + return Theme.getThemeVectorIcon('ic_vectorlayer_polygon_18dp'); case Qgis.GeometryType.Null: case Qgis.GeometryType.Unknown: - return Theme.getThemeVectorIcon('ic_vectorlayer_table_18dp') + return Theme.getThemeVectorIcon('ic_vectorlayer_table_18dp'); } } else if (LayerType == "rasterlayer") { - return Theme.getThemeVectorIcon('ic_rasterlayer_18dp') + return Theme.getThemeVectorIcon('ic_rasterlayer_18dp'); } else if (LayerType == "meshlayer") { - return Theme.getThemeVectorIcon('ic_meshlayer_18dp') + return Theme.getThemeVectorIcon('ic_meshlayer_18dp'); } else if (LayerType == "vectortilelayer") { - return Theme.getThemeVectorIcon('ic_vectortilelayer_18dp') + return Theme.getThemeVectorIcon('ic_vectortilelayer_18dp'); } else if (LayerType == "annotationlayer") { - return Theme.getThemeVectorIcon('ic_annotationlayer_18dp') + return Theme.getThemeVectorIcon('ic_annotationlayer_18dp'); } else if (Type == "group") { - return Theme.getThemeVectorIcon('ic_group_18dp') + return Theme.getThemeVectorIcon('ic_group_18dp'); } else { - return '' + return ''; } } width: 16 @@ -218,15 +213,8 @@ ListView { Text { id: layerName - width: rectangle.width - - itemPadding - - 46 // legend icon + right padding - - (collapsedState.isVisible ? collapsedState.width : 0) - - (layerVisibility.isVisible ? layerVisibility.width : 0) - - (trackingBadge.isVisible ? trackingBadge.width + 5 : 0) - - (lockedBadge.isVisible ? lockedBadge.width + 5 : 0) - - (invalidBadge.isVisible ? invalidBadge.width + 5 : 0) - - (snappingBadge.isVisible ? snappingBadge.width + 5 : 0) + width: rectangle.width - itemPadding - 46 // legend icon + right padding + - (collapsedState.isVisible ? collapsedState.width : 0) - (layerVisibility.isVisible ? layerVisibility.width : 0) - (trackingBadge.isVisible ? trackingBadge.width + 5 : 0) - (lockedBadge.isVisible ? lockedBadge.width + 5 : 0) - (invalidBadge.isVisible ? invalidBadge.width + 5 : 0) - (snappingBadge.isVisible ? snappingBadge.width + 5 : 0) padding: 3 leftPadding: 0 text: Name @@ -237,11 +225,11 @@ ListView { opacity: Visible ? 1 : 0.25 color: { if (isSelectedLayer) - return Theme.light + return Theme.light; else if (IsValid) - return Theme.mainTextColor + return Theme.mainTextColor; else - return Theme.secondaryTextColor + return Theme.secondaryTextColor; } } @@ -260,10 +248,10 @@ ListView { icon.color: Theme.mainTextColor onClicked: { - displayToast(qsTr('This layer is is currently tracking the device position.')) + displayToast(qsTr('This layer is is currently tracking the device position.')); } - SequentialAnimation on bgcolor { + SequentialAnimation on bgcolor { running: isVisible && legend.isVisible loops: Animation.Infinite ColorAnimation { @@ -296,7 +284,7 @@ ListView { icon.color: Theme.errorColor onClicked: { - displayToast(qsTr('This layer is invalid. This might be due to a network issue, a missing file or a misconfiguration of the project.')) + displayToast(qsTr('This layer is invalid. This might be due to a network issue, a missing file or a misconfiguration of the project.')); } } @@ -317,21 +305,16 @@ ListView { onClicked: { if (ReadOnly) { - displayToast(qsTr('This layer is configured as "Read-Only" which disables adding, deleting and editing features.')) + displayToast(qsTr('This layer is configured as "Read-Only" which disables adding, deleting and editing features.')); } else { - displayToast(qsTr('This layer is configured as "Lock Geometries" which disables adding and deleting features, as well as modifying the geometries of existing features.')) + displayToast(qsTr('This layer is configured as "Lock Geometries" which disables adding and deleting features, as well as modifying the geometries of existing features.')); } } } QfToolButton { id: snappingBadge - property bool isVisible: stateMachine.state === "digitize" && - qgisProject.snappingConfig.mode === Qgis.SnappingMode.AdvancedConfiguration && - Type === "layer" && - LayerType === "vectorlayer" && - VectorLayerPointer.geometryType() !== Qgis.GeometryType.Null && - VectorLayerPointer.geometryType() !== Qgis.GeometryType.Unknown + property bool isVisible: stateMachine.state === "digitize" && qgisProject.snappingConfig.mode === Qgis.SnappingMode.AdvancedConfiguration && Type === "layer" && LayerType === "vectorlayer" && VectorLayerPointer.geometryType() !== Qgis.GeometryType.Null && VectorLayerPointer.geometryType() !== Qgis.GeometryType.Unknown visible: isVisible height: 24 width: 24 @@ -345,8 +328,8 @@ ListView { icon.color: SnappingEnabled ? 'white' : Theme.mainTextColor onClicked: { - SnappingEnabled = !SnappingEnabled - projectInfo.saveLayerSnappingConfiguration(VectorLayerPointer) + SnappingEnabled = !SnappingEnabled; + projectInfo.saveLayerSnappingConfiguration(VectorLayerPointer); } } } diff --git a/src/qml/LinePolygon.qml b/src/qml/LinePolygon.qml index c30edd179c..e51c070242 100644 --- a/src/qml/LinePolygon.qml +++ b/src/qml/LinePolygon.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import Theme 1.0 import org.qfield 1.0 import org.qgis 1.0 @@ -10,22 +9,23 @@ LinePolygonShape { onPolylinesChanged: { if (polylines.length > 0) { - const pathElements = [] - for(const polyline of polylines) { - var pathPolyline = componentPathPolyline.createObject(shapePath) - pathPolyline.path = polyline - pathElements.push(pathPolyline) + const pathElements = []; + for (const polyline of polylines) { + var pathPolyline = componentPathPolyline.createObject(shapePath); + pathPolyline.path = polyline; + pathElements.push(pathPolyline); } - shapePath.pathElements = pathElements + shapePath.pathElements = pathElements; } else { - shapePath.pathElements = [componentPathPolyline.createObject(shapePath)] + shapePath.pathElements = [componentPathPolyline.createObject(shapePath)]; } } Component { - id: componentPathPolyline; + id: componentPathPolyline - PathPolyline {} + PathPolyline { + } } Shape { @@ -37,9 +37,7 @@ LinePolygonShape { strokeColor: linePolygonShape.color strokeWidth: linePolygonShape.lineWidth / linePolygonShape.scale strokeStyle: ShapePath.SolidLine - fillColor: linePolygonShape.polylinesType === Qgis.GeometryType.Polygon - ? Qt.hsla(strokeColor.hslHue, strokeColor.hslSaturation, strokeColor.hslLightness, 0.25) - : "transparent" + fillColor: linePolygonShape.polylinesType === Qgis.GeometryType.Polygon ? Qt.hsla(strokeColor.hslHue, strokeColor.hslSaturation, strokeColor.hslLightness, 0.25) : "transparent" joinStyle: ShapePath.RoundJoin capStyle: ShapePath.RoundCap } diff --git a/src/qml/LocationMarker.qml b/src/qml/LocationMarker.qml index 21ed0dcb1e..0d6c522fae 100644 --- a/src/qml/LocationMarker.qml +++ b/src/qml/LocationMarker.qml @@ -1,10 +1,8 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 import QtQuick.Window 2.14 - import org.qgis 1.0 import Theme 1.0 - import "." Item { @@ -28,14 +26,11 @@ Item { property point screenLocation property real screenAccuracy - property bool isOnMapCanvas: screenLocation.x > 0 - && screenLocation.x < mapCanvas.width - && screenLocation.y > 0 - && screenLocation.y < mapCanvas.height + property bool isOnMapCanvas: screenLocation.x > 0 && screenLocation.x < mapCanvas.width && screenLocation.y > 0 && screenLocation.y < mapCanvas.height } function updateScreenLocation() { - props.screenLocation = mapSettings.coordinateToScreen( location ) - props.screenAccuracy = accuracy / mapSettings.mapUnitsPerPoint + props.screenLocation = mapSettings.coordinateToScreen(location); + props.screenAccuracy = accuracy / mapSettings.mapUnitsPerPoint; } Rectangle { @@ -47,7 +42,7 @@ Item { x: props.screenLocation.x - width / 2 y: props.screenLocation.y - height / 2 - radius: width/2 + radius: width / 2 color: locationMarker.semiOpaqueColor border.color: locationMarker.color @@ -77,20 +72,33 @@ Item { strokeWidth: 0 strokeColor: "transparent" fillGradient: LinearGradient { - x1: 24; y1: 48 - x2: 24; y2: 0 - GradientStop { position: 0.0; color: locationMarker.color } - GradientStop { position: 1.0; color: locationMarker.semiOpaqueColor } + x1: 24 + y1: 48 + x2: 24 + y2: 0 + GradientStop { + position: 0.0 + color: locationMarker.color + } + GradientStop { + position: 1.0 + color: locationMarker.semiOpaqueColor + } } joinStyle: ShapePath.MiterJoin PathAngleArc { - centerX: 24; centerY: 48 - radiusX: 48; radiusY: 48 + centerX: 24 + centerY: 48 + radiusX: 48 + radiusY: 48 startAngle: -90 - (compassDirectionMarker.wideness / 2) sweepAngle: compassDirectionMarker.wideness } - PathLine { x: 24; y: 48 } + PathLine { + x: 24 + y: 48 + } } } @@ -102,10 +110,18 @@ Item { strokeWidth: 0 strokeColor: "transparent" fillGradient: LinearGradient { - x1: 24; y1: 48 - x2: 24; y2: 0 - GradientStop { position: 0.0; color: locationMarker.color } - GradientStop { position: 1.0; color: locationMarker.semiOpaqueColor } + x1: 24 + y1: 48 + x2: 24 + y2: 0 + GradientStop { + position: 0.0 + color: locationMarker.color + } + GradientStop { + position: 1.0 + color: locationMarker.semiOpaqueColor + } } joinStyle: ShapePath.MiterJoin startX: 24 @@ -115,12 +131,18 @@ Item { x: 48 * Math.sin((180 - (compassDirectionMarker.wideness / 2)) * Math.PI / 180) + 24 y: 48 * Math.cos((180 - (compassDirectionMarker.wideness / 2)) * Math.PI / 180) + 48 } - PathLine { x: 24; y: 40 } + PathLine { + x: 24 + y: 40 + } PathLine { x: 48 * Math.sin((180 + (compassDirectionMarker.wideness / 2)) * Math.PI / 180) + 24 - y: 48 * Math.cos((180+- (compassDirectionMarker.wideness / 2)) * Math.PI / 180) + 48 + y: 48 * Math.cos((180 + -(compassDirectionMarker.wideness / 2)) * Math.PI / 180) + 48 + } + PathLine { + x: 24 + y: 48 } - PathLine { x: 24; y: 48 } } } } @@ -145,19 +167,31 @@ Item { joinStyle: ShapePath.MiterJoin startX: 13 startY: 2 - PathLine { x: 21; y: 22 } - PathLine { x: 13; y: 16 } - PathLine { x: 5; y: 22 } - PathLine { x: 13; y: 2 } + PathLine { + x: 21 + y: 22 + } + PathLine { + x: 13 + y: 16 + } + PathLine { + x: 5 + y: 22 + } + PathLine { + x: 13 + y: 2 + } } layer.enabled: true layer.effect: QfDropShadow { - transparentBorder: true - samples: 16 - color: "#99000000" - horizontalOffset: 0 - verticalOffset: 0 + transparentBorder: true + samples: 16 + color: "#99000000" + horizontalOffset: 0 + verticalOffset: 0 } } @@ -179,11 +213,11 @@ Item { layer.enabled: true layer.effect: QfDropShadow { - transparentBorder: true - samples: 16 - color: "#99000000" - horizontalOffset: 0 - verticalOffset: 0 + transparentBorder: true + samples: 16 + color: "#99000000" + horizontalOffset: 0 + verticalOffset: 0 } } @@ -197,9 +231,9 @@ Item { y: Math.min(mapCanvas.height - width, Math.max(0, props.screenLocation.y - width / 2)) transform: Rotation { - origin.x: edgeMarker.width / 2; - origin.y: edgeMarker.width / 2; - angle:-(Math.atan2(mapCanvas.width / 2 - props.screenLocation.x, mapCanvas.height / 2 - props.screenLocation.y) / Math.PI) * 180 + origin.x: edgeMarker.width / 2 + origin.y: edgeMarker.width / 2 + angle: -(Math.atan2(mapCanvas.width / 2 - props.screenLocation.x, mapCanvas.height / 2 - props.screenLocation.y) / Math.PI) * 180 } ShapePath { @@ -210,37 +244,45 @@ Item { joinStyle: ShapePath.MiterJoin startX: 10 startY: 0 - PathLine { x: 18; y: 20 } - PathLine { x: 2; y: 20 } - PathLine { x: 10; y: 0 } + PathLine { + x: 18 + y: 20 + } + PathLine { + x: 2 + y: 20 + } + PathLine { + x: 10 + y: 0 + } } layer.enabled: true layer.effect: QfDropShadow { - transparentBorder: true - samples: 16 - color: "#99000000" - horizontalOffset: 0 - verticalOffset: 0 + transparentBorder: true + samples: 16 + color: "#99000000" + horizontalOffset: 0 + verticalOffset: 0 } } Connections { target: mapSettings - function onExtentChanged() { - updateScreenLocation() + updateScreenLocation(); } function onRotationChanged() { - updateScreenLocation() + updateScreenLocation(); } function onOutputSizeChanged() { - updateScreenLocation() + updateScreenLocation(); } } onLocationChanged: { - updateScreenLocation() + updateScreenLocation(); } } diff --git a/src/qml/LocatorItem.qml b/src/qml/LocatorItem.qml index 992c5b0849..60e91ccd61 100644 --- a/src/qml/LocatorItem.qml +++ b/src/qml/LocatorItem.qml @@ -2,10 +2,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Item { @@ -29,47 +27,119 @@ Item { height: childrenRect.height states: [ - State { - name: "on" - PropertyChanges { target: searchFieldRect; visible: true; } - PropertyChanges { target: searchFieldRect; width: mainWindow.width - 62 } - PropertyChanges { target: codeReaderButton; visible: true; } - PropertyChanges { target: clearButton; visible: true; } - PropertyChanges { target: busyIndicator; visible: true; } - }, - State { - name: "off" - PropertyChanges { target: busyIndicator; visible: false; } - PropertyChanges { target: clearButton; visible: false; } - PropertyChanges { target: codeReaderButton; visible: false; } - PropertyChanges { target: searchFieldRect; width: 48 } - PropertyChanges { target: searchFieldRect; visible: false; } + State { + name: "on" + PropertyChanges { + target: searchFieldRect + visible: true + } + PropertyChanges { + target: searchFieldRect + width: mainWindow.width - 62 + } + PropertyChanges { + target: codeReaderButton + visible: true + } + PropertyChanges { + target: clearButton + visible: true + } + PropertyChanges { + target: busyIndicator + visible: true + } + }, + State { + name: "off" + PropertyChanges { + target: busyIndicator + visible: false } + PropertyChanges { + target: clearButton + visible: false + } + PropertyChanges { + target: codeReaderButton + visible: false + } + PropertyChanges { + target: searchFieldRect + width: 48 + } + PropertyChanges { + target: searchFieldRect + visible: false + } + } ] transitions: [ - Transition { - from: "off" - to: "on" - SequentialAnimation { - PropertyAnimation { target: searchFieldRect; property: "visible"; duration: 0 } - NumberAnimation { target: searchFieldRect; easing.type: Easing.InOutQuad; properties: "width"; duration: 250 } - PropertyAnimation { target: codeReaderButton; property: "visible"; duration: 0 } - PropertyAnimation { target: clearButton; property: "visible"; duration: 0 } - PropertyAnimation { target: busyIndicator; property: "visible"; duration: 0 } + Transition { + from: "off" + to: "on" + SequentialAnimation { + PropertyAnimation { + target: searchFieldRect + property: "visible" + duration: 0 + } + NumberAnimation { + target: searchFieldRect + easing.type: Easing.InOutQuad + properties: "width" + duration: 250 + } + PropertyAnimation { + target: codeReaderButton + property: "visible" + duration: 0 } - }, - Transition { - from: "on" - to: "off" - SequentialAnimation { - PropertyAnimation { target: busyIndicator; property: "visible"; duration: 0 } - PropertyAnimation { target: clearButton; property: "visible"; duration: 0 } - PropertyAnimation { target: codeReaderButton; property: "visible"; duration: 0 } - NumberAnimation { target: searchFieldRect; easing.type: Easing.InOutQuad; properties: "width"; duration: 150 } - PropertyAnimation { target: searchFieldRect; property: "visible"; duration: 0 } + PropertyAnimation { + target: clearButton + property: "visible" + duration: 0 + } + PropertyAnimation { + target: busyIndicator + property: "visible" + duration: 0 + } + } + }, + Transition { + from: "on" + to: "off" + SequentialAnimation { + PropertyAnimation { + target: busyIndicator + property: "visible" + duration: 0 + } + PropertyAnimation { + target: clearButton + property: "visible" + duration: 0 + } + PropertyAnimation { + target: codeReaderButton + property: "visible" + duration: 0 + } + NumberAnimation { + target: searchFieldRect + easing.type: Easing.InOutQuad + properties: "width" + duration: 150 + } + PropertyAnimation { + target: searchFieldRect + property: "visible" + duration: 0 } } + } ] LocatorModelSuperBridge { @@ -82,11 +152,11 @@ Item { featureListController: featureForm.extentController onMessageEmitted: { - displayToast(text) + displayToast(text); } - onSearchTextChangeRequested: (text) => { - searchField.text = text + onSearchTextChangeRequested: text => { + searchField.text = text; } } @@ -98,11 +168,11 @@ Item { Connections { target: iface - function onLoadProjectEnded(path,name) { + function onLoadProjectEnded(path, name) { if (searchField.text.length > 0) { // Any pre-existing results would most likely be invalid in a new project context, clear searchField.text = ''; - locatorItem.state = "off" + locatorItem.state = "off"; } } } @@ -113,7 +183,7 @@ Item { enabled: false function onDecoded(string) { - var prefix = locator.getPrefixFromSearchString(searchField.text) + var prefix = locator.getPrefixFromSearchString(searchField.text); searchField.text = prefix !== '' ? prefix + ' ' + string : string; } @@ -158,16 +228,14 @@ Item { } inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase onDisplayTextChanged: { - locatorItem.state = "on" - - searchTermHandled = false - searchTermChanged(searchField.displayText) + locatorItem.state = "on"; + searchTermHandled = false; + searchTermChanged(searchField.displayText); if (!searchTermHandled) { - locator.performSearch(searchField.displayText) + locator.performSearch(searchField.displayText); } - if (searchField.displayText == 'f ' && dashBoard.activeLayer == undefined) { - displayToast(qsTr('To search features within the active layer, select a vector layer through the legend.')) + displayToast(qsTr('To search features within the active layer, select a vector layer through the legend.')); } } } @@ -205,7 +273,7 @@ Item { searchField.text = ''; searchField.forceActiveFocus(); } else { - locatorItem.state = "off" + locatorItem.state = "off"; } } } @@ -227,7 +295,6 @@ Item { onClicked: { Qt.inputMethod.hide(); - codeReader.open(); codeReaderConnection.enabled = true; } @@ -235,15 +302,18 @@ Item { QfToolButton { id: searchButton - z:20 - anchors { right: parent.right; top: parent.top; } + z: 20 + anchors { + right: parent.right + top: parent.top + } - iconSource: Theme.getThemeVectorIcon( "ic_baseline_search_white" ) + iconSource: Theme.getThemeVectorIcon("ic_baseline_search_white") round: true bgcolor: Theme.mainColor onClicked: { - locatorItem.state = locatorItem.state =="off" ? "on" : "off" + locatorItem.state = locatorItem.state == "off" ? "on" : "off"; } onPressAndHold: { @@ -264,8 +334,11 @@ Item { visible: searchFieldRect.visible && resultsList.count > 0 clip: true - Behavior on height { - NumberAnimation { duration: 150; easing.type: Easing.InOutQuad } + Behavior on height { + NumberAnimation { + duration: 150 + easing.type: Easing.InOutQuad + } } ListView { @@ -275,7 +348,7 @@ Item { anchors.topMargin: 24 model: searchField.displayText !== '' ? locator.proxyModel() : locatorFilters width: parent.width - height: resultsList.count > 0 ? Math.min( contentHeight, mainWindow.height / 2 - searchFieldRect.height - 10 ) : 0 + height: resultsList.count > 0 ? Math.min(contentHeight, mainWindow.height / 2 - searchFieldRect.height - 10) : 0 clip: true delegate: searchField.displayText !== '' ? resultsComponent : filtersComponent @@ -353,9 +426,9 @@ Item { onClicked: { if (Prefix === 'f' && dashBoard.activeLayer == undefined) { - displayToast(qsTr('Activate a vector layer in the legend first to use this functionality'), 'warning') + displayToast(qsTr('Activate a vector layer in the legend first to use this functionality'), 'warning'); } else { - searchField.text = Prefix + ' ' + searchField.text = Prefix + ' '; } } } @@ -401,11 +474,7 @@ Item { id: nameCell anchors.left: parent.left anchors.right: parent.right - text: isFilterName - ? ResultFilterName - : typeof(model.Text) == 'string' - ? model.Text.trim() - : '' + text: isFilterName ? ResultFilterName : typeof (model.Text) == 'string' ? model.Text.trim() : '' leftPadding: 5 font.bold: false font.pointSize: Theme.resultFont.pointSize @@ -449,8 +518,8 @@ Item { iconSource: Theme.getThemeIcon(IconPath) onClicked: { - locatorItem.state = "off" - locator.triggerResultAtRow(delegateRect.resultIndex, Id) + locatorItem.state = "off"; + locator.triggerResultAtRow(delegateRect.resultIndex, Id); } } } @@ -473,8 +542,8 @@ Item { onClicked: { if (!isFilterName && !isGroup && nameCell.text !== '') { - locator.triggerResultAtRow(index) - locatorItem.state = "off" + locator.triggerResultAtRow(index); + locatorItem.state = "off"; } } } diff --git a/src/qml/LocatorSettings.qml b/src/qml/LocatorSettings.qml index 8ddd35cdca..7c61beebed 100644 --- a/src/qml/LocatorSettings.qml +++ b/src/qml/LocatorSettings.qml @@ -1,105 +1,103 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Popup { - id: popup + id: popup - property alias locatorFiltersModel: locatorfiltersList.model + property alias locatorFiltersModel: locatorfiltersList.model - width: Math.min(400, mainWindow.width - Theme.popupScreenEdgeMargin) - x: (parent.width - width) / 2 - y: (parent.height - height) / 2 - padding: 0 + width: Math.min(400, mainWindow.width - Theme.popupScreenEdgeMargin) + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + padding: 0 - Page { - id: page - width: parent.width - height: locatorfiltersList.height + 60 - padding: 10 - header: QfPageHeader { - id: pageHeader - title: qsTr( "Search Bar Settings" ) + Page { + id: page + width: parent.width + height: locatorfiltersList.height + 60 + padding: 10 + header: QfPageHeader { + id: pageHeader + title: qsTr("Search Bar Settings") - showBackButton: false - showApplyButton: false - showCancelButton: true - backgroundFill: false + showBackButton: false + showApplyButton: false + showCancelButton: true + backgroundFill: false - onCancel: { - popup.close() - } - } + onCancel: { + popup.close(); + } + } - Column { - spacing: 4 - width: parent.width + Column { + spacing: 4 + width: parent.width - ListView { - id: locatorfiltersList - width: parent.width - height: Math.min( childrenRect.height, mainWindow.height - 160 ); - clip: true + ListView { + id: locatorfiltersList + width: parent.width + height: Math.min(childrenRect.height, mainWindow.height - 160) + clip: true - delegate: Rectangle { - id: rectangle - width: parent ? parent.width : undefined - height: inner.height - color: "transparent" + delegate: Rectangle { + id: rectangle + width: parent ? parent.width : undefined + height: inner.height + color: "transparent" - ColumnLayout { - id: inner - width: parent.width + ColumnLayout { + id: inner + width: parent.width - Text { - Layout.fillWidth: true - topPadding: 5 - leftPadding: 5 - text: Name - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - } - Text { - Layout.fillWidth: true - leftPadding: 5 - bottomPadding: 5 - text: Description - font: Theme.tipFont - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - } - Text { - visible: Default ? false : true - Layout.fillWidth: true - leftPadding: 5 - bottomPadding: 5 - text: qsTr('When disabled, this locator filter can still be used by typing the prefix %1 in the search bar.').arg(''+Prefix+'') - font: Theme.tipFont - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - } - CheckBox { - Layout.fillWidth: true - topPadding: 5 - bottomPadding: 5 - text: qsTr('Enable %1 locator by default').arg(''+Name+'') - font: Theme.tipFont - indicator.height: 16 - indicator.width: 16 - indicator.implicitHeight: 24 - indicator.implicitWidth: 24 - checked: Default? true : false - onCheckedChanged: Default = checked - } - } - } + Text { + Layout.fillWidth: true + topPadding: 5 + leftPadding: 5 + text: Name + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + } + Text { + Layout.fillWidth: true + leftPadding: 5 + bottomPadding: 5 + text: Description + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap } + Text { + visible: Default ? false : true + Layout.fillWidth: true + leftPadding: 5 + bottomPadding: 5 + text: qsTr('When disabled, this locator filter can still be used by typing the prefix %1 in the search bar.').arg('' + Prefix + '') + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap + } + CheckBox { + Layout.fillWidth: true + topPadding: 5 + bottomPadding: 5 + text: qsTr('Enable %1 locator by default').arg('' + Name + '') + font: Theme.tipFont + indicator.height: 16 + indicator.width: 16 + indicator.implicitHeight: 24 + indicator.implicitWidth: 24 + checked: Default ? true : false + onCheckedChanged: Default = checked + } + } } + } } + } } diff --git a/src/qml/MapCanvas.qml b/src/qml/MapCanvas.qml index 89ae7e57e8..2a07129e1e 100644 --- a/src/qml/MapCanvas.qml +++ b/src/qml/MapCanvas.qml @@ -14,11 +14,9 @@ * (at your option) any later version. * * * ***************************************************************************/ - import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQml 2.15 - import org.qgis 1.0 Item { @@ -65,21 +63,21 @@ Item { * number of times. */ function freeze(id) { - mapCanvasWrapper.__freezecount[id] = true - mapCanvasWrapper.freeze = true + mapCanvasWrapper.__freezecount[id] = true; + mapCanvasWrapper.freeze = true; } function unfreeze(id) { - delete mapCanvasWrapper.__freezecount[id] - mapCanvasWrapper.freeze = Object.keys(mapCanvasWrapper.__freezecount).length !== 0 + delete mapCanvasWrapper.__freezecount[id]; + mapCanvasWrapper.freeze = Object.keys(mapCanvasWrapper.__freezecount).length !== 0; } function zoomIn(point) { - mapCanvasWrapper.zoom(point, 0.67) + mapCanvasWrapper.zoom(point, 0.67); } function zoomOut(point) { - mapCanvasWrapper.zoom(point, 1.5) + mapCanvasWrapper.zoom(point, 1.5); } MapCanvasMap { @@ -103,26 +101,25 @@ Item { property bool longPressActive: false onSingleTapped: (eventPoint, button) => { - if (button === undefined) { - button = eventPoint.event.button - } - - if (button === Qt.RightButton) { - mapArea.rightClicked(point.position, "stylus") - } else { - mapArea.clicked(point.position, "stylus") - } - } + if (button === undefined) { + button = eventPoint.event.button; + } + if (button === Qt.RightButton) { + mapArea.rightClicked(point.position, "stylus"); + } else { + mapArea.clicked(point.position, "stylus"); + } + } onLongPressed: { - mapArea.longPressed(point.position, "stylus") - longPressActive = true + mapArea.longPressed(point.position, "stylus"); + longPressActive = true; } onPressedChanged: { if (longPressActive) - mapArea.longPressReleased("stylus") - longPressActive = false + mapArea.longPressReleased("stylus"); + longPressActive = false; } } @@ -145,32 +142,32 @@ Item { onActiveChanged: { if (active) { if (mainTapHandler.doublePressed) { - oldTranslationY = 0 - zoomCenter = centroid.position - isZooming = true - freeze('zoom') + oldTranslationY = 0; + zoomCenter = centroid.position; + isZooming = true; + freeze('zoom'); } else { - oldPos = centroid.position - isPanning = true - freeze('pan') + oldPos = centroid.position; + isPanning = true; + freeze('pan'); } } else { if (isZooming || isPanning) { - unfreeze(isZooming ? 'zoom' : 'pan') + unfreeze(isZooming ? 'zoom' : 'pan'); } - isZooming = false - isPanning = false + isZooming = false; + isPanning = false; } } onCentroidChanged: { if (active) { if (isZooming) { - mapCanvasWrapper.zoom(zoomCenter, Math.pow(0.8, (translation.y - oldTranslationY) / 60)) - oldTranslationY = translation.y + mapCanvasWrapper.zoom(zoomCenter, Math.pow(0.8, (translation.y - oldTranslationY) / 60)); + oldTranslationY = translation.y; } else if (isPanning) { - mapCanvasWrapper.pan(centroid.position, oldPos) - oldPos = centroid.position + mapCanvasWrapper.pan(centroid.position, oldPos); + oldPos = centroid.position; } } } @@ -184,8 +181,8 @@ Item { property var tapPoint onTriggered: { - mainTapHandler.doublePressed = false - confirmedClicked(tapPoint) + mainTapHandler.doublePressed = false; + confirmedClicked(tapPoint); } } @@ -200,38 +197,38 @@ Item { property bool doublePressed: false onLongPressed: { - mapArea.longPressed(Qt.point(point.position.x, point.position.y), "touch") - longPressActive = true - } + mapArea.longPressed(Qt.point(point.position.x, point.position.y), "touch"); + longPressActive = true; + } onPressedChanged: { - if (pressed) { - if (point.pressedButtons !== Qt.RightButton) { - if (timer.running) { - timer.stop() - doublePressed = true - } else { - doublePressed = false - } - } - } - } + if (pressed) { + if (point.pressedButtons !== Qt.RightButton) { + if (timer.running) { + timer.stop(); + doublePressed = true; + } else { + doublePressed = false; + } + } + } + } onTapped: (eventPoint, button) => { - if (button === Qt.RightButton) { - mapArea.rightClicked(Qt.point(eventPoint.position.x, eventPoint.position.y), "touch") - } else { - if (!doublePressed) { - timer.tapPoint = Qt.point(eventPoint.position.x, eventPoint.position.y) - timer.restart() - } else { - mapCanvasWrapper.zoom(Qt.point(eventPoint.position.x, eventPoint.position.y), 0.8) - } - } - } + if (button === Qt.RightButton) { + mapArea.rightClicked(Qt.point(eventPoint.position.x, eventPoint.position.y), "touch"); + } else { + if (!doublePressed) { + timer.tapPoint = Qt.point(eventPoint.position.x, eventPoint.position.y); + timer.restart(); + } else { + mapCanvasWrapper.zoom(Qt.point(eventPoint.position.x, eventPoint.position.y), 0.8); + } + } + } onCanceled: { - timer.stop() + timer.stop(); } } @@ -254,32 +251,32 @@ Item { onActiveChanged: { if (active) { if (mainTapHandler.doublePressed) { - oldTranslationY = 0 - zoomCenter = centroid.position - isZooming = true - freeze('zoom') + oldTranslationY = 0; + zoomCenter = centroid.position; + isZooming = true; + freeze('zoom'); } else { - oldPos = centroid.position - isPanning = true - freeze('pan') + oldPos = centroid.position; + isPanning = true; + freeze('pan'); } } else { if (isZooming || isPanning) { - unfreeze(isZooming ? 'zoom' : 'pan') + unfreeze(isZooming ? 'zoom' : 'pan'); } - isZooming = false - isPanning = false + isZooming = false; + isPanning = false; } } onCentroidChanged: { if (active) { if (isZooming) { - mapCanvasWrapper.zoom(zoomCenter, Math.pow(0.8, (translation.y - oldTranslationY) / 60)) - oldTranslationY = translation.y + mapCanvasWrapper.zoom(zoomCenter, Math.pow(0.8, (translation.y - oldTranslationY) / 60)); + oldTranslationY = translation.y; } else if (isPanning) { - mapCanvasWrapper.pan(centroid.position, oldPos) - oldPos = centroid.position + mapCanvasWrapper.pan(centroid.position, oldPos); + oldPos = centroid.position; } } } @@ -289,7 +286,7 @@ Item { id: secondaryDragHandler target: null enabled: interactive - grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything; + grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything acceptedDevices: PointerDevice.Stylus | PointerDevice.Mouse acceptedButtons: Qt.RightButton dragThreshold: 10 @@ -299,21 +296,20 @@ Item { onActiveChanged: { if (active) { - oldTranslationY = 0 - zoomCenter = centroid.position - freeze('zoom') + oldTranslationY = 0; + zoomCenter = centroid.position; + freeze('zoom'); } else { - grabPermissions: PointerHandler.TakeOverForbidden - unfreeze('zoom') + grabPermissions: PointerHandler.TakeOverForbidden; + unfreeze('zoom'); } } onTranslationChanged: { if (active) { - mapCanvasWrapper.zoom(zoomCenter, Math.pow(0.8, (oldTranslationY - translation.y)/60)) + mapCanvasWrapper.zoom(zoomCenter, Math.pow(0.8, (oldTranslationY - translation.y) / 60)); } - - oldTranslationY = translation.y + oldTranslationY = translation.y; } } @@ -329,18 +325,18 @@ Item { onActiveChanged: { if (active) { - freeze('pan') - oldPos = centroid.position + freeze('pan'); + oldPos = centroid.position; } else { - unfreeze('pan') + unfreeze('pan'); } } onCentroidChanged: { if (active) { - var oldPos1 = oldPos - oldPos = centroid.position - mapCanvasWrapper.pan(centroid.position, oldPos1) + var oldPos1 = oldPos; + oldPos = centroid.position; + mapCanvasWrapper.pan(centroid.position, oldPos1); } } } @@ -358,11 +354,11 @@ Item { onActiveChanged: { if (active) { - freeze('rotate') - oldTranslationY = 0 - translationThresholdReached = false + freeze('rotate'); + oldTranslationY = 0; + translationThresholdReached = false; } else { - unfreeze('rotate') + unfreeze('rotate'); } } @@ -370,78 +366,73 @@ Item { if (active) { if (translationThresholdReached) { if (oldTranslationY != 0) { - mapCanvasWrapper.rotate(oldTranslationY - translation.y) + mapCanvasWrapper.rotate(oldTranslationY - translation.y); } - oldTranslationY = translation.y - translationThresholdReached = true + oldTranslationY = translation.y; + translationThresholdReached = true; } else if (Math.abs(oldTranslationY - translation.y) > pinchHandler.rotationTreshold) { - oldTranslationY = translation.y - translationThresholdReached = true + oldTranslationY = translation.y; + translationThresholdReached = true; } } } } PinchHandler { - id: pinchHandler - enabled: interactive - target: null - acceptedButtons: Qt.NoButton | Qt.LeftButton - grabPermissions: PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByHandlersOfDifferentType - acceptedDevices: PointerDevice.TouchScreen - dragThreshold: 5 - - property real rotationTreshold: 20.0 - - property var oldPos - property real oldScale: 1.0 - property real oldRotation: 0.0 - - property bool rotationActive: false - property bool rotationTresholdReached: false - - onActiveChanged: { - if ( active ) { - freeze('pinch') - oldScale = 1.0 - oldRotation = 0.0 - rotationTresholdReached = false - oldPos = centroid.position - } else { - unfreeze('pinch') - } - } + id: pinchHandler + enabled: interactive + target: null + acceptedButtons: Qt.NoButton | Qt.LeftButton + grabPermissions: PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByHandlersOfDifferentType + acceptedDevices: PointerDevice.TouchScreen + dragThreshold: 5 - onCentroidChanged: { - var oldPos1 = oldPos - oldPos = centroid.position - if ( active ) - { - mapCanvasWrapper.pan(centroid.position, oldPos1) - } + property real rotationTreshold: 20.0 + + property var oldPos + property real oldScale: 1.0 + property real oldRotation: 0.0 + + property bool rotationActive: false + property bool rotationTresholdReached: false + + onActiveChanged: { + if (active) { + freeze('pinch'); + oldScale = 1.0; + oldRotation = 0.0; + rotationTresholdReached = false; + oldPos = centroid.position; + } else { + unfreeze('pinch'); } + } - onRotationChanged: { - if ( active && isMapRotationEnabled ) - { - if (rotationTresholdReached) - { - mapCanvasWrapper.rotate(rotation - oldRotation) - oldRotation = rotation - } - else if (Math.abs(rotation - oldRotation) > pinchHandler.rotationTreshold) - { - oldRotation = rotation - rotationTresholdReached = true - } - } + onCentroidChanged: { + var oldPos1 = oldPos; + oldPos = centroid.position; + if (active) { + mapCanvasWrapper.pan(centroid.position, oldPos1); } + } - onActiveScaleChanged: { - mapCanvasWrapper.zoom( pinchHandler.centroid.position, oldScale / pinchHandler.activeScale ) - mapCanvasWrapper.pan( pinchHandler.centroid.position, oldPos ) - oldScale = pinchHandler.activeScale + onRotationChanged: { + if (active && isMapRotationEnabled) { + if (rotationTresholdReached) { + mapCanvasWrapper.rotate(rotation - oldRotation); + oldRotation = rotation; + } else if (Math.abs(rotation - oldRotation) > pinchHandler.rotationTreshold) { + oldRotation = rotation; + rotationTresholdReached = true; + } } + } + + onActiveScaleChanged: { + mapCanvasWrapper.zoom(pinchHandler.centroid.position, oldScale / pinchHandler.activeScale); + mapCanvasWrapper.pan(pinchHandler.centroid.position, oldPos); + oldScale = pinchHandler.activeScale; + } } WheelHandler { @@ -449,12 +440,12 @@ Item { target: null grabPermissions: PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByItems - onWheel: (event) => { - if (event.angleDelta.y > 0) { - zoomIn(point.position) - } else { - zoomOut(point.position) - } - } + onWheel: event => { + if (event.angleDelta.y > 0) { + zoomIn(point.position); + } else { + zoomOut(point.position); + } + } } } diff --git a/src/qml/MeasuringTool.qml b/src/qml/MeasuringTool.qml index 8f4b3a252f..ebbee67eb0 100644 --- a/src/qml/MeasuringTool.qml +++ b/src/qml/MeasuringTool.qml @@ -1,24 +1,20 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Item { id: measuringTool property alias measuringRubberband: rubberband - property bool isClosingArea: rubberband.model.vertexCount > 2 - && vertexFirstLastDistance.screenDistance < 10 + property bool isClosingArea: rubberband.model.vertexCount > 2 && vertexFirstLastDistance.screenDistance < 10 property bool isArea: false MapToScreen { id: vertexFirstLastDistance mapSettings: rubberband.mapSettings - mapDistance: GeometryUtils.distanceBetweenPoints(rubberband.model.firstCoordinate, - rubberband.model.currentCoordinate) + mapDistance: GeometryUtils.distanceBetweenPoints(rubberband.model.firstCoordinate, rubberband.model.currentCoordinate) } Repeater { @@ -34,13 +30,10 @@ Item { visible: rubberband.model.vertexCount > 1 - x: vertexToScreen.screenPoint.x - width/2 - y: vertexToScreen.screenPoint.y - width/2 + x: vertexToScreen.screenPoint.x - width / 2 + y: vertexToScreen.screenPoint.y - width / 2 - width: isClosingArea - && (index === 0 || index === rubberband.model.vertexCount - 1) - ? 20 - : 10 + width: isClosingArea && (index === 0 || index === rubberband.model.vertexCount - 1) ? 20 : 10 height: width ShapePath { @@ -48,9 +41,12 @@ Item { strokeWidth: 5 fillColor: "transparent" PathAngleArc { - centerX: shape.width / 2; centerY: centerX - radiusX: centerX; radiusY: centerX - startAngle: 0; sweepAngle: 360 + centerX: shape.width / 2 + centerY: centerX + radiusX: centerX + radiusY: centerX + startAngle: 0 + sweepAngle: 360 } } ShapePath { @@ -58,9 +54,12 @@ Item { strokeWidth: 3 fillColor: "transparent" PathAngleArc { - centerX: shape.width / 2; centerY: centerX - radiusX: centerX; radiusY: centerX - startAngle: 0; sweepAngle: 360 + centerX: shape.width / 2 + centerY: centerX + radiusX: centerX + radiusY: centerX + startAngle: 0 + sweepAngle: 360 } } } @@ -72,9 +71,7 @@ Item { model: RubberbandModel { frozen: false - geometryType: isClosingArea || isArea - ? Qgis.GeometryType.Polygon - : Qgis.GeometryType.Line + geometryType: isClosingArea || isArea ? Qgis.GeometryType.Polygon : Qgis.GeometryType.Line crs: rubberband.mapSettings.destinationCrs } } @@ -83,8 +80,7 @@ Item { target: rubberband.model function onVertexCountChanged() { - if (rubberband.model.vertexCount > 2 - && vertexFirstLastDistance.screenDistance < 10) { + if (rubberband.model.vertexCount > 2 && vertexFirstLastDistance.screenDistance < 10) { isArea = true; } else if (rubberband.model.vertexCount <= 1) { isArea = false; diff --git a/src/qml/MessageLog.qml b/src/qml/MessageLog.qml index d0ef13e525..07443d15ec 100644 --- a/src/qml/MessageLog.qml +++ b/src/qml/MessageLog.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 @@ -14,16 +13,16 @@ Page { signal finished header: QfPageHeader { - title: qsTr( 'Message Logs' ) + title: qsTr('Message Logs') - showBackButton: true - showApplyButton: false - showCancelButton: false + showBackButton: true + showApplyButton: false + showCancelButton: false - topMargin: mainWindow.sceneTopMargin + topMargin: mainWindow.sceneTopMargin - onFinished: messageLog.finished() - } + onFinished: messageLog.finished() + } ColumnLayout { anchors.margins: 8 @@ -33,11 +32,11 @@ Page { spacing: 10 Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - color: Theme.controlBackgroundColor - border.color: Theme.controlBorderColor - border.width: 1 + Layout.fillWidth: true + Layout.fillHeight: true + color: Theme.controlBackgroundColor + border.color: Theme.controlBorderColor + border.width: 1 ListView { id: table @@ -71,7 +70,7 @@ Page { id: datetext objectName: 'dateText' padding: 5 - text: MessageDateTime.replace(' ','\n') + text: MessageDateTime.replace(' ', '\n') font: Theme.tipFont color: Theme.secondaryTextColor } @@ -82,7 +81,7 @@ Page { Text { id: tagtext objectName: 'tagText' - padding: MessageTag ? 5: 0 + padding: MessageTag ? 5 : 0 text: MessageTag font.pointSize: Theme.tipFont.pointSize font.bold: true @@ -101,12 +100,11 @@ Page { MouseArea { anchors.fill: parent - onClicked: - { - copyHelper.text = messagetext.text - copyHelper.selectAll() - copyHelper.copy() - displayToast(qsTr("Message text copied")) + onClicked: { + copyHelper.text = messagetext.text; + copyHelper.selectAll(); + copyHelper.copy(); + displayToast(qsTr("Message text copied")); } } } @@ -115,40 +113,40 @@ Page { } } - TextEdit{ - id: copyHelper - visible: false + TextEdit { + id: copyHelper + visible: false } QfButton { - text: qsTr("Log runtime profiler") - Layout.fillWidth: true + text: qsTr("Log runtime profiler") + Layout.fillWidth: true - onClicked: { - iface.logRuntimeProfiler() - } + onClicked: { + iface.logRuntimeProfiler(); + } } QfButton { - text: qsTr("Clear message log") - Layout.fillWidth: true + text: qsTr("Clear message log") + Layout.fillWidth: true - onClicked: { - table.model.clear() - displayToast(qsTr("Message log cleared")) - messageLog.finished() - } + onClicked: { + table.model.clear(); + displayToast(qsTr("Message log cleared")); + messageLog.finished(); + } } QfButton { - id: submitLog - Layout.fillWidth: true - text: qsTr("Send application log") - visible: qfieldSettings.enableInfoCollection && platformUtilities.capabilities & PlatformUtilities.SentryFramework + id: submitLog + Layout.fillWidth: true + text: qsTr("Send application log") + visible: qfieldSettings.enableInfoCollection && platformUtilities.capabilities & PlatformUtilities.SentryFramework - onClicked: { - applicationLogDialog.open() - } + onClicked: { + applicationLogDialog.open(); + } } } @@ -158,11 +156,11 @@ Page { focus: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height - 80 ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height - 80) / 2 onAboutToShow: { - appliationLogInput.text = '' + appliationLogInput.text = ''; } Column { @@ -209,9 +207,9 @@ Page { standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - var applicationLogMessage = appliationLogInput.text.trim() - iface.sendLog(applicationLogMessage != '' ? applicationLogMessage : 'Manual log submission', includeCloudInformationCheckBox.checked ? cloudConnection.username : '') - displayToast(qsTr("Your application log is being sent…")) + var applicationLogMessage = appliationLogInput.text.trim(); + iface.sendLog(applicationLogMessage != '' ? applicationLogMessage : 'Manual log submission', includeCloudInformationCheckBox.checked ? cloudConnection.username : ''); + displayToast(qsTr("Your application log is being sent…")); } } @@ -219,13 +217,13 @@ Page { target: model function onRowsInserted(parent, first, last) { - if ( !visible ) - unreadMessages = true + if (!visible) + unreadMessages = true; } } onVisibleChanged: { - if ( visible ) - unreadMessages = false + if (visible) + unreadMessages = false; } } diff --git a/src/qml/NavigationBar.qml b/src/qml/NavigationBar.qml index 319517a7e3..f16ac0413d 100644 --- a/src/qml/NavigationBar.qml +++ b/src/qml/NavigationBar.qml @@ -14,11 +14,8 @@ * (at your option) any later version. * * * ***************************************************************************/ - - import QtQuick 2.14 import QtQuick.Controls 2.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -61,7 +58,7 @@ Rectangle { signal processingRunClicked - anchors.top:parent.top + anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: toolBar.topMargin + 48 @@ -88,22 +85,14 @@ Rectangle { height: toolBar.topMargin + 48 - color: ( featureFormList.model.constraintsHardValid && featureFormList.model.constraintsSoftValid ) || toolBar.state !== "Edit" ? Theme.mainColor : !featureFormList.model.constraintsHardValid ? Theme.errorColor : Theme.warningColor + color: (featureFormList.model.constraintsHardValid && featureFormList.model.constraintsSoftValid) || toolBar.state !== "Edit" ? Theme.mainColor : !featureFormList.model.constraintsHardValid ? Theme.errorColor : Theme.warningColor clip: true focus: true Text { // Insure that the text is always visually centered by using the same left and right margi - property double balancedMargin: Math.max( (saveButton.visible ? saveButton.width : 0) - + (previousButton.visible ? previousButton.width : 0) - + (nextButton.visible ? nextButton.width : 0) - + (multiClearButton.visible ? multiClearButton.width : 0), - (cancelButton.visible ? cancelButton.width : 0) - + (editButton.visible ? editButton.width : 0) - + (editGeomButton.visible ? editGeomButton.width : 0) - + (multiEditButton.visible ? multiEditButton.width : 0) - + (menuButton.visible ? menuButton.width : 0) ) + property double balancedMargin: Math.max((saveButton.visible ? saveButton.width : 0) + (previousButton.visible ? previousButton.width : 0) + (nextButton.visible ? nextButton.width : 0) + (multiClearButton.visible ? multiClearButton.width : 0), (cancelButton.visible ? cancelButton.width : 0) + (editButton.visible ? editButton.width : 0) + (editGeomButton.visible ? editGeomButton.width : 0) + (multiEditButton.visible ? multiEditButton.width : 0) + (menuButton.visible ? menuButton.width : 0)) font: Theme.strongFont color: Theme.light anchors.left: parent.left @@ -115,15 +104,11 @@ Rectangle { height: parent.height - toolBar.topMargin text: { - if ( model && selection && selection.focusedItem > -1 && (toolBar.state === 'Navigation' || toolBar.state === 'Edit') ) { - var featurePosition = model.count > 1 - ? ( ( selection.focusedItem + 1 ) + '/' + model.count + ': ' ) - : ''; - - return featurePosition + FeatureUtils.displayName(selection.focusedLayer, selection.focusedFeature) - } - else { - return toolBar.title + if (model && selection && selection.focusedItem > -1 && (toolBar.state === 'Navigation' || toolBar.state === 'Edit')) { + var featurePosition = model.count > 1 ? ((selection.focusedItem + 1) + '/' + model.count + ': ') : ''; + return featurePosition + FeatureUtils.displayName(selection.focusedLayer, selection.focusedFeature); + } else { + return toolBar.title; } } @@ -145,40 +130,39 @@ Rectangle { property bool isTracing: false onPressed: { - startX = mouse.x - startY = mouse.y - lastX = mouse.x - lastY = mouse.y - velocity = 0 - distance = 0 - isTracing = true + startX = mouse.x; + startY = mouse.y; + lastX = mouse.x; + lastY = mouse.y; + velocity = 0; + distance = 0; + isTracing = true; } onPositionChanged: { - if ( !isTracing ) - return - - var currentVelocity = Math.abs(mouse.y - lastY) - lastX = mouse.x - lastY = mouse.y - velocity = (velocity + currentVelocity) / 2.0 - distance = Math.abs(mouse.y - startY) - isTracing = velocity > 15 && distance > parent.height + if (!isTracing) + return; + var currentVelocity = Math.abs(mouse.y - lastY); + lastX = mouse.x; + lastY = mouse.y; + velocity = (velocity + currentVelocity) / 2.0; + distance = Math.abs(mouse.y - startY); + isTracing = velocity > 15 && distance > parent.height; } onReleased: { - if ( !isTracing ) { - toolBar.statusIndicatorSwiped(getDirection()) + if (!isTracing) { + toolBar.statusIndicatorSwiped(getDirection()); } else { - toolBar.statusIndicatorClicked() + toolBar.statusIndicatorClicked(); } } function getDirection() { - var diffX = lastX - startX - var diffY = lastY - startY + var diffX = lastX - startX; + var diffY = lastY - startY; if (Math.abs(diffX) > Math.abs(diffY)) { - return lastX < startX ? 'left' : 'right' + return lastX < startX ? 'left' : 'right'; } - return lastY < startY ? 'up' : 'down' + return lastY < startY ? 'up' : 'down'; } } } @@ -196,12 +180,12 @@ Rectangle { height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_chevron_right_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_chevron_right_white_24dp") - enabled: ( toolBar.state == "Navigation" ) + enabled: (toolBar.state == "Navigation") onClicked: { - if ( toolBar.model && ( selection.focusedItem + 1 ) < toolBar.model.count ) { + if (toolBar.model && (selection.focusedItem + 1) < toolBar.model.count) { selection.focusedItem = selection.focusedItem + 1; } else { selection.focusedItem = -1; @@ -209,7 +193,7 @@ Rectangle { } } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -228,22 +212,20 @@ Rectangle { height: 48 clip: true - iconSource: toolBar.state == "Navigation" - ? Theme.getThemeIcon( "ic_chevron_left_white_24dp" ) - : Theme.getThemeVectorIcon( "ic_arrow_left_white_24dp" ) + iconSource: toolBar.state == "Navigation" ? Theme.getThemeIcon("ic_chevron_left_white_24dp") : Theme.getThemeVectorIcon("ic_arrow_left_white_24dp") enabled: toolBar.state != "Edit" && !toolBar.multiSelection onClicked: { - if ( toolBar.model && ( selection.focusedItem > 0 ) ) { - selection.focusedItem = selection.focusedItem - 1; - } else { - selection.focusedItem = -1; - backClicked(); - } + if (toolBar.model && (selection.focusedItem > 0)) { + selection.focusedItem = selection.focusedItem - 1; + } else { + selection.focusedItem = -1; + backClicked(); + } } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -262,20 +244,20 @@ Rectangle { height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_check_white_48dp" ) + iconSource: Theme.getThemeIcon("ic_check_white_48dp") opacity: featureFormList.model.constraintsHardValid ? 1.0 : 0.3 onClicked: { - if (toolBar.state == "ProcessingLaunch") { - processingRunClicked() - } else { - if( featureFormList.model.constraintsHardValid ) { - toolBar.save() - } else { - displayToast( "Constraints not valid", 'warning' ) - } - } - } - Behavior on width { + if (toolBar.state == "ProcessingLaunch") { + processingRunClicked(); + } else { + if (featureFormList.model.constraintsHardValid) { + toolBar.save(); + } else { + displayToast("Constraints not valid", 'warning'); + } + } + } + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -290,17 +272,17 @@ Rectangle { anchors.topMargin: toolBar.topMargin visible: !qfieldSettings.autoSave && toolBar.state == "Edit" - width: visible ? 48: 0 + width: visible ? 48 : 0 height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_clear_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_clear_white_24dp") onClicked: { - toolBar.cancel() + toolBar.cancel(); } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -312,28 +294,24 @@ Rectangle { property bool readOnly: false - visible: stateMachine.state === "digitize" - && ! selection.focusedGeometry.isNull - && ! featureFormList.model.featureModel.geometryLocked - && ( projectInfo.editRights || editButton.isCreatedCloudFeature ) - && toolBar.state == "Navigation" && !readOnly && projectInfo.editRights + visible: stateMachine.state === "digitize" && !selection.focusedGeometry.isNull && !featureFormList.model.featureModel.geometryLocked && (projectInfo.editRights || editButton.isCreatedCloudFeature) && toolBar.state == "Navigation" && !readOnly && projectInfo.editRights anchors.right: editButton.left anchors.top: parent.top anchors.topMargin: toolBar.topMargin - iconSource: Theme.getThemeIcon( "ic_edit_geometry_white" ) + iconSource: Theme.getThemeIcon("ic_edit_geometry_white") width: visible ? 48 : 0 height: 48 clip: true onClicked: { - extentController.zoomToSelected(true) - toolBar.editGeometryButtonClicked() + extentController.zoomToSelected(true); + toolBar.editGeometryButtonClicked(); } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -343,7 +321,7 @@ Rectangle { target: selection function onFocusedItemChanged() { - editGeomButton.readOnly = selection.focusedLayer && selection.focusedLayer.readOnly + editGeomButton.readOnly = selection.focusedLayer && selection.focusedLayer.readOnly; } } } @@ -358,18 +336,18 @@ Rectangle { anchors.top: parent.top anchors.topMargin: toolBar.topMargin - visible: toolBar.state == "Navigation" && supportsEditing && ( projectInfo.editRights || isCreatedCloudFeature ) + visible: toolBar.state == "Navigation" && supportsEditing && (projectInfo.editRights || isCreatedCloudFeature) width: visible ? 48 : 0 height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_edit_attributes_white" ) + iconSource: Theme.getThemeIcon("ic_edit_attributes_white") onClicked: { - toolBar.editAttributesButtonClicked() + toolBar.editAttributesButtonClicked(); } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -379,16 +357,13 @@ Rectangle { target: selection function onFocusedItemChanged() { - editButton.supportsEditing = selection.focusedLayer && selection.focusedLayer.supportsEditing + editButton.supportsEditing = selection.focusedLayer && selection.focusedLayer.supportsEditing; } function onFocusedFeatureChanged() { if (QFieldCloudUtils.getProjectId(qgisProject.fileName) != '') { - editButton.isCreatedCloudFeature = cloudProjectsModel.layerObserver.deltaFileWrapper.isCreatedFeature( - selection.focusedLayer, - selection.focusedFeature - ) + editButton.isCreatedCloudFeature = cloudProjectsModel.layerObserver.deltaFileWrapper.isCreatedFeature(selection.focusedLayer, selection.focusedFeature); } else { - editButton.isCreatedCloudFeature = false + editButton.isCreatedCloudFeature = false; } } } @@ -406,17 +381,17 @@ Rectangle { height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_dot_menu_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_dot_menu_white_24dp") onClicked: { - if ( toolBar.state == "Indication" ) { - featureListMenu.popup(menuButton.x + menuButton.width - featureListMenu.width, menuButton.y); - } else if ( toolBar.state == "Navigation" ) { - featureMenu.popup(menuButton.x + menuButton.width - featureMenu.width, menuButton.y); - } + if (toolBar.state == "Indication") { + featureListMenu.popup(menuButton.x + menuButton.width - featureListMenu.width, menuButton.y); + } else if (toolBar.state == "Navigation") { + featureMenu.popup(menuButton.x + menuButton.width - featureMenu.width, menuButton.y); + } } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -435,13 +410,13 @@ Rectangle { height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_clear_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_clear_white_24dp") - enabled: ( toolBar.multiSelection && toolBar.model ) + enabled: (toolBar.multiSelection && toolBar.model) - onClicked: toggleMultiSelection(); + onClicked: toggleMultiSelection() - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -455,7 +430,7 @@ Rectangle { anchors.top: parent.top anchors.topMargin: toolBar.topMargin - width: ( toolBar.state == "Indication" && toolBar.multiSelection && toolBar.model ? 48: 0 ) + width: (toolBar.state == "Indication" && toolBar.multiSelection && toolBar.model ? 48 : 0) visible: width > 0 height: 48 verticalAlignment: Text.AlignVCenter @@ -474,23 +449,20 @@ Rectangle { anchors.top: parent.top anchors.topMargin: toolBar.topMargin - visible: toolBar.state == "Indication" - && toolBar.model && toolBar.model.canEditAttributesSelection && toolBar.model.selectedCount > 1 - && projectInfo.editRights + visible: toolBar.state == "Indication" && toolBar.model && toolBar.model.canEditAttributesSelection && toolBar.model.selectedCount > 1 && projectInfo.editRights width: visible ? 48 : 0 height: 48 clip: true - iconSource: Theme.getThemeIcon( "ic_edit_attributes_white" ) + iconSource: Theme.getThemeIcon("ic_edit_attributes_white") - enabled: toolBar.model && toolBar.model.canEditAttributesSelection && toolBar.model.selectedCount > 1 - && projectInfo.editRights + enabled: toolBar.model && toolBar.model.canEditAttributesSelection && toolBar.model.selectedCount > 1 && projectInfo.editRights onClicked: { multiEditClicked(); } - Behavior on width { + Behavior on width { PropertyAnimation { easing.type: Easing.OutQuart } @@ -499,24 +471,24 @@ Rectangle { Menu { id: featureListMenu - title: qsTr( "Feature List Menu" ) + title: qsTr("Feature List Menu") width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } topMargin: mainWindow.sceneTopMargin bottomMargin: mainWindow.sceneBottomMargin MenuItem { - text: qsTr( 'Toggle Feature Selection' ) + text: qsTr('Toggle Feature Selection') checkable: true checked: toolBar.multiSelection @@ -526,24 +498,26 @@ Rectangle { leftPadding: Theme.menuItemCheckLeftPadding onTriggered: { - toggleMultiSelection(); + toggleMultiSelection(); } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { - text: qsTr( 'Print Atlas Feature(s) to PDF' ) - icon.source: Theme.getThemeIcon( "ic_print_white_24dp" ) - enabled: toolBar.model && toolBar.model.selectedCount > 0 && LayerUtils.isAtlasCoverageLayer( toolBar.model.selectedLayer ) + text: qsTr('Print Atlas Feature(s) to PDF') + icon.source: Theme.getThemeIcon("ic_print_white_24dp") + enabled: toolBar.model && toolBar.model.selectedCount > 0 && LayerUtils.isAtlasCoverageLayer(toolBar.model.selectedLayer) font: Theme.defaultFont height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: { - featureListMenu.close(); - showAtlasMenu(); + featureListMenu.close(); + showAtlasMenu(); } } @@ -556,44 +530,44 @@ Rectangle { MenuItem { id: mergeSelectedFeaturesBtn - text: qsTr( 'Merge Selected Features' ) - icon.source: Theme.getThemeIcon( "ic_merge_features_white_24dp" ) + text: qsTr('Merge Selected Features') + icon.source: Theme.getThemeIcon("ic_merge_features_white_24dp") enabled: toolBar.model && toolBar.model.canMergeSelection && toolBar.model.selectedCount > 1 && projectInfo.editRights font: Theme.defaultFont leftPadding: Theme.menuItemLeftPadding - onTriggered: multiMergeClicked(); + onTriggered: multiMergeClicked() } MenuItem { id: moveSelectedFeaturesBtn - text: qsTr( 'Move Selected Feature(s)' ) - icon.source: Theme.getThemeVectorIcon( "ic_move_white_24dp" ) + text: qsTr('Move Selected Feature(s)') + icon.source: Theme.getThemeVectorIcon("ic_move_white_24dp") enabled: toolBar.model && toolBar.model.canMoveSelection && projectInfo.editRights font: Theme.defaultFont leftPadding: Theme.menuItemLeftPadding - onTriggered: multiMoveClicked(); + onTriggered: multiMoveClicked() } MenuItem { id: duplicateSelectedFeaturesBtn - text: qsTr( 'Duplicate Selected Feature(s)' ) - icon.source: Theme.getThemeVectorIcon( "ic_duplicate_black_24dp" ) + text: qsTr('Duplicate Selected Feature(s)') + icon.source: Theme.getThemeVectorIcon("ic_duplicate_black_24dp") enabled: toolBar.model && toolBar.model.canDuplicateSelection && projectInfo.insertRights font: Theme.defaultFont leftPadding: Theme.menuItemLeftPadding - onTriggered: multiDuplicateClicked(); + onTriggered: multiDuplicateClicked() } MenuItem { id: deleteSelectedFeaturesBtn - text: qsTr( 'Delete Selected Feature(s)' ) - icon.source: Theme.getThemeIcon( "ic_delete_forever_white_24dp" ) + text: qsTr('Delete Selected Feature(s)') + icon.source: Theme.getThemeIcon("ic_delete_forever_white_24dp") enabled: toolBar.model && toolBar.model.canDeleteSelection && projectInfo.editRights visible: enabled height: enabled ? undefined : 0 @@ -601,7 +575,7 @@ Rectangle { font: Theme.defaultFont leftPadding: Theme.menuItemLeftPadding - onTriggered: multiDeleteClicked(); + onTriggered: multiDeleteClicked() } MenuSeparator { @@ -610,34 +584,34 @@ Rectangle { MenuItem { id: processingSelectedFeaturesBtn - text: qsTr( 'Process Selected Feature(s)' ) - icon.source: Theme.getThemeVectorIcon( "ic_processing_black_24dp" ) + text: qsTr('Process Selected Feature(s)') + icon.source: Theme.getThemeVectorIcon("ic_processing_black_24dp") enabled: toolBar.model && toolBar.model.canProcessSelection && projectInfo.editRights font: Theme.defaultFont leftPadding: Theme.menuItemLeftPadding - onTriggered: multiProcessingClicked(); + onTriggered: multiProcessingClicked() } } Menu { id: featureMenu - title: qsTr( "Feature Menu" ) + title: qsTr("Feature Menu") topMargin: mainWindow.sceneTopMargin bottomMargin: mainWindow.sceneBottomMargin width: { - const toolbarWidth = featureMenuActionsToolbar.childrenRect.width + 4 - let result = 50; - let padding = 0; - for (let i = 1; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + const toolbarWidth = featureMenuActionsToolbar.childrenRect.width + 4; + let result = 50; + let padding = 0; + for (let i = 1; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } Row { @@ -655,13 +629,13 @@ Rectangle { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_copy_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_copy_black_24dp") iconColor: enabled ? Theme.mainTextColor : Theme.mainTextDisabledColor bgcolor: enabled && hovered ? parent.hoveredColor : "#00ffffff" onClicked: { - clipboardManager.copyFeatureToClipboard(featureFormList.model.featureModel.feature, true) - mainWindow.displayToast(qsTr('Feature attributes copied to clipboard')) + clipboardManager.copyFeatureToClipboard(featureFormList.model.featureModel.feature, true); + mainWindow.displayToast(qsTr('Feature attributes copied to clipboard')); } } @@ -670,18 +644,18 @@ Rectangle { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_paste_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_paste_black_24dp") iconColor: enabled ? Theme.mainTextColor : Theme.mainTextDisabledColor bgcolor: enabled && hovered ? parent.hoveredColor : "#00ffffff" enabled: clipboardManager && clipboardManager.holdsFeature onClicked: { - var feature = clipboardManager.pasteFeatureFromClipboard() + var feature = clipboardManager.pasteFeatureFromClipboard(); if (featureFormList.model.featureModel.updateAttributesFromFeature(feature)) { - featureFormList.model.featureModel.save() - mainWindow.displayToast(qsTr('Feature attributes updated from clipboard')) + featureFormList.model.featureModel.save(); + mainWindow.displayToast(qsTr('Feature attributes updated from clipboard')); } else { - mainWindow.displayToast(qsTr('No feature attributes were updated from clipboard')) + mainWindow.displayToast(qsTr('No feature attributes were updated from clipboard')); } } } @@ -691,10 +665,10 @@ Rectangle { height: 48 width: 48 round: true - iconSource: Theme.getThemeIcon( "ic_print_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_print_white_24dp") iconColor: enabled ? Theme.mainTextColor : Theme.mainTextDisabledColor bgcolor: enabled && hovered ? parent.hoveredColor : "#00ffffff" - enabled: LayerUtils.isAtlasCoverageLayer( selection.focusedLayer ) + enabled: LayerUtils.isAtlasCoverageLayer(selection.focusedLayer) onClicked: { featureMenu.close(); @@ -707,33 +681,35 @@ Rectangle { height: 48 width: 48 round: true - iconSource: Theme.getThemeIcon( "ic_navigation_flag_purple_24dp" ) + iconSource: Theme.getThemeIcon("ic_navigation_flag_purple_24dp") iconColor: enabled ? Theme.mainTextColor : Theme.mainTextDisabledColor bgcolor: enabled && hovered ? parent.hoveredColor : "#00ffffff" onClicked: { featureMenu.close(); destinationClicked(); - mainWindow.displayToast(qsTr('Feature set as navigation destination')) + mainWindow.displayToast(qsTr('Feature set as navigation destination')); } } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { - text: qsTr( 'Zoom to Feature' ) - icon.source: Theme.getThemeIcon( "ic_fullscreen_white_24dp" ) + text: qsTr('Zoom to Feature') + icon.source: Theme.getThemeIcon("ic_fullscreen_white_24dp") font: Theme.defaultFont height: 48 leftPadding: Theme.menuItemLeftPadding - onTriggered: extentController.zoomToSelected(); + onTriggered: extentController.zoomToSelected() } MenuItem { - text: qsTr( 'Auto-Zoom to Feature' ) + text: qsTr('Auto-Zoom to Feature') font: Theme.defaultFont height: 48 @@ -752,70 +728,58 @@ Rectangle { MenuItem { id: moveFeatureBtn - text: qsTr( 'Move Feature' ) - icon.source: Theme.getThemeVectorIcon( "ic_move_white_24dp" ) - enabled: ( - (projectInfo.editRights || editButton.isCreatedCloudFeature) - && (!selection.focusedLayer || !featureFormList.model.featureModel.geometryLocked) - ) + text: qsTr('Move Feature') + icon.source: Theme.getThemeVectorIcon("ic_move_white_24dp") + enabled: ((projectInfo.editRights || editButton.isCreatedCloudFeature) && (!selection.focusedLayer || !featureFormList.model.featureModel.geometryLocked)) visible: enabled font: Theme.defaultFont height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - onTriggered: moveClicked(); + onTriggered: moveClicked() } MenuItem { id: duplicateFeatureBtn - text: qsTr( 'Duplicate Feature' ) - icon.source: Theme.getThemeVectorIcon( "ic_duplicate_black_24dp" ) - enabled: ( - projectInfo.insertRights - && (!selection.focusedLayer || !selection.focusedLayer.customProperty( "QFieldSync/is_geometry_locked", false )) - ) + text: qsTr('Duplicate Feature') + icon.source: Theme.getThemeVectorIcon("ic_duplicate_black_24dp") + enabled: (projectInfo.insertRights && (!selection.focusedLayer || !selection.focusedLayer.customProperty("QFieldSync/is_geometry_locked", false))) visible: enabled font: Theme.defaultFont height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - onTriggered: duplicateClicked(); + onTriggered: duplicateClicked() } MenuItem { id: transferFeatureAttributesBtn - text: qsTr( 'Update Attributes From Feature' ) - icon.source: Theme.getThemeVectorIcon( "ic_transfer_into_black_24dp" ) - enabled: ( - projectInfo.insertRights - && (!selection.focusedLayer || !selection.focusedLayer.customProperty( "QFieldSync/is_geometry_locked", false )) - ) + text: qsTr('Update Attributes From Feature') + icon.source: Theme.getThemeVectorIcon("ic_transfer_into_black_24dp") + enabled: (projectInfo.insertRights && (!selection.focusedLayer || !selection.focusedLayer.customProperty("QFieldSync/is_geometry_locked", false))) visible: enabled font: Theme.defaultFont height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - onTriggered: transferClicked(); + onTriggered: transferClicked() } MenuItem { id: deleteFeatureBtn - text: qsTr( 'Delete Feature' ) - icon.source: Theme.getThemeIcon( "ic_delete_forever_white_24dp" ) - enabled: ( - (projectInfo.editRights || editButton.isCreatedCloudFeature) - && (!selection.focusedLayer || !selection.focusedLayer.customProperty( "QFieldSync/is_geometry_locked", false )) - ) + text: qsTr('Delete Feature') + icon.source: Theme.getThemeIcon("ic_delete_forever_white_24dp") + enabled: ((projectInfo.editRights || editButton.isCreatedCloudFeature) && (!selection.focusedLayer || !selection.focusedLayer.customProperty("QFieldSync/is_geometry_locked", false))) visible: enabled font: Theme.defaultFont height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - onTriggered: deleteClicked(); + onTriggered: deleteClicked() } } @@ -825,26 +789,26 @@ Rectangle { property alias printTimer: timer property alias printName: timer.printName - title: qsTr( "Print Atlas Feature(s)" ) + title: qsTr("Print Atlas Feature(s)") - signal enablePrintItem( int rows ) + signal enablePrintItem(int rows) width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } topMargin: mainWindow.sceneTopMargin bottomMargin: mainWindow.sceneBottomMargin MenuItem { - text: qsTr( 'Select template below' ) + text: qsTr('Select template below') font: Theme.defaultFont height: 48 @@ -857,8 +821,8 @@ Rectangle { id: atlasListInstantiator model: PrintLayoutListModel { - project: qgisProject - atlasCoverageLayer: toolBar.state === "Indication" ? model.selectedLayer : selection.focusedLayer + project: qgisProject + atlasCoverageLayer: toolBar.state === "Indication" ? model.selectedLayer : selection.focusedLayer } MenuItem { @@ -869,13 +833,17 @@ Rectangle { leftPadding: Theme.menuItemLeftPadding onTriggered: { - displayToast( qsTr( 'Printing...') ) - atlasMenu.printName = Title - atlasMenu.printTimer.restart(); + displayToast(qsTr('Printing...')); + atlasMenu.printName = Title; + atlasMenu.printTimer.restart(); } } - onObjectAdded: (index, object) => { atlasMenu.insertItem(index+1, object) } - onObjectRemoved: (index, object) => { atlasMenu.removeItem(object) } + onObjectAdded: (index, object) => { + atlasMenu.insertItem(index + 1, object); + } + onObjectRemoved: (index, object) => { + atlasMenu.removeItem(object); + } } Timer { @@ -886,31 +854,28 @@ Rectangle { interval: 500 repeat: false onTriggered: { - var ids = []; - if ( toolBar.state === "Indication" ) { - for( var i = 0; i < model.selectedFeatures.length; i++ ) { - ids.push(model.selectedFeatures[i].id) - } - } else { - ids.push(selection.focusedFeature.id) - } - if ( iface.printAtlasFeatures( printName, ids ) ) { - displayToast( qsTr( 'Atlas feature(s) successfully printed and placed in your project folder' ) ); + var ids = []; + if (toolBar.state === "Indication") { + for (var i = 0; i < model.selectedFeatures.length; i++) { + ids.push(model.selectedFeatures[i].id); } + } else { + ids.push(selection.focusedFeature.id); + } + if (iface.printAtlasFeatures(printName, ids)) { + displayToast(qsTr('Atlas feature(s) successfully printed and placed in your project folder')); + } } } } function showAtlasMenu() { - if (atlasListInstantiator.model.rowCount() > 1) - { - atlasMenu.popup(menuButton.x + menuButton.width - atlasMenu.width, menuButton.y); - } - else - { - displayToast( qsTr( 'Printing...') ) - atlasMenu.printName = atlasListInstantiator.model.titleAt( 0 ); - atlasMenu.printTimer.restart(); - } + if (atlasListInstantiator.model.rowCount() > 1) { + atlasMenu.popup(menuButton.x + menuButton.width - atlasMenu.width, menuButton.y); + } else { + displayToast(qsTr('Printing...')); + atlasMenu.printName = atlasListInstantiator.model.titleAt(0); + atlasMenu.printTimer.restart(); + } } } diff --git a/src/qml/NavigationHighlight.qml b/src/qml/NavigationHighlight.qml index 9dd86bcafa..a8b58551a7 100644 --- a/src/qml/NavigationHighlight.qml +++ b/src/qml/NavigationHighlight.qml @@ -1,8 +1,6 @@ import QtQuick 2.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Item { @@ -12,7 +10,7 @@ Item { LinePolygon { visible: positionSource.active mapSettings: navigation.mapSettings - geometry: QgsGeometryWrapper { + geometry: QgsGeometryWrapper { qgsGeometry: navigation.path crs: navigation.mapSettings.crs ? navigation.mapSettings.crs : CoordinateReferenceSystemUtils.invalidCrs() } diff --git a/src/qml/NavigationInformationView.qml b/src/qml/NavigationInformationView.qml index 7561dc27e9..23431ef7d9 100644 --- a/src/qml/NavigationInformationView.qml +++ b/src/qml/NavigationInformationView.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -38,8 +37,8 @@ Rectangle { } else { navigation.previousDestinationVertex(); } - - if (interval > 100) interval = interval * 0.8; + if (interval > 100) + interval = interval * 0.8; } } @@ -67,16 +66,16 @@ Rectangle { iconColor: Theme.mainTextColor onPressed: { - navigation.previousDestinationVertex() + navigation.previousDestinationVertex(); featureVertexTimer.moveForward = false; - featureVertexTimer.interval = 700 - featureVertexTimer.restart() + featureVertexTimer.interval = 700; + featureVertexTimer.restart(); } onReleased: { - featureVertexTimer.stop() + featureVertexTimer.stop(); } onCanceled: { - featureVertexTimer.stop() + featureVertexTimer.stop(); } } @@ -104,16 +103,16 @@ Rectangle { iconColor: Theme.mainTextColor onPressed: { - navigation.nextDestinationVertex() + navigation.nextDestinationVertex(); featureVertexTimer.moveForward = true; - featureVertexTimer.interval = 700 - featureVertexTimer.restart() + featureVertexTimer.interval = 700; + featureVertexTimer.restart(); } onReleased: { - featureVertexTimer.stop() + featureVertexTimer.stop(); } onCanceled: { - featureVertexTimer.stop() + featureVertexTimer.stop(); } } } @@ -126,8 +125,8 @@ Rectangle { width: parent.width height: grid.rows * navigationInformationView.cellHeight flow: GridLayout.TopToBottom - rows: parent.width > 620? 1 : 2 - property double cellWidth: grid.width / ( ceilsCount / grid.rows ) + rows: parent.width > 620 ? 1 : 2 + property double cellWidth: grid.width / (ceilsCount / grid.rows) Rectangle { height: cellHeight @@ -144,18 +143,14 @@ Rectangle { Layout.fillWidth: false font: Theme.tipFont color: Theme.secondaryTextColor - text: coordinatesIsXY - ? coordinatesIsGeographic ? qsTr( "Lon" ) : qsTr( "X" ) - : coordinatesIsGeographic ? qsTr( "Lat" ) : qsTr( "Y" ) + text: coordinatesIsXY ? coordinatesIsGeographic ? qsTr("Lon") : qsTr("X") : coordinatesIsGeographic ? qsTr("Lat") : qsTr("Y") } Text { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: coordinatesIsXY - ? Number( coordinates.x ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) - : Number( coordinates.y ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) + text: coordinatesIsXY ? Number(coordinates.x).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) : Number(coordinates.y).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) elide: Text.ElideRight } } @@ -176,18 +171,14 @@ Rectangle { Layout.fillWidth: false font: Theme.tipFont color: Theme.secondaryTextColor - text: coordinatesIsXY - ? coordinatesIsGeographic ? qsTr( "Lat" ) : qsTr( "Y" ) - : coordinatesIsGeographic ? qsTr( "Lon" ) : qsTr( "X" ) + text: coordinatesIsXY ? coordinatesIsGeographic ? qsTr("Lat") : qsTr("Y") : coordinatesIsGeographic ? qsTr("Lon") : qsTr("X") } Text { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: coordinatesIsXY - ? Number( coordinates.y ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) - : Number( coordinates.x ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) + text: coordinatesIsXY ? Number(coordinates.y).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) : Number(coordinates.x).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) elide: Text.ElideRight } } @@ -215,9 +206,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.active && positionSource.positionInformation && positionSource.positionInformation.latitudeValid - ? UnitTypes.formatDistance( navigation.distance * UnitTypes.fromUnitToUnitFactor( navigation.distanceUnits, projectInfo.distanceUnits ), 3, projectInfo.distanceUnits ) - : qsTr( "N/A" ) + text: positionSource.active && positionSource.positionInformation && positionSource.positionInformation.latitudeValid ? UnitTypes.formatDistance(navigation.distance * UnitTypes.fromUnitToUnitFactor(navigation.distanceUnits, projectInfo.distanceUnits), 3, projectInfo.distanceUnits) : qsTr("N/A") elide: Text.ElideRight } } @@ -245,9 +234,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.active && positionSource.positionInformation && positionSource.positionInformation.latitudeValid - ? Number( navigation.bearing ).toLocaleString( Qt.locale(), 'f', 1 ) + '°' - : qsTr( "N/A" ) + text: positionSource.active && positionSource.positionInformation && positionSource.positionInformation.latitudeValid ? Number(navigation.bearing).toLocaleString(Qt.locale(), 'f', 1) + '°' : qsTr("N/A") elide: Text.ElideRight } } diff --git a/src/qml/NavigationRenderer.qml b/src/qml/NavigationRenderer.qml index 700cf748e8..ddf82ee1f6 100644 --- a/src/qml/NavigationRenderer.qml +++ b/src/qml/NavigationRenderer.qml @@ -1,131 +1,138 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Item { - id: navigationRenderer + id: navigationRenderer + + property var pointIndex: undefined + property int pointType: NavigationModel.Destination + + property MapSettings mapSettings + property alias geometryWrapper: geometryWrapper - property var pointIndex: undefined - property int pointType: NavigationModel.Destination + QgsGeometryWrapper { + id: geometryWrapper + } - property MapSettings mapSettings - property alias geometryWrapper: geometryWrapper + Connections { + target: geometryWrapper - QgsGeometryWrapper { - id: geometryWrapper + function onQgsGeometryChanged() { + geometryComponent.sourceComponent = undefined; + if (geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point) { + geometryComponent.sourceComponent = pointHighlight; + } } + } - Connections { - target: geometryWrapper + Component { + id: pointHighlight - function onQgsGeometryChanged() { - geometryComponent.sourceComponent = undefined - if (geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point) { - geometryComponent.sourceComponent = pointHighlight - } + Repeater { + model: geometryWrapper.pointList() + + Item { + property CoordinateTransformer ct: CoordinateTransformer { + id: _ct + sourceCrs: geometryWrapper.crs + sourcePosition: modelData + destinationCrs: mapCanvas.mapSettings.destinationCrs + transformContext: qgisProject ? qgisProject.transformContext : CoordinateReferenceSystemUtils.emptyTransformContext() } - } - Component { - id: pointHighlight - - Repeater { - model: geometryWrapper.pointList() - - Item { - property CoordinateTransformer ct: CoordinateTransformer { - id: _ct - sourceCrs: geometryWrapper.crs - sourcePosition: modelData - destinationCrs: mapCanvas.mapSettings.destinationCrs - transformContext: qgisProject ? qgisProject.transformContext : CoordinateReferenceSystemUtils.emptyTransformContext() - } - - MapToScreen { - id: mapToScreenPosition - mapSettings: mapCanvas.mapSettings - mapPoint: _ct.projectedPosition - } - - property bool isOnMapCanvas: mapToScreenPosition.screenPoint.x > 0 - && mapToScreenPosition.screenPoint.x < mapCanvas.width - && mapToScreenPosition.screenPoint.y > 0 - && mapToScreenPosition.screenPoint.y < mapCanvas.height - Rectangle { - id: point - visible: isOnMapCanvas - x: mapToScreenPosition.screenPoint.x - width / 2 - y: mapToScreenPosition.screenPoint.y - height / 2 - - width: 16 - height: 16 - color: Theme.navigationColor - border.color: "white" - border.width: 3 - transform: Rotation { origin.x: point.width / 2; origin.y: point.width / 2; angle: 45} - - layer.enabled: true - layer.samples: 4 - layer.effect: QfDropShadow { - transparentBorder: true - radius: 8 - color: "#99000000" - horizontalOffset: 0 - verticalOffset: 0 - } - } - - Shape { - id: edgePoint - visible: !isOnMapCanvas - width: 20 - height: 24 - - x: Math.min(mapCanvas.width - width, Math.max(0, mapToScreenPosition.screenPoint.x - width / 2)) - y: Math.min(mapCanvas.height - width, Math.max(0, mapToScreenPosition.screenPoint.y - width / 2)) - - transform: Rotation { - origin.x: edgePoint.width / 2; - origin.y: edgePoint.width / 2; - angle: -(Math.atan2(mapCanvas.width / 2 - mapToScreenPosition.screenPoint.x, mapCanvas.height / 2 - mapToScreenPosition.screenPoint.y) / Math.PI) * 180 - } - - ShapePath { - strokeWidth: 3 - strokeColor: "white" - strokeStyle: ShapePath.SolidLine - fillColor: Theme.navigationColor - joinStyle: ShapePath.MiterJoin - startX: 10 - startY: 0 - PathLine { x: 18; y: 20 } - PathLine { x: 2; y: 20 } - PathLine { x: 10; y: 0 } - } - - layer.enabled: true - layer.samples: 4 - layer.effect: QfDropShadow { - transparentBorder: true - radius: 8 - color: "#99000000" - horizontalOffset: 0 - verticalOffset: 0 - } - } - } + MapToScreen { + id: mapToScreenPosition + mapSettings: mapCanvas.mapSettings + mapPoint: _ct.projectedPosition + } + + property bool isOnMapCanvas: mapToScreenPosition.screenPoint.x > 0 && mapToScreenPosition.screenPoint.x < mapCanvas.width && mapToScreenPosition.screenPoint.y > 0 && mapToScreenPosition.screenPoint.y < mapCanvas.height + Rectangle { + id: point + visible: isOnMapCanvas + x: mapToScreenPosition.screenPoint.x - width / 2 + y: mapToScreenPosition.screenPoint.y - height / 2 + + width: 16 + height: 16 + color: Theme.navigationColor + border.color: "white" + border.width: 3 + transform: Rotation { + origin.x: point.width / 2 + origin.y: point.width / 2 + angle: 45 + } + + layer.enabled: true + layer.samples: 4 + layer.effect: QfDropShadow { + transparentBorder: true + radius: 8 + color: "#99000000" + horizontalOffset: 0 + verticalOffset: 0 + } } - } - Loader { - id: geometryComponent - // the sourceComponent is updated with the connection on wrapper qgsGeometryChanged signal - // but it needs to be ready on first used - sourceComponent: geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point ? pointHighlight : undefined + Shape { + id: edgePoint + visible: !isOnMapCanvas + width: 20 + height: 24 + + x: Math.min(mapCanvas.width - width, Math.max(0, mapToScreenPosition.screenPoint.x - width / 2)) + y: Math.min(mapCanvas.height - width, Math.max(0, mapToScreenPosition.screenPoint.y - width / 2)) + + transform: Rotation { + origin.x: edgePoint.width / 2 + origin.y: edgePoint.width / 2 + angle: -(Math.atan2(mapCanvas.width / 2 - mapToScreenPosition.screenPoint.x, mapCanvas.height / 2 - mapToScreenPosition.screenPoint.y) / Math.PI) * 180 + } + + ShapePath { + strokeWidth: 3 + strokeColor: "white" + strokeStyle: ShapePath.SolidLine + fillColor: Theme.navigationColor + joinStyle: ShapePath.MiterJoin + startX: 10 + startY: 0 + PathLine { + x: 18 + y: 20 + } + PathLine { + x: 2 + y: 20 + } + PathLine { + x: 10 + y: 0 + } + } + + layer.enabled: true + layer.samples: 4 + layer.effect: QfDropShadow { + transparentBorder: true + radius: 8 + color: "#99000000" + horizontalOffset: 0 + verticalOffset: 0 + } + } + } } + } + + Loader { + id: geometryComponent + // the sourceComponent is updated with the connection on wrapper qgsGeometryChanged signal + // but it needs to be ready on first used + sourceComponent: geometryWrapper && geometryWrapper.qgsGeometry.type === Qgis.GeometryType.Point ? pointHighlight : undefined + } } - diff --git a/src/qml/Nyuki.qml b/src/qml/Nyuki.qml index 4699bf6a08..4298eff5a4 100644 --- a/src/qml/Nyuki.qml +++ b/src/qml/Nyuki.qml @@ -24,7 +24,12 @@ Item { transitions: Transition { from: "*" to: "*" - NumberAnimation { target: nyukiContainer; property: "anchors.bottomMargin"; duration: 1000; easing.type: Easing.InOutQuad } + NumberAnimation { + target: nyukiContainer + property: "anchors.bottomMargin" + duration: 1000 + easing.type: Easing.InOutQuad + } } Image { @@ -39,20 +44,20 @@ Item { sourceSize.height: 1024 Rectangle { - width: 12 - height: 12 - color: "white" - x: 83 - y: 83 - radius: 5 + width: 12 + height: 12 + color: "white" + x: 83 + y: 83 + radius: 5 } Rectangle { - width: 12 - height: 12 - color: "white" - x: 105 - y: 83 - radius: 5 + width: 12 + height: 12 + color: "white" + x: 105 + y: 83 + radius: 5 } Rectangle { id: nyukiLeft @@ -65,9 +70,11 @@ Item { rotation: 0 transformOrigin: Item.TopLeft SequentialAnimation { - PauseAnimation { duration: 1000 } + PauseAnimation { + duration: 1000 + } NumberAnimation { - target: nyukiLeft + target: nyukiLeft property: "rotation" to: 359 duration: 2000 @@ -88,9 +95,11 @@ Item { rotation: 0 transformOrigin: Item.TopRight SequentialAnimation { - PauseAnimation { duration: 1000 } + PauseAnimation { + duration: 1000 + } NumberAnimation { - target: nyukiRight + target: nyukiRight property: "rotation" to: -359 duration: 2000 @@ -102,4 +111,3 @@ Item { } } } - diff --git a/src/qml/OverlayFeatureFormDrawer.qml b/src/qml/OverlayFeatureFormDrawer.qml index 4eb8057760..47c6bc9b9f 100644 --- a/src/qml/OverlayFeatureFormDrawer.qml +++ b/src/qml/OverlayFeatureFormDrawer.qml @@ -2,7 +2,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Window 2.14 - import org.qfield 1.0 Drawer { @@ -19,18 +18,18 @@ Drawer { closePolicy: Popup.NoAutoClose // prevent accidental feature addition when clicking outside of the popup drawer width: { - if (qfieldSettings.fullScreenIdentifyView || parent.width < parent.height || parent.width < 300) { - parent.width - } else { - Math.min(Math.max(200, parent.width / 2.25), parent.width) - } + if (qfieldSettings.fullScreenIdentifyView || parent.width < parent.height || parent.width < 300) { + parent.width; + } else { + Math.min(Math.max(200, parent.width / 2.25), parent.width); + } } height: { - if (qfieldSettings.fullScreenIdentifyView || parent.width > parent.height) { - parent.height - } else { - Math.min(Math.max(200, parent.height / 2), parent.height) - } + if (qfieldSettings.fullScreenIdentifyView || parent.width > parent.height) { + parent.height; + } else { + Math.min(Math.max(200, parent.height / 2), parent.height); + } } interactive: overlayFeatureForm.model.constraintsHardValid || qfieldSettings.autoSave ? true : false @@ -41,32 +40,31 @@ Drawer { * If the drawer is closed by back key or integrated functionality (by Drawer) it has to save in the end * To make a difference between these scenarios we need position of the drawer and the isSaved flag of the FeatureForm */ - onOpened: { - isAdding = true + isAdding = true; } onClosed: { - if ( !digitizingToolbar.geometryRequested ) { - if( !overlayFeatureForm.isSaved ) { - overlayFeatureForm.confirm() - } else { - overlayFeatureForm.isSaved = false //reset - } - digitizingRubberband.model.reset() - featureModel.resetFeature() - isAdding = false + if (!digitizingToolbar.geometryRequested) { + if (!overlayFeatureForm.isSaved) { + overlayFeatureForm.confirm(); + } else { + overlayFeatureForm.isSaved = false; //reset } + digitizingRubberband.model.reset(); + featureModel.resetFeature(); + isAdding = false; + } } Connections { - target: digitizingToolbar + target: digitizingToolbar - function onGeometryRequestedChanged() { - if ( digitizingToolbar.geometryRequested && overlayFeatureFormDrawer.isAdding ) { - overlayFeatureFormDrawer.close() // note: the digitizing toolbar will re-open the drawer to avoid panel stacking issues - } + function onGeometryRequestedChanged() { + if (digitizingToolbar.geometryRequested && overlayFeatureFormDrawer.isAdding) { + overlayFeatureFormDrawer.close(); // note: the digitizing toolbar will re-open the drawer to avoid panel stacking issues } + } } FeatureForm { @@ -81,14 +79,14 @@ Drawer { property bool isSaved: false model: AttributeFormModel { - id: attributeFormModel - featureModel: FeatureModel { - project: qgisProject - positionInformation: coordinateLocator.positionInformation - positionLocked: coordinateLocator.overrideLocation !== undefined - topSnappingResult: coordinateLocator.topSnappingResult - cloudUserInformation: projectInfo.cloudUserInformation - } + id: attributeFormModel + featureModel: FeatureModel { + project: qgisProject + positionInformation: coordinateLocator.positionInformation + positionLocked: coordinateLocator.overrideLocation !== undefined + topSnappingResult: coordinateLocator.topSnappingResult + cloudUserInformation: projectInfo.cloudUserInformation + } } state: "Add" @@ -96,21 +94,21 @@ Drawer { focus: overlayFeatureFormDrawer.opened onConfirmed: { - displayToast( qsTr( "Changes saved" ) ) + displayToast(qsTr("Changes saved")); //close drawer if still open - if ( overlayFeatureFormDrawer.position > 0 ) { + if (overlayFeatureFormDrawer.position > 0) { overlayFeatureForm.isSaved = true; //because just saved overlayFeatureFormDrawer.close(); } else { - overlayFeatureForm.isSaved = false //reset + overlayFeatureForm.isSaved = false; //reset } digitizingToolbar.digitizingLogger.writeCoordinates(); } onCancelled: { - displayToast( qsTr( "Changes discarded" ) ) + displayToast(qsTr("Changes discarded")); //close drawer if still open - if ( overlayFeatureFormDrawer.position > 0 ) { + if (overlayFeatureFormDrawer.position > 0) { overlayFeatureForm.isSaved = true; //because never changed overlayFeatureFormDrawer.close(); } else { @@ -119,27 +117,27 @@ Drawer { digitizingToolbar.digitizingLogger.clearCoordinates(); } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - if( overlayFeatureForm.model.constraintsHardValid || qfieldSettings.autoSave ) { - overlayFeatureFormDrawer.close() + if (overlayFeatureForm.model.constraintsHardValid || qfieldSettings.autoSave) { + overlayFeatureFormDrawer.close(); } else { //block closing to fix constraints or cancel with button - displayToast( qsTr( "Constraints not valid" ), 'warning' ) + displayToast(qsTr("Constraints not valid"), 'warning'); } - event.accepted = true + event.accepted = true; } } Component.onCompleted: { - focusstack.addFocusTaker( this ) + focusstack.addFocusTaker(this); } } Component.onCompleted: { if (Material.roundedScale) { - Material.roundedScale = Material.NotRounded + Material.roundedScale = Material.NotRounded; } - close() + close(); } } diff --git a/src/qml/PluginManagerSettings.qml b/src/qml/PluginManagerSettings.qml index c6113db632..eefd3ac806 100644 --- a/src/qml/PluginManagerSettings.qml +++ b/src/qml/PluginManagerSettings.qml @@ -1,10 +1,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Popup { @@ -23,7 +21,7 @@ Popup { padding: 10 header: QfPageHeader { id: pageHeader - title: qsTr( "Plugins" ) + title: qsTr("Plugins") showBackButton: false showApplyButton: false @@ -31,7 +29,7 @@ Popup { backgroundFill: false onCancel: { - popup.close() + popup.close(); } } @@ -61,7 +59,8 @@ Popup { visible: model.count > 0 clip: true - model: ListModel {} + model: ListModel { + } delegate: Rectangle { id: rectangle @@ -102,9 +101,9 @@ Popup { anchors.fill: parent onClicked: { if (!Enabled) { - pluginManager.enableAppPlugin(Uuid) + pluginManager.enableAppPlugin(Uuid); } else { - pluginManager.disableAppPlugin(Uuid) + pluginManager.disableAppPlugin(Uuid); } } } @@ -117,11 +116,11 @@ Popup { checked: Enabled onClicked: { - Enabled = checked == true + Enabled = checked == true; if (Enabled) { - pluginManager.enableAppPlugin(Uuid) + pluginManager.enableAppPlugin(Uuid); } else { - pluginManager.disableAppPlugin(Uuid) + pluginManager.disableAppPlugin(Uuid); } } } @@ -135,11 +134,11 @@ Popup { font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap - onLinkActivated: (link) => { - authorDetails.authorName = Author - authorDetails.authorHomepage = Homepage - authorDetails.open() - } + onLinkActivated: link => { + authorDetails.authorName = Author; + authorDetails.authorHomepage = Homepage; + authorDetails.open(); + } } Label { @@ -152,16 +151,16 @@ Popup { Label { Layout.fillWidth: true - text: "" + (Version != "" ? qsTr("Uninstall version %1").arg(Version) : qsTr("Uninstall plugin")) + "" + text: "" + (Version != "" ? qsTr("Uninstall version %1").arg(Version) : qsTr("Uninstall plugin")) + "" font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap - onLinkActivated: (link) => { - uninstallConfirmation.pluginName = Name - uninstallConfirmation.pluginUuid = Uuid - uninstallConfirmation.open() - } + onLinkActivated: link => { + uninstallConfirmation.pluginName = Name; + uninstallConfirmation.pluginUuid = Uuid; + uninstallConfirmation.open(); + } } } } @@ -176,11 +175,11 @@ Popup { text: qsTr("Install plugin from URL") onClicked: { - installFromUrlDialog.open() + installFromUrlDialog.open(); } onDropdownClicked: { - pluginsManagementMenu.popup(installFromUrlButton.width - pluginsManagementMenu.width + 10, installFromUrlButton.y + 10) + pluginsManagementMenu.popup(installFromUrlButton.width - pluginsManagementMenu.width + 10, installFromUrlButton.y + 10); } } @@ -192,9 +191,9 @@ Popup { let result = 50; let padding = 0; for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); } return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } @@ -207,7 +206,7 @@ Popup { leftPadding: Theme.menuItemLeftPadding onTriggered: { - pluginManager.clearPluginPermissions() + pluginManager.clearPluginPermissions(); } } } @@ -218,8 +217,8 @@ Popup { id: authorDetails title: authorName parent: mainWindow.contentItem - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height - 80 ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height - 80) / 2 property string authorName: "" property string authorHomepage: "" @@ -244,8 +243,8 @@ Popup { font: Theme.defaultFont color: Theme.mainTextColor - onLinkActivated: (link) => { - Qt.openUrlExternally(link) + onLinkActivated: link => { + Qt.openUrlExternally(link); } } @@ -269,11 +268,11 @@ Popup { focus: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height - 80 ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height - 80) / 2 onAboutToShow: { - installFromUrlInput.text = '' + installFromUrlInput.text = ''; } Column { @@ -304,7 +303,7 @@ Popup { standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - pluginManager.installFromUrl(installFromUrlInput.text) + pluginManager.installFromUrl(installFromUrlInput.text); } } @@ -312,8 +311,8 @@ Popup { id: uninstallConfirmation title: "Uninstall Plugin" parent: mainWindow.contentItem - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height - 80 ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height - 80) / 2 property string pluginName: "" property string pluginUuid: "" @@ -341,7 +340,7 @@ Popup { standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - pluginManager.uninstall(pluginUuid) + pluginManager.uninstall(pluginUuid); } } @@ -349,56 +348,62 @@ Popup { target: pluginManager function onInstallTriggered(name) { - pageHeader.busyIndicatorState = "on" - pageHeader.busyIndicatorValue = 0 - - displayToast(qsTr("Installing %1").arg(name)) + pageHeader.busyIndicatorState = "on"; + pageHeader.busyIndicatorValue = 0; + displayToast(qsTr("Installing %1").arg(name)); } function onInstallProgress(progress) { - pageHeader.busyIndicatorValue = progress + pageHeader.busyIndicatorValue = progress; } function onInstallEnded(uuid, error) { - pageHeader.busyIndicatorState = "off" - + pageHeader.busyIndicatorState = "off"; if (uuid !== '') { - pluginManager.enableAppPlugin(uuid) + pluginManager.enableAppPlugin(uuid); } else { - displayToast(qsTr('Plugin installation failed: '+error, 'error')) + displayToast(qsTr('Plugin installation failed: ' + error, 'error')); } } function onAppPluginEnabled(uuid) { - for(let i = 0; i < pluginsList.model.count; i++) { + for (let i = 0; i < pluginsList.model.count; i++) { if (pluginsList.model.get(i).Uuid === uuid) { - pluginsList.model.get(i).Enabled = true + pluginsList.model.get(i).Enabled = true; } } } function onAppPluginDisabled(uuid) { - for(let i = 0; i < pluginsList.model.count; i++) { + for (let i = 0; i < pluginsList.model.count; i++) { if (pluginsList.model.get(i).Uuid === uuid) { - pluginsList.model.get(i).Enabled = false + pluginsList.model.get(i).Enabled = false; } } } function onAvailableAppPluginsChanged() { - refreshAppPluginsList() + refreshAppPluginsList(); } } function refreshAppPluginsList() { - pluginsList.model.clear() - + pluginsList.model.clear(); for (const plugin of pluginManager.availableAppPlugins) { - pluginsList.model.append({"Uuid":plugin.uuid, "Enabled":pluginManager.isAppPluginEnabled(plugin.uuid), "Name":plugin.name, "Description":plugin.description, "Author":plugin.author, "Homepage":plugin.homepage, "Icon": plugin.icon, "Version": plugin.version}) + pluginsList.model.append({ + "Uuid": plugin.uuid, + "Enabled": pluginManager.isAppPluginEnabled(plugin.uuid), + "Name": plugin.name, + "Description": plugin.description, + "Author": plugin.author, + "Homepage": plugin.homepage, + "Icon": plugin.icon, + "Version": plugin.version + }); } } Component.onCompleted: { - refreshAppPluginsList() + refreshAppPluginsList(); } } diff --git a/src/qml/PositioningDeviceSettings.qml b/src/qml/PositioningDeviceSettings.qml index aacf810884..3ac0e21090 100644 --- a/src/qml/PositioningDeviceSettings.qml +++ b/src/qml/PositioningDeviceSettings.qml @@ -1,192 +1,202 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Popup { - id: popup - parent: mainWindow.contentItem + id: popup + parent: mainWindow.contentItem - signal apply + signal apply - width: mainWindow.width - Theme.popupScreenEdgeMargin * 2 - height: mainWindow.height - Theme.popupScreenEdgeMargin * 2 - x: Theme.popupScreenEdgeMargin - y: Theme.popupScreenEdgeMargin - padding: 0 + width: mainWindow.width - Theme.popupScreenEdgeMargin * 2 + height: mainWindow.height - Theme.popupScreenEdgeMargin * 2 + x: Theme.popupScreenEdgeMargin + y: Theme.popupScreenEdgeMargin + padding: 0 - property alias name: positioningDeviceName.text - property alias type: positioningDeviceType.currentValue + property alias name: positioningDeviceName.text + property alias type: positioningDeviceType.currentValue - function generateName() { - return positioningDeviceItem.item.generateName(); - } + function generateName() { + return positioningDeviceItem.item.generateName(); + } - function setType(type) { - for(var i = 0; i < positioningDeviceType.model.count; i++) { - if (positioningDeviceType.model.get(i)["value"] === type) { - positioningDeviceType.currentIndex = i; - break; - } + function setType(type) { + for (var i = 0; i < positioningDeviceType.model.count; i++) { + if (positioningDeviceType.model.get(i)["value"] === type) { + positioningDeviceType.currentIndex = i; + break; } } - - function setSettings(settings) { - positioningDeviceItem.item.setSettings(settings); + } + + function setSettings(settings) { + positioningDeviceItem.item.setSettings(settings); + } + + function getSettings() { + return positioningDeviceItem.item.getSettings(); + } + + Component.onCompleted: { + if (withBluetooth) { + positioningDeviceTypeModel.insert(0, { + "name": qsTr('Bluetooth (NMEA)'), + "value": PositioningDeviceModel.BluetoothDevice + }); } - - function getSettings() { - return positioningDeviceItem.item.getSettings(); + if (withSerialPort) { + positioningDeviceTypeModel.insert(positioningDeviceTypeModel.count, { + "name": qsTr('Serial port (NMEA)'), + "value": PositioningDeviceModel.SerialPortDevice + }); } - - Component.onCompleted: { - if (withBluetooth) { - positioningDeviceTypeModel.insert(0, {'name': qsTr('Bluetooth (NMEA)'), 'value': PositioningDeviceModel.BluetoothDevice}) + positioningDeviceType.model = positioningDeviceTypeModel; + } + + Page { + id: page + width: parent.width + height: parent.height + padding: 10 + header: QfPageHeader { + id: pageHeader + title: qsTr("Positioning Device Settings") + + showBackButton: false + showApplyButton: true + showCancelButton: true + + onCancel: { + popup.close(); } - if (withSerialPort) { - positioningDeviceTypeModel.insert(positioningDeviceTypeModel.count, {'name': qsTr('Serial port (NMEA)'), 'value': PositioningDeviceModel.SerialPortDevice}); + + onApply: { + popup.apply(); + popup.close(); } - positioningDeviceType.model = positioningDeviceTypeModel } - Page { - id: page - width: parent.width - height: parent.height - padding: 10 - header: QfPageHeader { - id: pageHeader - title: qsTr("Positioning Device Settings") - - showBackButton: false - showApplyButton: true - showCancelButton: true - - onCancel: { - popup.close() - } + ColumnLayout { + spacing: 5 + width: parent.width - onApply: { - popup.apply() - popup.close() - } - } + Label { + Layout.fillWidth: true + text: qsTr("Name:") + font: Theme.defaultFont + wrapMode: Text.WordWrap + } - ColumnLayout { - spacing: 5 - width: parent.width + QfTextField { + id: positioningDeviceName + Layout.fillWidth: true + font: Theme.defaultFont + placeholderText: displayText == '' ? qsTr('Leave empty to auto-fill') : '' + } - Label { - Layout.fillWidth: true - text: qsTr("Name:") - font: Theme.defaultFont - wrapMode: Text.WordWrap - } + Label { + Layout.fillWidth: true + text: qsTr("Connection type:") + font: Theme.defaultFont + wrapMode: Text.WordWrap + } - QfTextField { - id: positioningDeviceName - Layout.fillWidth: true - font: Theme.defaultFont - placeholderText: displayText == '' ? qsTr('Leave empty to auto-fill') : '' + ComboBox { + id: positioningDeviceType + Layout.fillWidth: true + font: Theme.defaultFont + + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin + + textRole: "name" + valueRole: "value" + + delegate: ItemDelegate { + width: positioningDeviceType.width + height: 36 + icon.source: { + switch (value) { + case PositioningDeviceModel.BluetoothDevice: + return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp'); + case PositioningDeviceModel.TcpDevice: + return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp'); + case PositioningDeviceModel.UdpDevice: + return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp'); + case PositioningDeviceModel.SerialPortDevice: + return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp'); } + return ''; + } + icon.width: 24 + icon.height: 24 + text: name + font: Theme.defaultFont + highlighted: positioningDeviceType.highlightedIndex === index + } - Label { - Layout.fillWidth: true - text: qsTr("Connection type:") - font: Theme.defaultFont - wrapMode: Text.WordWrap + contentItem: MenuItem { + width: positioningDeviceComboBox.width + height: 36 + + icon.source: { + switch (positioningDeviceType.currentValue) { + case PositioningDeviceModel.BluetoothDevice: + return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp'); + case PositioningDeviceModel.TcpDevice: + return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp'); + case PositioningDeviceModel.UdpDevice: + return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp'); + case PositioningDeviceModel.SerialPortDevice: + return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp'); } + return ''; + } + icon.width: 24 + icon.height: 24 - ComboBox { - id: positioningDeviceType - Layout.fillWidth: true - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - textRole: "name" - valueRole: "value" - - delegate: ItemDelegate { - width: positioningDeviceType.width - height: 36 - icon.source: { - switch(value) { - case PositioningDeviceModel.BluetoothDevice: - return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp') - case PositioningDeviceModel.TcpDevice: - return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp') - case PositioningDeviceModel.UdpDevice: - return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp') - case PositioningDeviceModel.SerialPortDevice: - return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp') - } - return ''; - } - icon.width: 24 - icon.height: 24 - text: name - font: Theme.defaultFont - highlighted: positioningDeviceType.highlightedIndex === index - } - - contentItem: MenuItem { - width: positioningDeviceComboBox.width - height: 36 - - icon.source: { - switch(positioningDeviceType.currentValue) { - case PositioningDeviceModel.BluetoothDevice: - return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp') - case PositioningDeviceModel.TcpDevice: - return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp') - case PositioningDeviceModel.UdpDevice: - return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp') - case PositioningDeviceModel.SerialPortDevice: - return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp') - } - return ''; - } - icon.width: 24 - icon.height: 24 - - text: positioningDeviceType.currentText - font: Theme.defaultFont - - onClicked: positioningDeviceType.popup.open() - } - } + text: positioningDeviceType.currentText + font: Theme.defaultFont - ListModel { - id: positioningDeviceTypeModel - ListElement { name: qsTr('TCP (NMEA)'); value: PositioningDeviceModel.TcpDevice } - ListElement { name: qsTr('UDP (NMEA)'); value: PositioningDeviceModel.UdpDevice } - } + onClicked: positioningDeviceType.popup.open() + } + } - Loader { - id: positioningDeviceItem - Layout.fillWidth: true - Layout.fillHeight: true - source: { - switch(positioningDeviceType.currentValue) { - case PositioningDeviceModel.BluetoothDevice: - return "qrc:/qml/BluetoothDeviceChooser.qml"; - case PositioningDeviceModel.TcpDevice: - return "qrc:/qml/TcpDeviceChooser.qml"; - case PositioningDeviceModel.UdpDevice: - return "qrc:/qml/UdpDeviceChooser.qml"; - case PositioningDeviceModel.SerialPortDevice: - return "qrc:/qml/SerialPortDeviceChooser.qml"; - } - return ''; - } - } + ListModel { + id: positioningDeviceTypeModel + ListElement { + name: qsTr('TCP (NMEA)') + value: PositioningDeviceModel.TcpDevice + } + ListElement { + name: qsTr('UDP (NMEA)') + value: PositioningDeviceModel.UdpDevice } + } + + Loader { + id: positioningDeviceItem + Layout.fillWidth: true + Layout.fillHeight: true + source: { + switch (positioningDeviceType.currentValue) { + case PositioningDeviceModel.BluetoothDevice: + return "qrc:/qml/BluetoothDeviceChooser.qml"; + case PositioningDeviceModel.TcpDevice: + return "qrc:/qml/TcpDeviceChooser.qml"; + case PositioningDeviceModel.UdpDevice: + return "qrc:/qml/UdpDeviceChooser.qml"; + case PositioningDeviceModel.SerialPortDevice: + return "qrc:/qml/SerialPortDeviceChooser.qml"; + } + return ''; + } + } } + } } diff --git a/src/qml/PositioningInformationView.qml b/src/qml/PositioningInformationView.qml index 038322acdd..08d3d074c1 100644 --- a/src/qml/PositioningInformationView.qml +++ b/src/qml/PositioningInformationView.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -33,9 +32,9 @@ Rectangle { Grid { id: grid flow: GridLayout.TopToBottom - rows: ( positionSource.deviceId === '' ? 1 : 2 ) * ( parent.width > 1000? 1 : parent.width > 620? 2 : 3 ) + rows: (positionSource.deviceId === '' ? 1 : 2) * (parent.width > 1000 ? 1 : parent.width > 620 ? 2 : 3) width: parent.width - property double cellWidth: grid.width / ( ( positionSource.deviceId === '' ? 1 : 2 ) * 6 / grid.rows ) + property double cellWidth: grid.width / ((positionSource.deviceId === '' ? 1 : 2) * 6 / grid.rows) Rectangle { height: cellHeight @@ -52,22 +51,14 @@ Rectangle { Layout.fillWidth: false font: Theme.tipFont color: Theme.secondaryTextColor - text: coordinatesIsXY - ? coordinatesIsGeographic ? qsTr( "Lon" ) : qsTr( "X" ) - : coordinatesIsGeographic ? qsTr( "Lat" ) : qsTr( "Y" ) + text: coordinatesIsXY ? coordinatesIsGeographic ? qsTr("Lon") : qsTr("X") : coordinatesIsGeographic ? qsTr("Lat") : qsTr("Y") } Text { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: coordinatesIsXY - ? positionSource.positionInformation && positionSource.positionInformation.longitudeValid - ? Number( coordinates.x ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) - : qsTr( "N/A" ) - : positionSource.positionInformation && positionSource.positionInformation.latitudeValid - ? Number( coordinates.y ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) - : qsTr( "N/A" ) + text: coordinatesIsXY ? positionSource.positionInformation && positionSource.positionInformation.longitudeValid ? Number(coordinates.x).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) : qsTr("N/A") : positionSource.positionInformation && positionSource.positionInformation.latitudeValid ? Number(coordinates.y).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) : qsTr("N/A") elide: Text.ElideRight } } @@ -88,25 +79,15 @@ Rectangle { Layout.fillWidth: false font: Theme.tipFont color: Theme.secondaryTextColor - text: coordinatesIsXY - ? coordinatesIsGeographic ? qsTr( "Lat" ) : qsTr( "Y" ) - : coordinatesIsGeographic ? qsTr( "Lon" ) : qsTr( "X" ) - + text: coordinatesIsXY ? coordinatesIsGeographic ? qsTr("Lat") : qsTr("Y") : coordinatesIsGeographic ? qsTr("Lon") : qsTr("X") } Text { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: coordinatesIsXY - ? positionSource.positionInformation && positionSource.positionInformation.longitudeValid - ? Number( coordinates.y ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) - : qsTr( "N/A" ) - : positionSource.positionInformation && positionSource.positionInformation.latitudeValid - ? Number( coordinates.x ).toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3 ) - : qsTr( "N/A" ) + text: coordinatesIsXY ? positionSource.positionInformation && positionSource.positionInformation.longitudeValid ? Number(coordinates.y).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) : qsTr("N/A") : positionSource.positionInformation && positionSource.positionInformation.latitudeValid ? Number(coordinates.x).toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 7 : 3) : qsTr("N/A") elide: Text.ElideRight - } } } @@ -134,27 +115,25 @@ Rectangle { font: Theme.tipFont color: textColor text: { - var altitude = '' + var altitude = ''; if (positionSource.positionInformation && positionSource.positionInformation.elevationValid) { - altitude += Number(positionSource.projectedPosition.z * distanceUnitFactor).toLocaleString(Qt.locale(), 'f', 3) + ' ' + distanceUnitAbbreviation + ' ' - var details = [] + altitude += Number(positionSource.projectedPosition.z * distanceUnitFactor).toLocaleString(Qt.locale(), 'f', 3) + ' ' + distanceUnitAbbreviation + ' '; + var details = []; if (positionSource.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile) { - details.push('grid') + details.push('grid'); } else if (positionSource.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromDevice) { - details.push('ortho.') + details.push('ortho.'); } if (!isNaN(parseFloat(antennaHeight))) { - details.push('ant.') + details.push('ant.'); } if (details.length > 0) { - altitude += ' (%1)'.arg( details.join(', ')) + altitude += ' (%1)'.arg(details.join(', ')); } - } - else - { + } else { altitude += qsTr('N/A'); } - return altitude + return altitude; } elide: Text.ElideRight } @@ -183,9 +162,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.positionInformation && positionSource.positionInformation.speedValid - ? positionSource.positionInformation.speed.toLocaleString(Qt.locale(), 'f', 3) + " m/s" - : qsTr( "N/A" ) + text: positionSource.positionInformation && positionSource.positionInformation.speedValid ? positionSource.positionInformation.speed.toLocaleString(Qt.locale(), 'f', 3) + " m/s" : qsTr("N/A") elide: Text.ElideRight } } @@ -213,9 +190,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.positionInformation && positionSource.positionInformation.haccValid - ? Number(positionSource.positionInformation.hacc * distanceUnitFactor).toLocaleString(Qt.locale(), 'f', 3) + ' ' + distanceUnitAbbreviation - : qsTr("N/A") + text: positionSource.positionInformation && positionSource.positionInformation.haccValid ? Number(positionSource.positionInformation.hacc * distanceUnitFactor).toLocaleString(Qt.locale(), 'f', 3) + ' ' + distanceUnitAbbreviation : qsTr("N/A") elide: Text.ElideRight } } @@ -243,9 +218,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.positionInformation && positionSource.positionInformation.vaccValid - ? Number(positionSource.positionInformation.vacc * distanceUnitFactor).toLocaleString(Qt.locale(), 'f', 3) + ' ' + distanceUnitAbbreviation - : qsTr("N/A") + text: positionSource.positionInformation && positionSource.positionInformation.vaccValid ? Number(positionSource.positionInformation.vacc * distanceUnitFactor).toLocaleString(Qt.locale(), 'f', 3) + ' ' + distanceUnitAbbreviation : qsTr("N/A") elide: Text.ElideRight } } @@ -274,9 +247,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.positionInformation && !isNaN(positionSource.positionInformation.pdop) - ? positionSource.positionInformation.pdop.toLocaleString(Qt.locale(), 'f', 1) - : qsTr('N/A') + text: positionSource.positionInformation && !isNaN(positionSource.positionInformation.pdop) ? positionSource.positionInformation.pdop.toLocaleString(Qt.locale(), 'f', 1) : qsTr('N/A') elide: Text.ElideRight } } @@ -305,9 +276,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.positionInformation && !isNaN(positionSource.positionInformation.hdop) - ? positionSource.positionInformation.hdop.toLocaleString(Qt.locale(), 'f', 1) - : qsTr('N/A') + text: positionSource.positionInformation && !isNaN(positionSource.positionInformation.hdop) ? positionSource.positionInformation.hdop.toLocaleString(Qt.locale(), 'f', 1) : qsTr('N/A') elide: Text.ElideRight } } @@ -336,9 +305,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: textColor - text: positionSource.positionInformation && !isNaN(positionSource.positionInformation.vdop) - ? positionSource.positionInformation.vdop.toLocaleString(Qt.locale(), 'f', 1) - : qsTr('N/A') + text: positionSource.positionInformation && !isNaN(positionSource.positionInformation.vdop) ? positionSource.positionInformation.vdop.toLocaleString(Qt.locale(), 'f', 1) : qsTr('N/A') elide: Text.ElideRight } } diff --git a/src/qml/PositioningPreciseView.qml b/src/qml/PositioningPreciseView.qml index 7f91448b2d..6a59d1f57f 100644 --- a/src/qml/PositioningPreciseView.qml +++ b/src/qml/PositioningPreciseView.qml @@ -2,10 +2,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Shapes 1.14 - import Theme 1.0 import org.qfield 1.0 - import "." Item { @@ -23,8 +21,7 @@ Item { property double positionX: Math.min(precision, projectDistance) * Math.cos((navigation.bearing - (!isNaN(positionSource.orientation) ? positionSource.orientation : 0) - 90) * Math.PI / 180) * (preciseTarget.width / 2) / precision property double positionY: Math.min(precision, projectDistance) * Math.sin((navigation.bearing - (!isNaN(positionSource.orientation) ? positionSource.orientation : 0) - 90) * Math.PI / 180) * (preciseTarget.width / 2) / precision property double positionZ: hasZ ? Math.min(precision, Math.max(-precision, -projectVerticalDistance)) * ((preciseElevation.height - 15) / 2) / precision : 0.0 - property point positionCenter: Qt.point(preciseTarget.width / 2 + preciseTarget.x + preciseTarget.parent.x, - preciseTarget.height / 2 + preciseTarget.y + preciseTarget.parent.y) + property point positionCenter: Qt.point(preciseTarget.width / 2 + preciseTarget.x + preciseTarget.parent.x, preciseTarget.height / 2 + preciseTarget.y + preciseTarget.parent.y) property string negativeLabel: UnitTypes.formatDistance(-precision, 2, projectInfo.distanceUnits) property string positiveLabel: UnitTypes.formatDistance(precision, 2, projectInfo.distanceUnits) @@ -54,8 +51,7 @@ Item { Shape { id: preciseTarget - width: Math.min(positioningPreciseView.height - 10, - positioningPreciseView.width - preciseElevation.width - labelTarget.contentWidth - labelElevation.width - 20) + width: Math.min(positioningPreciseView.height - 10, positioningPreciseView.width - preciseElevation.width - labelTarget.contentWidth - labelElevation.width - 20) height: width rotation: !isNaN(positionSource.orientation) ? -positionSource.orientation + positionSource.bearingTrueNorth : 0 @@ -118,7 +114,7 @@ Item { centerX: preciseTarget.width / 2 centerY: centerX radiusX: preciseTarget.width / 8 - radiusY:radiusX + radiusY: radiusX startAngle: 0 sweepAngle: 360 } @@ -134,7 +130,7 @@ Item { centerX: preciseTarget.width / 2 centerY: centerX radiusX: preciseTarget.width / 4 - radiusY:radiusX + radiusY: radiusX startAngle: 0 sweepAngle: 360 } @@ -150,7 +146,7 @@ Item { centerX: preciseTarget.width / 2 centerY: centerX radiusX: preciseTarget.width / 2.66 - radiusY:radiusX + radiusY: radiusX startAngle: 0 sweepAngle: 360 } @@ -212,7 +208,6 @@ Item { styleColor: Theme.mainBackgroundColor text: '270' } - } Rectangle { @@ -276,7 +271,7 @@ Item { joinStyle: ShapePath.MiterJoin startX: preciseVerticalPosition.width / 2 startY: startX - scale: Math.abs(projectVerticalDistance) <= precision ? Qt.size(1,1) : Qt.size(0,0); + scale: Math.abs(projectVerticalDistance) <= precision ? Qt.size(1, 1) : Qt.size(0, 0) PathAngleArc { centerX: preciseVerticalPosition.width / 2 centerY: centerX @@ -296,10 +291,19 @@ Item { joinStyle: ShapePath.MiterJoin startX: preciseVerticalPosition.width / 2 startY: 0 - scale: Math.abs(projectVerticalDistance) > precision ? Qt.size(1,1) : Qt.size(0,0); - PathLine { x: preciseVerticalPosition.width - 2; y: preciseVerticalPosition.width } - PathLine { x: 2; y: preciseVerticalPosition.width } - PathLine { x: preciseVerticalPosition.width / 2; y: 0 } + scale: Math.abs(projectVerticalDistance) > precision ? Qt.size(1, 1) : Qt.size(0, 0) + PathLine { + x: preciseVerticalPosition.width - 2 + y: preciseVerticalPosition.width + } + PathLine { + x: 2 + y: preciseVerticalPosition.width + } + PathLine { + x: preciseVerticalPosition.width / 2 + y: 0 + } } } @@ -332,13 +336,11 @@ Item { strokeWidth: 1 strokeColor: "transparent" strokeStyle: ShapePath.SolidLine - fillColor: hasReachedTarget - ? Qt.hsla(Theme.mainColor.hslHue, Theme.mainColor.hslSaturation, Theme.mainColor.hslLightness, 0.4) - : Theme.positionColor + fillColor: hasReachedTarget ? Qt.hsla(Theme.mainColor.hslHue, Theme.mainColor.hslSaturation, Theme.mainColor.hslLightness, 0.4) : Theme.positionColor fillRule: ShapePath.WindingFill startX: preciseHorizontalPosition.width / 2 startY: startX - scale: projectDistance <= precision ? Qt.size(1,1) : Qt.size(0,0); + scale: projectDistance <= precision ? Qt.size(1, 1) : Qt.size(0, 0) PathAngleArc { centerX: preciseHorizontalPosition.width / 2 centerY: centerX @@ -358,10 +360,19 @@ Item { joinStyle: ShapePath.MiterJoin startX: preciseHorizontalPosition.width / 2 startY: 0 - scale: projectDistance > precision ? Qt.size(1,1) : Qt.size(0,0); - PathLine { x: preciseHorizontalPosition.width - 2; y: preciseHorizontalPosition.width } - PathLine { x: 2; y: preciseHorizontalPosition.width } - PathLine { x: preciseHorizontalPosition.width / 2; y: 0 } + scale: projectDistance > precision ? Qt.size(1, 1) : Qt.size(0, 0) + PathLine { + x: preciseHorizontalPosition.width - 2 + y: preciseHorizontalPosition.width + } + PathLine { + x: 2 + y: preciseHorizontalPosition.width + } + PathLine { + x: preciseHorizontalPosition.width / 2 + y: 0 + } } } @@ -380,11 +391,20 @@ Item { fillColor: "transparent" startX: preciseHorizontalPosition.width / 2 startY: 0 - scale: hasReachedTarget ? Qt.size(1,1) : Qt.size(0,0); + scale: hasReachedTarget ? Qt.size(1, 1) : Qt.size(0, 0) - PathLine { x: preciseHorizontalPosition.width / 2; y: preciseHorizontalPosition.height } - PathMove { x: 0; y: preciseHorizontalPosition.height / 2 } - PathLine { x: preciseHorizontalPosition.width; y: preciseHorizontalPosition.height / 2 } + PathLine { + x: preciseHorizontalPosition.width / 2 + y: preciseHorizontalPosition.height + } + PathMove { + x: 0 + y: preciseHorizontalPosition.height / 2 + } + PathLine { + x: preciseHorizontalPosition.width + y: preciseHorizontalPosition.height / 2 + } } } @@ -401,7 +421,7 @@ Item { styleColor: Theme.mainBackgroundColor property int decimals: projectDistance >= 1000 ? 3 : projectDistance >= 0.10 ? 2 : 1 - text: qsTr('Dist.') + ': ' + UnitTypes.formatDistance( projectDistance, decimals, projectInfo.distanceUnits ) + text: qsTr('Dist.') + ': ' + UnitTypes.formatDistance(projectDistance, decimals, projectInfo.distanceUnits) } Rectangle { @@ -438,8 +458,7 @@ Item { anchors.left: parent.left anchors.margins: 5 - visible: (navigation.proximityAlarm || positioningPreciseView.hasAlarmSnoozed) - && projectDistance <= positioningPreciseView.precision + visible: (navigation.proximityAlarm || positioningPreciseView.hasAlarmSnoozed) && projectDistance <= positioningPreciseView.precision enabled: visible round: true @@ -447,7 +466,7 @@ Item { iconSource: positioningPreciseView.hasAlarmSnoozed ? Theme.getThemeVectorIcon('ic_alarm_purple_24dp') : Theme.getThemeVectorIcon('ic_alarm_white_24dp') onClicked: { - positioningPreciseView.hasAlarmSnoozed = !positioningPreciseView.hasAlarmSnoozed + positioningPreciseView.hasAlarmSnoozed = !positioningPreciseView.hasAlarmSnoozed; } } diff --git a/src/qml/PositioningSettings.qml b/src/qml/PositioningSettings.qml index 4f586bf131..4c95ec744b 100644 --- a/src/qml/PositioningSettings.qml +++ b/src/qml/PositioningSettings.qml @@ -1,50 +1,49 @@ import QtQuick 2.14 import QtCore - import org.qfield 1.0 Settings { - property bool positioningActivated: false - property bool positioningCoordinateLock: false + property bool positioningActivated: false + property bool positioningCoordinateLock: false - property string positioningDevice: "" - property string positioningDeviceName: qsTr( "Internal device" ); - property int elevationCorrectionMode: Positioning.ElevationCorrectionMode.None - property bool logging: false + property string positioningDevice: "" + property string positioningDeviceName: qsTr("Internal device") + property int elevationCorrectionMode: Positioning.ElevationCorrectionMode.None + property bool logging: false - property bool showPositionInformation: false + property bool showPositionInformation: false - property bool alwaysShowPreciseView: false - property real preciseViewPrecision: 2.5 - property bool preciseViewProximityAlarm: true + property bool alwaysShowPreciseView: false + property real preciseViewPrecision: 2.5 + property bool preciseViewProximityAlarm: true - property bool accuracyIndicator: false - property real accuracyBad: 5.0 - property real accuracyExcellent: 1.0 - property bool accuracyRequirement: false + property bool accuracyIndicator: false + property real accuracyBad: 5.0 + property real accuracyExcellent: 1.0 + property bool accuracyRequirement: false - property bool averagedPositioning: false - property int averagedPositioningMinimumCount: 1 - property bool averagedPositioningAutomaticStop: true + property bool averagedPositioning: false + property int averagedPositioningMinimumCount: 1 + property bool averagedPositioningAutomaticStop: true - property real antennaHeight: 0.0 - property bool antennaHeightActivated: false - property bool skipAltitudeCorrection: false + property real antennaHeight: 0.0 + property bool antennaHeightActivated: false + property bool skipAltitudeCorrection: false - property string verticalGrid: "" + property string verticalGrid: "" - property bool trackerTimeIntervalConstraint: false - property double trackerTimeInterval: 30 - property bool trackerMinimumDistanceConstraint: false - property double trackerMinimumDistance: 30 - property bool trackerSensorCaptureConstraint: false - property bool trackerMeetAllConstraints: false + property bool trackerTimeIntervalConstraint: false + property double trackerTimeInterval: 30 + property bool trackerMinimumDistanceConstraint: false + property double trackerMinimumDistance: 30 + property bool trackerSensorCaptureConstraint: false + property bool trackerMeetAllConstraints: false - property bool trackerErroneousDistanceSafeguard: false - property double trackerErroneousDistance: 100 + property bool trackerErroneousDistanceSafeguard: false + property double trackerErroneousDistance: 100 - property int trackerMeasureType: 0 - property int digitizingMeasureType: 1 + property int trackerMeasureType: 0 + property int digitizingMeasureType: 1 - property bool geofencingPreventDigitizingDuringAlert: false + property bool geofencingPreventDigitizingDuringAlert: false } diff --git a/src/qml/ProcessingAlgorithmForm.qml b/src/qml/ProcessingAlgorithmForm.qml index ff9048bede..538b0e610a 100644 --- a/src/qml/ProcessingAlgorithmForm.qml +++ b/src/qml/ProcessingAlgorithmForm.qml @@ -3,7 +3,6 @@ import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import Theme 1.0 import org.qfield 1.0 @@ -21,7 +20,7 @@ Item { filters: ProcessingAlgorithmParametersModel.GeneralParameterFilter onAlgorithmIdChanged: { - filters = ProcessingAlgorithmParametersModel.GeneralParameterFilter + filters = ProcessingAlgorithmParametersModel.GeneralParameterFilter; } } @@ -34,9 +33,7 @@ Item { Layout.fillWidth: true Layout.preferredHeight: defaultHeight - model: processingAlgorithmParametersModel.hasAdvancedParameters - ? [qsTr("General Parameters"), qsTr("Advanced Parameters"), qsTr("Help")] - : [qsTr("General Parameters"), qsTr("Help")] + model: processingAlgorithmParametersModel.hasAdvancedParameters ? [qsTr("General Parameters"), qsTr("Advanced Parameters"), qsTr("Help")] : [qsTr("General Parameters"), qsTr("Help")] delegate: TabButton { id: tabButton @@ -52,7 +49,7 @@ Item { height: 48 onClicked: { - tabRow.currentIndex = index + tabRow.currentIndex = index; } background: Rectangle { @@ -75,7 +72,7 @@ Item { } onCurrentIndexChanged: { - processingAlgorithmParametersModel.filters = currentIndex == 0 ? ProcessingAlgorithmParametersModel.GeneralParameterFilter : ProcessingAlgorithmParametersModel.AdvancedParameterFilter + processingAlgorithmParametersModel.filters = currentIndex == 0 ? ProcessingAlgorithmParametersModel.GeneralParameterFilter : ProcessingAlgorithmParametersModel.AdvancedParameterFilter; } } @@ -236,11 +233,14 @@ Item { property string widget: ParameterType property var configuration: ParameterConfiguration - anchors { left: parent.left; right: parent.right } + anchors { + left: parent.left + right: parent.right + } active: true source: { - return 'processingparameterwidgets/' + widget + '.qml' + return 'processingparameterwidgets/' + widget + '.qml'; } } @@ -248,7 +248,7 @@ Item { target: parameterWidgetLoader.item function onValueChangeRequested(value) { - ParameterValue = value + ParameterValue = value; } } } diff --git a/src/qml/ProcessingAlgorithmPreview.qml b/src/qml/ProcessingAlgorithmPreview.qml index cce8a24e1c..8f4e885c0e 100644 --- a/src/qml/ProcessingAlgorithmPreview.qml +++ b/src/qml/ProcessingAlgorithmPreview.qml @@ -1,5 +1,4 @@ import QtQuick 2.14 - import Theme 1.0 import org.qgis 1.0 import org.qfield 1.0 diff --git a/src/qml/ProcessingAlgorithmsList.qml b/src/qml/ProcessingAlgorithmsList.qml index af91bcc4ba..b492ff2931 100644 --- a/src/qml/ProcessingAlgorithmsList.qml +++ b/src/qml/ProcessingAlgorithmsList.qml @@ -3,7 +3,6 @@ import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import Theme 1.0 import org.qfield 1.0 @@ -45,7 +44,7 @@ Item { height: 48 onClicked: { - tabRow.currentIndex = index + tabRow.currentIndex = index; } background: Rectangle { @@ -68,9 +67,7 @@ Item { } onCurrentIndexChanged: { - processingAlgorithmsModel.filters = currentIndex == 0 - ? ProcessingAlgorithmsModel.InPlaceFilter | ProcessingAlgorithmsModel.FavoriteFilter - : ProcessingAlgorithmsModel.InPlaceFilter + processingAlgorithmsModel.filters = currentIndex == 0 ? ProcessingAlgorithmsModel.InPlaceFilter | ProcessingAlgorithmsModel.FavoriteFilter : ProcessingAlgorithmsModel.InPlaceFilter; } } @@ -94,7 +91,10 @@ Item { color: Theme.controlBorderColor Text { - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } font.bold: true font.pointSize: Theme.resultFont.pointSize color: Theme.mainTextColor @@ -107,10 +107,10 @@ Item { id: itemBackground anchors { left: parent ? parent.left : undefined - right: parent ? parent.right: undefined + right: parent ? parent.right : undefined } focus: true - height: Math.max( 48, itemText.height ) + height: Math.max(48, itemText.height) color: "transparent" Ripple { @@ -142,7 +142,7 @@ Item { anchors.fill: parent onClicked: { - processingAlgorithmsList.algorithmSelected(AlgorithmId) + processingAlgorithmsList.algorithmSelected(AlgorithmId); } } @@ -160,7 +160,7 @@ Item { opacity: AlgorithmFavorite ? 1.0 : 0.75 onClicked: { - AlgorithmFavorite = !AlgorithmFavorite + AlgorithmFavorite = !AlgorithmFavorite; } } diff --git a/src/qml/QFieldAudioRecorder.qml b/src/qml/QFieldAudioRecorder.qml index db365bd3e8..9585321464 100644 --- a/src/qml/QFieldAudioRecorder.qml +++ b/src/qml/QFieldAudioRecorder.qml @@ -4,16 +4,14 @@ import QtQuick.Layouts 1.14 import QtQuick.Shapes 1.14 import QtMultimedia import QtCore - import org.qfield 1.0 - import Theme 1.0 Popup { - id : audioRecorder + id: audioRecorder signal finished(string path) - signal canceled() + signal canceled property bool preRecording: true property bool hasRecordedClip: player.duration > 0 @@ -32,10 +30,9 @@ Popup { onAboutToShow: { preRecording = true; - player.source = '' - + player.source = ''; if (microphonePermission.status === Qt.PermissionStatus.Undetermined) { - microphonePermission.request() + microphonePermission.request(); } } @@ -64,11 +61,11 @@ Popup { running: false onTriggered: { - var path = recorder.actualLocation.toString() + var path = recorder.actualLocation.toString(); // On Android, the file protocol prefix is present while on Linux it isn't - var filePos = path.indexOf('file://') - path = filePos == -1 ? 'file://' + path : path - player.source = path + var filePos = path.indexOf('file://'); + path = filePos == -1 ? 'file://' + path : path; + player.source = path; } } @@ -90,7 +87,6 @@ Popup { playerLoader.stop(); loaded = true; } - positionSlider.to = duration / 1000; positionSlider.value = 0; } @@ -131,12 +127,12 @@ Popup { id: closeButton Layout.rightMargin: 10 Layout.alignment: Qt.AlignVCenter - iconSource: Theme.getThemeIcon( 'ic_close_black_24dp' ) + iconSource: Theme.getThemeIcon('ic_close_black_24dp') iconColor: Theme.mainTextColor bgcolor: "transparent" onClicked: { - audioRecorder.canceled() + audioRecorder.canceled(); } } } @@ -163,14 +159,14 @@ Popup { SequentialAnimation { NumberAnimation { - target: levelFeedback + target: levelFeedback property: "width" to: 120 + (Math.min(audioFeedback.width, audioFeedback.height) - 120) duration: 2000 easing.type: Easing.InOutQuad } NumberAnimation { - target: levelFeedback + target: levelFeedback property: "width" to: 120 duration: 2000 @@ -197,7 +193,12 @@ Popup { radius: recorder.recorderState === MediaRecorder.RecordingState ? 10 : width / 2 color: "#FFFFFF" - Behavior on radius { PropertyAnimation { duration: 250; easing.type: Easing.InOutQuad } } + Behavior on radius { + PropertyAnimation { + duration: 250 + easing.type: Easing.InOutQuad + } + } } onClicked: { @@ -211,7 +212,7 @@ Popup { playerLoader.start(); } else { playerLoader.stop(); - player.source = '' + player.source = ''; recorder.record(); } } @@ -228,17 +229,15 @@ Popup { enabled: audioRecorder.hasRecordedClip opacity: enabled ? 1 : 0.25 - iconSource: player.playbackState == MediaPlayer.PlayingState - ? Theme.getThemeVectorIcon('ic_pause_black_24dp') - : Theme.getThemeVectorIcon('ic_play_black_24dp') + iconSource: player.playbackState == MediaPlayer.PlayingState ? Theme.getThemeVectorIcon('ic_pause_black_24dp') : Theme.getThemeVectorIcon('ic_play_black_24dp') iconColor: Theme.mainTextColor bgcolor: "transparent" onClicked: { if (player.playbackState == MediaPlayer.PlayingState) { - player.pause() + player.pause(); } else { - player.play() + player.play(); } } } @@ -254,7 +253,7 @@ Popup { opacity: enabled ? 1 : 0.25 onMoved: { - player.seek(value * 1000) + player.seek(value * 1000); } } @@ -275,7 +274,7 @@ Popup { seconds -= hours * 60 * 60; var minutes = Math.floor(seconds / 60) + ''; seconds = (seconds - minutes * 60) + ''; - return hours.padStart(2,'0') + ':' + minutes.padStart(2,'0') + ':' + seconds.padStart(2,'0'); + return hours.padStart(2, '0') + ':' + minutes.padStart(2, '0') + ':' + seconds.padStart(2, '0'); } else { return '-'; } @@ -292,15 +291,15 @@ Popup { enabled: audioRecorder.hasRecordedClip opacity: enabled ? 1 : 0.2 Layout.alignment: Qt.AlignVCenter - iconSource: Theme.getThemeIcon( 'ic_check_black_48dp' ) + iconSource: Theme.getThemeIcon('ic_check_black_48dp') iconColor: enabled ? "white" : Theme.mainTextColor bgcolor: enabled ? Theme.mainColor : "transparent" round: true onClicked: { - var path = recorder.actualLocation.toString() - var filePos = path.indexOf('file://') - audioRecorder.finished(filePos === 0 ? path.substring(7) : path) + var path = recorder.actualLocation.toString(); + var filePos = path.indexOf('file://'); + audioRecorder.finished(filePos === 0 ? path.substring(7) : path); audioRecorder.close(); } } diff --git a/src/qml/QFieldCamera.qml b/src/qml/QFieldCamera.qml index 44c24bee79..dd6bec9603 100644 --- a/src/qml/QFieldCamera.qml +++ b/src/qml/QFieldCamera.qml @@ -4,9 +4,7 @@ import QtQuick.Shapes import QtQuick.Window import QtMultimedia import QtCore - import org.qfield 1.0 - import Theme 1.0 Popup { @@ -20,7 +18,7 @@ Popup { property var currentPosition signal finished(string path) - signal canceled() + signal canceled x: 0 y: 0 @@ -35,35 +33,35 @@ Popup { property string state: "PhotoCapture" onStateChanged: { if (state == "PhotoCapture") { - photoPreview.source = '' - videoPreview.source = '' + photoPreview.source = ''; + videoPreview.source = ''; } else if (state == "VideoCapture") { - photoPreview.source = '' - videoPreview.source = '' + photoPreview.source = ''; + videoPreview.source = ''; } } onAboutToShow: { if (cameraPermission.status === Qt.PermissionStatus.Undetermined) { - cameraPermission.request() + cameraPermission.request(); } if (microphonePermission.status === Qt.PermissionStatus.Undetermined) { - microphonePermission.request() + microphonePermission.request(); } } Component.onCompleted: { - let cameraPicked = false + let cameraPicked = false; if (settings.deviceId != '') { - for(const device of mediaDevices.videoInputs) { + for (const device of mediaDevices.videoInputs) { if (device.id == settings.deviceId) { - camera.cameraDevice = device - cameraPicked = true + camera.cameraDevice = device; + cameraPicked = true; } } } if (!cameraPicked) { - camera.cameraDevice = mediaDevices.defaultVideoInput + camera.cameraDevice = mediaDevices.defaultVideoInput; } } @@ -92,7 +90,7 @@ Popup { } MediaDevices { - id: mediaDevices + id: mediaDevices } CaptureSession { @@ -104,20 +102,20 @@ Popup { active: cameraItem.visible && cameraPermission.status === Qt.PermissionStatus.Granted function zoomIn(increase) { - var zoom = camera.zoomFactor + increase + var zoom = camera.zoomFactor + increase; if (zoom < camera.maximumZoomFactor) { - camera.zoomFactor = zoom + camera.zoomFactor = zoom; } else { - camera.zoomFactor = camera.maximumZoomFactor + camera.zoomFactor = camera.maximumZoomFactor; } } function zoomOut(decrease) { var zoom = camera.zoomFactor - decrease; if (zoom > 1) { - camera.zoomFactor = zoom + camera.zoomFactor = zoom; } else { - camera.zoomFactor = 1 + camera.zoomFactor = 1; } } } @@ -126,9 +124,9 @@ Popup { id: imageCapture onImageSaved: (requestId, path) => { - currentPath = path - photoPreview.source = 'file://'+path - cameraItem.state = "PhotoPreview" + currentPath = path; + photoPreview.source = 'file://' + path; + cameraItem.state = "PhotoPreview"; } } recorder: MediaRecorder { @@ -136,8 +134,8 @@ Popup { onRecorderStateChanged: { if (cameraItem.state == "VideoPreview" && recorderState === MediaRecorder.StoppedState) { - videoPreview.source = captureSession.recorder.actualLocation - videoPreview.play() + videoPreview.source = captureSession.recorder.actualLocation; + videoPreview.play(); } } } @@ -156,12 +154,8 @@ Popup { property bool isLandscape: (mainWindow.width / mainWindow.height) > (videoOutput.contentRect.width / videoOutput.contentRect.height) - width: isLandscape - ? videoOutput.contentRect.width * mainWindow.height / videoOutput.contentRect.height - : mainWindow.width - height: isLandscape - ? mainWindow.height - : videoOutput.contentRect.height * mainWindow.width / videoOutput.contentRect.width + width: isLandscape ? videoOutput.contentRect.width * mainWindow.height / videoOutput.contentRect.height : mainWindow.width + height: isLandscape ? mainWindow.height : videoOutput.contentRect.height * mainWindow.width / videoOutput.contentRect.width ShapePath { strokeColor: "#99000000" @@ -171,13 +165,34 @@ Popup { startX: grid.width / 3 startY: 0 - PathLine { x: grid.width / 3; y: grid.height } - PathMove { x: grid.width / 3 * 2; y: 0 } - PathLine { x: grid.width / 3 * 2; y: grid.height } - PathMove { x: 0; y: grid.height / 3 } - PathLine { x: grid.width; y: grid.height / 3 } - PathMove { x: 0; y: grid.height / 3 * 2 } - PathLine { x: grid.width; y: grid.height / 3 * 2 } + PathLine { + x: grid.width / 3 + y: grid.height + } + PathMove { + x: grid.width / 3 * 2 + y: 0 + } + PathLine { + x: grid.width / 3 * 2 + y: grid.height + } + PathMove { + x: 0 + y: grid.height / 3 + } + PathLine { + x: grid.width + y: grid.height / 3 + } + PathMove { + x: 0 + y: grid.height / 3 * 2 + } + PathLine { + x: grid.width + y: grid.height / 3 * 2 + } } ShapePath { @@ -188,13 +203,34 @@ Popup { startX: grid.width / 3 startY: 0 - PathLine { x: grid.width / 3; y: grid.height } - PathMove { x: grid.width / 3 * 2; y: 0 } - PathLine { x: grid.width / 3 * 2; y: grid.height } - PathMove { x: 0; y: grid.height / 3 } - PathLine { x: grid.width; y: grid.height / 3 } - PathMove { x: 0; y: grid.height / 3 * 2 } - PathLine { x: grid.width; y: grid.height / 3 * 2 } + PathLine { + x: grid.width / 3 + y: grid.height + } + PathMove { + x: grid.width / 3 * 2 + y: 0 + } + PathLine { + x: grid.width / 3 * 2 + y: grid.height + } + PathMove { + x: 0 + y: grid.height / 3 + } + PathLine { + x: grid.width + y: grid.height / 3 + } + PathMove { + x: 0 + y: grid.height / 3 * 2 + } + PathLine { + x: grid.width + y: grid.height / 3 * 2 + } } } @@ -225,13 +261,13 @@ Popup { enabled: cameraItem.visible && cameraItem.isCapturing anchors.fill: parent - onPinchUpdated: (pinch) => { - if (pinch.scale > pinch.previousScale) { - camera.zoomIn(0.05) - } else { - camera.zoomOut(0.05) - } - } + onPinchUpdated: pinch => { + if (pinch.scale > pinch.previousScale) { + camera.zoomIn(0.05); + } else { + camera.zoomOut(0.05); + } + } } WheelHandler { @@ -239,14 +275,11 @@ Popup { target: null grabPermissions: PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByItems - onWheel: (event) => { - if (event.angleDelta.y > 0) - { - camera.zoomIn(0.25) - } - else - { - camera.zoomOut(0.25) + onWheel: event => { + if (event.angleDelta.y > 0) { + camera.zoomIn(0.25); + } else { + camera.zoomOut(0.25); } } } @@ -280,49 +313,41 @@ Popup { height: 64 radius: 32 color: Theme.darkGraySemiOpaque - border.color: cameraItem.state == "VideoCapture" && captureSession.recorder.recorderState !== MediaRecorder.StoppedState - ? "red" - : "white" + border.color: cameraItem.state == "VideoCapture" && captureSession.recorder.recorderState !== MediaRecorder.StoppedState ? "red" : "white" border.width: 2 QfToolButton { id: captureButton anchors.centerIn: parent - visible: camera.cameraStatus == Camera.ActiveStatus || - camera.cameraStatus == Camera.LoadedStatus || - camera.cameraStatus == Camera.StandbyStatus + visible: camera.cameraStatus == Camera.ActiveStatus || camera.cameraStatus == Camera.LoadedStatus || camera.cameraStatus == Camera.StandbyStatus round: true roundborder: true - iconSource: cameraItem.state == "PhotoPreview" || cameraItem.state == "VideoPreview" - ? Theme.getThemeIcon("ic_check_white_48dp") - : '' - bgcolor: cameraItem.state == "PhotoPreview" || cameraItem.state == "VideoPreview" - ? Theme.mainColor - : cameraItem.state == "VideoCapture" ? "red" : "white" + iconSource: cameraItem.state == "PhotoPreview" || cameraItem.state == "VideoPreview" ? Theme.getThemeIcon("ic_check_white_48dp") : '' + bgcolor: cameraItem.state == "PhotoPreview" || cameraItem.state == "VideoPreview" ? Theme.mainColor : cameraItem.state == "VideoCapture" ? "red" : "white" onClicked: { if (cameraItem.state == "PhotoCapture") { - captureSession.imageCapture.captureToFile(qgisProject.homePath+ '/DCIM/') - currentPosition = positionSource.positionInformation + captureSession.imageCapture.captureToFile(qgisProject.homePath + '/DCIM/'); + currentPosition = positionSource.positionInformation; } else if (cameraItem.state == "VideoCapture") { if (captureSession.recorder.recorderState === MediaRecorder.StoppedState) { - captureSession.recorder.record() + captureSession.recorder.record(); } else { - cameraItem.state = "VideoPreview" - captureSession.recorder.stop() - var path = captureSession.recorder.actualLocation.toString() - var filePos = path.indexOf('file://') - currentPath = filePos === 0 ? path.substring(7) : path + cameraItem.state = "VideoPreview"; + captureSession.recorder.stop(); + var path = captureSession.recorder.actualLocation.toString(); + var filePos = path.indexOf('file://'); + currentPath = filePos === 0 ? path.substring(7) : path; } } else if (cameraItem.state == "PhotoPreview" || cameraItem.state == "VideoPreview") { if (cameraItem.state == "PhotoPreview") { if (settings.geoTagging && positionSource.active) { - FileUtils.addImageMetadata(currentPath, currentPosition) + FileUtils.addImageMetadata(currentPath, currentPosition); } } - cameraItem.finished(currentPath) + cameraItem.finished(currentPath); } } } @@ -339,7 +364,7 @@ Popup { bgcolor: Theme.darkGraySemiOpaque round: true - text: camera.zoomFactor.toFixed(1) +'X' + text: camera.zoomFactor.toFixed(1) + 'X' font: Theme.tinyFont onClicked: { @@ -355,7 +380,7 @@ Popup { y: cameraItem.isPortraitMode ? (parent.height - height) / 2 : (parent.height / 4) - (height / 2) iconSource: { - switch(camera.flashMode) { + switch (camera.flashMode) { case Camera.FlashAuto: return Theme.getThemeVectorIcon('ic_flash_auto_black_24dp'); case Camera.FlashOn: @@ -363,7 +388,7 @@ Popup { case Camera.FlashOff: return Theme.getThemeVectorIcon('ic_flash_off_black_24dp'); default: - return''; + return ''; } } iconColor: "white" @@ -374,7 +399,7 @@ Popup { if (camera.flashMode === Camera.FlashOff) { camera.flashMode = Camera.FlashOn; } else { - camera.flashMode = Camera.FlashOff + camera.flashMode = Camera.FlashOff; } } } @@ -401,7 +426,7 @@ Popup { seconds -= hours * 60 * 60; var minutes = Math.floor(seconds / 60) + ''; seconds = (seconds - minutes * 60) + ''; - return hours.padStart(2,'0') + ':' + minutes.padStart(2,'0') + ':' + seconds.padStart(2,'0'); + return hours.padStart(2, '0') + ':' + minutes.padStart(2, '0') + ':' + seconds.padStart(2, '0'); } else { // tiny bit of a cheat here as the first second isn't triggered return '00:00:01'; @@ -434,15 +459,15 @@ Popup { onClicked: { if (cameraItem.state == "PhotoPreview") { - cameraItem.state = "PhotoCapture" + cameraItem.state = "PhotoCapture"; } else if (cameraItem.state == "VideoPreview") { - videoPreview.stop() - cameraItem.state = "VideoCapture" + videoPreview.stop(); + cameraItem.state = "VideoCapture"; } else { if (currentPath != '') { - platformUtilities.rmFile(currentPath) + platformUtilities.rmFile(currentPath); } - cameraItem.canceled() + cameraItem.canceled(); } } } @@ -464,7 +489,7 @@ Popup { round: true onClicked: { - cameraSelectionMenu.popup(cameraSelectionButton.x, cameraSelectionButton.y) + cameraSelectionMenu.popup(cameraSelectionButton.x, cameraSelectionButton.y); } } @@ -472,14 +497,14 @@ Popup { id: cameraSelectionMenu width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : 0; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : 0; } Repeater { @@ -489,11 +514,7 @@ Popup { property string deviceId: modelData.id property bool isDefault: modelData.isDefault - text: modelData.description + - (modelData.position !== CameraDevice.UnspecifiedPosition - ? ' (' + (modelData.position === CameraDevice.FrontFace - ? qsTr('front') : qsTr('back')) + ')' - : '') + text: modelData.description + (modelData.position !== CameraDevice.UnspecifiedPosition ? ' (' + (modelData.position === CameraDevice.FrontFace ? qsTr('front') : qsTr('back')) + ')' : '') height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -507,8 +528,8 @@ Popup { onCheckedChanged: { if (checked && settings.deviceId !== modelData.id) { - settings.deviceId = modelData.id - camera.cameraDevice = modelData + settings.deviceId = modelData.id; + camera.cameraDevice = modelData; } } } @@ -530,8 +551,8 @@ Popup { onClicked: { if (positionSource.active) { - settings.geoTagging = !settings.geoTagging - displayToast(settings.geoTagging ? qsTr("Geotagging enabled") : qsTr("Geotagging disabled")) + settings.geoTagging = !settings.geoTagging; + displayToast(settings.geoTagging ? qsTr("Geotagging enabled") : qsTr("Geotagging disabled")); } } } @@ -550,8 +571,8 @@ Popup { round: true onClicked: { - settings.showGrid = !settings.showGrid - displayToast(settings.showGrid ? qsTr("Grid enabled") : qsTr("Grid disabled")) + settings.showGrid = !settings.showGrid; + displayToast(settings.showGrid ? qsTr("Grid enabled") : qsTr("Grid disabled")); } } } diff --git a/src/qml/QFieldCloudDeltaHistory.qml b/src/qml/QFieldCloudDeltaHistory.qml index 916c004e3c..0cc073d45e 100644 --- a/src/qml/QFieldCloudDeltaHistory.qml +++ b/src/qml/QFieldCloudDeltaHistory.qml @@ -1,156 +1,153 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Popup { - id: popup + id: popup - property alias model: deltaList.model + property alias model: deltaList.model - width: Math.min( 400, mainWindow.width - Theme.popupScreenEdgeMargin * 2 ) - x: (parent.width - width) / 2 - y: (parent.height - page.height) / 2 - padding: 0 + width: Math.min(400, mainWindow.width - Theme.popupScreenEdgeMargin * 2) + x: (parent.width - width) / 2 + y: (parent.height - page.height) / 2 + padding: 0 - onOpened: function () { - page.height = mainWindow.height - 160 + 60 + onOpened: function () { + page.height = mainWindow.height - 160 + 60; + if (cloudProjectsModel.currentProjectId) { + cloudProjectsModel.refreshProjectDeltaList(cloudProjectsModel.currentProjectId); + } + } + + onClosed: function () { + deltaList.model = null; + } + + Page { + id: page + width: parent.width + height: deltaList.height + 60 + padding: 10 + header: ToolBar { + id: toolBar + height: 48 + + background: Rectangle { + color: "transparent" + } - if ( cloudProjectsModel.currentProjectId ) { - cloudProjectsModel.refreshProjectDeltaList(cloudProjectsModel.currentProjectId) + Label { + anchors.centerIn: parent + leftPadding: 48 + rightPadding: 48 + width: parent.width - 20 + text: !!model ? qsTr("Push History") : qsTr("Loading…") + font: Theme.strongFont + color: Theme.mainColor + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap } - } - onClosed: function () { - deltaList.model = null - } + QfToolButton { + id: closeButton + anchors { + top: parent.top + right: parent.right + } + iconSource: Theme.getThemeIcon('ic_close_black_24dp') + iconColor: Theme.mainTextColor + bgcolor: Theme.mainBackgroundColor - Page { - id: page - width: parent.width - height: deltaList.height + 60 - padding: 10 - header: ToolBar { - id: toolBar - height: 48 - - background: Rectangle { - color: "transparent" - } + onClicked: { + popup.close(); + } + } + } - Label { - anchors.centerIn: parent - leftPadding: 48 - rightPadding: 48 - width: parent.width - 20 - text: !!model ? qsTr( "Push History" ) : qsTr( "Loading…" ) - font: Theme.strongFont - color: Theme.mainColor - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } + Column { + spacing: 4 + width: parent.width - QfToolButton { - id: closeButton - anchors { - top: parent.top - right: parent.right - } - iconSource: Theme.getThemeIcon( 'ic_close_black_24dp' ) - iconColor: Theme.mainTextColor - bgcolor: Theme.mainBackgroundColor + Label { + leftPadding: 48 + rightPadding: 48 + width: parent.width + visible: !!model && model.rowCount === 0 - onClicked: { - popup.close(); - } - } - } + text: qsTr("No changes have been pushed yet!") + color: Theme.mainTextDisabledColor + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } - Column { - spacing: 4 + ListView { + id: deltaList + width: parent.width + height: visible ? mainWindow.height - 160 : 0 + visible: deltaList && deltaList.model !== undefined && deltaList.model.rowCount !== 0 + clip: true + + delegate: Rectangle { + id: rectangle + width: parent ? parent.width : undefined + height: inner.height + color: "transparent" + + ColumnLayout { + id: inner width: parent.width - Label { - leftPadding: 48 - rightPadding: 48 - width: parent.width - visible: !!model && model.rowCount === 0 - - text: qsTr( "No changes have been pushed yet!" ) - color: Theme.mainTextDisabledColor - horizontalAlignment: Text.AlignHCenter + Text { + Layout.fillWidth: true + topPadding: 5 + leftPadding: 5 + text: { + var dt = new Date(CreatedAt); + return dt.toLocaleString(); + } + font: Theme.defaultFont + color: Theme.mainTextColor wrapMode: Text.WordWrap } - ListView { - id: deltaList - width: parent.width - height: visible ? mainWindow.height - 160 : 0 - visible: deltaList && deltaList.model !== undefined && deltaList.model.rowCount !== 0 - clip: true - - delegate: Rectangle { - id: rectangle - width: parent ? parent.width : undefined - height: inner.height - color: "transparent" - - ColumnLayout { - id: inner - width: parent.width - - Text { - Layout.fillWidth: true - topPadding: 5 - leftPadding: 5 - text: { - var dt = new Date(CreatedAt) - return dt.toLocaleString() - } - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - } - - Text { - Layout.fillWidth: true - leftPadding: 5 - bottomPadding: 5 - text: { - var status = '' - switch(Status) { - case DeltaListModel.PendingStatus: - status = 'pending' - break; - case DeltaListModel.BusyStatus: - status = 'busy' - break; - case DeltaListModel.AppliedStatus: - status = 'applied' - break; - case DeltaListModel.ConflictStatus: - status = 'conflict' - break; - case DeltaListModel.NotAppliedStatus: - status = 'not applied' - break; - case DeltaListModel.ErrorStatus: - status = 'error' - break; - } - return 'Status: ' + status + ( Output != '' ? ' (' + Output + ')' : '' ) - } - font: Theme.tipFont - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - } - } + Text { + Layout.fillWidth: true + leftPadding: 5 + bottomPadding: 5 + text: { + var status = ''; + switch (Status) { + case DeltaListModel.PendingStatus: + status = 'pending'; + break; + case DeltaListModel.BusyStatus: + status = 'busy'; + break; + case DeltaListModel.AppliedStatus: + status = 'applied'; + break; + case DeltaListModel.ConflictStatus: + status = 'conflict'; + break; + case DeltaListModel.NotAppliedStatus: + status = 'not applied'; + break; + case DeltaListModel.ErrorStatus: + status = 'error'; + break; } + return 'Status: ' + status + (Output != '' ? ' (' + Output + ')' : ''); + } + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap } + } } + } } + } } diff --git a/src/qml/QFieldCloudLogin.qml b/src/qml/QFieldCloudLogin.qml index 94eb59f078..cc2c131705 100644 --- a/src/qml/QFieldCloudLogin.qml +++ b/src/qml/QFieldCloudLogin.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 @@ -56,7 +55,7 @@ Item { id: loginFeedbackLabel Layout.fillWidth: true visible: false - text: qsTr( "Failed to sign in" ) + text: qsTr("Failed to sign in") horizontalAlignment: Text.AlignHCenter font: Theme.defaultFont color: Theme.errorColor @@ -67,18 +66,17 @@ Item { function onLoginFailed(reason) { if (!qfieldCloudLogin.parent.visible) - return - - loginFeedbackLabel.visible = true - loginFeedbackLabel.text = reason + return; + loginFeedbackLabel.visible = true; + loginFeedbackLabel.text = reason; } function onStatusChanged() { - if (cloudConnection.status === QFieldCloudConnection.Connecting) { - loginFeedbackLabel.visible = false - loginFeedbackLabel.text = '' + if (cloudConnection.status === QFieldCloudConnection.Connecting) { + loginFeedbackLabel.visible = false; + loginFeedbackLabel.text = ''; } else { - loginFeedbackLabel.visible = cloudConnection.status === QFieldCloudConnection.Disconnected && loginFeedbackLabel.text.length + loginFeedbackLabel.visible = cloudConnection.status === QFieldCloudConnection.Disconnected && loginFeedbackLabel.text.length; } } } @@ -87,9 +85,8 @@ Item { Text { id: serverUrlLabel Layout.fillWidth: true - visible: cloudConnection.status === QFieldCloudConnection.Disconnected - && ( cloudConnection.url !== cloudConnection.defaultUrl || isServerUrlEditingActive ) - text: qsTr( "Server URL\n(Leave empty to use the default server)" ) + visible: cloudConnection.status === QFieldCloudConnection.Disconnected && (cloudConnection.url !== cloudConnection.defaultUrl || isServerUrlEditingActive) + text: qsTr("Server URL\n(Leave empty to use the default server)") horizontalAlignment: Text.AlignHCenter font: Theme.defaultFont color: 'gray' @@ -100,23 +97,21 @@ Item { id: serverUrlField Layout.preferredWidth: parent.width / 1.3 Layout.alignment: Qt.AlignHCenter - visible: cloudConnection.status === QFieldCloudConnection.Disconnected - && ( prefixUrlWithProtocol(cloudConnection.url) !== cloudConnection.defaultUrl || isServerUrlEditingActive ) + visible: cloudConnection.status === QFieldCloudConnection.Disconnected && (prefixUrlWithProtocol(cloudConnection.url) !== cloudConnection.defaultUrl || isServerUrlEditingActive) enabled: visible height: Math.max(fontMetrics.height, fontMetrics.boundingRect(text).height) + 34 font: Theme.defaultFont horizontalAlignment: Text.AlignHCenter - text: prefixUrlWithProtocol(cloudConnection.url )=== cloudConnection.defaultUrl ? '' : cloudConnection.url + text: prefixUrlWithProtocol(cloudConnection.url) === cloudConnection.defaultUrl ? '' : cloudConnection.url onTextChanged: text = text.replace(/\s+/g, '') onEditingFinished: cloudConnection.url = text ? prefixUrlWithProtocol(text) : cloudConnection.defaultUrl onReturnPressed: loginFormSumbitHandler() function prefixUrlWithProtocol(url) { - if (!url || url.startsWith('http://') || url.startsWith('https://') ) - return url - - return 'https://' + url + if (!url || url.startsWith('http://') || url.startsWith('https://')) + return url; + return 'https://' + url; } } @@ -124,7 +119,7 @@ Item { id: usernamelabel Layout.fillWidth: true visible: cloudConnection.status === QFieldCloudConnection.Disconnected - text: qsTr( "Username or email" ) + text: qsTr("Username or email") horizontalAlignment: Text.AlignHCenter font: Theme.defaultFont color: Theme.mainTextColor @@ -142,14 +137,14 @@ Item { horizontalAlignment: Text.AlignHCenter onTextChanged: text = text.replace(/\s+/g, '') - onReturnPressed: loginFormSumbitHandler(); + onReturnPressed: loginFormSumbitHandler() } Text { id: passwordlabel Layout.fillWidth: true visible: cloudConnection.status === QFieldCloudConnection.Disconnected - text: qsTr( "Password" ) + text: qsTr("Password") horizontalAlignment: Text.AlignHCenter font: Theme.defaultFont color: Theme.mainTextColor @@ -177,7 +172,7 @@ Item { QfButton { Layout.fillWidth: true - text: cloudConnection.status == QFieldCloudConnection.LoggedIn ? qsTr( "Sign out" ) : cloudConnection.status == QFieldCloudConnection.Connecting ? qsTr( "Signing in, please wait" ) : qsTr( "Sign in" ) + text: cloudConnection.status == QFieldCloudConnection.LoggedIn ? qsTr("Sign out") : cloudConnection.status == QFieldCloudConnection.Connecting ? qsTr("Signing in, please wait") : qsTr("Sign in") enabled: cloudConnection.status != QFieldCloudConnection.Connecting onClicked: loginFormSumbitHandler() @@ -187,7 +182,7 @@ Item { id: cloudRegisterLabel Layout.fillWidth: true Layout.topMargin: 6 - text: qsTr( 'New user?') + ' ' + qsTr( 'Register an account' ) + '.' + text: qsTr('New user?') + ' ' + qsTr('Register an account') + '.' horizontalAlignment: Text.AlignHCenter font: Theme.defaultFont color: Theme.mainTextColor @@ -195,13 +190,13 @@ Item { wrapMode: Text.WordWrap visible: cloudConnection.status === QFieldCloudConnection.Disconnected - onLinkActivated: (link) => { + onLinkActivated: link => { if (Qt.platform.os === "ios" || Qt.platform.os === "android") { - browserPopup.url = link - browserPopup.fullscreen = true - browserPopup.open() + browserPopup.url = link; + browserPopup.fullscreen = true; + browserPopup.open(); } else { - Qt.openUrlExternally(link) + Qt.openUrlExternally(link); } } } @@ -209,21 +204,22 @@ Item { Text { id: cloudIntroLabel Layout.fillWidth: true - text: qsTr( 'The easiest way to transfer you project from QGIS to your devices!' ) + - ' ' + qsTr( 'Learn more about QFieldCloud' ) + '.' + text: qsTr('The easiest way to transfer you project from QGIS to your devices!') + ' ' + qsTr('Learn more about QFieldCloud') + '.' horizontalAlignment: Text.AlignHCenter font: Theme.defaultFont color: Theme.mainTextColor textFormat: Text.RichText wrapMode: Text.WordWrap - onLinkActivated: (link) => { Qt.openUrlExternally(link) } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } } Item { - // spacer item - Layout.fillWidth: true - Layout.fillHeight: true + // spacer item + Layout.fillWidth: true + Layout.fillHeight: true } } } @@ -232,27 +228,26 @@ Item { target: cloudConnection function onStatusChanged() { - if ( cloudConnection.status === QFieldCloudConnection.LoggedIn ) - usernameField.text = cloudConnection.username + if (cloudConnection.status === QFieldCloudConnection.LoggedIn) + usernameField.text = cloudConnection.username; } } function loginFormSumbitHandler() { if (cloudConnection.status == QFieldCloudConnection.LoggedIn) { - cloudConnection.logout() + cloudConnection.logout(); } else { - cloudConnection.username = usernameField.text - cloudConnection.password = passwordField.text - cloudConnection.login() + cloudConnection.username = usernameField.text; + cloudConnection.password = passwordField.text; + cloudConnection.login(); } } function toggleServerUrlEditing() { - if ( cloudConnection.url != cloudConnection.defaultUrl ) { - isServerUrlEditingActive = true - return + if (cloudConnection.url != cloudConnection.defaultUrl) { + isServerUrlEditingActive = true; + return; } - - isServerUrlEditingActive = !isServerUrlEditingActive + isServerUrlEditingActive = !isServerUrlEditingActive; } } diff --git a/src/qml/QFieldCloudPackageLayersFeedback.qml b/src/qml/QFieldCloudPackageLayersFeedback.qml index 66f778a994..6e917794b2 100644 --- a/src/qml/QFieldCloudPackageLayersFeedback.qml +++ b/src/qml/QFieldCloudPackageLayersFeedback.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 @@ -17,8 +16,8 @@ Dialog { width: mainWindow.width - 20 font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 title: qsTr("QFieldCloud had troubles packaging your project") @@ -30,7 +29,7 @@ Dialog { Label { Layout.fillWidth: true - text: qsTr( "Some layers have not been packaged correctly on QFieldCloud. These layers might be misconfigured or their data source is not accessible from the QFieldCloud server. Please check the logs of the latest packaging job on the qfield.cloud website." ) + text: qsTr("Some layers have not been packaged correctly on QFieldCloud. These layers might be misconfigured or their data source is not accessible from the QFieldCloud server. Please check the logs of the latest packaging job on the qfield.cloud website.") wrapMode: Text.WordWrap } @@ -54,4 +53,3 @@ Dialog { standardButtons: Dialog.Ok } - diff --git a/src/qml/QFieldCloudPopup.qml b/src/qml/QFieldCloudPopup.qml index d9e413f85a..5ebc1fd9ba 100644 --- a/src/qml/QFieldCloudPopup.qml +++ b/src/qml/QFieldCloudPopup.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 @@ -19,23 +18,19 @@ Popup { showCancelButton: false showApplyButton: false - busyIndicatorState: cloudConnection.status === QFieldCloudConnection.Connecting - || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading - || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading - ? 'on' - : 'off' + busyIndicatorState: cloudConnection.status === QFieldCloudConnection.Connecting || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading ? 'on' : 'off' topMargin: mainWindow.sceneTopMargin onFinished: { if (connectionSettings.visible) { - if ( cloudConnection.status === QFieldCloudConnection.LoggedIn ) { + if (cloudConnection.status === QFieldCloudConnection.LoggedIn) { connectionSettings.visible = false; } else { - popup.close() + popup.close(); } } else { - popup.close() + popup.close(); } } } @@ -51,19 +46,19 @@ Popup { Layout.fillWidth: true font: Theme.defaultFont color: Theme.mainTextColor - text: qsTr('The current project is not stored on QFieldCloud.

') + - qsTr('Storing projects on QFieldCloud offers seamless synchronization, offline editing, and team management.

') + - ' ' + qsTr( 'Learn more about QFieldCloud' ) + '.' + text: qsTr('The current project is not stored on QFieldCloud.

') + qsTr('Storing projects on QFieldCloud offers seamless synchronization, offline editing, and team management.

') + ' ' + qsTr('Learn more about QFieldCloud') + '.' textFormat: Text.RichText wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter - onLinkActivated: (link) => { Qt.openUrlExternally(link) } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } } Item { - Layout.fillHeight: true - height: 15 + Layout.fillHeight: true + height: 15 } } @@ -87,18 +82,24 @@ Popup { visible: cloudConnection.status === QFieldCloudConnection.LoggedIn Text { - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - id: welcomeText - padding: 10 - text: switch(cloudConnection.status) { - case 0: qsTr( 'Disconnected from the cloud.' ); break; - case 1: qsTr( 'Connecting to the cloud.' ); break; - case 2: qsTr( 'Greetings %1.' ).arg( cloudConnection.username ); break; - } - wrapMode: Text.WordWrap - font: Theme.tipFont - color: Theme.mainTextColor + id: welcomeText + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + padding: 10 + text: switch (cloudConnection.status) { + case 0: + qsTr('Disconnected from the cloud.'); + break; + case 1: + qsTr('Connecting to the cloud.'); + break; + case 2: + qsTr('Greetings %1.').arg(cloudConnection.username); + break; + } + wrapMode: Text.WordWrap + font: Theme.tipFont + color: Theme.mainTextColor } Rectangle { @@ -107,7 +108,7 @@ Popup { Layout.margins: 10 width: 48 height: 48 - radius: width/2 + radius: width / 2 border.color: Theme.mainColor border.width: 1 clip: true @@ -117,7 +118,7 @@ Popup { anchors.centerIn: parent width: 46 height: 46 - radius: width/2 + radius: width / 2 color: "white" visible: false layer.enabled: true @@ -129,16 +130,14 @@ Popup { anchors.margins: 2 fillMode: Image.PreserveAspectCrop smooth: true - source: cloudConnection.avatarUrl !== '' - ? cloudConnection.avatarUrl - : 'qrc:/images/qfieldcloud_logo.svg' + source: cloudConnection.avatarUrl !== '' ? cloudConnection.avatarUrl : 'qrc:/images/qfieldcloud_logo.svg' width: 48 height: 48 sourceSize.width: width * screen.devicePixelRatio sourceSize.height: height * screen.devicePixelRatio layer.enabled: true layer.effect: QfOpacityMask { - maskSource: cloudAvatarMask + maskSource: cloudAvatarMask } onStatusChanged: { @@ -152,10 +151,8 @@ Popup { anchors.fill: parent onClicked: { - if (cloudConnection.status !== QFieldCloudConnection.LoggedIn || - cloudProjectsModel.currentProjectData.Status !== QFieldCloudProjectsModel.Idle) - return; - + if (cloudConnection.status !== QFieldCloudConnection.LoggedIn || cloudProjectsModel.currentProjectData.Status !== QFieldCloudProjectsModel.Idle) + return; if (!connectionSettings.visible) { connectionSettings.visible = true; projects.visible = false; @@ -169,7 +166,6 @@ Popup { } } - Text { id: wrongAccountText visible: cloudProjectsModel.currentProjectId != '' && cloudProjectsModel.currentProjectId !== cloudProjectsModel.currentProjectData.Id @@ -183,38 +179,36 @@ Popup { Layout.margins: 10 } - Text { id: statusText - visible: cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading || - cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading + visible: cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading font: Theme.tipFont color: Theme.secondaryTextColor - text: switch(cloudProjectsModel.currentProjectData.Status ) { - case QFieldCloudProjectsModel.Downloading: - if (cloudProjectsModel.currentProjectData.PackagingStatus === QFieldCloudProjectsModel.PackagingBusyStatus) { - return qsTr('QFieldCloud is packaging the latest data just for you; this might take some time, please hold tight') - } else { - if (cloudProjectsModel.currentProjectData.PackagingStatus === QFieldCloudProjectsModel.PackagingFinishedStatus - || cloudProjectsModel.currentProjectData.DownloadProgress > 0.0) { - if (cloudProjectsModel.currentProjectData.DownloadSize > 0) { - return qsTr( 'Downloading, %1% of %2 fetched' ).arg( Math.round(cloudProjectsModel.currentProjectData.DownloadProgress * 100 ) ).arg( FileUtils.representFileSize( cloudProjectsModel.currentProjectData.DownloadSize ) ) - } else { - return qsTr( 'Downloading, %1% fetched' ).arg( Math.round(cloudProjectsModel.currentProjectData.DownloadProgress * 100 ) ) - } - } else { - return qsTr( 'Reaching out to QFieldCloud to download project' ) - } - } - case QFieldCloudProjectsModel.Uploading: - switch ( cloudProjectsModel.currentProjectData.UploadDeltaStatus ) { - case QFieldCloudProjectsModel.DeltaFileLocalStatus: - return qsTr('Uploading %1%…').arg( Math.round(cloudProjectsModel.currentProjectData.UploadDeltaProgress * 100 ) ); - default: - return qsTr('QFieldCloud is applying the latest uploaded changes. This might take some time, please hold tight…') - } - default: ''; + text: switch (cloudProjectsModel.currentProjectData.Status) { + case QFieldCloudProjectsModel.Downloading: + if (cloudProjectsModel.currentProjectData.PackagingStatus === QFieldCloudProjectsModel.PackagingBusyStatus) { + return qsTr('QFieldCloud is packaging the latest data just for you; this might take some time, please hold tight'); + } else { + if (cloudProjectsModel.currentProjectData.PackagingStatus === QFieldCloudProjectsModel.PackagingFinishedStatus || cloudProjectsModel.currentProjectData.DownloadProgress > 0.0) { + if (cloudProjectsModel.currentProjectData.DownloadSize > 0) { + return qsTr('Downloading, %1% of %2 fetched').arg(Math.round(cloudProjectsModel.currentProjectData.DownloadProgress * 100)).arg(FileUtils.representFileSize(cloudProjectsModel.currentProjectData.DownloadSize)); + } else { + return qsTr('Downloading, %1% fetched').arg(Math.round(cloudProjectsModel.currentProjectData.DownloadProgress * 100)); } + } else { + return qsTr('Reaching out to QFieldCloud to download project'); + } + } + case QFieldCloudProjectsModel.Uploading: + switch (cloudProjectsModel.currentProjectData.UploadDeltaStatus) { + case QFieldCloudProjectsModel.DeltaFileLocalStatus: + return qsTr('Uploading %1%…').arg(Math.round(cloudProjectsModel.currentProjectData.UploadDeltaProgress * 100)); + default: + return qsTr('QFieldCloud is applying the latest uploaded changes. This might take some time, please hold tight…'); + } + default: + ''; + } wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter @@ -232,31 +226,31 @@ Popup { width: 128 height: 128 color: 'transparent' - visible: cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading || - cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading + visible: cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Downloading || cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Uploading Image { id: statusIcon anchors.fill: parent fillMode: Image.PreserveAspectFit smooth: true - source: switch(cloudProjectsModel.currentProjectData.Status ) { - case QFieldCloudProjectsModel.Downloading: - switch ( cloudProjectsModel.currentProjectData.PackagingStatus ) { - case QFieldCloudProjectsModel.PackagingFinishedStatus || cloudProjectsModel.currentProjectData.DownloadProgress > 0.0: - return Theme.getThemeVectorIcon('ic_cloud_download_24dp'); - default: - return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); - } - case QFieldCloudProjectsModel.Uploading: - switch ( cloudProjectsModel.currentProjectData.UploadDeltaStatus ) { - case QFieldCloudProjectsModel.DeltaFileLocalStatus: - return Theme.getThemeVectorIcon('ic_cloud_upload_24dp'); - default: - return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); - } - default: ''; - } + source: switch (cloudProjectsModel.currentProjectData.Status) { + case QFieldCloudProjectsModel.Downloading: + switch (cloudProjectsModel.currentProjectData.PackagingStatus) { + case QFieldCloudProjectsModel.PackagingFinishedStatus || cloudProjectsModel.currentProjectData.DownloadProgress > 0.0: + return Theme.getThemeVectorIcon('ic_cloud_download_24dp'); + default: + return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); + } + case QFieldCloudProjectsModel.Uploading: + switch (cloudProjectsModel.currentProjectData.UploadDeltaStatus) { + case QFieldCloudProjectsModel.DeltaFileLocalStatus: + return Theme.getThemeVectorIcon('ic_cloud_upload_24dp'); + default: + return Theme.getThemeVectorIcon('ic_cloud_active_24dp'); + } + default: + ''; + } width: parent.width height: parent.height sourceSize.width: width * screen.devicePixelRatio @@ -265,16 +259,16 @@ Popup { SequentialAnimation { OpacityAnimator { - from: 1 - to: 0.2 - duration: 2000 - target: statusIcon + from: 1 + to: 0.2 + duration: 2000 + target: statusIcon } OpacityAnimator { - from: 0.2 - to: 1 - duration: 2000 - target: statusIcon + from: 0.2 + to: 1 + duration: 2000 + target: statusIcon } running: cloudAnimation.visible loops: Animation.Infinite @@ -293,59 +287,53 @@ Popup { } QfCollapsibleMessage { - id: transferError + id: transferError - property bool hasError: false + property bool hasError: false - visible: hasError && cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Idle && !connectionSettings.visible + visible: hasError && cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Idle && !connectionSettings.visible - Layout.fillWidth: true - Layout.leftMargin: 10 - Layout.rightMargin: 10 + Layout.fillWidth: true + Layout.leftMargin: 10 + Layout.rightMargin: 10 - color: Theme.darkRed - detailsColor: Theme.secondaryTextColor - font: Theme.tipFont + color: Theme.darkRed + detailsColor: Theme.secondaryTextColor + font: Theme.tipFont - titleText: detailsText.startsWith('[QF/') - ? qsTr('A server error has occured, please try again.') - : qsTr('A network error has occured, please try again.'); - detailsText: '' + titleText: detailsText.startsWith('[QF/') ? qsTr('A server error has occured, please try again.') : qsTr('A network error has occured, please try again.') + detailsText: '' - Connections { - target: iface + Connections { + target: iface - function onLoadProjectEnded() { - transferError.hasError = false - } + function onLoadProjectEnded() { + transferError.hasError = false; } + } - Connections { - target: cloudProjectsModel - - function onPushFinished(projectId, hasError, errorString) { - transferError.hasError = hasError; + Connections { + target: cloudProjectsModel - if (transferError.visible) { - transferError.detailsText = errorString - } + function onPushFinished(projectId, hasError, errorString) { + transferError.hasError = hasError; + if (transferError.visible) { + transferError.detailsText = errorString; } + } - function onProjectDownloaded(projectId, projectName, hasError, errorString) { - transferError.hasError = hasError; - - if (transferError.visible) { - transferError.detailsText = errorString - } - - const projectData = cloudProjectsModel.getProjectData(projectId) - if (projectData.PackagedLayerErrors.length !== 0) - { - cloudPackageLayersFeedback.packagedLayersListViewModel = projectData.PackagedLayerErrors; - cloudPackageLayersFeedback.visible = true; - } + function onProjectDownloaded(projectId, projectName, hasError, errorString) { + transferError.hasError = hasError; + if (transferError.visible) { + transferError.detailsText = errorString; + } + const projectData = cloudProjectsModel.getProjectData(projectId); + if (projectData.PackagedLayerErrors.length !== 0) { + cloudPackageLayersFeedback.packagedLayersListViewModel = projectData.PackagedLayerErrors; + cloudPackageLayersFeedback.visible = true; } } + } } GridLayout { @@ -354,25 +342,22 @@ Popup { Layout.maximumWidth: 525 Layout.alignment: Qt.AlignHCenter width: parent.width - visible: !connectionSettings.visible && - cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Idle + visible: !connectionSettings.visible && cloudProjectsModel.currentProjectData.Status === QFieldCloudProjectsModel.Idle columns: 1 columnSpacing: parent.columnSpacing rowSpacing: parent.rowSpacing Text { + id: changesText property bool hasError: cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() property int changesCount: cloudProjectsModel.layerObserver.deltaFileWrapper.count - id: changesText font: Theme.tipFont color: hasError ? Theme.errorColor : Theme.mainTextColor text: { if (!hasError) { - return changesCount !== 0 - ? qsTr('There is/are %n local change(s)','',changesCount) - : qsTr('There are no local changes'); + return changesCount !== 0 ? qsTr('There is/are %n local change(s)', '', changesCount) : qsTr('There are no local changes'); } else { - return qsTr('The locally stored cloud project has been corrupted') + return qsTr('The locally stored cloud project has been corrupted'); } } wrapMode: Text.WordWrap @@ -386,8 +371,7 @@ Popup { Layout.fillWidth: true text: qsTr('Synchronize') visible: !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() - enabled: !!(cloudProjectsModel.currentProjectData && cloudProjectsModel.currentProjectData.CanSync) - && !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() + enabled: !!(cloudProjectsModel.currentProjectData && cloudProjectsModel.currentProjectData.CanSync) && !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() icon.source: Theme.getThemeIcon('ic_cloud_synchronize_24dp') onClicked: projectUpload(true) @@ -410,8 +394,7 @@ Popup { Layout.fillWidth: true text: qsTr('Push changes') visible: !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() - enabled: !!(cloudProjectsModel.currentProjectData && cloudProjectsModel.currentProjectData.CanSync) - && cloudProjectsModel.layerObserver.deltaFileWrapper.count > 0 && !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() + enabled: !!(cloudProjectsModel.currentProjectData && cloudProjectsModel.currentProjectData.CanSync) && cloudProjectsModel.layerObserver.deltaFileWrapper.count > 0 && !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() icon.source: Theme.getThemeIcon('ic_cloud_upload_24dp') onClicked: projectUpload(false) @@ -433,9 +416,7 @@ Popup { id: discardButton Layout.fillWidth: true bgcolor: Theme.darkRed - text: !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() - ? qsTr('Revert local changes') - : qsTr('Reset project') + text: !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() ? qsTr('Revert local changes') : qsTr('Reset project') enabled: cloudProjectsModel.layerObserver.deltaFileWrapper.count > 0 || cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() icon.source: Theme.getThemeVectorIcon('ic_undo_black_24dp') @@ -452,9 +433,7 @@ Popup { id: discardText font: Theme.tipFont color: Theme.secondaryTextColor - text: !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() - ? qsTr('Revert all modified features in the local layers. You cannot restore those changes.') - : qsTr('The local copy of this cloud project has been corrupted. Resetting the project will re-download the cloud version and will remove any local changes, make sure those were copied first if needed.\n\nWhile you can still view and use the project, it is strongly recommended to reset to avoid any accidental data loss as none of the changes made will be pushed back to the cloud.') + text: !cloudProjectsModel.layerObserver.deltaFileWrapper.hasError() ? qsTr('Revert all modified features in the local layers. You cannot restore those changes.') : qsTr('The local copy of this cloud project has been corrupted. Resetting the project will re-download the cloud version and will remove any local changes, make sure those were copied first if needed.\n\nWhile you can still view and use the project, it is strongly recommended to reset to avoid any accidental data loss as none of the changes made will be pushed back to the cloud.') wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter Layout.bottomMargin: 10 @@ -483,15 +462,15 @@ Popup { wrapMode: Text.WordWrap color: autoPush.checked ? Theme.mainTextColor : Theme.secondaryTextColor - text: qsTr('Automatically push changes every %n minute(s)','',0 + cloudProjectsModel.currentProjectData.AutoPushIntervalMins) + text: qsTr('Automatically push changes every %n minute(s)', '', 0 + cloudProjectsModel.currentProjectData.AutoPushIntervalMins) MouseArea { anchors.fill: parent onClicked: { if (!!cloudProjectsModel.currentProjectData.ForceAutoPush) { - displayToast(qsTr('The current project does not allow for auto-push to be turned off')) + displayToast(qsTr('The current project does not allow for auto-push to be turned off')); } else { - cloudProjectsModel.projectSetAutoPushEnabled(cloudProjectsModel.currentProjectId, !autoPush.checked) + cloudProjectsModel.projectSetAutoPushEnabled(cloudProjectsModel.currentProjectId, !autoPush.checked); } } } @@ -506,8 +485,8 @@ Popup { enabled: !cloudProjectsModel.currentProjectData.ForceAutoPush checked: !!cloudProjectsModel.currentProjectData.AutoPushEnabled - onClicked: { - cloudProjectsModel.projectSetAutoPushEnabled(cloudProjectsModel.currentProjectId, checked) + onClicked: { + cloudProjectsModel.projectSetAutoPushEnabled(cloudProjectsModel.currentProjectId, checked); } } @@ -519,12 +498,12 @@ Popup { onRunningChanged: { if (running && pushButton.enabled) { - const dtStr = cloudProjectsModel.currentProjectData.LastLocalPushDeltas + const dtStr = cloudProjectsModel.currentProjectData.LastLocalPushDeltas; if (dtStr) { - const dt = new Date(dtStr) - const now = new Date() + const dt = new Date(dtStr); + const now = new Date(); if ((now - dt) >= interval) { - projectUpload(false) + projectUpload(false); } } } @@ -532,7 +511,7 @@ Popup { onTriggered: { if (pushButton.enabled) { - projectUpload(false) + projectUpload(false); } } } @@ -543,44 +522,38 @@ Popup { font: Theme.tipFont color: Theme.secondaryTextColor text: { - var exportText = '' - var exportDt = cloudProjectsModel.currentProjectData.LastLocalExportedAt - var timeDeltaMinutes = null - + var exportText = ''; + var exportDt = cloudProjectsModel.currentProjectData.LastLocalExportedAt; + var timeDeltaMinutes = null; if (exportDt) { - exportDt = new Date(exportDt) - timeDeltaMinutes = parseInt( Math.max( new Date() - exportDt, 0 ) / (60 * 1000) ) - - if ( timeDeltaMinutes < 1) - exportText = qsTr( 'Last synchronized just now' ) + exportDt = new Date(exportDt); + timeDeltaMinutes = parseInt(Math.max(new Date() - exportDt, 0) / (60 * 1000)); + if (timeDeltaMinutes < 1) + exportText = qsTr('Last synchronized just now'); else if (timeDeltaMinutes < 60) - exportText = qsTr( 'Last synchronized %1 minutes ago' ).arg( timeDeltaMinutes ) + exportText = qsTr('Last synchronized %1 minutes ago').arg(timeDeltaMinutes); else if (exportDt.toLocaleDateString() === new Date().toLocaleDateString()) - exportText = qsTr( 'Last synchronized at %1' ).arg( exportDt.toLocaleTimeString() ) + exportText = qsTr('Last synchronized at %1').arg(exportDt.toLocaleTimeString()); else - exportText = qsTr( 'Last synchronized on %1' ).arg( exportDt.toLocaleString() ) + exportText = qsTr('Last synchronized on %1').arg(exportDt.toLocaleString()); } - - var pushText = '' - var pushDt = cloudProjectsModel.currentProjectData.LastLocalPushDeltas - + var pushText = ''; + var pushDt = cloudProjectsModel.currentProjectData.LastLocalPushDeltas; if (pushDt) { - pushDt = new Date(pushDt) - timeDeltaMinutes = parseInt( Math.max( new Date() - pushDt, 0 ) / (60 * 1000) ) - - if ( timeDeltaMinutes < 1 ) - pushText = qsTr( 'Last changes pushed just now' ) + pushDt = new Date(pushDt); + timeDeltaMinutes = parseInt(Math.max(new Date() - pushDt, 0) / (60 * 1000)); + if (timeDeltaMinutes < 1) + pushText = qsTr('Last changes pushed just now'); else if (timeDeltaMinutes < 60) - pushText = qsTr( 'Last changes pushed %1 minutes ago' ).arg( timeDeltaMinutes ) + pushText = qsTr('Last changes pushed %1 minutes ago').arg(timeDeltaMinutes); else if (pushDt.toLocaleDateString() === new Date().toLocaleDateString()) - pushText = qsTr( 'Last changes pushed at %1' ).arg( pushDt.toLocaleTimeString() ) + pushText = qsTr('Last changes pushed at %1').arg(pushDt.toLocaleTimeString()); else - pushText = qsTr( 'Last changes pushed on %1' ).arg( pushDt.toLocaleString() ) + pushText = qsTr('Last changes pushed on %1').arg(pushDt.toLocaleString()); } else { - pushText = qsTr( 'No changes pushed yet' ) + pushText = qsTr('No changes pushed yet'); } - - return pushDt > exportDt ? pushText + '\n' + exportText : exportText + '\n' + pushText + return pushDt > exportDt ? pushText + '\n' + exportText : exportText + '\n' + pushText; } wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter @@ -589,7 +562,7 @@ Popup { MouseArea { anchors.fill: parent onClicked: { - qfieldCloudDeltaHistory.open() + qfieldCloudDeltaHistory.open(); } } } @@ -623,8 +596,8 @@ Popup { } Item { - Layout.fillHeight: true - height: 15 + Layout.fillHeight: true + height: 15 } } } @@ -642,14 +615,14 @@ Popup { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Revert local changes" ) + title: qsTr("Revert local changes") Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( "Should local changes be reverted?" ) + text: qsTr("Should local changes be reverted?") } standardButtons: Dialog.Ok | Dialog.Cancel @@ -658,7 +631,7 @@ Popup { revertLocalChangesFromCurrentProject(); } onRejected: { - visible = false + visible = false; popup.focus = true; } } @@ -674,14 +647,14 @@ Popup { modal: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 - title: qsTr( "Reset cloud project" ) + title: qsTr("Reset cloud project") Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( "Last warning, resetting the cloud project will erase any local changes, are you sure you want to go ahead?" ) + text: qsTr("Last warning, resetting the cloud project will erase any local changes, are you sure you want to go ahead?") } standardButtons: Dialog.Ok | Dialog.Cancel @@ -690,47 +663,45 @@ Popup { resetCurrentProject(); } onRejected: { - visible = false + visible = false; popup.focus = true; } } function show() { - visible = !visible - - if ( cloudProjectsModel.currentProjectId && cloudConnection.hasToken && cloudConnection.status === QFieldCloudConnection.Disconnected ) { + visible = !visible; + if (cloudProjectsModel.currentProjectId && cloudConnection.hasToken && cloudConnection.status === QFieldCloudConnection.Disconnected) { cloudConnection.login(); } - - if ( cloudConnection.status === QFieldCloudConnection.Connecting ) { - displayToast(qsTr('Connecting cloud')) - } else if ( cloudProjectsModel.currentProjectData.ProjectFileOutdated ) { - displayToast(qsTr('This project has an updated project file on the cloud, you are advised to synchronize.'), 'warning') - } else if ( cloudProjectsModel.currentProjectData.ProjectOutdated ) { - displayToast(qsTr('This project has updated data on the cloud, you should synchronize.')) + if (cloudConnection.status === QFieldCloudConnection.Connecting) { + displayToast(qsTr('Connecting cloud')); + } else if (cloudProjectsModel.currentProjectData.ProjectFileOutdated) { + displayToast(qsTr('This project has an updated project file on the cloud, you are advised to synchronize.'), 'warning'); + } else if (cloudProjectsModel.currentProjectData.ProjectOutdated) { + displayToast(qsTr('This project has updated data on the cloud, you should synchronize.')); } } function projectUpload(shouldDownloadUpdates) { if (cloudProjectsModel.currentProjectData && cloudProjectsModel.currentProjectData.CanSync) { - cloudProjectsModel.projectUpload(cloudProjectsModel.currentProjectId, shouldDownloadUpdates) + cloudProjectsModel.projectUpload(cloudProjectsModel.currentProjectId, shouldDownloadUpdates); } } function revertLocalChangesFromCurrentProject() { if (cloudProjectsModel.currentProjectData && cloudProjectsModel.currentProjectData.CanSync) { if (cloudProjectsModel.revertLocalChangesFromCurrentProject(cloudProjectsModel.currentProjectId)) { - displayToast(qsTr('Local changes reverted')) + displayToast(qsTr('Local changes reverted')); } else { - displayToast(qsTr('Failed to revert changes'), 'error') + displayToast(qsTr('Failed to revert changes'), 'error'); } } else { - displayToast(qsTr('No changes to revert')) + displayToast(qsTr('No changes to revert')); } } function resetCurrentProject() { - cloudProjectsModel.discardLocalChangesFromCurrentProject(cloudProjectsModel.currentProjectId) - cloudProjectsModel.downloadProject(cloudProjectsModel.currentProjectId, true) + cloudProjectsModel.discardLocalChangesFromCurrentProject(cloudProjectsModel.currentProjectId); + cloudProjectsModel.downloadProject(cloudProjectsModel.currentProjectId, true); } } diff --git a/src/qml/QFieldCloudScreen.qml b/src/qml/QFieldCloudScreen.qml index f0ee44a20b..1564a00a20 100644 --- a/src/qml/QFieldCloudScreen.qml +++ b/src/qml/QFieldCloudScreen.qml @@ -2,10 +2,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQml.Models 2.14 - import org.qfield 1.0 import Theme 1.0 - import "." Page { @@ -16,20 +14,18 @@ Page { property LayerObserver layerObserver header: QfPageHeader { - title: qsTr("QFieldCloud Projects") + title: qsTr("QFieldCloud Projects") - showBackButton: true - showApplyButton: false - showCancelButton: false + showBackButton: true + showApplyButton: false + showCancelButton: false - busyIndicatorState: cloudConnection.status === QFieldCloudConnection.Connecting || - cloudConnection.state === QFieldCloudConnection.Busy ? 'on' : 'off' || - cloudProjectsModel.busyProjectIds.length > 0 + busyIndicatorState: cloudConnection.status === QFieldCloudConnection.Connecting || cloudConnection.state === QFieldCloudConnection.Busy ? 'on' : 'off' || cloudProjectsModel.busyProjectIds.length > 0 - topMargin: mainWindow.sceneTopMargin + topMargin: mainWindow.sceneTopMargin - onFinished: parent.finished() - } + onFinished: parent.finished() + } ColumnLayout { anchors.fill: parent @@ -38,88 +34,92 @@ Page { spacing: 2 RowLayout { - id: connectionInformation - spacing: 2 + id: connectionInformation + spacing: 2 + Layout.fillWidth: true + visible: cloudConnection.hasToken || cloudProjectsModel.rowCount() > 0 + + Label { Layout.fillWidth: true - visible: cloudConnection.hasToken || cloudProjectsModel.rowCount() > 0 - - Label { - Layout.fillWidth: true - padding: 10 - opacity: projects.visible ? 1 : 0 - text: switch(cloudConnection.status) { - case 0: qsTr( 'Disconnected from the cloud.' ); break; - case 1: qsTr( 'Connecting to the cloud.' ); break; - case 2: qsTr( 'Greetings %1.' ).arg( cloudConnection.username ); break; - } - wrapMode: Text.WordWrap - font: Theme.tipFont - color: Theme.mainTextColor + padding: 10 + opacity: projects.visible ? 1 : 0 + text: switch (cloudConnection.status) { + case 0: + qsTr('Disconnected from the cloud.'); + break; + case 1: + qsTr('Connecting to the cloud.'); + break; + case 2: + qsTr('Greetings %1.').arg(cloudConnection.username); + break; } + wrapMode: Text.WordWrap + font: Theme.tipFont + color: Theme.mainTextColor + } + + Rectangle { + id: cloudAvatarRect + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.margins: 10 + width: 48 + height: 48 + border.color: Theme.mainColor + border.width: 1 + radius: width / 2 + clip: true Rectangle { - id: cloudAvatarRect - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - Layout.margins: 10 + id: cloudAvatarMask + anchors.centerIn: parent + width: 46 + height: 46 + radius: width / 2 + color: "white" + visible: false + layer.enabled: true + } + + Image { + id: cloudAvatar + anchors.fill: parent + anchors.margins: 2 + fillMode: Image.PreserveAspectFit + smooth: true + source: cloudConnection.avatarUrl !== '' ? cloudConnection.avatarUrl : 'qrc:/images/qfieldcloud_logo.svg' width: 48 height: 48 - border.color: Theme.mainColor - border.width: 1 - radius: width/2 - clip: true - - Rectangle { - id: cloudAvatarMask - anchors.centerIn: parent - width: 46 - height: 46 - radius: width/2 - color: "white" - visible: false - layer.enabled: true + sourceSize.width: width * screen.devicePixelRatio + sourceSize.height: height * screen.devicePixelRatio + layer.enabled: true + layer.effect: QfOpacityMask { + maskSource: cloudAvatarMask } - Image { - id: cloudAvatar - anchors.fill: parent - anchors.margins: 2 - fillMode: Image.PreserveAspectFit - smooth: true - source: cloudConnection.avatarUrl !== '' - ? cloudConnection.avatarUrl - : 'qrc:/images/qfieldcloud_logo.svg' - width: 48 - height: 48 - sourceSize.width: width * screen.devicePixelRatio - sourceSize.height: height * screen.devicePixelRatio - layer.enabled: true - layer.effect: QfOpacityMask { - maskSource: cloudAvatarMask - } - - onStatusChanged: { - // In case the avatar URL fails to load or the image is corrupted, revert to our lovely Nyuki - if (status == Image.Error) { - source = 'qrc:/images/qfieldcloud_logo.svg'; - } + onStatusChanged: { + // In case the avatar URL fails to load or the image is corrupted, revert to our lovely Nyuki + if (status == Image.Error) { + source = 'qrc:/images/qfieldcloud_logo.svg'; } } + } - MouseArea { - anchors.fill: parent + MouseArea { + anchors.fill: parent - onClicked: { - if (!connectionSettings.visible) { - connectionSettings.visible = true - projects.visible = false - } else { - connectionSettings.visible = false - projects.visible = true - refreshProjectsListBtn.forceActiveFocus() - } + onClicked: { + if (!connectionSettings.visible) { + connectionSettings.visible = true; + projects.visible = false; + } else { + connectionSettings.visible = false; + projects.visible = true; + refreshProjectsListBtn.forceActiveFocus(); } } } + } } ColumnLayout { @@ -148,8 +148,8 @@ Page { } Item { - Layout.fillHeight: true - height: 15 + Layout.fillHeight: true + height: 15 } } @@ -173,7 +173,7 @@ Page { font: Theme.defaultFont enabled: (cloudConnection.state === QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0) onClicked: { - filterBar.currentIndex = index + filterBar.currentIndex = index; } } } @@ -186,303 +186,288 @@ Page { border.width: 1 ListView { - id: table + id: table - property bool overshootRefresh: false - property bool refreshing: false + property bool overshootRefresh: false + property bool refreshing: false - model: QFieldCloudProjectsFilterModel { - projectsModel: cloudProjectsModel - filter: filterBar.currentIndex === 0 - ? QFieldCloudProjectsFilterModel.PrivateProjects - : QFieldCloudProjectsFilterModel.PublicProjects - showLocalOnly: cloudConnection.status !== QFieldCloudConnection.LoggedIn + model: QFieldCloudProjectsFilterModel { + projectsModel: cloudProjectsModel + filter: filterBar.currentIndex === 0 ? QFieldCloudProjectsFilterModel.PrivateProjects : QFieldCloudProjectsFilterModel.PublicProjects + showLocalOnly: cloudConnection.status !== QFieldCloudConnection.LoggedIn - onFilterChanged: { - if (cloudConnection.state === QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0) { - refreshProjectsList(filter === QFieldCloudProjectsFilterModel.PublicProjects); - } - } - } - - ScrollBar.vertical: ScrollBar { - active: true - visible: table.contentHeight > table.height ? true : false + onFilterChanged: { + if (cloudConnection.state === QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0) { + refreshProjectsList(filter === QFieldCloudProjectsFilterModel.PublicProjects); + } } + } - anchors.fill: parent - anchors.margins: 1 - section.property: "Owner" - section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels - section.delegate: Component { - /* section header: layer name */ - Rectangle { - width:parent.width - height: 30 - color: Theme.controlBorderColor + ScrollBar.vertical: ScrollBar { + active: true + visible: table.contentHeight > table.height ? true : false + } - Text { - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } - font.bold: true - font.pointSize: Theme.resultFont.pointSize - color: Theme.mainTextColor - text: section + anchors.fill: parent + anchors.margins: 1 + section.property: "Owner" + section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels + section.delegate: Component { + /* section header: layer name */ + Rectangle { + width: parent.width + height: 30 + color: Theme.controlBorderColor + + Text { + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter } + font.bold: true + font.pointSize: Theme.resultFont.pointSize + color: Theme.mainTextColor + text: section } } - clip: true + } + clip: true - onMovingChanged: { - if ( !moving && overshootRefresh && cloudConnection.state === QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0 ) { - refreshProjectsList(filterBar.currentIndex !== 0); - } - overshootRefresh = false; + onMovingChanged: { + if (!moving && overshootRefresh && cloudConnection.state === QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0) { + refreshProjectsList(filterBar.currentIndex !== 0); } + overshootRefresh = false; + } + + onVerticalOvershootChanged: { + if (verticalOvershoot < -100) + overshootRefresh = true; + } - onVerticalOvershootChanged: { - if ( verticalOvershoot < -100 ) - overshootRefresh = true; + delegate: Rectangle { + id: rectangle + + property bool isPressed: false + property string projectId: Id + property string projectOwner: Owner + property string projectName: Name + property string projectLocalPath: LocalPath + property int status: Status + + width: parent ? parent.width : undefined + height: line.height + color: "transparent" + + ProgressBar { + anchors.bottom: line.bottom + anchors.bottomMargin: -6 + anchors.left: line.left + anchors.leftMargin: line.leftPadding + width: line.width - 20 + height: 6 + indeterminate: PackagingStatus !== QFieldCloudProjectsModel.PackagingFinishedStatus && DownloadProgress === 0.0 + value: DownloadProgress + visible: Status === QFieldCloudProjectsModel.ProjectStatus.Downloading + z: 1 } - delegate: Rectangle { - id: rectangle - - property bool isPressed: false - property string projectId: Id - property string projectOwner: Owner - property string projectName: Name - property string projectLocalPath: LocalPath - property int status: Status - - width: parent ? parent.width : undefined - height: line.height - color: "transparent" - - ProgressBar { - anchors.bottom: line.bottom - anchors.bottomMargin: -6 - anchors.left: line.left - anchors.leftMargin: line.leftPadding - width: line.width - 20 - height: 6 - indeterminate: PackagingStatus !== QFieldCloudProjectsModel.PackagingFinishedStatus && DownloadProgress === 0.0 - value: DownloadProgress - visible: Status === QFieldCloudProjectsModel.ProjectStatus.Downloading - z: 1 + Row { + id: line + Layout.fillWidth: true + leftPadding: 6 + rightPadding: 10 + topPadding: 4 + bottomPadding: 8 + spacing: 0 + + Image { + id: type + anchors.verticalCenter: inner.verticalCenter + source: { + if (cloudConnection.status !== QFieldCloudConnection.LoggedIn) { + return Theme.getThemeVectorIcon('ic_cloud_project_offline_48dp'); + } else { + var status = ''; + switch (Status) { + case QFieldCloudProjectsModel.ProjectStatus.Downloading: + return Theme.getThemeVectorIcon('ic_cloud_project_download_48dp'); + case QFieldCloudProjectsModel.ProjectStatus.Uploading: + return Theme.getThemeVectorIcon('ic_cloud_project_upload_48dp'); + default: + break; + } + switch (Checkout) { + case QFieldCloudProjectsModel.LocalCheckout: + return Theme.getThemeVectorIcon('ic_cloud_project_localonly_48dp'); + case QFieldCloudProjectsModel.RemoteCheckout: + return Theme.getThemeVectorIcon('ic_cloud_project_download_48dp'); + default: + break; + } + return Theme.getThemeVectorIcon('ic_cloud_project_48dp'); + } } - - Row { - id: line - Layout.fillWidth: true - leftPadding: 6 - rightPadding: 10 - topPadding: 4 - bottomPadding: 8 - spacing: 0 - - Image { - id: type - anchors.verticalCenter: inner.verticalCenter - source: { - if ( cloudConnection.status !== QFieldCloudConnection.LoggedIn ) { - return Theme.getThemeVectorIcon('ic_cloud_project_offline_48dp') - } else { - var status = '' - - switch (Status) { - case QFieldCloudProjectsModel.ProjectStatus.Downloading: - return Theme.getThemeVectorIcon('ic_cloud_project_download_48dp') - case QFieldCloudProjectsModel.ProjectStatus.Uploading: - return Theme.getThemeVectorIcon('ic_cloud_project_upload_48dp') - default: - break - } - - switch (Checkout) { - case QFieldCloudProjectsModel.LocalCheckout: - return Theme.getThemeVectorIcon('ic_cloud_project_localonly_48dp') - case QFieldCloudProjectsModel.RemoteCheckout: - return Theme.getThemeVectorIcon('ic_cloud_project_download_48dp') - default: - break + sourceSize.width: 80 + sourceSize.height: 80 + width: 40 + height: 40 + opacity: Status === QFieldCloudProjectsModel.ProjectStatus.Downloading ? 0.3 : 1 + } + ColumnLayout { + id: inner + width: rectangle.width - type.width - 10 + Text { + id: projectTitle + topPadding: 5 + leftPadding: 3 + text: Name + font.pointSize: Theme.tipFont.pointSize + font.underline: true + color: Theme.mainColor + opacity: rectangle.isPressed ? 0.8 : 1 + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + Text { + id: projectNote + leftPadding: 3 + text: { + if (cloudConnection.status !== QFieldCloudConnection.LoggedIn) { + return qsTr('(Available locally)'); + } else { + var status = ''; + + // TODO I think these should be shown as UI badges + switch (Status) { + case QFieldCloudProjectsModel.ProjectStatus.Idle: + break; + case QFieldCloudProjectsModel.ProjectStatus.Downloading: + if (PackagingStatus === QFieldCloudProjectsModel.PackagingBusyStatus) { + status = qsTr('QFieldCloud is packaging the latest data just for you; this might take some time, please hold tight'); + } else { + if (PackagingStatus === QFieldCloudProjectsModel.PackagingFinishedStatus || DownloadProgress > 0.0) { + if (DownloadSize > 0) { + status = qsTr('Downloading, %1% of %2 fetched').arg(Math.round(DownloadProgress * 100)).arg(FileUtils.representFileSize(DownloadSize)); + } else { + status = qsTr('Downloading, %1% fetched').arg(Math.round(DownloadProgress * 100)); } - - return Theme.getThemeVectorIcon('ic_cloud_project_48dp') + } else { + status = qsTr('Reaching out to QFieldCloud to download project'); } } - sourceSize.width: 80 - sourceSize.height: 80 - width: 40 - height: 40 - opacity: Status === QFieldCloudProjectsModel.ProjectStatus.Downloading ? 0.3 : 1 - } - ColumnLayout { - id: inner - width: rectangle.width - type.width - 10 - Text { - id: projectTitle - topPadding: 5 - leftPadding: 3 - text: Name - font.pointSize: Theme.tipFont.pointSize - font.underline: true - color: Theme.mainColor - opacity: rectangle.isPressed ? 0.8 : 1 - wrapMode: Text.WordWrap - Layout.fillWidth: true - } - Text { - id: projectNote - leftPadding: 3 - text: { - if ( cloudConnection.status !== QFieldCloudConnection.LoggedIn ) { - return qsTr( '(Available locally)' ) - } else { - var status = '' - - // TODO I think these should be shown as UI badges - switch (Status) { - case QFieldCloudProjectsModel.ProjectStatus.Idle: - break - case QFieldCloudProjectsModel.ProjectStatus.Downloading: - if (PackagingStatus === QFieldCloudProjectsModel.PackagingBusyStatus) { - status = qsTr('QFieldCloud is packaging the latest data just for you; this might take some time, please hold tight') - } else { - if (PackagingStatus === QFieldCloudProjectsModel.PackagingFinishedStatus || DownloadProgress > 0.0) { - if (DownloadSize > 0) { - status = qsTr( 'Downloading, %1% of %2 fetched' ).arg( Math.round(DownloadProgress * 100) ).arg( FileUtils.representFileSize( DownloadSize ) ) - } else { - status = qsTr( 'Downloading, %1% fetched' ).arg( Math.round(DownloadProgress * 100) ) - } - } else { - status = qsTr( 'Reaching out to QFieldCloud to download project' ) - } - } - break - case QFieldCloudProjectsModel.ProjectStatus.Uploading: - status = qsTr( 'Uploading…' ) - break - default: - break - } - - switch (ErrorStatus) { - case QFieldCloudProjectsModel.NoErrorStatus: - break - case QFieldCloudProjectsModel.DownloadErrorStatus: - status = qsTr('Downloading error. ') + ErrorString - break - case QFieldCloudProjectsModel.UploadErrorStatus: - status = qsTr('Uploading error. ') + ErrorString - break - } - - if ( ! status ) { - switch (Checkout) { - case QFieldCloudProjectsModel.LocalCheckout: - status = qsTr( 'Available locally, missing on the cloud' ) - break - case QFieldCloudProjectsModel.RemoteCheckout: - status = qsTr( 'Available on the cloud, missing locally' ) - break - case QFieldCloudProjectsModel.LocalAndRemoteCheckout: - status = qsTr( 'Available locally' ) - if (ProjectOutdated) { - status += qsTr( ', updated data available on the cloud'); - } - break - default: - break - } - } - - var localChanges = ( LocalDeltasCount > 0 ) ? qsTr('Has changes. ') : '' - var str = '%1 (%2%3)'.arg(Description).arg(localChanges).arg(status) - - return str.trim() - } - } - visible: text != "" - font.pointSize: Theme.tipFont.pointSize - 2 - font.italic: true - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + break; + case QFieldCloudProjectsModel.ProjectStatus.Uploading: + status = qsTr('Uploading…'); + break; + default: + break; + } + switch (ErrorStatus) { + case QFieldCloudProjectsModel.NoErrorStatus: + break; + case QFieldCloudProjectsModel.DownloadErrorStatus: + status = qsTr('Downloading error. ') + ErrorString; + break; + case QFieldCloudProjectsModel.UploadErrorStatus: + status = qsTr('Uploading error. ') + ErrorString; + break; + } + if (!status) { + switch (Checkout) { + case QFieldCloudProjectsModel.LocalCheckout: + status = qsTr('Available locally, missing on the cloud'); + break; + case QFieldCloudProjectsModel.RemoteCheckout: + status = qsTr('Available on the cloud, missing locally'); + break; + case QFieldCloudProjectsModel.LocalAndRemoteCheckout: + status = qsTr('Available locally'); + if (ProjectOutdated) { + status += qsTr(', updated data available on the cloud'); + } + break; + default: + break; } + } + var localChanges = (LocalDeltasCount > 0) ? qsTr('Has changes. ') : ''; + var str = '%1 (%2%3)'.arg(Description).arg(localChanges).arg(status); + return str.trim(); } + } + visible: text != "" + font.pointSize: Theme.tipFont.pointSize - 2 + font.italic: true + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true } + } } + } - Label { - anchors.fill: parent - horizontalAlignment: Qt.AlignHCenter - verticalAlignment: Qt.AlignVCenter - visible: parent.count == 0 - text: table.refreshing ? qsTr("Refreshing projects list") : qsTr("No projects found") - font: Theme.strongTipFont - color: Theme.secondaryTextColor - } + Label { + anchors.fill: parent + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + visible: parent.count == 0 + text: table.refreshing ? qsTr("Refreshing projects list") : qsTr("No projects found") + font: Theme.strongTipFont + color: Theme.secondaryTextColor + } - MouseArea { - property Item pressedItem - anchors.fill: parent - onClicked: (mouse) => { - var item = table.itemAt( - table.contentX + mouse.x, - table.contentY + mouse.y - ) - if (item) { - if (item.projectLocalPath != '') { - qfieldcloudScreen.visible = false - iface.loadFile(item.projectLocalPath); - } else { - // fetch remote project - displayToast( qsTr( "Downloading project %1" ).arg( item.projectName ) ) - cloudProjectsModel.projectPackageAndDownload( item.projectId ) - } + MouseArea { + property Item pressedItem + anchors.fill: parent + onClicked: mouse => { + var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); + if (item) { + if (item.projectLocalPath != '') { + qfieldcloudScreen.visible = false; + iface.loadFile(item.projectLocalPath); + } else { + // fetch remote project + displayToast(qsTr("Downloading project %1").arg(item.projectName)); + cloudProjectsModel.projectPackageAndDownload(item.projectId); } } - onPressed: (mouse) => { - var item = table.itemAt( - table.contentX + mouse.x, - table.contentY + mouse.y - ) - if (item) { - pressedItem = item - pressedItem.isPressed = true - } + } + onPressed: mouse => { + var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); + if (item) { + pressedItem = item; + pressedItem.isPressed = true; } - onCanceled: { - if (pressedItem) { - pressedItem.isPressed = false - pressedItem = null - } + } + onCanceled: { + if (pressedItem) { + pressedItem.isPressed = false; + pressedItem = null; } - onReleased: { - if (pressedItem) { - pressedItem.isPressed = false - pressedItem = null - } + } + onReleased: { + if (pressedItem) { + pressedItem.isPressed = false; + pressedItem = null; } + } - onPressAndHold: (mouse) => { - var item = table.itemAt( - table.contentX + mouse.x, - table.contentY + mouse.y - ) - if (item) { - projectActions.projectId = item.projectId - projectActions.projectOwner = item.projectOwner - projectActions.projectName = item.projectName - projectActions.projectLocalPath = item.projectLocalPath - downloadProject.visible = item.projectLocalPath === '' && item.status !== QFieldCloudProjectsModel.ProjectStatus.Downloading - openProject.visible = item.projectLocalPath !== '' - removeProject.visible = item.projectLocalPath !== '' - cancelDownloadProject.visible = item.status === QFieldCloudProjectsModel.ProjectStatus.Downloading - projectActions.popup(mouse.x, mouse.y) - } + onPressAndHold: mouse => { + var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); + if (item) { + projectActions.projectId = item.projectId; + projectActions.projectOwner = item.projectOwner; + projectActions.projectName = item.projectName; + projectActions.projectLocalPath = item.projectLocalPath; + downloadProject.visible = item.projectLocalPath === '' && item.status !== QFieldCloudProjectsModel.ProjectStatus.Downloading; + openProject.visible = item.projectLocalPath !== ''; + removeProject.visible = item.projectLocalPath !== ''; + cancelDownloadProject.visible = item.status === QFieldCloudProjectsModel.ProjectStatus.Downloading; + projectActions.popup(mouse.x, mouse.y); } } + } } } @@ -497,14 +482,14 @@ Page { title: qsTr('Project Actions') width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } topMargin: mainWindow.sceneTopMargin @@ -518,9 +503,9 @@ Page { height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Download Project" ) + text: qsTr("Download Project") onTriggered: { - cloudProjectsModel.projectPackageAndDownload(projectActions.projectId) + cloudProjectsModel.projectPackageAndDownload(projectActions.projectId); } } @@ -532,10 +517,10 @@ Page { height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Open Project" ) + text: qsTr("Open Project") onTriggered: { - if ( projectActions.projectLocalPath != '') { - qfieldcloudScreen.visible = false + if (projectActions.projectLocalPath != '') { + qfieldcloudScreen.visible = false; iface.loadFile(projectActions.projectLocalPath); } } @@ -549,14 +534,13 @@ Page { height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Remove Stored Project" ) + text: qsTr("Remove Stored Project") onTriggered: { - cloudProjectsModel.removeLocalProject(projectActions.projectId) + cloudProjectsModel.removeLocalProject(projectActions.projectId); iface.removeRecentProject(projectActions.projectLocalPath); - welcomeScreen.model.reloadModel() - + welcomeScreen.model.reloadModel(); if (projectActions.projectLocalPath === qgisProject.fileName) { - iface.clearProject() + iface.clearProject(); } } } @@ -569,35 +553,33 @@ Page { height: visible ? 48 : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Cancel Project Download" ) + text: qsTr("Cancel Project Download") onTriggered: { - cloudProjectsModel.projectCancelDownload(projectActions.projectId) + cloudProjectsModel.projectCancelDownload(projectActions.projectId); } } } Text { - id: projectsTips - Layout.alignment: Qt.AlignLeft - Layout.fillWidth: true - Layout.topMargin: 5 - Layout.bottomMargin: 5 - text: qsTr( "Press and hold over a cloud project for a menu of additional actions." ) - font: Theme.tipFont - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap + id: projectsTips + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.topMargin: 5 + Layout.bottomMargin: 5 + text: qsTr("Press and hold over a cloud project for a menu of additional actions.") + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap } QfButton { - id: refreshProjectsListBtn - Layout.fillWidth: true - Layout.bottomMargin: mainWindow.sceneBottomMargin - text: qsTr( "Refresh projects list" ) - enabled: cloudConnection.status === QFieldCloudConnection.LoggedIn - && cloudConnection.state === QFieldCloudConnection.Idle - && cloudProjectsModel.busyProjectIds.length === 0 - - onClicked: refreshProjectsList(filterBar.currentIndex !== 0) + id: refreshProjectsListBtn + Layout.fillWidth: true + Layout.bottomMargin: mainWindow.sceneBottomMargin + text: qsTr("Refresh projects list") + enabled: cloudConnection.status === QFieldCloudConnection.LoggedIn && cloudConnection.state === QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0 + + onClicked: refreshProjectsList(filterBar.currentIndex !== 0) } } } @@ -609,54 +591,50 @@ Page { if (table.refreshing) { table.refreshing = false; } - if (cloudConnection.status === QFieldCloudConnection.LoggedIn) prepareCloudLogin(); } } function refreshProjectsList(shouldRefreshPublic) { - if ( cloudConnection.state !== QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0 ) { + if (cloudConnection.state !== QFieldCloudConnection.Idle && cloudProjectsModel.busyProjectIds.length === 0) { return; } - table.refreshing = true; - cloudProjectsModel.refreshProjectsList(shouldRefreshPublic); - displayToast( qsTr( "Refreshing projects list" ) ); + displayToast(qsTr("Refreshing projects list")); } function prepareCloudLogin() { - if ( visible ) { - if ( cloudConnection.status == QFieldCloudConnection.Disconnected ) { - if ( cloudConnection.hasToken ) { + if (visible) { + if (cloudConnection.status == QFieldCloudConnection.Disconnected) { + if (cloudConnection.hasToken) { cloudConnection.login(); - - projects.visible = true - connectionSettings.visible = false + projects.visible = true; + connectionSettings.visible = false; } else { - projects.visible = false - connectionSettings.visible = true + projects.visible = false; + connectionSettings.visible = true; } } else { - projects.visible = true - connectionSettings.visible = false + projects.visible = true; + connectionSettings.visible = false; } } } Component.onCompleted: { - prepareCloudLogin() + prepareCloudLogin(); } onVisibleChanged: { - prepareCloudLogin() + prepareCloudLogin(); } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true - finished() + event.accepted = true; + finished(); } } } diff --git a/src/qml/QFieldLocalDataPickerScreen.qml b/src/qml/QFieldLocalDataPickerScreen.qml index bfa109cce2..9359794c39 100644 --- a/src/qml/QFieldLocalDataPickerScreen.qml +++ b/src/qml/QFieldLocalDataPickerScreen.qml @@ -2,7 +2,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQml.Models 2.14 - import org.qfield 1.0 import Theme 1.0 @@ -15,9 +14,7 @@ Page { signal finished(var loading) header: QfPageHeader { - title: projectFolderView - ? qsTr("Project Folder") - : qsTr("Local Projects & Datasets") + title: projectFolderView ? qsTr("Project Folder") : qsTr("Local Projects & Datasets") showBackButton: true showApplyButton: false @@ -29,7 +26,7 @@ Page { if (table.model.currentDepth > 1) { table.model.moveUp(); } else { - parent.finished(false) + parent.finished(false); } } } @@ -60,9 +57,7 @@ Page { Text { Layout.fillWidth: true visible: text !== '' - text: table.model.currentPath !== 'root' - ? table.model.currentPath - : '' + text: table.model.currentPath !== 'root' ? table.model.currentPath : '' font: Theme.tipFont color: Theme.mainTextColor wrapMode: Text.NoWrap @@ -85,7 +80,8 @@ Page { ListView { id: table - model: LocalFilesModel {} + model: LocalFilesModel { + } anchors.fill: parent anchors.margins: 1 @@ -96,16 +92,20 @@ Page { section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels section.delegate: Component { Rectangle { - width:parent.width + width: parent.width height: 30 color: Theme.controlBorderColor Text { - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } font.bold: true font.pointSize: Theme.resultFont.pointSize color: Theme.mainTextColor - text: { switch (parseInt(section)) { + text: { + switch (parseInt(section)) { case LocalFilesModel.Folder: return qsTr('Folders'); case LocalFilesModel.Project: @@ -128,12 +128,8 @@ Page { property int itemType: ItemType property string itemTitle: ItemTitle property string itemPath: ItemPath - property bool itemMenuLoadable: !projectFolderView && - (ItemMetaType === LocalFilesModel.Project || ItemMetaType === LocalFilesModel.Dataset) - property bool itemMenuVisible: (platformUtilities.capabilities & PlatformUtilities.CustomExport || - platformUtilities.capabilities & PlatformUtilities.CustomSend) && - (ItemMetaType === LocalFilesModel.Dataset - || (ItemType === LocalFilesModel.SimpleFolder && table.model.currentPath !== 'root')) + property bool itemMenuLoadable: !projectFolderView && (ItemMetaType === LocalFilesModel.Project || ItemMetaType === LocalFilesModel.Dataset) + property bool itemMenuVisible: (platformUtilities.capabilities & PlatformUtilities.CustomExport || platformUtilities.capabilities & PlatformUtilities.CustomSend) && (ItemMetaType === LocalFilesModel.Dataset || (ItemType === LocalFilesModel.SimpleFolder && table.model.currentPath !== 'root')) width: parent ? parent.width : undefined height: line.height @@ -158,7 +154,7 @@ Page { if (ItemHasThumbnail) { return "image://localfiles/" + ItemPath; } else { - switch(ItemType) { + switch (ItemType) { case LocalFilesModel.ApplicationFolder: return Theme.getThemeVectorIcon('ic_folder_qfield_gray_48dp'); case LocalFilesModel.ExternalStorage: @@ -209,7 +205,7 @@ Page { text: { var info = ''; - switch(ItemType) { + switch (ItemType) { case LocalFilesModel.ProjectFile: info = qsTr('Project file'); break; @@ -240,17 +236,15 @@ Page { Layout.bottomMargin: 5 bgcolor: "transparent" - iconSource: Theme.getThemeIcon( "ic_dot_menu_gray_24dp" ) + iconSource: Theme.getThemeIcon("ic_dot_menu_gray_24dp") iconColor: Theme.mainTextColor onClicked: { - var gc = mapToItem(qfieldLocalDataPickerScreen, 0, 0) - - itemMenu.itemMetaType = ItemMetaType - itemMenu.itemType = ItemType - itemMenu.itemPath = ItemPath - itemMenu.popup(gc.x + width - itemMenu.width, - gc.y - height) + var gc = mapToItem(qfieldLocalDataPickerScreen, 0, 0); + itemMenu.itemMetaType = ItemMetaType; + itemMenu.itemType = ItemType; + itemMenu.itemPath = ItemPath; + itemMenu.popup(gc.x + width - itemMenu.width, gc.y - height); } } } @@ -260,65 +254,52 @@ Page { property Item pressedItem anchors.fill: parent anchors.rightMargin: 48 - onClicked: (mouse) => { + onClicked: mouse => { if (itemMenu.visible) { itemMenu.close(); } else if (importMenu.visible) { importMenu.close(); } else { - var item = table.itemAt( - table.contentX + mouse.x, - table.contentY + mouse.y - ) + var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); if (item) { - if (item.itemMetaType === LocalFilesModel.Folder || - item.itemMetaType === LocalFilesModel.Favorite) { + if (item.itemMetaType === LocalFilesModel.Folder || item.itemMetaType === LocalFilesModel.Favorite) { table.model.currentPath = item.itemPath; - } else if (!qfieldLocalDataPickerScreen.projectFolderView && - (item.itemMetaType === LocalFilesModel.Project - || item.itemMetaType === LocalFilesModel.Dataset)) { + } else if (!qfieldLocalDataPickerScreen.projectFolderView && (item.itemMetaType === LocalFilesModel.Project || item.itemMetaType === LocalFilesModel.Dataset)) { iface.loadFile(item.itemPath, item.itemTitle); finished(true); } } } } - onPressed: (mouse) => { + onPressed: mouse => { if (itemMenu.visible || importMenu.visible) return; - - var item = table.itemAt( - table.contentX + mouse.x, - table.contentY + mouse.y - ) + var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); if (item && item.itemMenuLoadable) { - pressedItem = item.children[0].children[1].children[0] - pressedItem.color = "#5a8725" + pressedItem = item.children[0].children[1].children[0]; + pressedItem.color = "#5a8725"; } } onCanceled: { if (pressedItem) { - pressedItem.color = Theme.mainColor - pressedItem = null + pressedItem.color = Theme.mainColor; + pressedItem = null; } } onReleased: { if (pressedItem) { - pressedItem.color = Theme.mainColor - pressedItem = null + pressedItem.color = Theme.mainColor; + pressedItem = null; } } - onPressAndHold: (mouse) => { - var item = table.itemAt( - table.contentX + mouse.x, - table.contentY + mouse.y - ) + onPressAndHold: mouse => { + var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); if (item && item.itemMenuVisible) { - itemMenu.itemMetaType = item.itemMetaType - itemMenu.itemType = item.itemType - itemMenu.itemPath = item.itemPath - itemMenu.popup(mouse.x, mouse.y) + itemMenu.itemMetaType = item.itemMetaType; + itemMenu.itemType = item.itemType; + itemMenu.itemPath = item.itemPath; + itemMenu.popup(mouse.x, mouse.y); } } } @@ -329,10 +310,7 @@ Page { round: true // Since the project menu only has one action for now, hide if PlatformUtilities.UpdateProjectFromArchive is missing - property bool isLocalProject: qgisProject - && QFieldCloudUtils.getProjectId(qgisProject.fileName) === '' - && (projectInfo.filePath.endsWith('.qgs') || projectInfo.filePath.endsWith('.qgz')) - && platformUtilities.capabilities & PlatformUtilities.UpdateProjectFromArchive + property bool isLocalProject: qgisProject && QFieldCloudUtils.getProjectId(qgisProject.fileName) === '' && (projectInfo.filePath.endsWith('.qgs') || projectInfo.filePath.endsWith('.qgz')) && platformUtilities.capabilities & PlatformUtilities.UpdateProjectFromArchive visible: (projectFolderView && isLocalProject && table.model.currentDepth === 1) || table.model.currentPath === 'root' anchors.bottom: parent.bottom @@ -341,14 +319,14 @@ Page { anchors.rightMargin: 10 bgcolor: Theme.mainColor - iconSource: Theme.getThemeIcon( "ic_add_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_add_white_24dp") onClicked: { - var xy = mapToItem(mainWindow.contentItem, actionButton.width, actionButton.height) + var xy = mapToItem(mainWindow.contentItem, actionButton.width, actionButton.height); if (projectFolderView) { - projectMenu.popup(xy.x - projectMenu.width, xy.y - projectMenu.height - header.height) + projectMenu.popup(xy.x - projectMenu.width, xy.y - projectMenu.height - header.height); } else { - importMenu.popup(xy.x - importMenu.width, xy.y - importMenu.height - header.height) + importMenu.popup(xy.x - importMenu.width, xy.y - importMenu.height - header.height); } } } @@ -364,14 +342,14 @@ Page { title: qsTr('Item Actions') width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; } topMargin: sceneTopMargin @@ -379,8 +357,7 @@ Page { MenuItem { id: sendDatasetTo - enabled: platformUtilities.capabilities & PlatformUtilities.CustomSend - && itemMenu.itemMetaType == LocalFilesModel.Dataset + enabled: platformUtilities.capabilities & PlatformUtilities.CustomSend && itemMenu.itemMetaType == LocalFilesModel.Dataset visible: enabled font: Theme.defaultFont @@ -388,14 +365,15 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Send to..." ) - onTriggered: { platformUtilities.sendDatasetTo(itemMenu.itemPath); } + text: qsTr("Send to...") + onTriggered: { + platformUtilities.sendDatasetTo(itemMenu.itemPath); + } } MenuItem { id: exportDatasetTo - enabled: platformUtilities.capabilities & PlatformUtilities.CustomExport - && itemMenu.itemMetaType == LocalFilesModel.Dataset + enabled: platformUtilities.capabilities & PlatformUtilities.CustomExport && itemMenu.itemMetaType == LocalFilesModel.Dataset visible: enabled font: Theme.defaultFont @@ -403,30 +381,31 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Export to folder..." ) - onTriggered: { platformUtilities.exportDatasetTo(itemMenu.itemPath); } + text: qsTr("Export to folder...") + onTriggered: { + platformUtilities.exportDatasetTo(itemMenu.itemPath); + } } MenuItem { id: removeDataset - enabled: itemMenu.itemMetaType == LocalFilesModel.Dataset - && !qfieldLocalDataPickerScreen.projectFolderView - && table.model.isDeletedAllowedInCurrentPath + enabled: itemMenu.itemMetaType == LocalFilesModel.Dataset && !qfieldLocalDataPickerScreen.projectFolderView && table.model.isDeletedAllowedInCurrentPath visible: enabled font: Theme.defaultFont width: parent.width - height: enabled? undefined : 0 + height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Remove dataset" ) - onTriggered: { platformUtilities.removeDataset(itemMenu.itemPath); } + text: qsTr("Remove dataset") + onTriggered: { + platformUtilities.removeDataset(itemMenu.itemPath); + } } MenuItem { id: exportFolderTo - enabled: platformUtilities.capabilities & PlatformUtilities.CustomExport && - itemMenu.itemMetaType == LocalFilesModel.Folder + enabled: platformUtilities.capabilities & PlatformUtilities.CustomExport && itemMenu.itemMetaType == LocalFilesModel.Folder visible: enabled font: Theme.defaultFont @@ -434,14 +413,15 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Export to folder..." ) - onTriggered: { platformUtilities.exportFolderTo(itemMenu.itemPath); } + text: qsTr("Export to folder...") + onTriggered: { + platformUtilities.exportFolderTo(itemMenu.itemPath); + } } MenuItem { id: sendCompressedFolderTo - enabled: platformUtilities.capabilities & PlatformUtilities.CustomSend - && itemMenu.itemMetaType == LocalFilesModel.Folder + enabled: platformUtilities.capabilities & PlatformUtilities.CustomSend && itemMenu.itemMetaType == LocalFilesModel.Folder visible: enabled font: Theme.defaultFont @@ -449,15 +429,15 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Send compressed folder to..." ) - onTriggered: { platformUtilities.sendCompressedFolderTo(itemMenu.itemPath); } + text: qsTr("Send compressed folder to...") + onTriggered: { + platformUtilities.sendCompressedFolderTo(itemMenu.itemPath); + } } MenuItem { id: removeProjectFolder - enabled: itemMenu.itemMetaType == LocalFilesModel.Folder - && !qfieldLocalDataPickerScreen.projectFolderView - && table.model.isDeletedAllowedInCurrentPath + enabled: itemMenu.itemMetaType == LocalFilesModel.Folder && !qfieldLocalDataPickerScreen.projectFolderView && table.model.isDeletedAllowedInCurrentPath visible: enabled font: Theme.defaultFont @@ -465,8 +445,10 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Remove project folder" ) - onTriggered: { platformUtilities.removeFolder(itemMenu.itemPath); } + text: qsTr("Remove project folder") + onTriggered: { + platformUtilities.removeFolder(itemMenu.itemPath); + } } } @@ -476,14 +458,14 @@ Page { title: qsTr('Import Actions') width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; } topMargin: sceneTopMargin @@ -499,8 +481,10 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Import project from folder" ) - onTriggered: { platformUtilities.importProjectFolder(); } + text: qsTr("Import project from folder") + onTriggered: { + platformUtilities.importProjectFolder(); + } } MenuItem { @@ -513,8 +497,10 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Import project from ZIP" ) - onTriggered: { platformUtilities.importProjectArchive(); } + text: qsTr("Import project from ZIP") + onTriggered: { + platformUtilities.importProjectArchive(); + } } MenuItem { @@ -527,8 +513,10 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Import dataset(s)" ) - onTriggered: { platformUtilities.importDatasets(); } + text: qsTr("Import dataset(s)") + onTriggered: { + platformUtilities.importDatasets(); + } } MenuSeparator { @@ -545,10 +533,10 @@ Page { width: parent.width leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Import URL" ) + text: qsTr("Import URL") onTriggered: { - importUrlDialog.open() - importUrlInput.focus = true + importUrlDialog.open(); + importUrlInput.focus = true; } } @@ -563,8 +551,10 @@ Page { width: parent.width leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Storage management help" ) - onTriggered: { Qt.openUrlExternally("https://docs.qfield.org/get-started/storage/") } + text: qsTr("Storage management help") + onTriggered: { + Qt.openUrlExternally("https://docs.qfield.org/get-started/storage/"); + } } } @@ -574,14 +564,14 @@ Page { title: qsTr('Project Actions') width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; } topMargin: sceneTopMargin @@ -597,8 +587,10 @@ Page { height: enabled ? undefined : 0 leftPadding: Theme.menuItemLeftPadding - text: qsTr( "Update project from ZIP" ) - onTriggered: { platformUtilities.updateProjectFromArchive(projectInfo.filePath); } + text: qsTr("Update project from ZIP") + onTriggered: { + platformUtilities.updateProjectFromArchive(projectInfo.filePath); + } } } } @@ -609,11 +601,11 @@ Page { focus: true font: Theme.defaultFont - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height - 80 ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height - 80) / 2 onAboutToShow: { - importUrlInput.text = '' + importUrlInput.text = ''; } Column { @@ -644,7 +636,7 @@ Page { standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - iface.importUrl(importUrlInput.text) + iface.importUrl(importUrlInput.text); } } @@ -658,9 +650,9 @@ Page { } } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true + event.accepted = true; if (table.model.currentDepth > 1) { table.model.moveUp(); } else { @@ -670,6 +662,6 @@ Page { } onVisibleChanged: { - focus = visible + focus = visible; } } diff --git a/src/qml/QFieldSettings.qml b/src/qml/QFieldSettings.qml index 0a41315af4..1258b3a065 100644 --- a/src/qml/QFieldSettings.qml +++ b/src/qml/QFieldSettings.qml @@ -2,9 +2,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtCore - import org.qfield 1.0 - import Theme 1.0 Page { @@ -29,7 +27,7 @@ Page { Component.onCompleted: { if (settings.valueBool('nativeCameraLaunched', false)) { // a crash occured while the native camera was launched, disable it - nativeCamera = false + nativeCamera = false; } } @@ -51,127 +49,127 @@ Page { onEnableInfoCollectionChanged: { if (enableInfoCollection) { - iface.initiateSentry() + iface.initiateSentry(); } else { - iface.closeSentry() + iface.closeSentry(); } } onDigitizingVolumeKeysChanged: { - platformUtilities.setHandleVolumeKeys(digitizingVolumeKeys && stateMachine.state != 'browse') + platformUtilities.setHandleVolumeKeys(digitizingVolumeKeys && stateMachine.state != 'browse'); } onFingerTapDigitizingChanged: { - coordinateLocator.sourceLocation = undefined + coordinateLocator.sourceLocation = undefined; } } ListModel { - id: canvasSettingsModel - ListElement { - title: qsTr( "Show scale bar" ) - description: '' - settingAlias: "showScaleBar" - isVisible: true - } - ListElement { - title: qsTr( "Show bookmarks" ) - description: qsTr( "When switched on, user's saved and currently opened project bookmarks will be displayed on the map." ) - settingAlias: "showBookmarks" - isVisible: true - } - ListElement { - title: qsTr( "Enable map rotation" ) - description: qsTr( "When switched on, the map can be rotated by the user." ) - settingAlias: "enableMapRotation" - isVisible: true - } + id: canvasSettingsModel + ListElement { + title: qsTr("Show scale bar") + description: '' + settingAlias: "showScaleBar" + isVisible: true + } + ListElement { + title: qsTr("Show bookmarks") + description: qsTr("When switched on, user's saved and currently opened project bookmarks will be displayed on the map.") + settingAlias: "showBookmarks" + isVisible: true + } + ListElement { + title: qsTr("Enable map rotation") + description: qsTr("When switched on, the map can be rotated by the user.") + settingAlias: "enableMapRotation" + isVisible: true + } } ListModel { - id: digitizingEditingSettingsModel - ListElement { - title: qsTr( "Show digitizing information" ) - description: qsTr( "When switched on, coordinate information, such as latitude and longitude, is overlayed onto the map while digitizing new features or using the measure tool." ) - settingAlias: "numericalDigitizingInformation" - isVisible: true - } - ListElement { - title: qsTr( "Fast editing mode" ) - description: qsTr( "If enabled, the feature is stored after having a valid geometry and the constraints are fulfilled and atributes are commited immediately." ) - settingAlias: "autoSave" - isVisible: true - } - ListElement { - title: qsTr( "Use volume keys to digitize" ) - description: qsTr( "If enabled, pressing the device's volume up key will add a vertex while pressing volume down key will remove the last entered vertex during digitizing sessions." ) - settingAlias: "digitizingVolumeKeys" - isVisible: true - } - ListElement { - title: qsTr( "Allow finger tap on canvas to add vertices" ) - description: qsTr( "When enabled, tapping on the map canvas with a finger will add a vertex at the tapped location." ) - settingAlias: "fingerTapDigitizing" - isVisible: true - } - ListElement { - title: qsTr( "Consider mouse as a touchscreen device" ) - description: qsTr( "When enabled, the mouse will act as if it was a finger. When disabled, the mouse will match the stylus behavior." ) - settingAlias: "mouseAsTouchScreen" - isVisible: true - } - Component.onCompleted: { - for (var i = 0; i < count; i++) { - if (get(i).settingAlias === 'digitizingVolumeKeys') { - setProperty(i, 'isVisible', platformUtilities.capabilities & PlatformUtilities.VolumeKeys ? true : false) - } else { - setProperty(i, 'isVisible', true) - } - } + id: digitizingEditingSettingsModel + ListElement { + title: qsTr("Show digitizing information") + description: qsTr("When switched on, coordinate information, such as latitude and longitude, is overlayed onto the map while digitizing new features or using the measure tool.") + settingAlias: "numericalDigitizingInformation" + isVisible: true + } + ListElement { + title: qsTr("Fast editing mode") + description: qsTr("If enabled, the feature is stored after having a valid geometry and the constraints are fulfilled and atributes are commited immediately.") + settingAlias: "autoSave" + isVisible: true + } + ListElement { + title: qsTr("Use volume keys to digitize") + description: qsTr("If enabled, pressing the device's volume up key will add a vertex while pressing volume down key will remove the last entered vertex during digitizing sessions.") + settingAlias: "digitizingVolumeKeys" + isVisible: true + } + ListElement { + title: qsTr("Allow finger tap on canvas to add vertices") + description: qsTr("When enabled, tapping on the map canvas with a finger will add a vertex at the tapped location.") + settingAlias: "fingerTapDigitizing" + isVisible: true + } + ListElement { + title: qsTr("Consider mouse as a touchscreen device") + description: qsTr("When enabled, the mouse will act as if it was a finger. When disabled, the mouse will match the stylus behavior.") + settingAlias: "mouseAsTouchScreen" + isVisible: true + } + Component.onCompleted: { + for (var i = 0; i < count; i++) { + if (get(i).settingAlias === 'digitizingVolumeKeys') { + setProperty(i, 'isVisible', platformUtilities.capabilities & PlatformUtilities.VolumeKeys ? true : false); + } else { + setProperty(i, 'isVisible', true); + } } + } } ListModel { - id: interfaceSettingsModel - ListElement { - title: qsTr( "Maximized attribute form" ) - description: '' - settingAlias: "fullScreenIdentifyView" - isVisible: true - } - ListElement { - title: qsTr( "Fixed scale navigation" ) - description: qsTr( "When fixed scale navigation is active, focusing on a search result will pan to the feature. With fixed scale navigation disabled it will pan and zoom to the feature." ) - settingAlias: "locatorKeepScale" - isVisible: true - } + id: interfaceSettingsModel + ListElement { + title: qsTr("Maximized attribute form") + description: '' + settingAlias: "fullScreenIdentifyView" + isVisible: true + } + ListElement { + title: qsTr("Fixed scale navigation") + description: qsTr("When fixed scale navigation is active, focusing on a search result will pan to the feature. With fixed scale navigation disabled it will pan and zoom to the feature.") + settingAlias: "locatorKeepScale" + isVisible: true + } } ListModel { - id: advancedSettingsModel - ListElement { - title: qsTr( "Use native camera" ) - description: qsTr( "If disabled, QField will use a minimalist internal camera instead of the camera app on the device.
Tip: Enable this option and install the open camera app to create geo tagged photos." ) - settingAlias: "nativeCamera" - isVisible: true - } - ListElement { - title: qsTr( "Send anonymized metrics" ) - description: qsTr( "If enabled, anonymized metrics will be collected and sent to help improve QField for everyone." ) - settingAlias: "enableInfoCollection" - isVisible: true - } - Component.onCompleted: { - for (var i = 0; i < count; i++) { - if (get(i).settingAlias === 'nativeCamera') { - setProperty(i, 'isVisible', platformUtilities.capabilities & PlatformUtilities.NativeCamera ? true : false) - } else if (get(i).settingAlias === 'enableInfoCollection') { - setProperty(i, 'isVisible', platformUtilities.capabilities & PlatformUtilities.SentryFramework ? true : false) - } else { - setProperty(i, 'isVisible', true) - } - } + id: advancedSettingsModel + ListElement { + title: qsTr("Use native camera") + description: qsTr("If disabled, QField will use a minimalist internal camera instead of the camera app on the device.
Tip: Enable this option and install the open camera app to create geo tagged photos.") + settingAlias: "nativeCamera" + isVisible: true + } + ListElement { + title: qsTr("Send anonymized metrics") + description: qsTr("If enabled, anonymized metrics will be collected and sent to help improve QField for everyone.") + settingAlias: "enableInfoCollection" + isVisible: true + } + Component.onCompleted: { + for (var i = 0; i < count; i++) { + if (get(i).settingAlias === 'nativeCamera') { + setProperty(i, 'isVisible', platformUtilities.capabilities & PlatformUtilities.NativeCamera ? true : false); + } else if (get(i).settingAlias === 'enableInfoCollection') { + setProperty(i, 'isVisible', platformUtilities.capabilities & PlatformUtilities.SentryFramework ? true : false); + } else { + setProperty(i, 'isVisible', true); + } } + } } Rectangle { @@ -258,1356 +256,1380 @@ Page { onCurrentIndexChanged: bar.currentIndex = swipeView.currentIndex Item { - ScrollView { - topPadding: 5 - leftPadding: 0 - rightPadding: 0 - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - ScrollBar.vertical.policy: ScrollBar.AsNeeded - contentWidth: generalSettingsGrid.width - contentHeight: generalSettingsGrid.height - anchors.fill: parent - clip: true - - ColumnLayout { - id: generalSettingsGrid - width: parent.parent.width - - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - - columns: 2 - columnSpacing: 0 - rowSpacing: 5 - - Label { - text: qsTr('Map Canvas') - font: Theme.strongFont - color: Theme.mainColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.topMargin: 5 - Layout.columnSpan: 2 - } + ScrollView { + topPadding: 5 + leftPadding: 0 + rightPadding: 0 + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + contentWidth: generalSettingsGrid.width + contentHeight: generalSettingsGrid.height + anchors.fill: parent + clip: true - Rectangle { - Layout.fillWidth: true - Layout.columnSpan: 2 - height: 1 - color: Theme.mainColor - } - } - - ListView { - Layout.preferredWidth: mainWindow.width - Layout.preferredHeight: childrenRect.height - interactive: false - - model: canvasSettingsModel - - delegate: listItem - } + ColumnLayout { + id: generalSettingsGrid + width: parent.parent.width + + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + + columns: 2 + columnSpacing: 0 + rowSpacing: 5 + + Label { + text: qsTr('Map Canvas') + font: Theme.strongFont + color: Theme.mainColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.topMargin: 5 + Layout.columnSpan: 2 + } - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 + Rectangle { + Layout.fillWidth: true + Layout.columnSpan: 2 + height: 1 + color: Theme.mainColor + } + } - columns: 2 - columnSpacing: 0 - rowSpacing: 5 + ListView { + Layout.preferredWidth: mainWindow.width + Layout.preferredHeight: childrenRect.height + interactive: false - Label { - Layout.fillWidth: true - Layout.columnSpan: 2 - text: qsTr( "Map canvas rendering quality:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + model: canvasSettingsModel - wrapMode: Text.WordWrap - } + delegate: listItem + } - ComboBox { - id: renderingQualityComboBox - enabled: true - Layout.fillWidth: true - Layout.columnSpan: 2 - Layout.alignment: Qt.AlignVCenter - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - model: ListModel { - ListElement { name: qsTr('Best quality'); value: 1.0 } - ListElement { name: qsTr('Lower quality'); value: 0.75 } - ListElement { name: qsTr('Lowest quality'); value: 0.5 } - } - textRole: "name" - valueRole: "value" - - property bool initialized: false - - onCurrentValueChanged: { - if (initialized) { - quality = currentValue - } - } - - Component.onCompleted: { - currentIndex = indexOfValue(quality) - initialized = true - } - } + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 - Label { - text: qsTr( "A lower quality trades rendering precision in favor of lower memory usage and rendering time." ) - font: Theme.tipFont - color: Theme.secondaryTextColor - textFormat: Qt.RichText - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.columnSpan: 2 + columns: 2 + columnSpacing: 0 + rowSpacing: 5 - onLinkActivated: (link) => { Qt.openUrlExternally(link) } - } + Label { + Layout.fillWidth: true + Layout.columnSpan: 2 + text: qsTr("Map canvas rendering quality:") + font: Theme.defaultFont + color: Theme.mainTextColor - Label { - text: qsTr('Digitizing & Editing') - font: Theme.strongFont - color: Theme.mainColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.topMargin: 5 - Layout.columnSpan: 2 - } + wrapMode: Text.WordWrap + } - Rectangle { - Layout.fillWidth: true - Layout.columnSpan: 2 - height: 1 - color: Theme.mainColor - } + ComboBox { + id: renderingQualityComboBox + enabled: true + Layout.fillWidth: true + Layout.columnSpan: 2 + Layout.alignment: Qt.AlignVCenter + font: Theme.defaultFont + + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin + + model: ListModel { + ListElement { + name: qsTr('Best quality') + value: 1.0 } + ListElement { + name: qsTr('Lower quality') + value: 0.75 + } + ListElement { + name: qsTr('Lowest quality') + value: 0.5 + } + } + textRole: "name" + valueRole: "value" - ListView { - Layout.preferredWidth: mainWindow.width - Layout.preferredHeight: childrenRect.height - interactive: false - - model: digitizingEditingSettingsModel + property bool initialized: false - delegate: listItem + onCurrentValueChanged: { + if (initialized) { + quality = currentValue; } + } - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - - columns: 2 - columnSpacing: 0 - rowSpacing: 5 - - Label { - text: qsTr('User Interface') - font: Theme.strongFont - color: Theme.mainColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.topMargin: 5 - Layout.columnSpan: 2 - } + Component.onCompleted: { + currentIndex = indexOfValue(quality); + initialized = true; + } + } - Rectangle { - Layout.fillWidth: true - Layout.columnSpan: 2 - height: 1 - color: Theme.mainColor - } + Label { + text: qsTr("A lower quality trades rendering precision in favor of lower memory usage and rendering time.") + font: Theme.tipFont + color: Theme.secondaryTextColor + textFormat: Qt.RichText + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.columnSpan: 2 + + onLinkActivated: link => { + Qt.openUrlExternally(link); + } + } - Label { - text: qsTr("Customize search bar") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.topMargin: 5 - - MouseArea { - anchors.fill: parent - onClicked: showSearchBarSettings.clicked() - } - } + Label { + text: qsTr('Digitizing & Editing') + font: Theme.strongFont + color: Theme.mainColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.topMargin: 5 + Layout.columnSpan: 2 + } - QfToolButton { - id: showSearchBarSettings - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 - Layout.alignment: Qt.AlignVCenter - clip: true + Rectangle { + Layout.fillWidth: true + Layout.columnSpan: 2 + height: 1 + color: Theme.mainColor + } + } - iconSource: Theme.getThemeIcon( "ic_ellipsis_green_24dp" ) - bgcolor: "transparent" + ListView { + Layout.preferredWidth: mainWindow.width + Layout.preferredHeight: childrenRect.height + interactive: false - onClicked: { - locatorSettings.open(); - locatorSettings.focus = true; - } - } + model: digitizingEditingSettingsModel - Label { - text: qsTr("Manage plugins") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - - MouseArea { - anchors.fill: parent - onClicked: showPluginManagerSettings.clicked() - } - } + delegate: listItem + } - QfToolButton { - id: showPluginManagerSettings - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 - Layout.alignment: Qt.AlignVCenter - clip: true + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + + columns: 2 + columnSpacing: 0 + rowSpacing: 5 + + Label { + text: qsTr('User Interface') + font: Theme.strongFont + color: Theme.mainColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.topMargin: 5 + Layout.columnSpan: 2 + } - iconSource: Theme.getThemeIcon( "ic_ellipsis_green_24dp" ) - bgcolor: "transparent" + Rectangle { + Layout.fillWidth: true + Layout.columnSpan: 2 + height: 1 + color: Theme.mainColor + } - onClicked: { - pluginManagerSettings.open(); - pluginManagerSettings.focus = true; - } - } - } + Label { + text: qsTr("Customize search bar") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.topMargin: 5 + + MouseArea { + anchors.fill: parent + onClicked: showSearchBarSettings.clicked() + } + } + QfToolButton { + id: showSearchBarSettings + Layout.preferredWidth: 48 + Layout.preferredHeight: 48 + Layout.alignment: Qt.AlignVCenter + clip: true - ListView { - Layout.preferredWidth: mainWindow.width - Layout.preferredHeight: childrenRect.height - interactive: false + iconSource: Theme.getThemeIcon("ic_ellipsis_green_24dp") + bgcolor: "transparent" - model: interfaceSettingsModel + onClicked: { + locatorSettings.open(); + locatorSettings.focus = true; + } + } - delegate: listItem - } + Label { + text: qsTr("Manage plugins") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + anchors.fill: parent + onClicked: showPluginManagerSettings.clicked() + } + } - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - Layout.topMargin: 5 - Layout.bottomMargin: 5 + QfToolButton { + id: showPluginManagerSettings + Layout.preferredWidth: 48 + Layout.preferredHeight: 48 + Layout.alignment: Qt.AlignVCenter + clip: true - columns: 1 - columnSpacing: 0 - rowSpacing: 0 + iconSource: Theme.getThemeIcon("ic_ellipsis_green_24dp") + bgcolor: "transparent" - visible: platformUtilities.capabilities & PlatformUtilities.AdjustBrightness + onClicked: { + pluginManagerSettings.open(); + pluginManagerSettings.focus = true; + } + } + } - Label { - Layout.fillWidth: true + ListView { + Layout.preferredWidth: mainWindow.width + Layout.preferredHeight: childrenRect.height + interactive: false - text: qsTr('Dim screen when idling') - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - } + model: interfaceSettingsModel - QfSlider { - Layout.fillWidth: true + delegate: listItem + } - id: slider - value: settings ? settings.value('dimTimeoutSeconds', 40) : 40 - from: 0 - to: 180 - stepSize: 10 - suffixText: " s" - implicitHeight: 40 + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + Layout.topMargin: 5 + Layout.bottomMargin: 5 - onMoved: function () { - iface.setScreenDimmerTimeout(value) - settings.setValue('dimTimeoutSeconds', value) - } - } + columns: 1 + columnSpacing: 0 + rowSpacing: 0 - Label { - Layout.fillWidth: true - text: qsTr('Time of inactivity in seconds before the screen brightness get be dimmed to preserve battery.') + visible: platformUtilities.capabilities & PlatformUtilities.AdjustBrightness - font: Theme.tipFont - color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - } - } + Label { + Layout.fillWidth: true - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - Layout.topMargin: 5 - Layout.bottomMargin: 40 + text: qsTr('Dim screen when idling') + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + } - columns: 1 - columnSpacing: 0 - rowSpacing: 5 + QfSlider { + id: slider + Layout.fillWidth: true + value: settings ? settings.value('dimTimeoutSeconds', 40) : 40 + from: 0 + to: 180 + stepSize: 10 + suffixText: " s" + implicitHeight: 40 + + onMoved: function () { + iface.setScreenDimmerTimeout(value); + settings.setValue('dimTimeoutSeconds', value); + } + } - Label { - Layout.fillWidth: true - text: qsTr( "Appearance:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + Label { + Layout.fillWidth: true + text: qsTr('Time of inactivity in seconds before the screen brightness get be dimmed to preserve battery.') - wrapMode: Text.WordWrap - } + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap + } + } - ComboBox { - id: appearanceComboBox - enabled: true - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - model: ListModel { - ListElement { name: qsTr('Follow system appearance'); value: 'system' } - ListElement { name: qsTr('Light theme'); value: 'light' } - ListElement { name: qsTr('Dark theme'); value: 'dark' } - } - textRole: "name" - valueRole: "value" - - property bool initialized: false - - onCurrentValueChanged: { - if (initialized) { - settings.setValue("appearance", currentValue) - Theme.applyAppearance() - } - } - - Component.onCompleted: { - var appearance = settings.value("appearance", 'system') - currentIndex = indexOfValue(appearance) - initialized = true - } - } + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + Layout.topMargin: 5 + Layout.bottomMargin: 40 - Label { - Layout.fillWidth: true - text: qsTr( "Font size:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + columns: 1 + columnSpacing: 0 + rowSpacing: 5 - wrapMode: Text.WordWrap - } + Label { + Layout.fillWidth: true + text: qsTr("Appearance:") + font: Theme.defaultFont + color: Theme.mainTextColor - ComboBox { - id: fontScaleComboBox - enabled: true - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - model: ListModel { - ListElement { name: qsTr('Tiny'); value: 0.75 } - ListElement { name: qsTr('Normal'); value: 1.0 } - ListElement { name: qsTr('Large'); value: 1.5 } - ListElement { name: qsTr('Extra-large'); value: 2.0 } - } - textRole: "name" - valueRole: "value" - - property bool initialized: false - - onCurrentValueChanged: { - if (initialized) { - settings.setValue("fontScale", currentValue) - Theme.applyFontScale() - } - } - - Component.onCompleted: { - var fontScale = settings.value("fontScale", 1.0) - currentIndex = indexOfValue(fontScale) - initialized = true - } - } + wrapMode: Text.WordWrap + } - Label { - Layout.fillWidth: true - text: qsTr( "Language:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + ComboBox { + id: appearanceComboBox + enabled: true + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + font: Theme.defaultFont + + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin + + model: ListModel { + ListElement { + name: qsTr('Follow system appearance') + value: 'system' + } + ListElement { + name: qsTr('Light theme') + value: 'light' + } + ListElement { + name: qsTr('Dark theme') + value: 'dark' + } + } + textRole: "name" + valueRole: "value" - wrapMode: Text.WordWrap - } + property bool initialized: false - Label { - id: languageTip - visible: false + onCurrentValueChanged: { + if (initialized) { + settings.setValue("appearance", currentValue); + Theme.applyAppearance(); + } + } - Layout.fillWidth: true - text: qsTr( "To apply the selected user interface language, QField needs to completely shutdown and restart." ) - font: Theme.tipFont - color: Theme.warningColor + Component.onCompleted: { + var appearance = settings.value("appearance", 'system'); + currentIndex = indexOfValue(appearance); + initialized = true; + } + } - wrapMode: Text.WordWrap - } + Label { + Layout.fillWidth: true + text: qsTr("Font size:") + font: Theme.defaultFont + color: Theme.mainTextColor - ComboBox { - id: languageComboBox - enabled: true - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneBottomMargin - - property variant languageCodes: undefined - property string currentLanguageCode: undefined - - onCurrentIndexChanged: { - if (currentLanguageCode != undefined) { - settings.setValue("customLanguage",languageCodes[currentIndex]); - languageTip.visible = languageCodes[currentIndex] !== currentLanguageCode; - } - } - - Component.onCompleted: { - var customLanguageCode = settings.value('customLanguage', ''); - - var languages = iface.availableLanguages(); - languageCodes = [""].concat(Object.keys(languages)); - - var systemLanguage = qsTr( "system" ); - var systemLanguageSuffix = systemLanguage !== 'system' ? ' (system)' : '' - var items = [systemLanguage + systemLanguageSuffix] - languageComboBox.model = items.concat(Object.values(languages)); - languageComboBox.currentIndex = languageCodes.indexOf(customLanguageCode); - currentLanguageCode = customLanguageCode || '' - languageTip.visible = false - } - } + wrapMode: Text.WordWrap + } - Label { - text: qsTr( "Found a missing or incomplete language? %1Join the translator community.%2" ) - .arg( '' ) - .arg( '' ); - font: Theme.tipFont - color: Theme.secondaryTextColor - textFormat: Qt.RichText - wrapMode: Text.WordWrap - Layout.fillWidth: true - - onLinkActivated: (link) => { Qt.openUrlExternally(link) } - } + ComboBox { + id: fontScaleComboBox + enabled: true + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + font: Theme.defaultFont + + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin + + model: ListModel { + ListElement { + name: qsTr('Tiny') + value: 0.75 + } + ListElement { + name: qsTr('Normal') + value: 1.0 } + ListElement { + name: qsTr('Large') + value: 1.5 + } + ListElement { + name: qsTr('Extra-large') + value: 2.0 + } + } + textRole: "name" + valueRole: "value" - GridLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - - columns: 2 - columnSpacing: 0 - rowSpacing: 5 - - visible: platformUtilities.capabilities & PlatformUtilities.NativeCamera || platformUtilities.capabilities & PlatformUtilities.SentryFramework - - Label { - text: qsTr('Advanced') - font: Theme.strongFont - color: Theme.mainColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.topMargin: 5 - Layout.columnSpan: 2 - } + property bool initialized: false - Rectangle { - Layout.fillWidth: true - Layout.columnSpan: 2 - height: 1 - color: Theme.mainColor - } + onCurrentValueChanged: { + if (initialized) { + settings.setValue("fontScale", currentValue); + Theme.applyFontScale(); } + } - ListView { - Layout.preferredWidth: mainWindow.width - Layout.preferredHeight: childrenRect.height - interactive: false - - model: advancedSettingsModel + Component.onCompleted: { + var fontScale = settings.value("fontScale", 1.0); + currentIndex = indexOfValue(fontScale); + initialized = true; + } + } - delegate: listItem - } + Label { + Layout.fillWidth: true + text: qsTr("Language:") + font: Theme.defaultFont + color: Theme.mainTextColor - Item { - // spacer item - Layout.fillWidth: true - Layout.fillHeight: true - Layout.minimumHeight: mainWindow.sceneBottomMargin + 20 - } + wrapMode: Text.WordWrap } - } - } - Item { - ScrollView { - topPadding: 5 - leftPadding: 20 - rightPadding: 20 - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - ScrollBar.vertical.policy: ScrollBar.AsNeeded - contentWidth: positioningGrid.width - contentHeight: positioningGrid.height - anchors.fill: parent - clip: true + Label { + id: languageTip + visible: false - ColumnLayout { - id: positioningGrid - width: parent.parent.width - spacing: 10 + Layout.fillWidth: true + text: qsTr("To apply the selected user interface language, QField needs to completely shutdown and restart.") + font: Theme.tipFont + color: Theme.warningColor - GridLayout { - Layout.fillWidth: true + wrapMode: Text.WordWrap + } - columns: 2 - columnSpacing: 0 - rowSpacing: 5 + ComboBox { + id: languageComboBox + enabled: true + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + font: Theme.defaultFont - Label { - Layout.fillWidth: true - Layout.columnSpan: 2 - text: qsTr( "Positioning device in use:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneBottomMargin - wrapMode: Text.WordWrap - } + property variant languageCodes: undefined + property string currentLanguageCode: undefined - RowLayout { - Layout.fillWidth: true - Layout.columnSpan: 2 - - ComboBox { - id: positioningDeviceComboBox - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - textRole: 'DeviceName' - valueRole: 'DeviceType' - model: PositioningDeviceModel { - id: positioningDeviceModel - } - - delegate: ItemDelegate { - width: positioningDeviceComboBox.width - height: 36 - icon.source: { - switch(DeviceType) { - case PositioningDeviceModel.InternalDevice: - return Theme.getThemeVectorIcon('ic_internal_receiver_black_24dp') - case PositioningDeviceModel.BluetoothDevice: - return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp') - case PositioningDeviceModel.TcpDevice: - return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp') - case PositioningDeviceModel.UdpDevice: - return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp') - case PositioningDeviceModel.SerialPortDevice: - return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp') - } - return ''; - } - icon.width: 24 - icon.height: 24 - text: DeviceName - font: Theme.defaultFont - highlighted: positioningDeviceComboBox.highlightedIndex === index - } - - contentItem: MenuItem { - width: positioningDeviceComboBox.width - height: 36 - - icon.source: { - switch(positioningDeviceComboBox.currentValue) { - case PositioningDeviceModel.InternalDevice: - return Theme.getThemeVectorIcon('ic_internal_receiver_black_24dp') - case PositioningDeviceModel.BluetoothDevice: - return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp') - case PositioningDeviceModel.TcpDevice: - return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp') - case PositioningDeviceModel.UdpDevice: - return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp') - case PositioningDeviceModel.SerialPortDevice: - return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp') - } - return ''; - } - icon.width: 24 - icon.height: 24 - - text: positioningDeviceComboBox.currentText - font: Theme.defaultFont - - onClicked: positioningDeviceComboBox.popup.open() - } - - onCurrentIndexChanged: { - var modelIndex = positioningDeviceModel.index(currentIndex, 0); - positioningSettings.positioningDevice = positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceId) - positioningSettings.positioningDeviceName = positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceName); - - verticalGridShiftComboBox.reload() - } - - Component.onCompleted: { - currentIndex = positioningDeviceModel.findIndexFromDeviceId(settings.value('positioningDevice','')) - } - } + onCurrentIndexChanged: { + if (currentLanguageCode != undefined) { + settings.setValue("customLanguage", languageCodes[currentIndex]); + languageTip.visible = languageCodes[currentIndex] !== currentLanguageCode; } + } + + Component.onCompleted: { + var customLanguageCode = settings.value('customLanguage', ''); + var languages = iface.availableLanguages(); + languageCodes = [""].concat(Object.keys(languages)); + var systemLanguage = qsTr("system"); + var systemLanguageSuffix = systemLanguage !== 'system' ? ' (system)' : ''; + var items = [systemLanguage + systemLanguageSuffix]; + languageComboBox.model = items.concat(Object.values(languages)); + languageComboBox.currentIndex = languageCodes.indexOf(customLanguageCode); + currentLanguageCode = customLanguageCode || ''; + languageTip.visible = false; + } + } - RowLayout { - Layout.fillWidth: true - Layout.columnSpan: 2 + Label { + text: qsTr("Found a missing or incomplete language? %1Join the translator community.%2").arg('').arg('') + font: Theme.tipFont + color: Theme.secondaryTextColor + textFormat: Qt.RichText + wrapMode: Text.WordWrap + Layout.fillWidth: true + + onLinkActivated: link => { + Qt.openUrlExternally(link); + } + } + } - QfButton { - leftPadding: 10 - rightPadding: 10 - text: qsTr('Add') + GridLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + + columns: 2 + columnSpacing: 0 + rowSpacing: 5 + + visible: platformUtilities.capabilities & PlatformUtilities.NativeCamera || platformUtilities.capabilities & PlatformUtilities.SentryFramework + + Label { + text: qsTr('Advanced') + font: Theme.strongFont + color: Theme.mainColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.topMargin: 5 + Layout.columnSpan: 2 + } - onClicked: { - positioningDeviceSettings.originalName = ''; - positioningDeviceSettings.name = ''; - positioningDeviceSettings.open() - } - } + Rectangle { + Layout.fillWidth: true + Layout.columnSpan: 2 + height: 1 + color: Theme.mainColor + } + } - Item { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - } + ListView { + Layout.preferredWidth: mainWindow.width + Layout.preferredHeight: childrenRect.height + interactive: false - QfButton { - leftPadding: 10 - rightPadding: 10 - text: qsTr('Edit') - enabled: positioningDeviceComboBox.currentIndex > 0 - - onClicked: { - var modelIndex = positioningDeviceModel.index(positioningDeviceComboBox.currentIndex, 0); - var name = positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceName); - positioningDeviceSettings.originalName = name; - positioningDeviceSettings.name = name; - positioningDeviceSettings.setType(positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceType)) - positioningDeviceSettings.setSettings(positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceSettings)) - positioningDeviceSettings.open(); - } - } + model: advancedSettingsModel - QfButton { - leftPadding: 10 - rightPadding: 10 - text: qsTr('Remove') - enabled: positioningDeviceComboBox.currentIndex > 0 - - onClicked: { - var modelIndex = positioningDeviceModel.index(positioningDeviceComboBox.currentIndex, 0); - positioningDeviceComboBox.currentIndex = 0; - positioningDeviceModel.removeDevice(positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceName)); - } - } - } + delegate: listItem + } - QfButton { - id: connectButton - Layout.fillWidth: true - Layout.columnSpan: 2 - Layout.topMargin: 5 - text: { - switch (positionSource.device.socketState) { - case QAbstractSocket.ConnectedState: - case QAbstractSocket.BoundState: - return qsTr('Connected to %1').arg(positioningSettings.positioningDeviceName) - case QAbstractSocket.UnconnectedState: - return qsTr('Connect to %1').arg(positioningSettings.positioningDeviceName) - default: - return qsTr('Connecting to %1').arg(positioningSettings.positioningDeviceName) - } - } - enabled: positionSource.device.socketState === QAbstractSocket.UnconnectedState - visible: positionSource.deviceId !== '' - - onClicked: { - // make sure positioning is active when connecting to the bluetooth device - if (!positioningSettings.positioningActivated) { - positioningSettings.positioningActivated = true - } else { - positionSource.device.connectDevice() - } - } - } + Item { + // spacer item + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: mainWindow.sceneBottomMargin + 20 + } + } + } + } + + Item { + ScrollView { + topPadding: 5 + leftPadding: 20 + rightPadding: 20 + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + contentWidth: positioningGrid.width + contentHeight: positioningGrid.height + anchors.fill: parent + clip: true + + ColumnLayout { + id: positioningGrid + width: parent.parent.width + spacing: 10 + + GridLayout { + Layout.fillWidth: true + + columns: 2 + columnSpacing: 0 + rowSpacing: 5 + + Label { + Layout.fillWidth: true + Layout.columnSpan: 2 + text: qsTr("Positioning device in use:") + font: Theme.defaultFont + color: Theme.mainTextColor + + wrapMode: Text.WordWrap } - GridLayout { + RowLayout { + Layout.fillWidth: true + Layout.columnSpan: 2 + + ComboBox { + id: positioningDeviceComboBox Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + font: Theme.defaultFont - columns: 2 - columnSpacing: 0 - rowSpacing: 5 + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin - Label { - text: qsTr("Show position information") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + textRole: 'DeviceName' + valueRole: 'DeviceType' + model: PositioningDeviceModel { + id: positioningDeviceModel + } - MouseArea { - anchors.fill: parent - onClicked: showPositionInformation.toggle() + delegate: ItemDelegate { + width: positioningDeviceComboBox.width + height: 36 + icon.source: { + switch (DeviceType) { + case PositioningDeviceModel.InternalDevice: + return Theme.getThemeVectorIcon('ic_internal_receiver_black_24dp'); + case PositioningDeviceModel.BluetoothDevice: + return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp'); + case PositioningDeviceModel.TcpDevice: + return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp'); + case PositioningDeviceModel.UdpDevice: + return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp'); + case PositioningDeviceModel.SerialPortDevice: + return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp'); } + return ''; + } + icon.width: 24 + icon.height: 24 + text: DeviceName + font: Theme.defaultFont + highlighted: positioningDeviceComboBox.highlightedIndex === index } - QfSwitch { - id: showPositionInformation - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - checked: positioningSettings.showPositionInformation - onCheckedChanged: { - positioningSettings.showPositionInformation = checked + contentItem: MenuItem { + width: positioningDeviceComboBox.width + height: 36 + + icon.source: { + switch (positioningDeviceComboBox.currentValue) { + case PositioningDeviceModel.InternalDevice: + return Theme.getThemeVectorIcon('ic_internal_receiver_black_24dp'); + case PositioningDeviceModel.BluetoothDevice: + return Theme.getThemeVectorIcon('ic_bluetooth_receiver_black_24dp'); + case PositioningDeviceModel.TcpDevice: + return Theme.getThemeVectorIcon('ic_tcp_receiver_black_24dp'); + case PositioningDeviceModel.UdpDevice: + return Theme.getThemeVectorIcon('ic_udp_receiver_black_24dp'); + case PositioningDeviceModel.SerialPortDevice: + return Theme.getThemeVectorIcon('ic_serial_port_receiver_black_24dp'); } - } + return ''; + } + icon.width: 24 + icon.height: 24 - Label { - id: measureLabel - Layout.fillWidth: true - Layout.columnSpan: 2 - text: qsTr( "Measure (M) value attached to vertices:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + text: positioningDeviceComboBox.currentText + font: Theme.defaultFont - wrapMode: Text.WordWrap + onClicked: positioningDeviceComboBox.popup.open() } - ComboBox { - id: measureComboBox - Layout.fillWidth: true - Layout.columnSpan: 2 - Layout.alignment: Qt.AlignVCenter - font: Theme.defaultFont - - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin - - property bool loaded: false - Component.onCompleted: { - // This list matches the Tracker::MeasureType enum, with SecondsSinceStart removed - var measurements = [ - qsTr("Timestamp (milliseconds since epoch)"), - qsTr("Ground speed"), - qsTr("Bearing"), - qsTr("Horizontal accuracy"), - qsTr("Vertical accuracy"), - qsTr("PDOP"), - qsTr("HDOP"), - qsTr("VDOP") - ]; - - measureComboBox.model = measurements; - measureComboBox.currentIndex = positioningSettings.digitizingMeasureType - 1; - loaded = true; - } - - onCurrentIndexChanged: { - if (loaded) { - positioningSettings.digitizingMeasureType = currentIndex + 1; - } - } + onCurrentIndexChanged: { + var modelIndex = positioningDeviceModel.index(currentIndex, 0); + positioningSettings.positioningDevice = positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceId); + positioningSettings.positioningDeviceName = positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceName); + verticalGridShiftComboBox.reload(); } - Label { - id: measureTipLabel - Layout.fillWidth: true - text: qsTr( "When digitizing features with the coordinate cursor locked to the current position, the measurement type selected above will be added to the geometry provided it has an M dimension." ) - font: Theme.tipFont - color: Theme.secondaryTextColor - - wrapMode: Text.WordWrap + Component.onCompleted: { + currentIndex = positioningDeviceModel.findIndexFromDeviceId(settings.value('positioningDevice', '')); } + } + } - Item { - // spacer item - Layout.fillWidth: true - Layout.fillHeight: true - } + RowLayout { + Layout.fillWidth: true + Layout.columnSpan: 2 - Label { - text: qsTr("Activate accuracy indicator") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + QfButton { + leftPadding: 10 + rightPadding: 10 + text: qsTr('Add') - MouseArea { - anchors.fill: parent - onClicked: accuracyIndicator.toggle() - } + onClicked: { + positioningDeviceSettings.originalName = ''; + positioningDeviceSettings.name = ''; + positioningDeviceSettings.open(); } + } - QfSwitch { - id: accuracyIndicator - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - checked: positioningSettings.accuracyIndicator - onCheckedChanged: { - positioningSettings.accuracyIndicator = checked - } + Item { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + + QfButton { + leftPadding: 10 + rightPadding: 10 + text: qsTr('Edit') + enabled: positioningDeviceComboBox.currentIndex > 0 + + onClicked: { + var modelIndex = positioningDeviceModel.index(positioningDeviceComboBox.currentIndex, 0); + var name = positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceName); + positioningDeviceSettings.originalName = name; + positioningDeviceSettings.name = name; + positioningDeviceSettings.setType(positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceType)); + positioningDeviceSettings.setSettings(positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceSettings)); + positioningDeviceSettings.open(); + } + } + + QfButton { + leftPadding: 10 + rightPadding: 10 + text: qsTr('Remove') + enabled: positioningDeviceComboBox.currentIndex > 0 + + onClicked: { + var modelIndex = positioningDeviceModel.index(positioningDeviceComboBox.currentIndex, 0); + positioningDeviceComboBox.currentIndex = 0; + positioningDeviceModel.removeDevice(positioningDeviceModel.data(modelIndex, PositioningDeviceModel.DeviceName)); } + } + } - Label { - text: qsTr("Bad accuracy below [m]") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - enabled: accuracyIndicator.checked - visible: accuracyIndicator.checked - Layout.leftMargin: 8 + QfButton { + id: connectButton + Layout.fillWidth: true + Layout.columnSpan: 2 + Layout.topMargin: 5 + text: { + switch (positionSource.device.socketState) { + case QAbstractSocket.ConnectedState: + case QAbstractSocket.BoundState: + return qsTr('Connected to %1').arg(positioningSettings.positioningDeviceName); + case QAbstractSocket.UnconnectedState: + return qsTr('Connect to %1').arg(positioningSettings.positioningDeviceName); + default: + return qsTr('Connecting to %1').arg(positioningSettings.positioningDeviceName); + } + } + enabled: positionSource.device.socketState === QAbstractSocket.UnconnectedState + visible: positionSource.deviceId !== '' + + onClicked: { + // make sure positioning is active when connecting to the bluetooth device + if (!positioningSettings.positioningActivated) { + positioningSettings.positioningActivated = true; + } else { + positionSource.device.connectDevice(); } + } + } + } - QfTextField { - id: accuracyBadInput - width: antennaHeightActivated.width - font: Theme.defaultFont - enabled: accuracyIndicator.checked - visible: accuracyIndicator.checked - horizontalAlignment: TextInput.AlignHCenter - Layout.preferredWidth: 60 - Layout.preferredHeight: font.height + 20 - - inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: DoubleValidator { locale: 'C' } - - Component.onCompleted: { - text = isNaN( positioningSettings.accuracyBad ) ? '' : positioningSettings.accuracyBad - } + GridLayout { + Layout.fillWidth: true - onTextChanged: { - if( text.length === 0 || isNaN(text) ) { - positioningSettings.accuracyBad = NaN - } else { - positioningSettings.accuracyBad = parseFloat( text ) - } - } - } + columns: 2 + columnSpacing: 0 + rowSpacing: 5 - Label { - text: qsTr("Excellent accuracy above [m]") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - enabled: accuracyIndicator.checked - visible: accuracyIndicator.checked - Layout.leftMargin: 8 - } + Label { + text: qsTr("Show position information") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true - QfTextField { - id: accuracyExcellentInput - width: antennaHeightActivated.width - font: Theme.defaultFont - enabled: accuracyIndicator.checked - visible: accuracyIndicator.checked - horizontalAlignment: TextInput.AlignHCenter - Layout.preferredWidth: 60 - Layout.preferredHeight: font.height + 20 - - inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: DoubleValidator { locale: 'C' } - - Component.onCompleted: { - text = isNaN( positioningSettings.accuracyExcellent ) ? '' : positioningSettings.accuracyExcellent - } + MouseArea { + anchors.fill: parent + onClicked: showPositionInformation.toggle() + } + } - onTextChanged: { - if( text.length === 0 || isNaN(text) ) { - positioningSettings.accuracyExcellent = NaN - } else { - positioningSettings.accuracyExcellent = parseFloat( text ) - } - } - } + QfSwitch { + id: showPositionInformation + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + checked: positioningSettings.showPositionInformation + onCheckedChanged: { + positioningSettings.showPositionInformation = checked; + } + } - Label { - text: qsTr("Enable accuracy requirement") - font: Theme.defaultFont - color: Theme.mainTextColor - enabled: accuracyIndicator.checked - visible: accuracyIndicator.checked - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.leftMargin: 8 - - MouseArea { - anchors.fill: parent - onClicked: accuracyIndicator.toggle() - } - } + Label { + id: measureLabel + Layout.fillWidth: true + Layout.columnSpan: 2 + text: qsTr("Measure (M) value attached to vertices:") + font: Theme.defaultFont + color: Theme.mainTextColor - QfSwitch { - id: accuracyRequirement - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - enabled: accuracyIndicator.checked - visible: accuracyIndicator.checked - checked: positioningSettings.accuracyRequirement - onCheckedChanged: { - positioningSettings.accuracyRequirement = checked - } - } + wrapMode: Text.WordWrap + } - Label { - text: qsTr( "When the accuracy indicator is enabled, a badge is attached to the location button and colored red if the accuracy value is below bad, yellow if it falls short of excellent, or green.

In addition, an accuracy restriction mode can be toggled on, which restricts vertex addition when locked to coordinate cursor to positions with an accuracy value above the bad threshold." ) - .arg("style='%1'".arg(Theme.toInlineStyles({color:Theme.accuracyBad}))) - .arg("style='%1'".arg(Theme.toInlineStyles({color:Theme.accuracyTolerated}))) - .arg("style='%1'".arg(Theme.toInlineStyles({color:Theme.accuracyExcellent}))) - font: Theme.tipFont - color: Theme.secondaryTextColor - textFormat: Qt.RichText - wrapMode: Text.WordWrap - Layout.fillWidth: true + ComboBox { + id: measureComboBox + Layout.fillWidth: true + Layout.columnSpan: 2 + Layout.alignment: Qt.AlignVCenter + font: Theme.defaultFont + + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin + + property bool loaded: false + Component.onCompleted: { + // This list matches the Tracker::MeasureType enum, with SecondsSinceStart removed + var measurements = [qsTr("Timestamp (milliseconds since epoch)"), qsTr("Ground speed"), qsTr("Bearing"), qsTr("Horizontal accuracy"), qsTr("Vertical accuracy"), qsTr("PDOP"), qsTr("HDOP"), qsTr("VDOP")]; + measureComboBox.model = measurements; + measureComboBox.currentIndex = positioningSettings.digitizingMeasureType - 1; + loaded = true; + } + + onCurrentIndexChanged: { + if (loaded) { + positioningSettings.digitizingMeasureType = currentIndex + 1; } + } + } - Item { - // empty cell in grid layout - width: 1 - } + Label { + id: measureTipLabel + Layout.fillWidth: true + text: qsTr("When digitizing features with the coordinate cursor locked to the current position, the measurement type selected above will be added to the geometry provided it has an M dimension.") + font: Theme.tipFont + color: Theme.secondaryTextColor - Label { - text: qsTr("Enable averaged positioning requirement") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + wrapMode: Text.WordWrap + } - MouseArea { - anchors.fill: parent - onClicked: averagedPositioning.toggle() - } - } + Item { + // spacer item + Layout.fillWidth: true + Layout.fillHeight: true + } - QfSwitch { - id: averagedPositioning - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - checked: positioningSettings.averagedPositioning - onCheckedChanged: { - positioningSettings.averagedPositioning = checked - } - } + Label { + text: qsTr("Activate accuracy indicator") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + anchors.fill: parent + onClicked: accuracyIndicator.toggle() + } + } - Label { - text: qsTr("Minimum number of positions collected") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - enabled: averagedPositioning.checked - visible: averagedPositioning.checked - Layout.leftMargin: 8 - } + QfSwitch { + id: accuracyIndicator + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + checked: positioningSettings.accuracyIndicator + onCheckedChanged: { + positioningSettings.accuracyIndicator = checked; + } + } - QfTextField { - id: averagedPositioningMinimumCount - width: averagedPositioning.width - font: Theme.defaultFont - enabled: averagedPositioning.checked - visible: averagedPositioning.checked - horizontalAlignment: TextInput.AlignHCenter - Layout.preferredWidth: 60 - Layout.preferredHeight: font.height + 20 - - inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: IntValidator { locale: 'C' } - - Component.onCompleted: { - text = isNaN( positioningSettings.averagedPositioningMinimumCount ) ? '' : positioningSettings.averagedPositioningMinimumCount - } + Label { + text: qsTr("Bad accuracy below [m]") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + enabled: accuracyIndicator.checked + visible: accuracyIndicator.checked + Layout.leftMargin: 8 + } - onTextChanged: { - if( text.length === 0 || isNaN(text) ) { - positioningSettings.averagedPositioningMinimumCount = NaN - } else { - positioningSettings.averagedPositioningMinimumCount = parseInt( text ) - } - } + QfTextField { + id: accuracyBadInput + width: antennaHeightActivated.width + font: Theme.defaultFont + enabled: accuracyIndicator.checked + visible: accuracyIndicator.checked + horizontalAlignment: TextInput.AlignHCenter + Layout.preferredWidth: 60 + Layout.preferredHeight: font.height + 20 + + inputMethodHints: Qt.ImhFormattedNumbersOnly + validator: DoubleValidator { + locale: 'C' + } + + Component.onCompleted: { + text = isNaN(positioningSettings.accuracyBad) ? '' : positioningSettings.accuracyBad; + } + + onTextChanged: { + if (text.length === 0 || isNaN(text)) { + positioningSettings.accuracyBad = NaN; + } else { + positioningSettings.accuracyBad = parseFloat(text); } + } + } - Label { - text: qsTr("Automatically end collection when minimum number is met") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - enabled: averagedPositioning.checked - visible: averagedPositioning.checked - Layout.leftMargin: 8 - - MouseArea { - anchors.fill: parent - onClicked: averagedPositioningAutomaticEnd.toggle() - } - } + Label { + text: qsTr("Excellent accuracy above [m]") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + enabled: accuracyIndicator.checked + visible: accuracyIndicator.checked + Layout.leftMargin: 8 + } - QfSwitch { - id: averagedPositioningAutomaticEnd - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - enabled: averagedPositioning.checked - visible: averagedPositioning.checked - checked: positioningSettings.averagedPositioningAutomaticStop - onCheckedChanged: { - positioningSettings.averagedPositioningAutomaticStop = checked - } + QfTextField { + id: accuracyExcellentInput + width: antennaHeightActivated.width + font: Theme.defaultFont + enabled: accuracyIndicator.checked + visible: accuracyIndicator.checked + horizontalAlignment: TextInput.AlignHCenter + Layout.preferredWidth: 60 + Layout.preferredHeight: font.height + 20 + + inputMethodHints: Qt.ImhFormattedNumbersOnly + validator: DoubleValidator { + locale: 'C' + } + + Component.onCompleted: { + text = isNaN(positioningSettings.accuracyExcellent) ? '' : positioningSettings.accuracyExcellent; + } + + onTextChanged: { + if (text.length === 0 || isNaN(text)) { + positioningSettings.accuracyExcellent = NaN; + } else { + positioningSettings.accuracyExcellent = parseFloat(text); } + } + } - Label { - text: qsTr("When enabled, digitizing vertices with a cursor locked to position will only accepted an averaged position from a minimum number of collected positions. Digitizing using averaged positions is done by pressing and holding the add vertex button, which will collect positions until the press is released. Accuracy requirement settings are respected when enabled.") - font: Theme.tipFont - color: Theme.secondaryTextColor - textFormat: Qt.RichText - wrapMode: Text.WordWrap - Layout.fillWidth: true - } + Label { + text: qsTr("Enable accuracy requirement") + font: Theme.defaultFont + color: Theme.mainTextColor + enabled: accuracyIndicator.checked + visible: accuracyIndicator.checked + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.leftMargin: 8 + + MouseArea { + anchors.fill: parent + onClicked: accuracyIndicator.toggle() + } + } - Item { - // empty cell in grid layout - width: 1 - } + QfSwitch { + id: accuracyRequirement + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + enabled: accuracyIndicator.checked + visible: accuracyIndicator.checked + checked: positioningSettings.accuracyRequirement + onCheckedChanged: { + positioningSettings.accuracyRequirement = checked; + } + } - Label { - text: qsTr("Prevent digitizing while geofencing is in alert mode") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + Label { + text: qsTr("When the accuracy indicator is enabled, a badge is attached to the location button and colored red if the accuracy value is below bad, yellow if it falls short of excellent, or green.

In addition, an accuracy restriction mode can be toggled on, which restricts vertex addition when locked to coordinate cursor to positions with an accuracy value above the bad threshold.").arg("style='%1'".arg(Theme.toInlineStyles({ + "color": Theme.accuracyBad + }))).arg("style='%1'".arg(Theme.toInlineStyles({ + "color": Theme.accuracyTolerated + }))).arg("style='%1'".arg(Theme.toInlineStyles({ + "color": Theme.accuracyExcellent + }))) + font: Theme.tipFont + color: Theme.secondaryTextColor + textFormat: Qt.RichText + wrapMode: Text.WordWrap + Layout.fillWidth: true + } - MouseArea { - anchors.fill: parent - onClicked: geofencingPreventDigitizingDuringAlert.toggle() - } - } + Item { + // empty cell in grid layout + width: 1 + } - QfSwitch { - id: geofencingPreventDigitizingDuringAlert - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - checked: positioningSettings.geofencingPreventDigitizingDuringAlert - onCheckedChanged: { - positioningSettings.geofencingPreventDigitizingDuringAlert = checked - } - } + Label { + text: qsTr("Enable averaged positioning requirement") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + anchors.fill: parent + onClicked: averagedPositioning.toggle() + } + } - Label { - text: qsTr( "When enabled, the digitizing of new features will be blocked if a project's geofencing is active and the current position triggers an alert." ) - font: Theme.tipFont - color: Theme.secondaryTextColor + QfSwitch { + id: averagedPositioning + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + checked: positioningSettings.averagedPositioning + onCheckedChanged: { + positioningSettings.averagedPositioning = checked; + } + } - wrapMode: Text.WordWrap - Layout.fillWidth: true - } + Label { + text: qsTr("Minimum number of positions collected") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + enabled: averagedPositioning.checked + visible: averagedPositioning.checked + Layout.leftMargin: 8 + } - Item { - // empty cell in grid layout - width: 1 + QfTextField { + id: averagedPositioningMinimumCount + width: averagedPositioning.width + font: Theme.defaultFont + enabled: averagedPositioning.checked + visible: averagedPositioning.checked + horizontalAlignment: TextInput.AlignHCenter + Layout.preferredWidth: 60 + Layout.preferredHeight: font.height + 20 + + inputMethodHints: Qt.ImhFormattedNumbersOnly + validator: IntValidator { + locale: 'C' + } + + Component.onCompleted: { + text = isNaN(positioningSettings.averagedPositioningMinimumCount) ? '' : positioningSettings.averagedPositioningMinimumCount; + } + + onTextChanged: { + if (text.length === 0 || isNaN(text)) { + positioningSettings.averagedPositioningMinimumCount = NaN; + } else { + positioningSettings.averagedPositioningMinimumCount = parseInt(text); } + } + } - Label { - text: qsTr("Antenna height compensation") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + Label { + text: qsTr("Automatically end collection when minimum number is met") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + enabled: averagedPositioning.checked + visible: averagedPositioning.checked + Layout.leftMargin: 8 + + MouseArea { + anchors.fill: parent + onClicked: averagedPositioningAutomaticEnd.toggle() + } + } - MouseArea { - anchors.fill: parent - onClicked: antennaHeightActivated.toggle() - } - } + QfSwitch { + id: averagedPositioningAutomaticEnd + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + enabled: averagedPositioning.checked + visible: averagedPositioning.checked + checked: positioningSettings.averagedPositioningAutomaticStop + onCheckedChanged: { + positioningSettings.averagedPositioningAutomaticStop = checked; + } + } - QfSwitch { - id: antennaHeightActivated - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - checked: positioningSettings.antennaHeightActivated - onCheckedChanged: { - positioningSettings.antennaHeightActivated = checked - } - } + Label { + text: qsTr("When enabled, digitizing vertices with a cursor locked to position will only accepted an averaged position from a minimum number of collected positions. Digitizing using averaged positions is done by pressing and holding the add vertex button, which will collect positions until the press is released. Accuracy requirement settings are respected when enabled.") + font: Theme.tipFont + color: Theme.secondaryTextColor + textFormat: Qt.RichText + wrapMode: Text.WordWrap + Layout.fillWidth: true + } - Label { - text: qsTr("Antenna height [m]") - enabled: antennaHeightActivated.checked - visible: antennaHeightActivated.checked - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - textFormat: Text.RichText - Layout.leftMargin: 8 - } + Item { + // empty cell in grid layout + width: 1 + } - QfTextField { - id: antennaHeightInput - enabled: antennaHeightActivated.checked - visible: antennaHeightActivated.checked - width: antennaHeightActivated.width - font: Theme.defaultFont - horizontalAlignment: TextInput.AlignHCenter - Layout.preferredWidth: 60 - Layout.preferredHeight: font.height + 20 - - inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: DoubleValidator { locale: 'C' } - - Component.onCompleted: { - text = isNaN( positioningSettings.antennaHeight ) ? '' : positioningSettings.antennaHeight - } + Label { + text: qsTr("Prevent digitizing while geofencing is in alert mode") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + anchors.fill: parent + onClicked: geofencingPreventDigitizingDuringAlert.toggle() + } + } - onTextChanged: { - if( text.length === 0 || isNaN(text) ) { - positioningSettings.antennaHeight = NaN - } else { - positioningSettings.antennaHeight = parseFloat( text ) - } - } - } + QfSwitch { + id: geofencingPreventDigitizingDuringAlert + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + checked: positioningSettings.geofencingPreventDigitizingDuringAlert + onCheckedChanged: { + positioningSettings.geofencingPreventDigitizingDuringAlert = checked; + } + } - Label { - text: qsTr( "This value will correct the Z values recorded from the positioning device. If a value of 1.6 is entered, QField will automatically subtract 1.6 from each recorded value. Make sure to insert the effective antenna height, i.e. pole length + antenna phase centre offset." ) - font: Theme.tipFont - color: Theme.secondaryTextColor + Label { + text: qsTr("When enabled, the digitizing of new features will be blocked if a project's geofencing is active and the current position triggers an alert.") + font: Theme.tipFont + color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - } + wrapMode: Text.WordWrap + Layout.fillWidth: true + } - Item { - // empty cell in grid layout - width: 1 - } + Item { + // empty cell in grid layout + width: 1 + } - Label { - text: qsTr( "Skip altitude correction" ) - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true + Label { + text: qsTr("Antenna height compensation") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + anchors.fill: parent + onClicked: antennaHeightActivated.toggle() + } + } - MouseArea { - anchors.fill: parent - onClicked: skipAltitudeCorrectionSwitch.toggle() - } - } + QfSwitch { + id: antennaHeightActivated + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + checked: positioningSettings.antennaHeightActivated + onCheckedChanged: { + positioningSettings.antennaHeightActivated = checked; + } + } - QfSwitch { - id: skipAltitudeCorrectionSwitch - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - checked: positioningSettings.skipAltitudeCorrection - onCheckedChanged: { - positioningSettings.skipAltitudeCorrection = checked - } + Label { + text: qsTr("Antenna height [m]") + enabled: antennaHeightActivated.checked + visible: antennaHeightActivated.checked + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + textFormat: Text.RichText + Layout.leftMargin: 8 + } + + QfTextField { + id: antennaHeightInput + enabled: antennaHeightActivated.checked + visible: antennaHeightActivated.checked + width: antennaHeightActivated.width + font: Theme.defaultFont + horizontalAlignment: TextInput.AlignHCenter + Layout.preferredWidth: 60 + Layout.preferredHeight: font.height + 20 + + inputMethodHints: Qt.ImhFormattedNumbersOnly + validator: DoubleValidator { + locale: 'C' + } + + Component.onCompleted: { + text = isNaN(positioningSettings.antennaHeight) ? '' : positioningSettings.antennaHeight; + } + + onTextChanged: { + if (text.length === 0 || isNaN(text)) { + positioningSettings.antennaHeight = NaN; + } else { + positioningSettings.antennaHeight = parseFloat(text); } + } + } - Label { - topPadding: 0 - text: qsTr( "Use the altitude as reported by the positioning device. Skip any altitude correction that may be implied by the coordinate system transformation." ) - font: Theme.tipFont - color: Theme.secondaryTextColor + Label { + text: qsTr("This value will correct the Z values recorded from the positioning device. If a value of 1.6 is entered, QField will automatically subtract 1.6 from each recorded value. Make sure to insert the effective antenna height, i.e. pole length + antenna phase centre offset.") + font: Theme.tipFont + color: Theme.secondaryTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - } + wrapMode: Text.WordWrap + Layout.fillWidth: true + } - Item { - // empty cell in grid layout - width: 1 - } + Item { + // empty cell in grid layout + width: 1 + } - Label { - text: qsTr( "Vertical grid shift in use:" ) - font: Theme.defaultFont - color: Theme.mainTextColor + Label { + text: qsTr("Skip altitude correction") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + + MouseArea { + anchors.fill: parent + onClicked: skipAltitudeCorrectionSwitch.toggle() + } + } - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.columnSpan: 2 - } + QfSwitch { + id: skipAltitudeCorrectionSwitch + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + checked: positioningSettings.skipAltitudeCorrection + onCheckedChanged: { + positioningSettings.skipAltitudeCorrection = checked; + } + } - ComboBox { - id: verticalGridShiftComboBox - Layout.fillWidth: true - Layout.columnSpan: 2 - font: Theme.defaultFont + Label { + topPadding: 0 + text: qsTr("Use the altitude as reported by the positioning device. Skip any altitude correction that may be implied by the coordinate system transformation.") + font: Theme.tipFont + color: Theme.secondaryTextColor - popup.font: Theme.defaultFont - popup.topMargin: mainWindow.sceneTopMargin - popup.bottomMargin: mainWindow.sceneTopMargin + wrapMode: Text.WordWrap + Layout.fillWidth: true + } - textRole: "text" - valueRole: "value" + Item { + // empty cell in grid layout + width: 1 + } - model: ListModel { - id: verticalGridShiftModel - } + Label { + text: qsTr("Vertical grid shift in use:") + font: Theme.defaultFont + color: Theme.mainTextColor - onCurrentValueChanged: { - if (reloading || currentValue == undefined) { - return - } + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.columnSpan: 2 + } - positioningSettings.elevationCorrectionMode = currentValue; + ComboBox { + id: verticalGridShiftComboBox + Layout.fillWidth: true + Layout.columnSpan: 2 + font: Theme.defaultFont - if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile) { - positioningSettings.verticalGrid = currentText - } else { - positioningSettings.verticalGrid = "" - } - } + popup.font: Theme.defaultFont + popup.topMargin: mainWindow.sceneTopMargin + popup.bottomMargin: mainWindow.sceneTopMargin - Component.onCompleted: reload() - - property bool reloading: false - function reload() { - reloading = true - - verticalGridShiftComboBox.model.clear() - verticalGridShiftComboBox.model.append({text: qsTr("None"), value: Positioning.ElevationCorrectionMode.None}); - - if (positionSource.device.capabilities() & AbstractGnssReceiver.OrthometricAltitude) - verticalGridShiftComboBox.model.append({text: qsTr("Orthometric from device"), value: Positioning.ElevationCorrectionMode.OrthometricFromDevice}); - - // Add geoid files to combobox - var geoidFiles = platformUtilities.availableGrids() - for (var i = 0; i < geoidFiles.length; i++) - verticalGridShiftComboBox.model.append({text: geoidFiles[i], value: Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile}); - - if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.None) - { - verticalGridShiftComboBox.currentIndex = indexOfValue(positioningSettings.elevationCorrectionMode) - positioningSettings.verticalGrid = ""; - } - else if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromDevice) - { - if (positionSource.device.capabilities() & AbstractGnssReceiver.OrthometricAltitude) - verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(positioningSettings.elevationCorrectionMode) - else - // Orthometric not available -> fallback to None - verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(Positioning.ElevationCorrectionMode.None) - positioningSettings.verticalGrid = ""; - } - else if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile) - { - var currentVerticalGridFileIndex = verticalGridShiftComboBox.find(positioningSettings.verticalGrid); - if (currentVerticalGridFileIndex < 1) - // Vertical index file not found -> fallback to None - verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(Positioning.ElevationCorrectionMode.None) - else - verticalGridShiftComboBox.currentIndex = currentVerticalGridFileIndex; - } - else - { - console.log("Warning unknown elevationCorrectionMode: '%1'".arg(positioningSettings.elevationCorrectionMode)) - - // Unknown mode -> fallback to None - verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(Positioning.ElevationCorrectionMode.None) - } - - reloading = false - } - } + textRole: "text" + valueRole: "value" - Label { - topPadding: 0 - rightPadding: antennaHeightActivated.width - text: qsTr( "Vertical grid shift is used to increase the altitude accuracy." ) - font: Theme.tipFont - color: Theme.secondaryTextColor + model: ListModel { + id: verticalGridShiftModel + } - wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.columnSpan: 2 + onCurrentValueChanged: { + if (reloading || currentValue == undefined) { + return; } - - Label { - text: qsTr("Log NMEA sentences from device to file") - font: Theme.defaultFont - color: Theme.mainTextColor - wrapMode: Text.WordWrap - Layout.fillWidth: true - visible: positionSource.device.capabilities() & AbstractGnssReceiver.Logging - - MouseArea { - anchors.fill: parent - onClicked: positionLogging.toggle() - } + positioningSettings.elevationCorrectionMode = currentValue; + if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile) { + positioningSettings.verticalGrid = currentText; + } else { + positioningSettings.verticalGrid = ""; } - - QfSwitch { - id: positionLogging - Layout.preferredWidth: implicitContentWidth - Layout.alignment: Qt.AlignTop - visible: positionSource.device.capabilities() & AbstractGnssReceiver.Logging - checked: positioningSettings.logging - onCheckedChanged: { - positioningSettings.logging = checked - } + } + + Component.onCompleted: reload() + + property bool reloading: false + function reload() { + reloading = true; + verticalGridShiftComboBox.model.clear(); + verticalGridShiftComboBox.model.append({ + "text": qsTr("None"), + "value": Positioning.ElevationCorrectionMode.None + }); + if (positionSource.device.capabilities() & AbstractGnssReceiver.OrthometricAltitude) + verticalGridShiftComboBox.model.append({ + "text": qsTr("Orthometric from device"), + "value": Positioning.ElevationCorrectionMode.OrthometricFromDevice + }); + + // Add geoid files to combobox + var geoidFiles = platformUtilities.availableGrids(); + for (var i = 0; i < geoidFiles.length; i++) + verticalGridShiftComboBox.model.append({ + "text": geoidFiles[i], + "value": Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile + }); + if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.None) { + verticalGridShiftComboBox.currentIndex = indexOfValue(positioningSettings.elevationCorrectionMode); + positioningSettings.verticalGrid = ""; + } else if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromDevice) { + if (positionSource.device.capabilities() & AbstractGnssReceiver.OrthometricAltitude) + verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(positioningSettings.elevationCorrectionMode); + else + // Orthometric not available -> fallback to None + verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(Positioning.ElevationCorrectionMode.None); + positioningSettings.verticalGrid = ""; + } else if (positioningSettings.elevationCorrectionMode === Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile) { + var currentVerticalGridFileIndex = verticalGridShiftComboBox.find(positioningSettings.verticalGrid); + if (currentVerticalGridFileIndex < 1) + // Vertical index file not found -> fallback to None + verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(Positioning.ElevationCorrectionMode.None); + else + verticalGridShiftComboBox.currentIndex = currentVerticalGridFileIndex; + } else { + console.log("Warning unknown elevationCorrectionMode: '%1'".arg(positioningSettings.elevationCorrectionMode)); + + // Unknown mode -> fallback to None + verticalGridShiftComboBox.currentIndex = verticalGridShiftComboBox.indexOfValue(Positioning.ElevationCorrectionMode.None); } + reloading = false; + } } - Item { - // spacer item - Layout.fillWidth: true - Layout.fillHeight: true - Layout.minimumHeight: mainWindow.sceneBottomMargin + 20 + Label { + topPadding: 0 + rightPadding: antennaHeightActivated.width + text: qsTr("Vertical grid shift is used to increase the altitude accuracy.") + font: Theme.tipFont + color: Theme.secondaryTextColor + + wrapMode: Text.WordWrap + Layout.fillWidth: true + Layout.columnSpan: 2 + } + + Label { + text: qsTr("Log NMEA sentences from device to file") + font: Theme.defaultFont + color: Theme.mainTextColor + wrapMode: Text.WordWrap + Layout.fillWidth: true + visible: positionSource.device.capabilities() & AbstractGnssReceiver.Logging + + MouseArea { + anchors.fill: parent + onClicked: positionLogging.toggle() + } } + + QfSwitch { + id: positionLogging + Layout.preferredWidth: implicitContentWidth + Layout.alignment: Qt.AlignTop + visible: positionSource.device.capabilities() & AbstractGnssReceiver.Logging + checked: positioningSettings.logging + onCheckedChanged: { + positioningSettings.logging = checked; + } + } + } + + Item { + // spacer item + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: mainWindow.sceneBottomMargin + 20 } } } + } Item { VariableEditor { - id: variableEditor - anchors.fill: parent - anchors.margins: 4 - anchors.bottomMargin: 4 + mainWindow.sceneBottomMargin + id: variableEditor + anchors.fill: parent + anchors.margins: 4 + anchors.bottomMargin: 4 + mainWindow.sceneBottomMargin } } } @@ -1622,15 +1644,12 @@ Page { if (originalName != '') { positioningDeviceModel.removeDevice(originalName); } - var name = positioningDeviceSettings.name; var type = positioningDeviceSettings.type; var settings = positioningDeviceSettings.getSettings(); - if (name === '') { name = positioningDeviceSettings.generateName(); } - var index = positioningDeviceModel.addDevice(type, name, settings); positioningDeviceComboBox.currentIndex = index; positioningDeviceComboBox.onCurrentIndexChanged(); @@ -1647,15 +1666,15 @@ Page { topMargin: mainWindow.sceneTopMargin onFinished: { - parent.finished() - variableEditor.apply() + parent.finished(); + variableEditor.apply(); } } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true - variableEditor.apply() + event.accepted = true; + variableEditor.apply(); } } } diff --git a/src/qml/QFieldSketcher.qml b/src/qml/QFieldSketcher.qml index 1a8fb61e40..b68b292639 100644 --- a/src/qml/QFieldSketcher.qml +++ b/src/qml/QFieldSketcher.qml @@ -2,7 +2,6 @@ import QtQuick 2.15 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtCore - import Theme 1.0 import org.qfield 1.0 @@ -10,7 +9,7 @@ Popup { id: sketcher signal finished(var path) - signal cancelled() + signal cancelled width: mainWindow.width height: mainWindow.height @@ -23,7 +22,7 @@ Popup { dim: true onOpened: { - contentItem.forceActiveFocus() + contentItem.forceActiveFocus(); } Settings { @@ -42,9 +41,12 @@ Popup { fillColor: Theme.mainBackgroundColor frameColor: Theme.mainColor - Behavior on zoomFactor { + Behavior on zoomFactor { enabled: !pinchHandler.active - NumberAnimation { duration: 100; easing.type: Easing.OutQuad; } + NumberAnimation { + duration: 100 + easing.type: Easing.OutQuad + } } } @@ -62,22 +64,22 @@ Popup { onActiveChanged: { if (active) { if (centroid.pressedButtons !== Qt.RightButton) { - drawingCanvas.strokeBegin(centroid.position, settings.strokeColor) + drawingCanvas.strokeBegin(centroid.position, settings.strokeColor); } else { - oldPosition = centroid.position + oldPosition = centroid.position; } } else { - drawingCanvas.strokeEnd(centroid.position) + drawingCanvas.strokeEnd(centroid.position); } } onCentroidChanged: { if (active) { if (centroid.pressedButtons === Qt.RightButton) { - drawingCanvas.pan(oldPosition, centroid.position) - oldPosition = centroid.position + drawingCanvas.pan(oldPosition, centroid.position); + oldPosition = centroid.position; } else { - drawingCanvas.strokeMove(centroid.position) + drawingCanvas.strokeMove(centroid.position); } } } @@ -95,15 +97,15 @@ Popup { onActiveChanged: { if (active) { - drawingCanvas.strokeBegin(centroid.position, settings.strokeColor) + drawingCanvas.strokeBegin(centroid.position, settings.strokeColor); } else { - drawingCanvas.strokeEnd(centroid.position) + drawingCanvas.strokeEnd(centroid.position); } } onCentroidChanged: { if (active) { - drawingCanvas.strokeMove(centroid.position) + drawingCanvas.strokeMove(centroid.position); } } } @@ -118,16 +120,16 @@ Popup { property point oldPosition - onScaleChanged: (delta) => { - if (active) { - drawingCanvas.zoomFactor = drawingCanvas.zoomFactor * delta - } - } - onTranslationChanged: (delta) => { - if (active) { - drawingCanvas.pan(Qt.point(0, 0), Qt.point(delta.x, delta.y)) - } - } + onScaleChanged: delta => { + if (active) { + drawingCanvas.zoomFactor = drawingCanvas.zoomFactor * delta; + } + } + onTranslationChanged: delta => { + if (active) { + drawingCanvas.pan(Qt.point(0, 0), Qt.point(delta.x, delta.y)); + } + } } WheelHandler { @@ -136,7 +138,9 @@ Popup { target: null grabPermissions: PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByItems - onWheel: (event) => { drawingCanvas.zoomFactor = drawingCanvas.zoomFactor * (event.angleDelta.y > 0 ? 1.25 : 0.75) } + onWheel: event => { + drawingCanvas.zoomFactor = drawingCanvas.zoomFactor * (event.angleDelta.y > 0 ? 1.25 : 0.75); + } } RowLayout { @@ -147,7 +151,7 @@ Popup { spacing: 3 Repeater { - model: [["#000000","#ffffff"], ["#ffffff","#000000"], ["#e41a1c","#e41a1c"], ["#377eb8","#377eb8"], ["#4daf4a","#4daf4a"]] + model: [["#000000", "#ffffff"], ["#ffffff", "#000000"], ["#e41a1c", "#e41a1c"], ["#377eb8", "#377eb8"], ["#4daf4a", "#4daf4a"]] QfToolButton { property color colorValue: modelData[0] @@ -159,19 +163,25 @@ Popup { scale: settings.strokeColor == colorValue ? 1 : 0.66 opacity: settings.strokeColor == colorValue ? 1 : 0.66 - Behavior on scale { + Behavior on scale { enabled: true - NumberAnimation { duration: 200; easing.type: Easing.OutQuad; } + NumberAnimation { + duration: 200 + easing.type: Easing.OutQuad + } } - Behavior on opacity { + Behavior on opacity { enabled: true - NumberAnimation { duration: 200; easing.type: Easing.OutQuad; } + NumberAnimation { + duration: 200 + easing.type: Easing.OutQuad + } } bgcolor: colorValue onClicked: { - settings.strokeColor = colorValue + settings.strokeColor = colorValue; } } } @@ -240,9 +250,9 @@ Popup { color: "#55000000" Text { + id: titleText anchors.centerIn: parent width: templateItem.width - id: titleText text: templateTitle font: Theme.tipFont color: "#ffffff" @@ -254,9 +264,9 @@ Popup { anchors.fill: parent onClicked: { if (templatePath !== '') { - drawingCanvas.createCanvasFromImage(templatePath) + drawingCanvas.createCanvasFromImage(templatePath); } else { - drawingCanvas.createBlankCanvas(mainWindow.width, mainWindow.height, "#ffffff") + drawingCanvas.createBlankCanvas(mainWindow.width, mainWindow.height, "#ffffff"); } } } @@ -279,8 +289,8 @@ Popup { round: true onClicked: { - sketcher.cancelled() - sketcher.close() + sketcher.cancelled(); + sketcher.close(); } } @@ -293,13 +303,13 @@ Popup { anchors.top: parent.top anchors.topMargin: mainWindow.sceneTopMargin + 5 - iconSource: Theme.getThemeVectorIcon( "ic_undo_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_undo_black_24dp") iconColor: "white" bgcolor: Theme.darkGraySemiOpaque round: true onClicked: { - drawingCanvas.undo() + drawingCanvas.undo(); } } @@ -312,20 +322,20 @@ Popup { anchors.top: parent.top anchors.topMargin: mainWindow.sceneTopMargin + 5 - iconSource: Theme.getThemeIcon( "ic_check_white_48dp" ) + iconSource: Theme.getThemeIcon("ic_check_white_48dp") iconColor: "white" bgcolor: drawingCanvas.isDirty ? Theme.mainColor : Theme.darkGraySemiOpaque round: true onClicked: { - sketcher.finished(drawingCanvas.save()) - sketcher.close() + sketcher.finished(drawingCanvas.save()); + sketcher.close(); } } } function loadImage(path) { - drawingCanvas.createCanvasFromImage(path) + drawingCanvas.createCanvasFromImage(path); } function clear() { diff --git a/src/qml/RelationCombobox.qml b/src/qml/RelationCombobox.qml index 4c6dda1197..da30dd5557 100644 --- a/src/qml/RelationCombobox.qml +++ b/src/qml/RelationCombobox.qml @@ -1,671 +1,686 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 Item { - id: relationCombobox - - property FeatureCheckListModel featureListModel - - property bool useCompleter: false - property bool useSearch: false - property bool allowAddFeature: false - property var relation: undefined - - Component.onCompleted: { - comboBox.currentIndex = featureListModel.findKey(value) - invalidWarning.visible = relation !== undefined ? !(relation.isValid) : false + id: relationCombobox + + property FeatureCheckListModel featureListModel + + property bool useCompleter: false + property bool useSearch: false + property bool allowAddFeature: false + property var relation: undefined + + Component.onCompleted: { + comboBox.currentIndex = featureListModel.findKey(value); + invalidWarning.visible = relation !== undefined ? !(relation.isValid) : false; + } + + anchors { + left: parent.left + right: parent.right + } + height: childrenRect.height + + property var currentKeyValue: value + property EmbeddedFeatureForm embeddedFeatureForm: embeddedPopup + + onCurrentKeyValueChanged: { + comboBox._cachedCurrentValue = currentKeyValue; + comboBox.currentIndex = featureListModel.findKey(currentKeyValue); + } + + EmbeddedFeatureForm { + id: addFeaturePopup + + embeddedLevel: form.embeddedLevel + 1 + digitizingToolbar: form.digitizingToolbar + codeReader: form.codeReader + + onFeatureSaved: { + var referencedValue = addFeaturePopup.attributeFormModel.attribute(relationCombobox.relation.resolveReferencedField(field.name)); + var index = featureListModel.findKey(referencedValue); + if (index < 0) { + // model not yet reloaded - keep the value and set it onModelReset + comboBox._cachedCurrentValue = referencedValue; + } else { + comboBox.currentIndex = index; + } + } + } + + Popup { + id: searchFeaturePopup + + parent: mainWindow.contentItem + x: Theme.popupScreenEdgeMargin + y: Theme.popupScreenEdgeMargin + z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature formes + width: parent.width - Theme.popupScreenEdgeMargin * 2 + height: parent.height - Theme.popupScreenEdgeMargin * 2 + padding: 0 + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + focus: visible + + onOpened: { + if (searchableText.typedFilter != '') { + searchField.text = searchableText.typedFilter; + } + if (resultsList.contentHeight > resultsList.height) { + searchField.forceActiveFocus(); + } } - anchors { - left: parent.left - right: parent.right + onClosed: { + searchField.text = ''; } - height: childrenRect.height - property var currentKeyValue: value - property EmbeddedFeatureForm embeddedFeatureForm: embeddedPopup + Page { + anchors.fill: parent - onCurrentKeyValueChanged: { - comboBox._cachedCurrentValue = currentKeyValue - comboBox.currentIndex = featureListModel.findKey(currentKeyValue) - } + header: QfPageHeader { + title: fieldLabel + showBackButton: false + showApplyButton: false + showCancelButton: true + onCancel: searchFeaturePopup.close() + } - EmbeddedFeatureForm { - id: addFeaturePopup + TextField { + id: searchField + z: 1 + anchors.left: parent.left + anchors.right: parent.right - embeddedLevel: form.embeddedLevel + 1 - digitizingToolbar: form.digitizingToolbar - codeReader: form.codeReader + placeholderText: !focus && displayText === '' ? qsTr("Search…") : '' + placeholderTextColor: Theme.mainColor - onFeatureSaved: { - var referencedValue = addFeaturePopup.attributeFormModel.attribute(relationCombobox.relation.resolveReferencedField(field.name)) - var index = featureListModel.findKey(referencedValue) - if ( index < 0 ) { - // model not yet reloaded - keep the value and set it onModelReset - comboBox._cachedCurrentValue = referencedValue - } else { - comboBox.currentIndex = index - } - } - } + height: fontMetrics.height * 2.5 + padding: 24 + bottomPadding: 9 + font: Theme.defaultFont + selectByMouse: true + verticalAlignment: TextInput.AlignVCenter - Popup { - id: searchFeaturePopup - - parent: mainWindow.contentItem - x: Theme.popupScreenEdgeMargin - y: Theme.popupScreenEdgeMargin - z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature formes - width: parent.width - Theme.popupScreenEdgeMargin * 2 - height: parent.height - Theme.popupScreenEdgeMargin * 2 - padding: 0 - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - focus: visible - - onOpened: { - if (searchableText.typedFilter != '') { - searchField.text = searchableText.typedFilter - } + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData - if (resultsList.contentHeight > resultsList.height) { - searchField.forceActiveFocus() + onDisplayTextChanged: { + featureListModel.searchTerm = searchField.displayText; } - } - onClosed: { - searchField.text = '' + Keys.onPressed: event => { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + if (featureListModel.rowCount() === 1) { + resultsList.itemAtIndex(0).performClick(); + searchFeaturePopup.close(); + } + } + } } - Page { - anchors.fill: parent - - header: QfPageHeader { - title: fieldLabel - showBackButton: false - showApplyButton: false - showCancelButton: true - onCancel: searchFeaturePopup.close() + QfToolButton { + id: clearButton + z: 1 + width: fontMetrics.height + height: fontMetrics.height + anchors { + top: searchField.top + right: searchField.right + topMargin: height - 7 + rightMargin: height - 7 } - TextField { - z: 1 - id: searchField - anchors.left: parent.left - anchors.right: parent.right - - placeholderText: !focus && displayText === '' ? qsTr("Search…") : '' - placeholderTextColor: Theme.mainColor + padding: 0 + iconSource: Theme.getThemeIcon("ic_clear_black_18dp") + iconColor: Theme.mainTextColor + bgcolor: "transparent" - height: fontMetrics.height * 2.5 - padding: 24 - bottomPadding: 9 - font: Theme.defaultFont - selectByMouse: true - verticalAlignment: TextInput.AlignVCenter + opacity: searchField.displayText.length > 0 ? 1 : 0.25 - inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData + onClicked: { + searchField.text = ''; + } + } - onDisplayTextChanged: { - featureListModel.searchTerm = searchField.displayText + ListView { + id: resultsList + anchors.left: parent.left + anchors.right: parent.right + anchors.top: searchField.bottom + model: featureListModel + width: parent.width + height: searchFeaturePopup.height - searchField.height - 50 + clip: true + + ScrollBar.vertical: ScrollBar { + policy: ScrollBar.AsNeeded + width: 6 + contentItem: Rectangle { + implicitWidth: 6 + implicitHeight: 25 + color: Theme.mainColor } + } + + section.property: featureListModel.groupField != "" ? "groupFieldValue" : "" + section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels + section.delegate: Component { + Rectangle { + width: parent.width + height: featureListModel.displayGroupName ? 30 : 5 + color: Theme.controlBackgroundAlternateColor - Keys.onPressed: (event)=> { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (featureListModel.rowCount() === 1) { - resultsList.itemAtIndex(0).performClick() - searchFeaturePopup.close() + Text { + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter } + font.bold: true + font.pointSize: Theme.resultFont.pointSize + color: Theme.mainTextColor + text: section + visible: featureListModel.displayGroupName } } } - QfToolButton { - id: clearButton - z: 1 - width: fontMetrics.height - height: fontMetrics.height - anchors { top: searchField.top; right: searchField.right; topMargin: height - 7; rightMargin: height - 7 } - - padding: 0 - iconSource: Theme.getThemeIcon("ic_clear_black_18dp") - iconColor: Theme.mainTextColor - bgcolor: "transparent" + delegate: Rectangle { + id: delegateRect - opacity: searchField.displayText.length > 0 ? 1 : 0.25 + property int idx: index + property string itemText: featureListModel.searchTerm != '' ? displayString.replace(new RegExp('(' + featureListModel.searchTerm + ')', "i"), '$1') : displayString - onClicked: { - searchField.text = ''; - } - } + anchors.margins: 10 + height: radioButton.visible ? radioButton.height : checkBoxButton.height + width: parent ? parent.width : undefined + color: model.checked ? Theme.mainColor : searchFeaturePopup.Material ? searchFeaturePopup.Material.dialogColor : Theme.mainBackgroundColor - ListView { - id: resultsList - anchors.left: parent.left - anchors.right: parent.right - anchors.top: searchField.bottom - model: featureListModel - width: parent.width - height: searchFeaturePopup.height - searchField.height - 50 - clip: true + Row { + RadioButton { + id: radioButton - ScrollBar.vertical: ScrollBar { - policy: ScrollBar.AsNeeded - width: 6 - contentItem: Rectangle { - implicitWidth: 6 - implicitHeight: 25 - color: Theme.mainColor - } - } + visible: !featureListModel.allowMulti + anchors.verticalCenter: parent.verticalCenter + width: resultsList.width - padding * 2 + padding: 12 - section.property: featureListModel.groupField != "" ? "groupFieldValue" : "" - section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels - section.delegate: Component { - Rectangle { - width:parent.width - height: featureListModel.displayGroupName ? 30 : 5 - color: Theme.controlBackgroundAlternateColor - - Text { - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } - font.bold: true - font.pointSize: Theme.resultFont.pointSize - color: Theme.mainTextColor - text: section - visible: featureListModel.displayGroupName - } - } - } + font.pointSize: Theme.defaultFont.pointSize + font.weight: model.checked ? Font.DemiBold : Font.Normal - delegate: Rectangle { - id: delegateRect - - property int idx: index - property string itemText: featureListModel.searchTerm != '' - ? displayString.replace(new RegExp('('+featureListModel.searchTerm+')', "i"), - '$1') - : displayString - - anchors.margins: 10 - height: radioButton.visible ? radioButton.height : checkBoxButton.height - width: parent ? parent.width : undefined - color: model.checked ? Theme.mainColor : searchFeaturePopup.Material ? searchFeaturePopup.Material.dialogColor : Theme.mainBackgroundColor - - Row { - RadioButton { - id: radioButton - - visible: !featureListModel.allowMulti - anchors.verticalCenter: parent.verticalCenter - width: resultsList.width - padding * 2 - padding: 12 - - font.pointSize: Theme.defaultFont.pointSize - font.weight: model.checked ? Font.DemiBold : Font.Normal - - checked: model.checked - indicator: Rectangle {} - - text: itemText - contentItem: Text { - text: parent.text - font: parent.font - width: parent.width - verticalAlignment: Text.AlignVCenter - leftPadding: parent.indicator.width + parent.spacing - elide: Text.ElideRight - color: featureListModel.searchTerm != '' ? Theme.secondaryTextColor : Theme.mainTextColor - textFormat: Text.RichText - } + checked: model.checked + indicator: Rectangle { } - CheckBox { - id: checkBoxButton - - visible: !!featureListModel.allowMulti - anchors.verticalCenter: parent.verticalCenter - width: resultsList.width - padding * 2 - padding: 12 - - font.pointSize: Theme.defaultFont.pointSize - font.weight: model.checked ? Font.DemiBold : Font.Normal - - text: itemText - contentItem: Text { - text: parent.text - font: parent.font - width: parent.width - verticalAlignment: Text.AlignVCenter - leftPadding: parent.indicator.width + parent.spacing - elide: Text.ElideRight - color: Theme.mainTextColor - textFormat: Text.RichText - } + text: itemText + contentItem: Text { + text: parent.text + font: parent.font + width: parent.width + verticalAlignment: Text.AlignVCenter + leftPadding: parent.indicator.width + parent.spacing + elide: Text.ElideRight + color: featureListModel.searchTerm != '' ? Theme.secondaryTextColor : Theme.mainTextColor + textFormat: Text.RichText } } + CheckBox { + id: checkBoxButton - /* bottom border */ - Rectangle { - anchors.bottom: parent.bottom - height: 1 - color: Theme.controlBorderColor - width: resultsList.width - } + visible: !!featureListModel.allowMulti + anchors.verticalCenter: parent.verticalCenter + width: resultsList.width - padding * 2 + padding: 12 + + font.pointSize: Theme.defaultFont.pointSize + font.weight: model.checked ? Font.DemiBold : Font.Normal - function performClick() { - model.checked = true; + text: itemText + contentItem: Text { + text: parent.text + font: parent.font + width: parent.width + verticalAlignment: Text.AlignVCenter + leftPadding: parent.indicator.width + parent.spacing + elide: Text.ElideRight + color: Theme.mainTextColor + textFormat: Text.RichText + } } } - MouseArea { - anchors.fill: parent - propagateComposedEvents: true - - onClicked: (mouse)=> { - var item = resultsList.itemAt(resultsList.contentX + mouse.x, resultsList.contentY + mouse.y) - if (!item) - return; + /* bottom border */ + Rectangle { + anchors.bottom: parent.bottom + height: 1 + color: Theme.controlBorderColor + width: resultsList.width + } - item.performClick() - model.checked = !model.checked + function performClick() { + model.checked = true; + } + } - if (!resultsList.model.allowMulti) { - searchFeaturePopup.close() - } + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + + onClicked: mouse => { + var item = resultsList.itemAt(resultsList.contentX + mouse.x, resultsList.contentY + mouse.y); + if (!item) + return; + item.performClick(); + model.checked = !model.checked; + if (!resultsList.model.allowMulti) { + searchFeaturePopup.close(); } } + } - onMovementStarted: { - Qt.inputMethod.hide() - } + onMovementStarted: { + Qt.inputMethod.hide(); } } } + } - RowLayout { - anchors { left: parent.left; right: parent.right } - - ComboBox { - id: comboBox - visible: !enabled || (!useSearch && !useCompleter && (relation !== undefined ? relation.isValid : true)) - Layout.fillWidth: true + RowLayout { + anchors { + left: parent.left + right: parent.right + } - property var _cachedCurrentValue + ComboBox { + id: comboBox + visible: !enabled || (!useSearch && !useCompleter && (relation !== undefined ? relation.isValid : true)) + Layout.fillWidth: true - model: featureListModel - textRole: 'display' - valueRole: 'keyFieldValue' + property var _cachedCurrentValue - onCurrentIndexChanged: { - var newValue = featureListModel.dataFromRowIndex(currentIndex, FeatureListModel.KeyFieldRole) - if (newValue !== currentKeyValue) { - valueChangeRequested(newValue, false) - } - } + model: featureListModel + textRole: 'display' + valueRole: 'keyFieldValue' - Connections { - target: featureListModel + onCurrentIndexChanged: { + var newValue = featureListModel.dataFromRowIndex(currentIndex, FeatureListModel.KeyFieldRole); + if (newValue !== currentKeyValue) { + valueChangeRequested(newValue, false); + } + } - function onModelReset() { - comboBox.currentIndex = featureListModel.findKey(comboBox._cachedCurrentValue) - } - } + Connections { + target: featureListModel - MouseArea { - anchors.fill: parent - propagateComposedEvents: true + function onModelReset() { + comboBox.currentIndex = featureListModel.findKey(comboBox._cachedCurrentValue); + } + } - onClicked: (mouse) => { mouse.accepted = false } - onPressed: (mouse) => { - forceActiveFocus() - mouse.accepted = false - } - onReleased: (mouse) => { mouse.accepted = false } - onDoubleClicked: (mouse) => { mouse.accepted = false } - onPositionChanged: (mouse) => { mouse.accepted = false } - onPressAndHold: (mouse) => { mouse.accepted = false } - } + MouseArea { + anchors.fill: parent + propagateComposedEvents: true - Component.onCompleted: { - comboBox.popup.z = 10000 // 1000s are embedded feature forms, use a higher value to insure popups always show above embedded feature formes - } + onClicked: mouse => { + mouse.accepted = false; + } + onPressed: mouse => { + forceActiveFocus(); + mouse.accepted = false; + } + onReleased: mouse => { + mouse.accepted = false; + } + onDoubleClicked: mouse => { + mouse.accepted = false; + } + onPositionChanged: mouse => { + mouse.accepted = false; + } + onPressAndHold: mouse => { + mouse.accepted = false; + } + } - font: Theme.defaultFont - - contentItem: Text { - leftPadding: enabled ? 5 : 0 - height: fontMetrics.height + 20 - text: comboBox.currentIndex == -1 && value !== undefined - ? '(' + value +')' - : comboBox.currentText - font: comboBox.font - color: value === undefined || !enabled ? Theme.mainTextDisabledColor : Theme.mainTextColor - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } + Component.onCompleted: { + comboBox.popup.z = 10000; // 1000s are embedded feature forms, use a higher value to insure popups always show above embedded feature formes + } - popup: Popup { - y: comboBox.height - 1 - width: comboBox.width - implicitHeight: contentItem.implicitHeight - padding: 1 - font: Theme.defaultFont - topMargin: mainWindow.sceneTopMargin - bottomMargin: mainWindow.sceneTopMargin - - contentItem: ListView { - clip: true - implicitHeight: Math.min(mainWindow.height - mainWindow.sceneTopMargin - mainWindow.sceneTopMargin, contentHeight) - model: comboBox.popup.visible ? comboBox.delegateModel : null - currentIndex: comboBox.highlightedIndex - - section.property: featureListModel.groupField != "" ? "groupFieldValue" : "" - section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels - section.delegate: Component { - Rectangle { - width:parent.width - height: featureListModel.displayGroupName ? 30 : 5 - color: Theme.mainBackgroundColor - - Text { - anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } - font.bold: true - font.pointSize: Theme.resultFont.pointSize - color: Theme.mainTextColor - text: section - visible: featureListModel.displayGroupName - } - } - } - - ScrollIndicator.vertical: ScrollIndicator { } - } - } + font: Theme.defaultFont + + contentItem: Text { + leftPadding: enabled ? 5 : 0 + height: fontMetrics.height + 20 + text: comboBox.currentIndex == -1 && value !== undefined ? '(' + value + ')' : comboBox.currentText + font: comboBox.font + color: value === undefined || !enabled ? Theme.mainTextDisabledColor : Theme.mainTextColor + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + popup: Popup { + y: comboBox.height - 1 + width: comboBox.width + implicitHeight: contentItem.implicitHeight + padding: 1 + font: Theme.defaultFont + topMargin: mainWindow.sceneTopMargin + bottomMargin: mainWindow.sceneTopMargin - background: Item { - implicitWidth: 120 - implicitHeight: 36 + contentItem: ListView { + clip: true + implicitHeight: Math.min(mainWindow.height - mainWindow.sceneTopMargin - mainWindow.sceneTopMargin, contentHeight) + model: comboBox.popup.visible ? comboBox.delegateModel : null + currentIndex: comboBox.highlightedIndex - Rectangle { - visible: !enabled - y: comboBox.height - 2 - width: comboBox.width - height: comboBox.activeFocus ? 2 : 1 - color: comboBox.activeFocus ? Theme.accentColor : Theme.accentLightColor - } + section.property: featureListModel.groupField != "" ? "groupFieldValue" : "" + section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels + section.delegate: Component { + Rectangle { + width: parent.width + height: featureListModel.displayGroupName ? 30 : 5 + color: Theme.mainBackgroundColor - Rectangle { - visible: enabled - anchors.fill: parent - border.color: comboBox.pressed ? Theme.accentColor : Theme.accentLightColor - border.width: comboBox.visualFocus ? 2 : 1 - color: Theme.controlBackgroundAlternateColor - radius: 2 + Text { + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter } + font.bold: true + font.pointSize: Theme.resultFont.pointSize + color: Theme.mainTextColor + text: section + visible: featureListModel.displayGroupName + } } - } + } - FontMetrics { - id: fontMetrics - font: comboBox.font + ScrollIndicator.vertical: ScrollIndicator { + } } + } - Rectangle { - id: searchable - visible: !comboBox.visible - height: fontMetrics.height + 12 - Layout.fillWidth: true - Layout.topMargin: 5 - Layout.bottomMargin: 5 - - Text { - id: searchableLabel - - property bool useCompleter: false - property string completer: '' - - anchors.verticalCenter: parent.verticalCenter - topPadding: 0 - leftPadding: 5 - rightPadding: 5 - bottomPadding: 0 - width: parent.width - dropDownArrowCanvas.width - dropDownArrowCanvas.anchors.rightMargin * 2 - height: fontMetrics.height + 12 - text: useCompleter ? completer : comboBox.displayText - font: comboBox.font - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - textFormat: Text.RichText - clip: true - elide: Text.ElideRight - - color: value === undefined || !enabled ? Theme.mainTextDisabledColor : searchableText.text === '' ? Theme.mainTextColor : Theme.mainTextDisabledColor - } - - TextField { - id: searchableText - - property string typedFilter: '' - - anchors.verticalCenter: parent.verticalCenter - topPadding: 0 - rightPadding: 5 - leftPadding: 5 - bottomPadding: 0 - topInset: 0 - bottomInset: 0 - width: parent.width - dropDownArrowCanvas.width - dropDownArrowCanvas.anchors.rightMargin * 2 - text: '' - font: comboBox.font - horizontalAlignment: TextInput.AlignLeft - verticalAlignment: TextInput.AlignVCenter + background: Item { + implicitWidth: 120 + implicitHeight: 36 - color: Theme.mainTextColor - background: Rectangle { - color: "transparent" - border.color: "transparent" - border.width: 0 - } + Rectangle { + visible: !enabled + y: comboBox.height - 2 + width: comboBox.width + height: comboBox.activeFocus ? 2 : 1 + color: comboBox.activeFocus ? Theme.accentColor : Theme.accentLightColor + } - inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData - - onDisplayTextChanged: { - if (activeFocus) { - if (text != comboBox.displayText) { - var trimmedText = text.trim() - var matches = featureListModel.findDisplayValueMatches(trimmedText) - if (matches.length > 0) { - var remainder = featureListModel.dataFromRowIndex(matches[0], featureListModel.DisplayStringRole).substring(trimmedText.length) - searchableLabel.completer = '' + trimmedText + '' + remainder + '' - color = Theme.mainTextColor - } else { - searchableLabel.completer = '' - color = Theme.warningColor - } - } else { - searchableLabel.completer = '' - } - } - } + Rectangle { + visible: enabled + anchors.fill: parent + border.color: comboBox.pressed ? Theme.accentColor : Theme.accentLightColor + border.width: comboBox.visualFocus ? 2 : 1 + color: Theme.controlBackgroundAlternateColor + radius: 2 + } + } + } - onActiveFocusChanged: { - searchableLabel.useCompleter = activeFocus - if (activeFocus) { - if (text === '') { - if (!featureListModel.addNull || comboBox.currentIndex != 0) { - text = comboBox.displayText - color = Theme.mainTextColor - } - searchableLabel.completer = '' - } - } else { - if (!isLastKeyPressedReturn) { - if (text === '' && featureListModel.addNull) { - comboBox.currentIndex = 0; - searchableLabel.completer = comboBox.displayText - } else { - applyAutoCompletion(true) - } - } else if (text !== '') { - // the last return-triggered auto completion didn't match anything, we have to reset the item state - text = '' - searchableLabel.completer = comboBox.displayText - } - } - } + FontMetrics { + id: fontMetrics + font: comboBox.font + } - property bool isLastKeyPressedReturn: false - Keys.onPressed: (event)=> { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (!isLastKeyPressedReturn) { - applyAutoCompletion() - } - isLastKeyPressedReturn = true - } else { - isLastKeyPressedReturn = false - } - } + Rectangle { + id: searchable + visible: !comboBox.visible + height: fontMetrics.height + 12 + Layout.fillWidth: true + Layout.topMargin: 5 + Layout.bottomMargin: 5 + + Text { + id: searchableLabel + + property bool useCompleter: false + property string completer: '' + + anchors.verticalCenter: parent.verticalCenter + topPadding: 0 + leftPadding: 5 + rightPadding: 5 + bottomPadding: 0 + width: parent.width - dropDownArrowCanvas.width - dropDownArrowCanvas.anchors.rightMargin * 2 + height: fontMetrics.height + 12 + text: useCompleter ? completer : comboBox.displayText + font: comboBox.font + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + textFormat: Text.RichText + clip: true + elide: Text.ElideRight + + color: value === undefined || !enabled ? Theme.mainTextDisabledColor : searchableText.text === '' ? Theme.mainTextColor : Theme.mainTextDisabledColor + } - function applyAutoCompletion(resetIfNone = false) { - var trimmedText = text.trim(); - var matches = featureListModel.findDisplayValueMatches(trimmedText) - if (matches.length > 0) { - text = '' - comboBox.currentIndex = matches[0] - searchableLabel.completer = comboBox.displayText - - if (matches.length > 1) { - // remember the typed filter in case users want to see the multiple hits by clicking on the search button - typedFilter = trimmedText - searchableTimer.restart() - } - } else if (resetIfNone) { - text = '' - searchableLabel.completer = comboBox.displayText - } - } + TextField { + id: searchableText + + property string typedFilter: '' + + anchors.verticalCenter: parent.verticalCenter + topPadding: 0 + rightPadding: 5 + leftPadding: 5 + bottomPadding: 0 + topInset: 0 + bottomInset: 0 + width: parent.width - dropDownArrowCanvas.width - dropDownArrowCanvas.anchors.rightMargin * 2 + text: '' + font: comboBox.font + horizontalAlignment: TextInput.AlignLeft + verticalAlignment: TextInput.AlignVCenter + + color: Theme.mainTextColor + background: Rectangle { + color: "transparent" + border.color: "transparent" + border.width: 0 + } - Timer { - id: searchableTimer - interval: 500 - onTriggered: { - searchableText.typedFilter = '' - } - } + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData + + onDisplayTextChanged: { + if (activeFocus) { + if (text != comboBox.displayText) { + var trimmedText = text.trim(); + var matches = featureListModel.findDisplayValueMatches(trimmedText); + if (matches.length > 0) { + var remainder = featureListModel.dataFromRowIndex(matches[0], featureListModel.DisplayStringRole).substring(trimmedText.length); + searchableLabel.completer = '' + trimmedText + '' + remainder + ''; + color = Theme.mainTextColor; + } else { + searchableLabel.completer = ''; + color = Theme.warningColor; + } + } else { + searchableLabel.completer = ''; } + } + } - Canvas { - id: dropDownArrowCanvas - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - width: 30 - height: 15 - contextType: "2d" - visible: !useCompleter - - onPaint: { - if (!context) { - return - } - context.reset(); - context.moveTo(10, 5); - context.lineTo(20, 5); - context.lineTo(15, 10); - context.closePath(); - context.fillStyle = !enabled ? Theme.mainTextDisabledColor : Theme.mainTextColor - context.fill(); - } - - onEnabledChanged: requestPaint() + onActiveFocusChanged: { + searchableLabel.useCompleter = activeFocus; + if (activeFocus) { + if (text === '') { + if (!featureListModel.addNull || comboBox.currentIndex != 0) { + text = comboBox.displayText; + color = Theme.mainTextColor; + } + searchableLabel.completer = ''; } + } else { + if (!isLastKeyPressedReturn) { + if (text === '' && featureListModel.addNull) { + comboBox.currentIndex = 0; + searchableLabel.completer = comboBox.displayText; + } else { + applyAutoCompletion(true); + } + } else if (text !== '') { + // the last return-triggered auto completion didn't match anything, we have to reset the item state + text = ''; + searchableLabel.completer = comboBox.displayText; + } + } + } - border.color: comboBox.pressed ? Theme.accentColor : Theme.accentLightColor - border.width: comboBox.visualFocus ? 2 : 1 - color: Theme.controlBackgroundAlternateColor - radius: 2 - - MouseArea { - enabled: !useCompleter - anchors.fill: parent + property bool isLastKeyPressedReturn: false + Keys.onPressed: event => { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + if (!isLastKeyPressedReturn) { + applyAutoCompletion(); + } + isLastKeyPressedReturn = true; + } else { + isLastKeyPressedReturn = false; + } + } - onClicked: (mouse) => { - mouse.accepted = true - searchFeaturePopup.open() - } + function applyAutoCompletion(resetIfNone = false) { + var trimmedText = text.trim(); + var matches = featureListModel.findDisplayValueMatches(trimmedText); + if (matches.length > 0) { + text = ''; + comboBox.currentIndex = matches[0]; + searchableLabel.completer = comboBox.displayText; + if (matches.length > 1) { + // remember the typed filter in case users want to see the multiple hits by clicking on the search button + typedFilter = trimmedText; + searchableTimer.restart(); } + } else if (resetIfNone) { + text = ''; + searchableLabel.completer = comboBox.displayText; + } } - QfToolButton { - id: searchButton + Timer { + id: searchableTimer + interval: 500 + onTriggered: { + searchableText.typedFilter = ''; + } + } + } - Layout.preferredWidth: enabled ? 48 : 0 - Layout.preferredHeight: 48 + Canvas { + id: dropDownArrowCanvas + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + width: 30 + height: 15 + contextType: "2d" + visible: !useCompleter + + onPaint: { + if (!context) { + return; + } + context.reset(); + context.moveTo(10, 5); + context.lineTo(20, 5); + context.lineTo(15, 10); + context.closePath(); + context.fillStyle = !enabled ? Theme.mainTextDisabledColor : Theme.mainTextColor; + context.fill(); + } - bgcolor: "transparent" - iconSource: Theme.getThemeIcon("ic_baseline_search_black") - iconColor: Theme.mainTextColor + onEnabledChanged: requestPaint() + } - visible: enabled + border.color: comboBox.pressed ? Theme.accentColor : Theme.accentLightColor + border.width: comboBox.visualFocus ? 2 : 1 + color: Theme.controlBackgroundAlternateColor + radius: 2 - onClicked: { - searchFeaturePopup.open() - } - } + MouseArea { + enabled: !useCompleter + anchors.fill: parent - QfToolButton { - id: addFeatureButton + onClicked: mouse => { + mouse.accepted = true; + searchFeaturePopup.open(); + } + } + } - Layout.preferredWidth: comboBox.enabled ? 48 : 0 - Layout.preferredHeight: 48 + QfToolButton { + id: searchButton - bgcolor: "transparent" - opacity: enabled ? 1 : 0.3 - iconSource: Theme.getThemeIcon("ic_add_black_48dp") - iconColor: Theme.mainTextColor + Layout.preferredWidth: enabled ? 48 : 0 + Layout.preferredHeight: 48 - visible: enabled && allowAddFeature && relation !== undefined && relation.isValid + bgcolor: "transparent" + iconSource: Theme.getThemeIcon("ic_baseline_search_black") + iconColor: Theme.mainTextColor - onClicked: { - embeddedPopup.state = 'Add' - embeddedPopup.currentLayer = relationCombobox.relation ? relationCombobox.relation.referencedLayer : null - embeddedPopup.open() - } - } + visible: enabled - Text { - id: invalidWarning - visible: false - text: qsTr( "Invalid relation") - color: Theme.errorColor - } + onClicked: { + searchFeaturePopup.open(); + } } - EmbeddedFeatureForm { - id: embeddedPopup + QfToolButton { + id: addFeatureButton - embeddedLevel: form.embeddedLevel + 1 - digitizingToolbar: form.digitizingToolbar - codeReader: form.codeReader + Layout.preferredWidth: comboBox.enabled ? 48 : 0 + Layout.preferredHeight: 48 - onFeatureSaved: { - var referencedValue = embeddedPopup.attributeFormModel.attribute(relationCombobox.relation.resolveReferencedField(field.name)) - var index = featureListModel.findKey(referencedValue) - if ( ( featureListModel.addNull == true && index < 1 ) || index < 0 ) { - // model not yet reloaded - keep the value and set it onModelReset - comboBox._cachedCurrentValue = referencedValue - } else { - comboBox.currentIndex = index - } - } + bgcolor: "transparent" + opacity: enabled ? 1 : 0.3 + iconSource: Theme.getThemeIcon("ic_add_black_48dp") + iconColor: Theme.mainTextColor + + visible: enabled && allowAddFeature && relation !== undefined && relation.isValid + + onClicked: { + embeddedPopup.state = 'Add'; + embeddedPopup.currentLayer = relationCombobox.relation ? relationCombobox.relation.referencedLayer : null; + embeddedPopup.open(); + } + } + + Text { + id: invalidWarning + visible: false + text: qsTr("Invalid relation") + color: Theme.errorColor + } + } + + EmbeddedFeatureForm { + id: embeddedPopup + + embeddedLevel: form.embeddedLevel + 1 + digitizingToolbar: form.digitizingToolbar + codeReader: form.codeReader + + onFeatureSaved: { + var referencedValue = embeddedPopup.attributeFormModel.attribute(relationCombobox.relation.resolveReferencedField(field.name)); + var index = featureListModel.findKey(referencedValue); + if ((featureListModel.addNull == true && index < 1) || index < 0) { + // model not yet reloaded - keep the value and set it onModelReset + comboBox._cachedCurrentValue = referencedValue; + } else { + comboBox.currentIndex = index; + } } + } } diff --git a/src/qml/Rubberband.qml b/src/qml/Rubberband.qml index 9cc146ce11..cb22039288 100644 --- a/src/qml/Rubberband.qml +++ b/src/qml/Rubberband.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import Theme 1.0 import org.qfield 1.0 import org.qgis 1.0 @@ -26,9 +25,7 @@ RubberbandShape { strokeColor: rubberbandShape.color strokeWidth: rubberbandShape.lineWidth / rubberbandShape.scale strokeStyle: ShapePath.SolidLine - fillColor: rubberbandShape.polylinesType === Qgis.GeometryType.Polygon - ? Qt.hsla(strokeColor.hslHue, strokeColor.hslSaturation, strokeColor.hslLightness, 0.25) - : "transparent" + fillColor: rubberbandShape.polylinesType === Qgis.GeometryType.Polygon ? Qt.hsla(strokeColor.hslHue, strokeColor.hslSaturation, strokeColor.hslLightness, 0.25) : "transparent" joinStyle: ShapePath.RoundJoin capStyle: ShapePath.RoundCap diff --git a/src/qml/ScaleBar.qml b/src/qml/ScaleBar.qml index f32b10071f..c246d8fce3 100644 --- a/src/qml/ScaleBar.qml +++ b/src/qml/ScaleBar.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Shapes 1.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 @@ -14,9 +13,9 @@ Item { height: childrenRect.height ScaleBarMeasurement { - id: measurement - project: qgisProject - referenceScreenLength: 300 + id: measurement + project: qgisProject + referenceScreenLength: 300 } Text { @@ -29,12 +28,13 @@ Item { styleColor: "#CCFFFFFF" states: State { - name: "narrow"; when: label.width > bar.width - AnchorChanges { - target: label - anchors.horizontalCenter: undefined - anchors.left: bar.left - } + name: "narrow" + when: label.width > bar.width + AnchorChanges { + target: label + anchors.horizontalCenter: undefined + anchors.left: bar.left + } } text: measurement.label @@ -51,16 +51,20 @@ Item { strokeWidth: barLine.strokeWidth + 1.5 strokeColor: "#CCFFFFFF" fillColor: "transparent" - startX: 0; startY: 0 + startX: 0 + startY: 0 PathLine { - x: 0; y: bar.height + x: 0 + y: bar.height } PathLine { - x: measurement.screenLength; y: bar.height + x: measurement.screenLength + y: bar.height } PathLine { - x: measurement.screenLength; y: 0 + x: measurement.screenLength + y: 0 } } @@ -69,16 +73,20 @@ Item { strokeWidth: scaleBar.lineWidth strokeColor: "#000000" fillColor: "transparent" - startX: 0; startY: 0 + startX: 0 + startY: 0 PathLine { - x: 0; y: bar.height + x: 0 + y: bar.height } PathLine { - x: measurement.screenLength; y: bar.height + x: measurement.screenLength + y: bar.height } PathLine { - x: measurement.screenLength; y: 0 + x: measurement.screenLength + y: 0 } } } diff --git a/src/qml/ScreenLocker.qml b/src/qml/ScreenLocker.qml index 3087a5b6dd..87fe466e71 100644 --- a/src/qml/ScreenLocker.qml +++ b/src/qml/ScreenLocker.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 Item { @@ -14,10 +13,10 @@ Item { onEnabledChanged: { if (enabled) { - unlockNode.opacity = 1 - unlockOpacityTimer.restart() + unlockNode.opacity = 1; + unlockOpacityTimer.restart(); } else { - unlockNode.opacity = 0 + unlockNode.opacity = 0; } } @@ -63,8 +62,8 @@ Item { anchors.fill: parent onPressed: { - unlockNode.opacity = 1 - unlockOpacityTimer.restart() + unlockNode.opacity = 1; + unlockOpacityTimer.restart(); } } @@ -82,8 +81,10 @@ Item { radius: width / 2 opacity: unlockHandler.entered ? 1 : 0 - Behavior on opacity { - NumberAnimation { duration: 250 } + Behavior on opacity { + NumberAnimation { + duration: 250 + } } } @@ -108,17 +109,15 @@ Item { height: 36 fillMode: Image.PreserveAspectFit smooth: true - source: unlockHandler.unlocked - ? Theme.getThemeVectorIcon('ic_lock_open_green_24dp') - : unlockHandler.entered - ? Theme.getThemeVectorIcon('ic_lock_open_white_24dp') - : Theme.getThemeVectorIcon('ic_lock_white_24dp') + source: unlockHandler.unlocked ? Theme.getThemeVectorIcon('ic_lock_open_green_24dp') : unlockHandler.entered ? Theme.getThemeVectorIcon('ic_lock_open_white_24dp') : Theme.getThemeVectorIcon('ic_lock_white_24dp') sourceSize.width: 96 sourceSize.height: 96 } - Behavior on opacity { - NumberAnimation { duration: 250 } + Behavior on opacity { + NumberAnimation { + duration: 250 + } } } @@ -137,40 +136,40 @@ Item { onActiveChanged: { if (active) { - var x = centroid.position.x - centerX - var y = centroid.position.y - centerY - var distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) + var x = centroid.position.x - centerX; + var y = centroid.position.y - centerY; + var distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); if (distance < screenLocker.threshold / 3) { - unlockOpacityTimer.stop() - entered = true + unlockOpacityTimer.stop(); + entered = true; } } else { if (unlocked) { - screenLocker.enabled = false + screenLocker.enabled = false; } else { - unlockOpacityTimer.restart() + unlockOpacityTimer.restart(); } - entered = false - unlocked = false - unlockNode.offsetX = 0 - unlockNode.offsetY = 0 + entered = false; + unlocked = false; + unlockNode.offsetX = 0; + unlockNode.offsetY = 0; } } onCentroidChanged: { if (entered) { - var x = centroid.position.x - centerX - var y = centroid.position.y - centerY - var distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) + var x = centroid.position.x - centerX; + var y = centroid.position.y - centerY; + var distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); if (distance < screenLocker.threshold) { - unlockNode.offsetX = x - unlockNode.offsetY = y - unlocked = false + unlockNode.offsetX = x; + unlockNode.offsetY = y; + unlocked = false; } else { - var angle = Math.atan2(x, y) - unlockNode.offsetX = screenLocker.threshold * Math.sin(angle) - unlockNode.offsetY = screenLocker.threshold * Math.cos(angle) - unlocked = true + var angle = Math.atan2(x, y); + unlockNode.offsetX = screenLocker.threshold * Math.sin(angle); + unlockNode.offsetY = screenLocker.threshold * Math.cos(angle); + unlocked = true; } } } @@ -183,8 +182,7 @@ Item { running: false onTriggered: { - unlockNode.opacity = 0 + unlockNode.opacity = 0; } } } - diff --git a/src/qml/SensorInformationView.qml b/src/qml/SensorInformationView.qml index 7c061e0514..b45a33edcc 100644 --- a/src/qml/SensorInformationView.qml +++ b/src/qml/SensorInformationView.qml @@ -1,7 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -17,9 +16,7 @@ Rectangle { property color backgroundColor: Theme.mainBackgroundColor property color alternateBackgroundColor: Theme.sensorBackgroundColor property color textColor: Theme.mainTextColor - property real contentHeight: parent.width > 620 - ? cellHeight * Math.ceil(grid.count / 3) - : cellHeight * Math.ceil(grid.count / 2) + property real contentHeight: parent.width > 620 ? cellHeight * Math.ceil(grid.count / 3) : cellHeight * Math.ceil(grid.count / 2) width: parent.width anchors.margins: 20 @@ -32,9 +29,7 @@ Rectangle { Layout.preferredHeight: childrenRect.height width: parent.width height: parent.height - cellWidth: parent.width > 620 - ? parent.width / 3 - : parent.width / 2 + cellWidth: parent.width > 620 ? parent.width / 3 : parent.width / 2 cellHeight: sensorInformationView.cellHeight flow: GridLayout.TopToBottom @@ -65,7 +60,7 @@ Rectangle { Layout.fillWidth: true font: Theme.tipFont color: sensorInformationView.textColor - text: SensorLastValue ? (SensorLastValue + '').trim() : qsTr( "N/A" ) + text: SensorLastValue ? (SensorLastValue + '').trim() : qsTr("N/A") verticalAlignment: Text.AlignVCenter elide: Text.ElideRight } diff --git a/src/qml/SerialPortDeviceChooser.qml b/src/qml/SerialPortDeviceChooser.qml index ace941640d..6abe8f29ad 100644 --- a/src/qml/SerialPortDeviceChooser.qml +++ b/src/qml/SerialPortDeviceChooser.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 - import Theme 1.0 Item { @@ -22,8 +20,10 @@ Item { } function getSettings() { - return {'name': deviceName, - 'address': deviceAddress}; + return { + "name": deviceName, + "address": deviceAddress + }; } Component.onCompleted: { @@ -38,9 +38,7 @@ Item { Label { Layout.fillWidth: true - text: serialPortComboBox.count > 0 - ? qsTr( "Select the serial port from the list below:" ) - : qsTr( "No serial ports detected, refresh the list once a device is connected." ) + text: serialPortComboBox.count > 0 ? qsTr("Select the serial port from the list below:") : qsTr("No serial ports detected, refresh the list once a device is connected.") font: Theme.defaultFont wrapMode: Text.WordWrap @@ -82,23 +80,23 @@ Item { } Label { - id: serialPortName - Layout.fillWidth: true - visible: deviceAddress != '' - font: Theme.defaultFont - color: Theme.secondaryTextColor - text: qsTr('Serial port display name:') + '\n ' + deviceName - wrapMode: Text.WordWrap + id: serialPortName + Layout.fillWidth: true + visible: deviceAddress != '' + font: Theme.defaultFont + color: Theme.secondaryTextColor + text: qsTr('Serial port display name:') + '\n ' + deviceName + wrapMode: Text.WordWrap } Label { - id: serialPortAddress - Layout.fillWidth: true - visible: deviceAddress != '' - font: Theme.defaultFont - color: Theme.secondaryTextColor - text: qsTr('Serial port address:') + '\n ' + deviceAddress - wrapMode: Text.WordWrap + id: serialPortAddress + Layout.fillWidth: true + visible: deviceAddress != '' + font: Theme.defaultFont + color: Theme.secondaryTextColor + text: qsTr('Serial port address:') + '\n ' + deviceAddress + wrapMode: Text.WordWrap } } } diff --git a/src/qml/TcpDeviceChooser.qml b/src/qml/TcpDeviceChooser.qml index fcd919af08..360667c3fb 100644 --- a/src/qml/TcpDeviceChooser.qml +++ b/src/qml/TcpDeviceChooser.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 - import Theme 1.0 Item { @@ -22,8 +20,10 @@ Item { } function getSettings() { - return {'address': deviceAddress.trim(), - 'port': parseInt(devicePort)}; + return { + "address": deviceAddress.trim(), + "port": parseInt(devicePort) + }; } GridLayout { @@ -34,32 +34,32 @@ Item { Label { Layout.fillWidth: true - text: qsTr( "Address:" ) + text: qsTr("Address:") font: Theme.defaultFont wrapMode: Text.WordWrap } QfTextField { - id: tcpDeviceAddress - Layout.fillWidth: true - font: Theme.defaultFont - text: '127.0.0.1' - inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase + id: tcpDeviceAddress + Layout.fillWidth: true + font: Theme.defaultFont + text: '127.0.0.1' + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase } Label { - Layout.fillWidth: true - text: qsTr( "Port:" ) - font: Theme.defaultFont - wrapMode: Text.WordWrap + Layout.fillWidth: true + text: qsTr("Port:") + font: Theme.defaultFont + wrapMode: Text.WordWrap } QfTextField { - id: tcpDevicePort - Layout.fillWidth: true - font: Theme.defaultFont - text: '9000' - inputMethodHints: Qt.ImhFormattedNumbersOnly + id: tcpDevicePort + Layout.fillWidth: true + font: Theme.defaultFont + text: '9000' + inputMethodHints: Qt.ImhFormattedNumbersOnly } } } diff --git a/src/qml/TemporalProperties.qml b/src/qml/TemporalProperties.qml index f6be20c358..47213d792c 100644 --- a/src/qml/TemporalProperties.qml +++ b/src/qml/TemporalProperties.qml @@ -1,175 +1,167 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 Popup { - id: popup - - property MapSettings mapSettings - - width: Math.min(350, mainWindow.width - Theme.popupScreenEdgeMargin ) - x: (parent.width - width) / 2 - y: (parent.height - height) / 2 - padding: 0 - - Page { - width: parent.width - padding: 10 - header: Label { - padding: 10 - topPadding: 15 - bottomPadding: 0 - width: parent.width - 20 - text: qsTr('Temporal Properties') - font: Theme.strongFont - color: Theme.mainColor - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } + id: popup + + property MapSettings mapSettings + + width: Math.min(350, mainWindow.width - Theme.popupScreenEdgeMargin) + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + padding: 0 + + Page { + width: parent.width + padding: 10 + header: Label { + padding: 10 + topPadding: 15 + bottomPadding: 0 + width: parent.width - 20 + text: qsTr('Temporal Properties') + font: Theme.strongFont + color: Theme.mainColor + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } - ColumnLayout { - spacing: 4 - width: parent.width - - CheckBox { - id: isTemporalCheckBox - Layout.fillWidth: true - topPadding: 5 - bottomPadding: 5 - text: qsTr('Enable temporal filter') - font: Theme.defaultFont - // visible for all layer tree items but nonspatial vector layer - indicator.height: 16 - indicator.width: 16 - indicator.implicitHeight: 24 - indicator.implicitWidth: 24 - checked: mapCanvas.mapSettings.isTemporal - - onClicked: { - mapCanvas.mapSettings.isTemporal = !mapCanvas.mapSettings.isTemporal; - } + ColumnLayout { + spacing: 4 + width: parent.width + + CheckBox { + id: isTemporalCheckBox + Layout.fillWidth: true + topPadding: 5 + bottomPadding: 5 + text: qsTr('Enable temporal filter') + font: Theme.defaultFont + // visible for all layer tree items but nonspatial vector layer + indicator.height: 16 + indicator.width: 16 + indicator.implicitHeight: 24 + indicator.implicitWidth: 24 + checked: mapCanvas.mapSettings.isTemporal + + onClicked: { + mapCanvas.mapSettings.isTemporal = !mapCanvas.mapSettings.isTemporal; + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + + QfTextField { + id: beginField + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 + + enabled: mapCanvas.mapSettings.isTemporal + font: Theme.defaultFont + horizontalAlignment: TextInput.AlignHCenter + + inputMethodHints: Qt.ImhDigitsOnly + inputMask: "9999-99-99 99:99:99;_" + + text: Qt.formatDateTime(mapCanvas.mapSettings.temporalBegin, "yyyy-MM-dd HH:mm:ss") + + onTextEdited: { + var newDate = Date.fromLocaleString(Qt.locale(), beginField.text, "yyyy-MM-dd HH:mm:ss"); + if (newDate.toLocaleString() !== "") { + mapCanvas.mapSettings.temporalBegin = newDate; + } else { + mapCanvas.mapSettings.temporalBegin = Date.fromLocaleString(''); } + } + } - RowLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - - QfTextField { - id: beginField - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - - enabled: mapCanvas.mapSettings.isTemporal - font: Theme.defaultFont - horizontalAlignment: TextInput.AlignHCenter - - inputMethodHints: Qt.ImhDigitsOnly - inputMask: "9999-99-99 99:99:99;_" - - text: Qt.formatDateTime(mapCanvas.mapSettings.temporalBegin, "yyyy-MM-dd HH:mm:ss") - - onTextEdited: { - var newDate = Date.fromLocaleString(Qt.locale(), beginField.text, "yyyy-MM-dd HH:mm:ss") - if ( newDate.toLocaleString() !== "" ) - { - mapCanvas.mapSettings.temporalBegin = newDate - } - else - { - mapCanvas.mapSettings.temporalBegin = Date.fromLocaleString('') - } - } - } - - QfToolButton { - iconSource: Theme.getThemeIcon("ic_calendar_month_black_24dp") - iconColor: Theme.mainTextColor - bgcolor: "transparent" - onClicked: { - calendarPanel.selectedDate = mapCanvas.mapSettings.temporalBegin - calendarPanel.temporalField = 'begin'; - calendarPanel.open(); - } - } - } + QfToolButton { + iconSource: Theme.getThemeIcon("ic_calendar_month_black_24dp") + iconColor: Theme.mainTextColor + bgcolor: "transparent" + onClicked: { + calendarPanel.selectedDate = mapCanvas.mapSettings.temporalBegin; + calendarPanel.temporalField = 'begin'; + calendarPanel.open(); + } + } + } - Label { - Layout.fillWidth: true + Label { + Layout.fillWidth: true - enabled: mapCanvas.mapSettings.isTemporal - font: Theme.defaultFont - horizontalAlignment: TextInput.AlignHCenter - text: '≤ t ≤' - } + enabled: mapCanvas.mapSettings.isTemporal + font: Theme.defaultFont + horizontalAlignment: TextInput.AlignHCenter + text: '≤ t ≤' + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 20 + Layout.rightMargin: 20 - RowLayout { - Layout.fillWidth: true - Layout.leftMargin: 20 - Layout.rightMargin: 20 - - - QfTextField { - id: endField - Layout.fillWidth: true - - enabled: mapCanvas.mapSettings.isTemporal - font: Theme.defaultFont - horizontalAlignment: TextInput.AlignHCenter - - inputMethodHints: Qt.ImhDigitsOnly - inputMask: "9999-99-99 99:99:99;_" - - text: Qt.formatDateTime(mapCanvas.mapSettings.temporalEnd, "yyyy-MM-dd HH:mm:ss") - - onTextEdited: { - var newDate = Date.fromLocaleString(Qt.locale(), endField.text, "yyyy-MM-dd HH:mm:ss") - if ( newDate.toLocaleString() !== "" ) - { - mapCanvas.mapSettings.temporalEnd = newDate - } - else - { - mapCanvas.mapSettings.temporalEnd = Date.fromLocaleString('') - } - } - } - - QfToolButton { - iconSource: Theme.getThemeIcon("ic_calendar_month_black_24dp") - iconColor: Theme.mainTextColor - bgcolor: "transparent" - onClicked: { - calendarPanel.selectedDate = mapCanvas.mapSettings.temporalEnd - calendarPanel.temporalField = 'end'; - calendarPanel.open(); - } - } + QfTextField { + id: endField + Layout.fillWidth: true + + enabled: mapCanvas.mapSettings.isTemporal + font: Theme.defaultFont + horizontalAlignment: TextInput.AlignHCenter + + inputMethodHints: Qt.ImhDigitsOnly + inputMask: "9999-99-99 99:99:99;_" + + text: Qt.formatDateTime(mapCanvas.mapSettings.temporalEnd, "yyyy-MM-dd HH:mm:ss") + + onTextEdited: { + var newDate = Date.fromLocaleString(Qt.locale(), endField.text, "yyyy-MM-dd HH:mm:ss"); + if (newDate.toLocaleString() !== "") { + mapCanvas.mapSettings.temporalEnd = newDate; + } else { + mapCanvas.mapSettings.temporalEnd = Date.fromLocaleString(''); } + } } + + QfToolButton { + iconSource: Theme.getThemeIcon("ic_calendar_month_black_24dp") + iconColor: Theme.mainTextColor + bgcolor: "transparent" + onClicked: { + calendarPanel.selectedDate = mapCanvas.mapSettings.temporalEnd; + calendarPanel.temporalField = 'end'; + calendarPanel.open(); + } + } + } } + } - QfCalendarPanel { - id: calendarPanel + QfCalendarPanel { + id: calendarPanel - property string temporalField: '' + property string temporalField: '' - isDateTime: true + isDateTime: true - onDateTimePicked: { - if (temporalField == 'begin') { - mapCanvas.mapSettings.temporalBegin = date - beginField.text = Qt.formatDateTime(date, "yyyy-MM-dd HH:mm:ss"); - } else if (temporalField == 'end') { - mapCanvas.mapSettings.temporalEnd = date - endField.text = Qt.formatDateTime(date, "yyyy-MM-dd HH:mm:ss"); - } - temporalField = ''; - } + onDateTimePicked: { + if (temporalField == 'begin') { + mapCanvas.mapSettings.temporalBegin = date; + beginField.text = Qt.formatDateTime(date, "yyyy-MM-dd HH:mm:ss"); + } else if (temporalField == 'end') { + mapCanvas.mapSettings.temporalEnd = date; + endField.text = Qt.formatDateTime(date, "yyyy-MM-dd HH:mm:ss"); + } + temporalField = ''; } + } } diff --git a/src/qml/Toast.qml b/src/qml/Toast.qml index e30588169e..c957f6b767 100644 --- a/src/qml/Toast.qml +++ b/src/qml/Toast.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 Popup { @@ -20,8 +19,10 @@ Popup { closePolicy: Popup.NoAutoClose opacity: 0 - Behavior on opacity { - NumberAnimation { duration: 250 } + Behavior on opacity { + NumberAnimation { + duration: 250 + } } background: Rectangle { @@ -58,9 +59,7 @@ Popup { property int absoluteWidth: toastFontMetrics.boundingRect(text).width + 10 - width: 40 + absoluteWidth + (toastIndicator.visible ? toastIndicator.width + 10 : 0) + (toastAction.visible ? toastAction.width + 10 : 0) > toast.width - ? toast.width - (toastIndicator.visible ? toastIndicator.width + 10 : 0) - (toastAction.visible ? toastAction.width + 10 : 0) - 40 - : absoluteWidth + width: 40 + absoluteWidth + (toastIndicator.visible ? toastIndicator.width + 10 : 0) + (toastAction.visible ? toastAction.width + 10 : 0) > toast.width ? toast.width - (toastIndicator.visible ? toastIndicator.width + 10 : 0) - (toastAction.visible ? toastAction.width + 10 : 0) - 40 : absoluteWidth wrapMode: Text.Wrap topPadding: 3 bottomPadding: 3 @@ -94,9 +93,9 @@ Popup { MouseArea { anchors.fill: parent - onPressed: { - toast.close() - toast.opacity = 0 + onPressed: { + toast.close(); + toast.opacity = 0; } } @@ -109,34 +108,32 @@ Popup { id: toastTimer interval: 3000 onTriggered: { - toast.opacity = 0 + toast.opacity = 0; } } onOpacityChanged: { - if ( opacity == 0 ) { - toastContent.visible = false - toast.close() + if (opacity == 0) { + toastContent.visible = false; + toast.close(); } } function show(text, type, action_text, action_function) { - toastMessage.text = text - toast.type = type || 'info' - + toastMessage.text = text; + toast.type = type || 'info'; if (action_text !== undefined && action_function !== undefined) { - toastAction.text = action_text - toastAction.act = action_function - toastTimer.interval = 5000 + toastAction.text = action_text; + toastAction.act = action_function; + toastTimer.interval = 5000; } else { - toastAction.text = '' - toastAction.act = undefined - toastTimer.interval = 3000 + toastAction.text = ''; + toastAction.act = undefined; + toastTimer.interval = 3000; } - - toastContent.visible = true - toast.open() - toast.opacity = 1 - toastTimer.restart() + toastContent.visible = true; + toast.open(); + toast.opacity = 1; + toastTimer.restart(); } } diff --git a/src/qml/TrackerSettings.qml b/src/qml/TrackerSettings.qml index 8494fc6710..5870862b21 100644 --- a/src/qml/TrackerSettings.qml +++ b/src/qml/TrackerSettings.qml @@ -1,12 +1,10 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 - -import '.' +import "." Popup { id: trackInformationPopup @@ -26,26 +24,23 @@ Popup { target: trackingModel function onTrackingSetupRequested(trackerIndex, skipSettings) { - tracker = trackings.itemAt(trackerIndex.row).tracker - + tracker = trackings.itemAt(trackerIndex.row).tracker; if (!skipSettings) { - trackerSettings.open() - trackerSettings.focus = true + trackerSettings.open(); + trackerSettings.focus = true; } else { - featureModel.resetAttributes() - featureModel.applyGeometry() - tracker.feature = featureModel.feature - + featureModel.resetAttributes(); + featureModel.applyGeometry(); + tracker.feature = featureModel.feature; if (embeddedAttributeFormModel.rowCount() > 0 && !featureModel.suppressFeatureForm()) { - embeddedFeatureForm.active = true + embeddedFeatureForm.active = true; } else { - trackingModel.startTracker(tracker.vectorLayer) - - displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)) + trackingModel.startTracker(tracker.vectorLayer); + displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)); if (featureModel.currentLayer.geometryType === Qgis.GeometryType.Point) { - projectInfo.saveTracker(featureModel.currentLayer) + projectInfo.saveTracker(featureModel.currentLayer); } - tracker = undefined + tracker = undefined; } } } @@ -53,27 +48,27 @@ Popup { onTrackerChanged: { if (tracker != undefined) { - featureModel.currentLayer = tracker.vectorLayer - timeInterval.checked = tracker.timeInterval > 0 - timeIntervalValue.text = tracker.timeInterval > 0 ? tracker.timeInterval : positioningSettings.trackerTimeInterval - minimumDistance.checked = tracker.minimumDistance > 0 - minimumDistanceValue.text = tracker.minimumDistance > 0 ? tracker.minimumDistance : positioningSettings.trackerMinimumDistance - erroneousDistanceSafeguard.checked = tracker.maximumDistance > 0 - erroneousDistanceValue.text = tracker.maximumDistance > 0 ? tracker.maximumDistance : positioningSettings.trackerErroneousDistance - sensorCapture.checked = tracker.sensorCapture - allConstraints.checked = tracker.conjunction && (timeInterval.checked + minimumDistance.checked + sensorCapture.checked) > 1 - measureComboBox.currentIndex = tracker.measureType - resumeTrackingButton.visible = tracker.feature.id >= 0 + featureModel.currentLayer = tracker.vectorLayer; + timeInterval.checked = tracker.timeInterval > 0; + timeIntervalValue.text = tracker.timeInterval > 0 ? tracker.timeInterval : positioningSettings.trackerTimeInterval; + minimumDistance.checked = tracker.minimumDistance > 0; + minimumDistanceValue.text = tracker.minimumDistance > 0 ? tracker.minimumDistance : positioningSettings.trackerMinimumDistance; + erroneousDistanceSafeguard.checked = tracker.maximumDistance > 0; + erroneousDistanceValue.text = tracker.maximumDistance > 0 ? tracker.maximumDistance : positioningSettings.trackerErroneousDistance; + sensorCapture.checked = tracker.sensorCapture; + allConstraints.checked = tracker.conjunction && (timeInterval.checked + minimumDistance.checked + sensorCapture.checked) > 1; + measureComboBox.currentIndex = tracker.measureType; + resumeTrackingButton.visible = tracker.feature.id >= 0; } } function applySettings() { - tracker.timeInterval = timeIntervalValue.text.length == 0 || !timeInterval.checked ? 0.0 : timeIntervalValue.text - tracker.minimumDistance = minimumDistanceValue.text.length == 0 || !minimumDistance.checked ? 0.0 : minimumDistanceValue.text - tracker.maximumDistance = erroneousDistanceValue.text.length == 0 || !erroneousDistanceSafeguard.checked ? 0.0 : erroneousDistanceValue.text - tracker.sensorCapture = sensorCapture.checked - tracker.conjunction = (timeInterval.checked + minimumDistance.checked + sensorCapture.checked) > 1 && allConstraints.checked - tracker.measureType = measureComboBox.currentIndex + tracker.timeInterval = timeIntervalValue.text.length == 0 || !timeInterval.checked ? 0.0 : timeIntervalValue.text; + tracker.minimumDistance = minimumDistanceValue.text.length == 0 || !minimumDistance.checked ? 0.0 : minimumDistanceValue.text; + tracker.maximumDistance = erroneousDistanceValue.text.length == 0 || !erroneousDistanceSafeguard.checked ? 0.0 : erroneousDistanceValue.text; + tracker.sensorCapture = sensorCapture.checked; + tracker.conjunction = (timeInterval.checked + minimumDistance.checked + sensorCapture.checked) > 1 && allConstraints.checked; + tracker.measureType = measureComboBox.currentIndex; } Page { @@ -81,9 +76,7 @@ Popup { anchors.fill: parent header: QfPageHeader { - title: tracker !== undefined && tracker.vectorLayer - ? qsTr("Tracking: %1").arg(tracker.vectorLayer.name) - : qsTr("Tracking") + title: tracker !== undefined && tracker.vectorLayer ? qsTr("Tracking: %1").arg(tracker.vectorLayer.name) : qsTr("Tracking") showApplyButton: false showCancelButton: false @@ -91,7 +84,7 @@ Popup { onBack: { if (tracker != undefined) { - trackingModel.stopTracker(tracker.vectorLayer) + trackingModel.stopTracker(tracker.vectorLayer); } close(); } @@ -155,7 +148,7 @@ Popup { Layout.alignment: Qt.AlignTop checked: false onCheckedChanged: { - positioningSettings.trackerTimeIntervalConstraint = checked + positioningSettings.trackerTimeIntervalConstraint = checked; } } @@ -180,15 +173,17 @@ Popup { Layout.preferredHeight: font.height + 20 inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: DoubleValidator { locale: 'C' } + validator: DoubleValidator { + locale: 'C' + } onTextChanged: { - positioningSettings.trackerTimeInterval = parseFloat( text ) + positioningSettings.trackerTimeInterval = parseFloat(text); } } Label { - text: qsTr( "When enabled, vertex additions will occur when the time between the last and new vertex meets a configured mimimum value." ) + text: qsTr("When enabled, vertex additions will occur when the time between the last and new vertex meets a configured mimimum value.") font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap @@ -217,7 +212,7 @@ Popup { Layout.alignment: Qt.AlignTop checked: false onCheckedChanged: { - positioningSettings.trackerMinimumDistanceConstraint = checked + positioningSettings.trackerMinimumDistanceConstraint = checked; } } @@ -228,7 +223,7 @@ Popup { } Label { - text: qsTr("Minimum distance [%1]").arg( UnitTypes.toAbbreviatedString( infoDistanceArea.lengthUnits ) ) + text: qsTr("Minimum distance [%1]").arg(UnitTypes.toAbbreviatedString(infoDistanceArea.lengthUnits)) font: Theme.defaultFont wrapMode: Text.WordWrap enabled: minimumDistance.checked @@ -248,15 +243,17 @@ Popup { Layout.preferredHeight: font.height + 20 inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: DoubleValidator { locale: 'C' } + validator: DoubleValidator { + locale: 'C' + } onTextChanged: { - positioningSettings.trackerMinimumDistance = parseFloat( text ) + positioningSettings.trackerMinimumDistance = parseFloat(text); } } Label { - text: qsTr( "When enabled, vertex additions will occur when the distance between the last and new vertex meets a configured mimimum value." ) + text: qsTr("When enabled, vertex additions will occur when the distance between the last and new vertex meets a configured mimimum value.") font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap @@ -285,12 +282,12 @@ Popup { Layout.alignment: Qt.AlignTop checked: false onCheckedChanged: { - positioningSettings.trackerSensorCaptureConstraint = checked + positioningSettings.trackerSensorCaptureConstraint = checked; } } Label { - text: qsTr( "When enabled, vertex additions will occur when sensors have captured new data." ) + text: qsTr("When enabled, vertex additions will occur when sensors have captured new data.") font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap @@ -319,12 +316,12 @@ Popup { Layout.alignment: Qt.AlignTop checked: false onCheckedChanged: { - positioningSettings.trackerMeetAllConstraints = checked + positioningSettings.trackerMeetAllConstraints = checked; } } Label { - text: qsTr( "When enabled, vertices will only be recorded when all active requirements are met. When disabled, individual requirement met will trigger vertex additions." ) + text: qsTr("When enabled, vertices will only be recorded when all active requirements are met. When disabled, individual requirement met will trigger vertex additions.") font: Theme.tipFont color: Theme.secondaryTextColor textFormat: Qt.RichText @@ -372,12 +369,12 @@ Popup { Layout.alignment: Qt.AlignTop checked: false onCheckedChanged: { - positioningSettings.trackerErroneousDistanceSafeguard = checked + positioningSettings.trackerErroneousDistanceSafeguard = checked; } } Label { - text: qsTr("Maximum tolerated distance [%1]").arg( UnitTypes.toAbbreviatedString( infoDistanceArea.lengthUnits ) ) + text: qsTr("Maximum tolerated distance [%1]").arg(UnitTypes.toAbbreviatedString(infoDistanceArea.lengthUnits)) font: Theme.defaultFont wrapMode: Text.WordWrap enabled: erroneousDistanceSafeguard.checked @@ -397,15 +394,17 @@ Popup { Layout.preferredHeight: font.height + 20 inputMethodHints: Qt.ImhFormattedNumbersOnly - validator: DoubleValidator { locale: 'C' } + validator: DoubleValidator { + locale: 'C' + } onTextChanged: { - positioningSettings.trackerErroneousDistance = parseFloat( text ) + positioningSettings.trackerErroneousDistance = parseFloat(text); } } Label { - text: qsTr( "When enabled, vertex addition will not occur when the distance between the last and new vertex is greater than a configured maximum value." ) + text: qsTr("When enabled, vertex addition will not occur when the distance between the last and new vertex is greater than a configured maximum value.") font: Theme.tipFont color: Theme.secondaryTextColor @@ -416,7 +415,7 @@ Popup { Label { id: measureLabel - text: qsTr( "Measure (M) value attached to vertices:" ) + text: qsTr("Measure (M) value attached to vertices:") font: Theme.defaultFont wrapMode: Text.WordWrap @@ -440,18 +439,7 @@ Popup { property bool loaded: false Component.onCompleted: { // This list matches the Tracker::MeasureType enum - var measurements = [ - qsTr("Elapsed time (seconds since start of tracking)"), - qsTr("Timestamp (milliseconds since epoch)"), - qsTr("Ground speed"), - qsTr("Bearing"), - qsTr("Horizontal accuracy"), - qsTr("Vertical accuracy"), - qsTr("PDOP"), - qsTr("HDOP"), - qsTr("VDOP") - ]; - + var measurements = [qsTr("Elapsed time (seconds since start of tracking)"), qsTr("Timestamp (milliseconds since epoch)"), qsTr("Ground speed"), qsTr("Bearing"), qsTr("Horizontal accuracy"), qsTr("Vertical accuracy"), qsTr("PDOP"), qsTr("HDOP"), qsTr("VDOP")]; model = measurements; loaded = true; } @@ -467,7 +455,7 @@ Popup { id: measureTipLabel visible: !LayerUtils.hasMValue(featureModel.currentLayer) Layout.fillWidth: true - text: qsTr( "To active the measurement functionality, make sure the vector layer's geometry type used for the tracking session has an M dimension." ) + text: qsTr("To active the measurement functionality, make sure the vector layer's geometry type used for the tracking session has an M dimension.") font: Theme.tipFont color: Theme.secondaryTextColor @@ -481,24 +469,24 @@ Popup { Layout.fillWidth: true Layout.leftMargin: 10 Layout.rightMargin: 10 - text: qsTr( "Start tracking") - icon.source: Theme.getThemeVectorIcon( 'directions_walk_24dp' ) + text: qsTr("Start tracking") + icon.source: Theme.getThemeVectorIcon('directions_walk_24dp') onClicked: { - applySettings() - featureModel.resetAttributes() - featureModel.applyGeometry() - tracker.feature = featureModel.feature + applySettings(); + featureModel.resetAttributes(); + featureModel.applyGeometry(); + tracker.feature = featureModel.feature; if (embeddedAttributeFormModel.rowCount() > 0 && !featureModel.suppressFeatureForm()) { - embeddedFeatureForm.active = true + embeddedFeatureForm.active = true; } else { - trackingModel.startTracker(tracker.vectorLayer) - displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)) + trackingModel.startTracker(tracker.vectorLayer); + displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)); if (featureModel.currentLayer.geometryType === Qgis.GeometryType.Point) { - projectInfo.saveTracker(featureModel.currentLayer) + projectInfo.saveTracker(featureModel.currentLayer); } - tracker = undefined - trackerSettings.close() + tracker = undefined; + trackerSettings.close(); } } } @@ -508,19 +496,19 @@ Popup { Layout.fillWidth: true Layout.leftMargin: 10 Layout.rightMargin: 10 - text: qsTr( "Resume tracking") - icon.source: Theme.getThemeVectorIcon( 'directions_walk_24dp' ) + text: qsTr("Resume tracking") + icon.source: Theme.getThemeVectorIcon('directions_walk_24dp') icon.color: Theme.mainColor bgcolor: "transparent" color: Theme.mainColor visible: false onClicked: { - applySettings() - trackingModel.startTracker(tracker.vectorLayer) - displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)) - projectInfo.saveTracker(featureModel.currentLayer) - trackerSettings.close() + applySettings(); + trackingModel.startTracker(tracker.vectorLayer); + displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)); + projectInfo.saveTracker(featureModel.currentLayer); + trackerSettings.close(); } } } @@ -530,7 +518,8 @@ Popup { id: featureModel project: qgisProject - geometry: Geometry {} + geometry: Geometry { + } positionInformation: coordinateLocator.positionInformation positionLocked: true @@ -548,8 +537,8 @@ Popup { sourceComponent: embeddedFeatureFormComponent active: false onLoaded: { - item.open() - item.forceActiveFocus() + item.open(); + item.forceActiveFocus(); } } @@ -582,25 +571,25 @@ Popup { state: 'Add' onTemporaryStored: { - tracker.feature = featureModel.feature - embeddedFeatureFormPopup.close() - embeddedFeatureForm.active = false - trackingModel.startTracker(tracker.vectorLayer) - displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)) + tracker.feature = featureModel.feature; + embeddedFeatureFormPopup.close(); + embeddedFeatureForm.active = false; + trackingModel.startTracker(tracker.vectorLayer); + displayToast(qsTr('Track on layer %1 started').arg(tracker.vectorLayer.name)); if (featureModel.currentLayer.geometryType === Qgis.GeometryType.Point) { - projectInfo.saveTracker(featureModel.currentLayer) + projectInfo.saveTracker(featureModel.currentLayer); } - tracker = undefined - trackerSettings.close() + tracker = undefined; + trackerSettings.close(); } onCancelled: { - embeddedFeatureFormPopup.close() - embeddedFeatureForm.active = false - embeddedFeatureForm.focus = false - trackingModel.stopTracker(tracker.vectorLayer) - tracker = undefined - trackerSettings.close() + embeddedFeatureFormPopup.close(); + embeddedFeatureForm.active = false; + embeddedFeatureForm.focus = false; + trackingModel.stopTracker(tracker.vectorLayer); + tracker = undefined; + trackerSettings.close(); } } } diff --git a/src/qml/TrackingSession.qml b/src/qml/TrackingSession.qml index a86c3e4eec..63beae2816 100644 --- a/src/qml/TrackingSession.qml +++ b/src/qml/TrackingSession.qml @@ -1,12 +1,10 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 - -import '.' +import "." Item { id: trackingSession @@ -14,7 +12,7 @@ Item { property var tracker: model Component.onCompleted: { - tracker.rubberModel = rubberbandModel + tracker.rubberModel = rubberbandModel; } RubberbandModel { @@ -25,25 +23,25 @@ Item { property int measureType: tracker.measureType measureValue: { - switch(measureType) { - case Tracker.SecondsSinceStart: - return ( positionSource.positionInformation.utcDateTime - tracker.startPositionTimestamp ) / 1000 - case Tracker.Timestamp: - return positionSource.positionInformation.utcDateTime.getTime() - case Tracker.GroundSpeed: - return positionSource.positionInformation.speed - case Tracker.Bearing: - return positionSource.positionInformation.direction - case Tracker.HorizontalAccuracy: - return positionSource.positionInformation.hacc - case Tracker.VerticalAccuracy: - return positionSource.positionInformation.vacc - case Tracker.PDOP: - return positionSource.positionInformation.pdop - case Tracker.HDOP: - return positionSource.positionInformation.hdop - case Tracker.VDOP: - return positionSource.positionInformation.vdop + switch (measureType) { + case Tracker.SecondsSinceStart: + return (positionSource.positionInformation.utcDateTime - tracker.startPositionTimestamp) / 1000; + case Tracker.Timestamp: + return positionSource.positionInformation.utcDateTime.getTime(); + case Tracker.GroundSpeed: + return positionSource.positionInformation.speed; + case Tracker.Bearing: + return positionSource.positionInformation.direction; + case Tracker.HorizontalAccuracy: + return positionSource.positionInformation.hacc; + case Tracker.VerticalAccuracy: + return positionSource.positionInformation.vacc; + case Tracker.PDOP: + return positionSource.positionInformation.pdop; + case Tracker.HDOP: + return positionSource.positionInformation.hdop; + case Tracker.VDOP: + return positionSource.positionInformation.vdop; } return 0; } @@ -55,30 +53,22 @@ Item { if (!tracker.isActive || vertexCount == 0) { return; } - if (geometryType === Qgis.GeometryType.Point) { - featureModel.applyGeometry() + featureModel.applyGeometry(); featureModel.resetFeatureId(); featureModel.resetAttributes(true); featureModel.create(); } else { - if ((geometryType === Qgis.GeometryType.Line && vertexCount > 2) || - (geometryType === Qgis.GeometryType.Polygon && vertexCount > 3)) - { - featureModel.applyGeometry() - - if ((geometryType === Qgis.GeometryType.Line && vertexCount == 3) || - (geometryType === Qgis.GeometryType.Polygon && vertexCount == 4)) - { + if ((geometryType === Qgis.GeometryType.Line && vertexCount > 2) || (geometryType === Qgis.GeometryType.Polygon && vertexCount > 3)) { + featureModel.applyGeometry(); + if ((geometryType === Qgis.GeometryType.Line && vertexCount == 3) || (geometryType === Qgis.GeometryType.Polygon && vertexCount == 4)) { // indirect action, no need to check for success and display a toast, the log is enough - featureModel.create() - tracker.feature = featureModel.feature - projectInfo.saveTracker(featureModel.currentLayer) - } - else - { + featureModel.create(); + tracker.feature = featureModel.feature; + projectInfo.saveTracker(featureModel.currentLayer); + } else { // indirect action, no need to check for success and display a toast, the log is enough - featureModel.save() + featureModel.save(); } } } @@ -89,10 +79,7 @@ Item { id: rubberband visible: tracker.visible - color: Qt.rgba(Math.min(0.75, Math.random()), - Math.min(0.75,Math.random()), - Math.min(0.75,Math.random()), - 0.6) + color: Qt.rgba(Math.min(0.75, Math.random()), Math.min(0.75, Math.random()), Math.min(0.75, Math.random()), 0.6) geometryType: Qgis.GeometryType.Line mapSettings: mapCanvas.mapSettings @@ -107,7 +94,7 @@ Item { onFeatureChanged: { if (!tracker.isActive) { - updateRubberband() + updateRubberband(); } } diff --git a/src/qml/UdpDeviceChooser.qml b/src/qml/UdpDeviceChooser.qml index 4cb2528194..f4b747fefc 100644 --- a/src/qml/UdpDeviceChooser.qml +++ b/src/qml/UdpDeviceChooser.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 - import Theme 1.0 Item { @@ -22,8 +20,10 @@ Item { } function getSettings() { - return {'address': deviceAddress.trim(), - 'port': parseInt(devicePort)}; + return { + "address": deviceAddress.trim(), + "port": parseInt(devicePort) + }; } GridLayout { @@ -34,32 +34,32 @@ Item { Label { Layout.fillWidth: true - text: qsTr( "Address:" ) + text: qsTr("Address:") font: Theme.defaultFont wrapMode: Text.WordWrap } QfTextField { - id: udpDeviceAddress - Layout.fillWidth: true - font: Theme.defaultFont - text: '127.0.0.1' - inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase + id: udpDeviceAddress + Layout.fillWidth: true + font: Theme.defaultFont + text: '127.0.0.1' + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase } Label { - Layout.fillWidth: true - text: qsTr( "Port:" ) - font: Theme.defaultFont - wrapMode: Text.WordWrap + Layout.fillWidth: true + text: qsTr("Port:") + font: Theme.defaultFont + wrapMode: Text.WordWrap } QfTextField { - id: udpDevicePort - Layout.fillWidth: true - font: Theme.defaultFont - text: '11111' - inputMethodHints: Qt.ImhFormattedNumbersOnly + id: udpDevicePort + Layout.fillWidth: true + font: Theme.defaultFont + text: '11111' + inputMethodHints: Qt.ImhFormattedNumbersOnly } } } diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index e1c28eaf05..fdaab91d18 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -1,18 +1,17 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 ColumnLayout { function reset() { - Qt.inputMethod.hide() - table.model.reloadVariables() + Qt.inputMethod.hide(); + table.model.reloadVariables(); } function apply() { - table.model.save() + table.model.save(); } anchors.fill: parent @@ -29,7 +28,8 @@ ColumnLayout { ListView { id: table - model: ExpressionVariableModel {} + model: ExpressionVariableModel { + } flickableDirection: Flickable.VerticalFlick boundsBehavior: Flickable.StopAtBounds clip: true @@ -79,11 +79,11 @@ ColumnLayout { } onTextChanged: { - table.model.setName(index, text) + table.model.setName(index, text); } onCursorRectangleChanged: { - variableNameTextAnimator.ensureCursorVisible(cursorRectangle) + variableNameTextAnimator.ensureCursorVisible(cursorRectangle); } } } @@ -116,11 +116,11 @@ ColumnLayout { } onTextChanged: { - table.model.setValue(index, text) + table.model.setValue(index, text); } onCursorRectangleChanged: { - variableValueTextAnimator.ensureCursorVisible(cursorRectangle) + variableValueTextAnimator.ensureCursorVisible(cursorRectangle); } } } @@ -137,7 +137,7 @@ ColumnLayout { bgcolor: "transparent" onClicked: { - table.model.removeCustomVariable(index) + table.model.removeCustomVariable(index); } } } @@ -151,10 +151,10 @@ ColumnLayout { text: qsTr("Add a new variable") onClicked: { - table.model.addCustomVariable("new_variable", "") - table.positionViewAtIndex(table.count - 1, ListView.visible) + table.model.addCustomVariable("new_variable", ""); + table.positionViewAtIndex(table.count - 1, ListView.visible); // TODO: Use Qt 5.13 itemAtIndex( index ) - table.children[0].children[table.count].children[0].children[0].forceActiveFocus() + table.children[0].children[table.count].children[0].children[0].forceActiveFocus(); } } } diff --git a/src/qml/VertexRubberband.qml b/src/qml/VertexRubberband.qml index e146357afd..634f7a8cc2 100644 --- a/src/qml/VertexRubberband.qml +++ b/src/qml/VertexRubberband.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQml 2.14 - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 Repeater { @@ -23,13 +21,11 @@ Repeater { visible: vertexRubberband.isVisible - x: mapToScreen.screenPoint.x - width/2 - y: mapToScreen.screenPoint.y - width/2 - opacity: !isCycling || (isAddingVertex && !ExistingVertex) || (!isAddingVertex && ExistingVertex) - ? 1.0 - : 0.25 + x: mapToScreen.screenPoint.x - width / 2 + y: mapToScreen.screenPoint.y - width / 2 + opacity: !isCycling || (isAddingVertex && !ExistingVertex) || (!isAddingVertex && ExistingVertex) ? 1.0 : 0.25 - width: ((isAddingVertex && !ExistingVertex) || (!isAddingVertex && ExistingVertex) ? 16 : 8) * (CurrentVertex ? 1.33 : 1) / (rotation == 0? 1 : 1.25) + width: ((isAddingVertex && !ExistingVertex) || (!isAddingVertex && ExistingVertex) ? 16 : 8) * (CurrentVertex ? 1.33 : 1) / (rotation == 0 ? 1 : 1.25) height: width radius: ExistingVertex ? width / 2 : 0 rotation: ExistingVertex ? 0 : 45 @@ -48,18 +44,9 @@ Repeater { anchors.fill: parent anchors.margins: 1 radius: ExistingVertex ? width / 2 : 0 - color: CurrentVertex - ? isAddingVertex - ? Theme.vertexNewColorSemiOpaque - : Theme.vertexSelectedColorSemiOpaque - : Theme.vertexColorSemiOpaque - border.color: CurrentVertex - ? isAddingVertex - ? Theme.vertexNewColor - : Theme.vertexSelectedColor - : Theme.vertexColor + color: CurrentVertex ? isAddingVertex ? Theme.vertexNewColorSemiOpaque : Theme.vertexSelectedColorSemiOpaque : Theme.vertexColorSemiOpaque + border.color: CurrentVertex ? isAddingVertex ? Theme.vertexNewColor : Theme.vertexSelectedColor : Theme.vertexColor border.width: (VertexModel.ExistingVertex ? 4 : 2) * (CurrentVertex ? 1.5 : 1) } } } - diff --git a/src/qml/VisibilityFadingRow.qml b/src/qml/VisibilityFadingRow.qml index f528617a90..7bb1461e9d 100644 --- a/src/qml/VisibilityFadingRow.qml +++ b/src/qml/VisibilityFadingRow.qml @@ -7,10 +7,20 @@ Row { opacity: 0 states: [ - State { when: visibilityFadingRow.stateVisible; - PropertyChanges { target: visibilityFadingRow; opacity: 1.0 }}, - State { when: !visibilityFadingRow.stateVisible; - PropertyChanges { target: visibilityFadingRow; opacity: 0.0 }} + State { + when: visibilityFadingRow.stateVisible + PropertyChanges { + target: visibilityFadingRow + opacity: 1.0 + } + }, + State { + when: !visibilityFadingRow.stateVisible + PropertyChanges { + target: visibilityFadingRow + opacity: 0.0 + } + } ] transitions: Transition { diff --git a/src/qml/WelcomeScreen.qml b/src/qml/WelcomeScreen.qml index 0b1ee6eff4..3a2368ee65 100644 --- a/src/qml/WelcomeScreen.qml +++ b/src/qml/WelcomeScreen.qml @@ -4,7 +4,6 @@ import QtQuick.Controls.Material.impl 2.14 import QtQuick.Layouts 1.14 import QtQuick.Particles 2.14 import QtCore - import org.qfield 1.0 import Theme 1.0 @@ -29,12 +28,12 @@ Page { Rectangle { id: welcomeBackground anchors.fill: parent - gradient: Gradient { - GradientStop { + gradient: Gradient { + GradientStop { position: 0.0 color: Theme.darkTheme ? "#99000000" : "#99A5A5A5" } - GradientStop { + GradientStop { position: 0.33 color: Theme.mainBackgroundColor } @@ -59,15 +58,15 @@ Page { width: mainWindow.width - ImageDial{ + ImageDial { id: imageDialLogo value: 1 Layout.margins: 6 Layout.topMargin: 14 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.preferredWidth: Math.min( 138, mainWindow.height / 4 ) - Layout.preferredHeight: Math.min( 138, mainWindow.height / 4 ) + Layout.preferredWidth: Math.min(138, mainWindow.height / 4) + Layout.preferredHeight: Math.min(138, mainWindow.height / 4) source: "qrc:/images/qfield_logo.svg" rotationOffset: 220 @@ -81,12 +80,15 @@ Page { Layout.topMargin: 10 Layout.bottomMargin: 10 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.preferredWidth: Math.min( 410, mainWindow.width - 30 ) + Layout.preferredWidth: Math.min(410, mainWindow.width - 30) Layout.preferredHeight: Math.max(ohno.childrenRect.height, intro.childrenRect.height, ohyeah.childrenRect.height) clip: true - Behavior on Layout.preferredHeight { - NumberAnimation { duration: 100; easing.type: Easing.InQuad; } + Behavior on Layout.preferredHeight { + NumberAnimation { + duration: 100 + easing.type: Easing.InQuad + } } interactive: false @@ -96,12 +98,12 @@ Page { Rectangle { anchors.fill: parent - gradient: Gradient { - GradientStop { + gradient: Gradient { + GradientStop { position: 0.0 color: "#4480cc28" } - GradientStop { + GradientStop { position: 0.88 color: "#0580cc28" } @@ -133,11 +135,11 @@ Page { rightPadding: 20 text: qsTr("Reach out") - icon.source: Theme.getThemeIcon( 'ic_create_white_24dp' ) + icon.source: Theme.getThemeIcon('ic_create_white_24dp') onClicked: { - Qt.openUrlExternally("https://www.qfield.org/") - feedbackView.Layout.preferredHeight = 0 + Qt.openUrlExternally("https://www.qfield.org/"); + feedbackView.Layout.preferredHeight = 0; } } } @@ -149,12 +151,12 @@ Page { Rectangle { anchors.fill: parent - gradient: Gradient { - GradientStop { + gradient: Gradient { + GradientStop { position: 0.0 color: "#4480cc28" } - GradientStop { + GradientStop { position: 0.88 color: "#0580cc28" } @@ -187,7 +189,7 @@ Page { round: true onClicked: { - feedbackView.currentIndex = 0 + feedbackView.currentIndex = 0; } } QfToolButton { @@ -196,7 +198,7 @@ Page { round: true onClicked: { - feedbackView.currentIndex = 2 + feedbackView.currentIndex = 2; } } } @@ -207,12 +209,12 @@ Page { Rectangle { anchors.fill: parent - gradient: Gradient { - GradientStop { + gradient: Gradient { + GradientStop { position: 0.0 color: "#4480cc28" } - GradientStop { + GradientStop { position: 0.88 color: "#0580cc28" } @@ -245,11 +247,11 @@ Page { rightPadding: 20 text: qsTr("Rate us") - icon.source: Theme.getThemeVectorIcon( 'ic_star_white_24dp' ) + icon.source: Theme.getThemeVectorIcon('ic_star_white_24dp') onClicked: { - Qt.openUrlExternally("market://details?id=ch.opengis.qfield") - feedbackView.Layout.preferredHeight = 0 + Qt.openUrlExternally("market://details?id=ch.opengis.qfield"); + feedbackView.Layout.preferredHeight = 0; } } } @@ -265,12 +267,15 @@ Page { Layout.topMargin: 10 Layout.bottomMargin: 10 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - Layout.preferredWidth: Math.min( 410, mainWindow.width - 20 ) + Layout.preferredWidth: Math.min(410, mainWindow.width - 20) Layout.preferredHeight: Math.max(collectionOhno.childrenRect.height, collectionIntro.childrenRect.height) clip: true - Behavior on Layout.preferredHeight { - NumberAnimation { duration: 100; easing.type: Easing.InQuad; } + Behavior on Layout.preferredHeight { + NumberAnimation { + duration: 100 + easing.type: Easing.InQuad + } } interactive: false @@ -280,12 +285,12 @@ Page { Rectangle { anchors.fill: parent - gradient: Gradient { - GradientStop { + gradient: Gradient { + GradientStop { position: 0.0 color: "#4480cc28" } - GradientStop { + GradientStop { position: 0.88 color: "#0580cc28" } @@ -315,12 +320,12 @@ Page { Rectangle { anchors.fill: parent - gradient: Gradient { - GradientStop { + gradient: Gradient { + GradientStop { position: 0.0 color: "#4480cc28" } - GradientStop { + GradientStop { position: 0.88 color: "#0580cc28" } @@ -351,8 +356,8 @@ Page { text: qsTr('I agree') onClicked: { - qfieldSettings.enableInfoCollection = true - collectionView.visible = false + qfieldSettings.enableInfoCollection = true; + collectionView.visible = false; } } @@ -362,8 +367,8 @@ Page { color: Theme.mainColor onClicked: { - qfieldSettings.enableInfoCollection = false - collectionView.visible = false + qfieldSettings.enableInfoCollection = false; + collectionView.visible = false; } } } @@ -406,23 +411,23 @@ Page { QfButton { id: cloudProjectButton Layout.fillWidth: true - text: qsTr( "QFieldCloud projects" ) + text: qsTr("QFieldCloud projects") onClicked: { - showQFieldCloudScreen() + showQFieldCloudScreen(); } } QfButton { id: localProjectButton Layout.fillWidth: true - text: qsTr( "Open local file" ) + text: qsTr("Open local file") onClicked: { - openLocalDataPicker() + openLocalDataPicker(); } } Text { id: recentText - text: qsTr( "Recent Projects" ) + text: qsTr("Recent Projects") font.pointSize: Theme.tipFont.pointSize font.bold: true color: Theme.mainTextColor @@ -440,7 +445,8 @@ Page { ListView { id: table - ScrollBar.vertical: ScrollBar {} + ScrollBar.vertical: ScrollBar { + } flickableDirection: Flickable.AutoFlickIfNeeded boundsBehavior: Flickable.StopAtBounds clip: true @@ -517,12 +523,16 @@ Page { Image { id: type anchors.verticalCenter: parent.verticalCenter - source: switch(ProjectType) { - case 0: return Theme.getThemeVectorIcon('ic_map_green_48dp'); // local project - case 1: return Theme.getThemeVectorIcon('ic_cloud_project_48dp'); // cloud project - case 2: return Theme.getThemeVectorIcon('ic_file_green_48dp'); // local dataset - default: return ''; - } + source: switch (ProjectType) { + case 0: + return Theme.getThemeVectorIcon('ic_map_green_48dp'); // local project + case 1: + return Theme.getThemeVectorIcon('ic_cloud_project_48dp'); // cloud project + case 2: + return Theme.getThemeVectorIcon('ic_file_green_48dp'); // local dataset + default: + return ''; + } sourceSize.width: 80 sourceSize.height: 80 width: 40 @@ -554,22 +564,19 @@ Page { bottomPadding: 4 text: { var notes = []; - - if ( index == 0 ) { - var firstRun = settings && !settings.value( "/QField/FirstRunFlag", false ) - if (!firstRun && firstShown === false) notes.push( qsTr( "Last session" ) ); + if (index == 0) { + var firstRun = settings && !settings.value("/QField/FirstRunFlag", false); + if (!firstRun && firstShown === false) + notes.push(qsTr("Last session")); } - - if ( ProjectPath === registry.defaultProject ) { - notes.push( qsTr( "Default project" ) ); + if (ProjectPath === registry.defaultProject) { + notes.push(qsTr("Default project")); } - - if ( ProjectPath === registry.baseMapProject ) { - notes.push( qsTr( "Base map" ) ); + if (ProjectPath === registry.baseMapProject) { + notes.push(qsTr("Base map")); } - - if ( notes.length > 0 ) { - return notes.join( '; ' ); + if (notes.length > 0) { + return notes.join('; '); } else { return ""; } @@ -590,40 +597,40 @@ Page { MouseArea { property Item pressedItem anchors.fill: parent - onClicked: (mouse) => { - var item = table.itemAt(mouse.x, mouse.y) + onClicked: mouse => { + var item = table.itemAt(mouse.x, mouse.y); if (item) { - if ( item.type == 1 && cloudConnection.hasToken && cloudConnection.status !== QFieldCloudConnection.LoggedIn ) { - cloudConnection.login() + if (item.type == 1 && cloudConnection.hasToken && cloudConnection.status !== QFieldCloudConnection.LoggedIn) { + cloudConnection.login(); } - iface.loadFile(item.path,item.title) + iface.loadFile(item.path, item.title); } } - onPressed: (mouse) => { - var item = table.itemAt(mouse.x, mouse.y) + onPressed: mouse => { + var item = table.itemAt(mouse.x, mouse.y); if (item) { - pressedItem = item - pressedItem.isPressed = true + pressedItem = item; + pressedItem.isPressed = true; } } onCanceled: { if (pressedItem) { - pressedItem.isPressed = false - pressedItem = null + pressedItem.isPressed = false; + pressedItem = null; } } onReleased: { if (pressedItem) { - pressedItem.isPressed = false - pressedItem = null + pressedItem.isPressed = false; + pressedItem = null; } } - onPressAndHold: (mouse) => { - var item = table.itemAt(mouse.x, mouse.y) + onPressAndHold: mouse => { + var item = table.itemAt(mouse.x, mouse.y); if (item) { recentProjectActions.recentProjectPath = item.path; recentProjectActions.recentProjectType = item.type; - recentProjectActions.popup(mouse.x, mouse.y) + recentProjectActions.popup(mouse.x, mouse.y); } } } @@ -652,16 +659,16 @@ Page { MenuItem { id: defaultProject - visible: recentProjectActions.recentProjectType != 2; + visible: recentProjectActions.recentProjectType != 2 font: Theme.defaultFont width: parent.width - height: visible ? 48: 0 + height: visible ? 48 : 0 leftPadding: Theme.menuItemCheckLeftPadding checkable: true checked: recentProjectActions.recentProjectPath === registry.defaultProject - text: qsTr( "Default Project" ) + text: qsTr("Default Project") onTriggered: { registry.defaultProject = recentProjectActions.recentProjectPath === registry.defaultProject ? '' : recentProjectActions.recentProjectPath; } @@ -669,16 +676,16 @@ Page { MenuItem { id: baseMapProject - visible: recentProjectActions.recentProjectType != 2; + visible: recentProjectActions.recentProjectType != 2 font: Theme.defaultFont width: parent.width - height: visible ? 48: 0 + height: visible ? 48 : 0 leftPadding: Theme.menuItemCheckLeftPadding checkable: true checked: recentProjectActions.recentProjectPath === registry.baseMapProject - text: qsTr( "Individual Datasets Base Map" ) + text: qsTr("Individual Datasets Base Map") onTriggered: { registry.baseMapProject = recentProjectActions.recentProjectPath === registry.baseMapProject ? '' : recentProjectActions.recentProjectPath; } @@ -695,12 +702,12 @@ Page { font: Theme.defaultFont width: parent.width - height: visible ? 48: 0 + height: visible ? 48 : 0 leftPadding: Theme.menuItemIconlessLeftPadding - text: qsTr( "Remove from Recent Projects" ) + text: qsTr("Remove from Recent Projects") onTriggered: { - iface.removeRecentProject( recentProjectActions.recentProjectPath ); + iface.removeRecentProject(recentProjectActions.recentProjectPath); model.reloadModel(); } } @@ -720,9 +727,7 @@ Page { wrapMode: Text.WordWrap color: reloadOnLaunch.checked ? Theme.mainTextColor : Theme.secondaryTextColor - text: registry.defaultProject != '' - ? qsTr('Load default project on launch') - : qsTr('Load last opened project on launch') + text: registry.defaultProject != '' ? qsTr('Load default project on launch') : qsTr('Load last opened project on launch') MouseArea { anchors.fill: parent @@ -739,7 +744,7 @@ Page { checked: registry.loadProjectOnLaunch onCheckedChanged: { - registry.loadProjectOnLaunch = checked + registry.loadProjectOnLaunch = checked; } } } @@ -756,7 +761,7 @@ Page { left: parent.left topMargin: mainWindow.sceneTopMargin } - iconSource: Theme.getThemeIcon( 'ic_chevron_left_black_24dp' ) + iconSource: Theme.getThemeIcon('ic_chevron_left_black_24dp') iconColor: Theme.mainTextColor bgcolor: "transparent" @@ -781,17 +786,17 @@ Page { onReleased: mouse.accepted = false onDoubleClicked: mouse.accepted = false onPressAndHold: mouse.accepted = false - onClicked: (mouse) => { - burstSomeSparkles(mouse.x, mouse.y) - mouse.accepted = false + onClicked: mouse => { + burstSomeSparkles(mouse.x, mouse.y); + mouse.accepted = false; } - onPressed: (mouse) => { - burstSomeSparkles(mouse.x, mouse.y) - mouse.accepted = false + onPressed: mouse => { + burstSomeSparkles(mouse.x, mouse.y); + mouse.accepted = false; } - onPositionChanged: (mouse) => { - burstSomeSparkles(mouse.x, mouse.y) - mouse.accepted = false + onPositionChanged: mouse => { + burstSomeSparkles(mouse.x, mouse.y); + mouse.accepted = false; } } @@ -864,61 +869,55 @@ Page { } function burstSomeSparkles(x, y) { - emitterParticles.burst(50, x, y) - emitterUnicorns.burst(1, x, y) + emitterParticles.burst(50, x, y); + emitterUnicorns.burst(1, x, y); } function adjustWelcomeScreen() { if (visible) { const currentProjectButtonVisible = !!qgisProject.fileName; - currentProjectButton.visible = currentProjectButtonVisible - + currentProjectButton.visible = currentProjectButtonVisible; if (firstShown) { welcomeText.text = " "; } else { - var firstRun = !settings.valueBool( "/QField/FirstRunDone", false ) - if ( firstRun ) { - welcomeText.text = qsTr( "Welcome to QField. First time using this application? Try the sample projects listed below." ) - settings.setValue( "/QField/FirstRunDone", true ) + var firstRun = !settings.valueBool("/QField/FirstRunDone", false); + if (firstRun) { + welcomeText.text = qsTr("Welcome to QField. First time using this application? Try the sample projects listed below."); + settings.setValue("/QField/FirstRunDone", true); } else { - welcomeText.text = qsTr( "Welcome back to QField." ) + welcomeText.text = qsTr("Welcome back to QField."); } } } } Component.onCompleted: { - adjustWelcomeScreen() - - var runCount = settings.value("/QField/RunCount",0) * 1 - var feedbackFormShown = settings.value("/QField/FeedbackFormShown",false) + adjustWelcomeScreen(); + var runCount = settings.value("/QField/RunCount", 0) * 1; + var feedbackFormShown = settings.value("/QField/FeedbackFormShown", false); if (!feedbackFormShown) { - var now = new Date() - var dt = settings.value("/QField/FirstRunDate", "") + var now = new Date(); + var dt = settings.value("/QField/FirstRunDate", ""); if (dt != "") { - dt = new Date(dt) - + dt = new Date(dt); var daysToPrompt = 30; var runsToPrompt = 5; if (runCount >= runsToPrompt && (now - dt) >= (daysToPrompt * 24 * 60 * 60 * 1000)) { - feedbackView.visible = true - settings.setValue("/QField/FeedbackFormShown",true) + feedbackView.visible = true; + settings.setValue("/QField/FeedbackFormShown", true); } } else { - settings.setValue("/QField/FirstRunDate", now.toISOString()) + settings.setValue("/QField/FirstRunDate", now.toISOString()); } } - if (platformUtilities.capabilities & PlatformUtilities.SentryFramework) { - var collectionFormShown = settings.value("/QField/CollectionFormShownV2",false) + var collectionFormShown = settings.value("/QField/CollectionFormShownV2", false); if (!collectionFormShown) { - collectionView.visible = true - settings.setValue("/QField/CollectionFormShownV2",true) + collectionView.visible = true; + settings.setValue("/QField/CollectionFormShownV2", true); } } - - settings.setValue("/QField/RunCount",runCount + 1) - + settings.setValue("/QField/RunCount", runCount + 1); if (registry.defaultProject != '') { if (!FileUtils.fileExists(registry.defaultProject)) { registry.defaultProject = ''; @@ -927,12 +926,12 @@ Page { } onVisibleChanged: { - adjustWelcomeScreen() - focus = visible + adjustWelcomeScreen(); + focus = visible; if (!visible) { - feedbackView.visible = false - collectionView.visible = false - firstShown = true + feedbackView.visible = false; + collectionView.visible = false; + firstShown = true; } } } diff --git a/src/qml/editorwidgets/CheckBox.qml b/src/qml/editorwidgets/CheckBox.qml index 40266c94e0..22d40f35e0 100644 --- a/src/qml/editorwidgets/CheckBox.qml +++ b/src/qml/editorwidgets/CheckBox.qml @@ -1,8 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 - import "." EditorWidgetBase { @@ -20,27 +18,21 @@ EditorWidgetBase { } Label { - id: checkValue - height: fontMetrics.height + 20 - anchors { - left: parent.left - right: checkBox.left - } + id: checkValue + height: fontMetrics.height + 20 + anchors { + left: parent.left + right: checkBox.left + } - topPadding: 10 - bottomPadding: 10 - font.pointSize: Theme.defaultFont.pointSize - font.bold: Theme.defaultFont.bold - font.italic: isNull - color: isEnabled && !isNull ? Theme.mainTextColor : Theme.mainTextDisabledColor + topPadding: 10 + bottomPadding: 10 + font.pointSize: Theme.defaultFont.pointSize + font.bold: Theme.defaultFont.bold + font.italic: isNull + color: isEnabled && !isNull ? Theme.mainTextColor : Theme.mainTextDisabledColor - text: !isNull - ? checkBox.checked - ? checkedLabel - : uncheckedLabel - : isEnabled - ? qsTr('NULL') - : '' + text: !isNull ? checkBox.checked ? checkedLabel : uncheckedLabel : isEnabled ? qsTr('NULL') : '' } QfSwitch { @@ -56,16 +48,16 @@ EditorWidgetBase { } checked: { - if (isBool) { - var actualValue = value - // Some datasets - such as Geopackage - can send the value as a 'True' or 'False' string, we have to work around that - if (!isNull && typeof value == 'string') { - actualValue = value.toLowerCase() === 'true' - } - return !isNull ? actualValue : false; - } else { - return !isNull ? String(value) === config['CheckedState'] : false; + if (isBool) { + var actualValue = value; + // Some datasets - such as Geopackage - can send the value as a 'True' or 'False' string, we have to work around that + if (!isNull && typeof value == 'string') { + actualValue = value.toLowerCase() === 'true'; } + return !isNull ? actualValue : false; + } else { + return !isNull ? String(value) === config['CheckedState'] : false; + } } } @@ -75,35 +67,34 @@ EditorWidgetBase { anchors.fill: parent onClicked: { - var editedValue = true + var editedValue = true; if (isBool) { - var actualValue = value + var actualValue = value; // Some datasets - such as Geopackage - can send the value as a 'True' or 'False' string, we have to work around that if (!isNull && typeof value == 'string') { - actualValue = value.toLowerCase() === 'true' + actualValue = value.toLowerCase() === 'true'; } - editedValue = !isNull ? !actualValue : true + editedValue = !isNull ? !actualValue : true; } else { if (!isNull) { // Type coercion is desired here as custom unchecked/checked states are stored as strings yet value could be integers - editedValue = value == config['CheckedState'] ? config['UncheckedState'] : config['CheckedState'] + editedValue = value == config['CheckedState'] ? config['UncheckedState'] : config['CheckedState']; } else { - editedValue = config['CheckedState'] + editedValue = config['CheckedState']; } } - - valueChangeRequested(editedValue, false) + valueChangeRequested(editedValue, false); } } Rectangle { - id: backgroundRect - anchors.left: parent.left - anchors.right: parent.right - y: checkValue.height - height - checkValue.bottomPadding / 2 - implicitWidth: 120 - height: checkBox.activeFocus || checkBox.pressed || checkArea.containsPress ? 2 : 1 - color: checkBox.activeFocus || checkBox.pressed || checkArea.containsPress ? Theme.accentColor : Theme.accentLightColor + id: backgroundRect + anchors.left: parent.left + anchors.right: parent.right + y: checkValue.height - height - checkValue.bottomPadding / 2 + implicitWidth: 120 + height: checkBox.activeFocus || checkBox.pressed || checkArea.containsPress ? 2 : 1 + color: checkBox.activeFocus || checkBox.pressed || checkArea.containsPress ? Theme.accentColor : Theme.accentLightColor } FontMetrics { diff --git a/src/qml/editorwidgets/DateTime.qml b/src/qml/editorwidgets/DateTime.qml index 15ed727eb8..3368dfa471 100644 --- a/src/qml/editorwidgets/DateTime.qml +++ b/src/qml/editorwidgets/DateTime.qml @@ -1,10 +1,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import Theme 1.0 - import "." import ".." @@ -21,7 +19,6 @@ import ".." to allow a full flexibility of field and display formats. */ - EditorWidgetBase { id: main @@ -34,24 +31,20 @@ EditorWidgetBase { enabled: isEnabled property bool isDateTimeType: field.isDateOrTime - property bool fieldIsDate: LayerUtils.fieldType( field ) === 'QDate' + property bool fieldIsDate: LayerUtils.fieldType(field) === 'QDate' property var currentValue: { - const formattedDate = formatDateTime( value ); + const formattedDate = formatDateTime(value); label.text = formattedDate; return formattedDate; } function formatDateTime(value) { // Will handle both null and undefined as date values - if ( value == null || value === '' ) { + if (value == null || value === '') { return qsTr('(no date)'); } else { - const displayFormat = config['display_format'] == null - ? 'yyyy-MM-dd' - : config['display_format']; - - if ( main.isDateTimeType ) - { + const displayFormat = config['display_format'] == null ? 'yyyy-MM-dd' : config['display_format']; + if (main.isDateTimeType) { // if the field is a QDate, the automatic conversion to JS date [1] // leads to the creation of date time object with the time zone. // For instance shapefiles has support for dates but not date/time or time. @@ -65,16 +58,13 @@ EditorWidgetBase { } else { return Qt.formatDateTime(value, displayFormat); } - } - else - { + } else { const date = Date.fromLocaleString(Qt.locale(), value, config['field_format']); return Qt.formatDateTime(date, displayFormat); } } } - Rectangle { visible: !enabled y: label.height - height @@ -88,7 +78,6 @@ EditorWidgetBase { anchors.left: parent.left anchors.right: parent.right - TextField { id: label @@ -105,12 +94,19 @@ EditorWidgetBase { inputMethodHints: Qt.ImhDigitsOnly // TODO[DR] generate input mask using regex - inputMask: if (config['display_format'] === "yyyy-MM-dd" ) { "9999-99-99;_" } - else if (config['display_format'] === "yyyy.MM.dd" ) { "9999.99.99;_" } - else if (config['display_format'] === "yyyy-MM-dd HH:mm:ss" ) { "9999-99-99 99:99:99;_" } - else if (config['display_format'] === "HH:mm:ss" ) { "99:99:99;_" } - else if (config['display_format'] === "HH:mm" ) { "99:99;_" } - else { "" } + inputMask: if (config['display_format'] === "yyyy-MM-dd") { + "9999-99-99;_"; + } else if (config['display_format'] === "yyyy.MM.dd") { + "9999.99.99;_"; + } else if (config['display_format'] === "yyyy-MM-dd HH:mm:ss") { + "9999-99-99 99:99:99;_"; + } else if (config['display_format'] === "HH:mm:ss") { + "99:99:99;_"; + } else if (config['display_format'] === "HH:mm") { + "99:99;_"; + } else { + ""; + } text: main.currentValue @@ -133,25 +129,21 @@ EditorWidgetBase { if (value !== undefined && value != '') { usedDate = value; } - todayButton.forceActiveFocus() - calendarPanel.selectedDate = usedDate + todayButton.forceActiveFocus(); + calendarPanel.selectedDate = usedDate; calendarPanel.open(); } } onTextEdited: { - var newDate = Date.fromLocaleString(Qt.locale(), label.text, config['display_format']) - if ( newDate.toLocaleString() !== "" ) - { - if ( !main.isDateTimeType ) - { - newDate = Qt.formatDateTime(newDate, config['field_format']) + var newDate = Date.fromLocaleString(Qt.locale(), label.text, config['display_format']); + if (newDate.toLocaleString() !== "") { + if (!main.isDateTimeType) { + newDate = Qt.formatDateTime(newDate, config['field_format']); } - valueChangeRequested(newDate, newDate === undefined) - } - else - { - valueChangeRequested(undefined, true) + valueChangeRequested(newDate, newDate === undefined); + } else { + valueChangeRequested(undefined, true); } } @@ -159,21 +151,19 @@ EditorWidgetBase { if (activeFocus) { // getting focus => placing cursor at proper position // TODO: make it work on empty value - var mytext = label.text - var cur = label.cursorPosition - while ( cur > 0 ) - { - if (!mytext.charAt(cur-1).match("[0-9]") ) - break - cur-- + var mytext = label.text; + var cur = label.cursorPosition; + while (cur > 0) { + if (!mytext.charAt(cur - 1).match("[0-9]")) + break; + cur--; } - label.cursorPosition = cur + label.cursorPosition = cur; } else { // leaving field => if invalid, clear - var newDate = Date.fromLocaleString(Qt.locale(), label.text, config['display_format']) - if ( newDate.toLocaleString() === "" ) - { - label.text = qsTr('(no date)') + var newDate = Date.fromLocaleString(Qt.locale(), label.text, config['display_format']); + if (newDate.toLocaleString() === "") { + label.text = qsTr('(no date)'); } } } @@ -188,16 +178,14 @@ EditorWidgetBase { padding: 0 iconSource: Theme.getThemeIcon("ic_clear_black_18dp") iconColor: Theme.mainTextColor - visible: (value !== undefined) && enabled - && (config['allow_null'] === undefined || config['allow_null']) + visible: (value !== undefined) && enabled && (config['allow_null'] === undefined || config['allow_null']) onClicked: { - valueChangeRequested(undefined, true) + valueChangeRequested(undefined, true); } } } - QfToolButton { id: todayButton width: enabled ? 48 : 0 @@ -207,21 +195,17 @@ EditorWidgetBase { iconColor: Theme.mainTextColor onClicked: { - if ( main.isDateTimeType ) - { - var currentDateTime = new Date() - valueChangeRequested(currentDateTime, false) - } - else - { - var currentDate = new Date() - var textDate = Qt.formatDateTime(currentDate, config['field_format']) - valueChangeRequested(textDate, false) + if (main.isDateTimeType) { + var currentDateTime = new Date(); + valueChangeRequested(currentDateTime, false); + } else { + var currentDate = new Date(); + var textDate = Qt.formatDateTime(currentDate, config['field_format']); + valueChangeRequested(textDate, false); } - displayToast(qsTr( 'Date value set to today.')) + displayToast(qsTr('Date value set to today.')); } } - } FontMetrics { @@ -233,11 +217,11 @@ EditorWidgetBase { id: calendarPanel isDateTime: !main.fieldIsDate onDateTimePicked: { - if ( main.isDateTimeType ) { - valueChangeRequested(date, date === undefined) + if (main.isDateTimeType) { + valueChangeRequested(date, date === undefined); } else { - var textDate = Qt.formatDateTime(date, config['field_format']) - valueChangeRequested(date, date === undefined) + var textDate = Qt.formatDateTime(date, config['field_format']); + valueChangeRequested(date, date === undefined); } } } diff --git a/src/qml/editorwidgets/EditorWidgetBase.qml b/src/qml/editorwidgets/EditorWidgetBase.qml index dc15f8cbad..00441808c2 100644 --- a/src/qml/editorwidgets/EditorWidgetBase.qml +++ b/src/qml/editorwidgets/EditorWidgetBase.qml @@ -2,47 +2,47 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 Item { - /* This property indicates whether the editor widget has been fully loaded by its Loader. + /* This property indicates whether the editor widget has been fully loaded by its Loader. * Note: prior to this property being true, signals emitted by the editor widget will not be * propagated. */ - property bool isLoaded: false - property bool hasMenu: false - property Menu menu: Menu { - id: itemMenu - title: qsTr( "Item Menu" ) - z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature formes + property bool isLoaded: false + property bool hasMenu: false + property Menu menu: Menu { + id: itemMenu + title: qsTr("Item Menu") + z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature formes - width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + width: { + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); } - - topMargin: mainWindow.sceneTopMargin - bottomMargin: mainWindow.sceneBottomMargin + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } - /* This signal is emmited when an editor widget has changed the value. + topMargin: mainWindow.sceneTopMargin + bottomMargin: mainWindow.sceneBottomMargin + } + + /* This signal is emmited when an editor widget has changed the value. */ - signal valueChangeRequested(var value, bool isNull) + signal valueChangeRequested(var value, bool isNull) - /* This signal is emitted when an editor widget is in need of a digitized geometry. The + /* This signal is emitted when an editor widget is in need of a digitized geometry. The * geometry will be returned through calling a requestedGeometryReceived(geometry) function * attached to editor widget which signaled the request. The corresponding * handler is \c onRequestGeometry. */ - signal requestGeometry(var item, var layer) + signal requestGeometry(var item, var layer) - /* This signal is emitted when an editor widget is requesting a barcode value. The + /* This signal is emitted when an editor widget is requesting a barcode value. The * decoded barcode value will be returned as a string through calling a requestedBarcodeReceived(string) function * attached to editor widget which signaled the request. The corresponding * handler is \c onRequestBarcode. */ - signal requestBarcode(var item) + signal requestBarcode(var item) } diff --git a/src/qml/editorwidgets/ExternalResource.qml b/src/qml/editorwidgets/ExternalResource.qml index 4e490a2ab3..d0a8b80822 100644 --- a/src/qml/editorwidgets/ExternalResource.qml +++ b/src/qml/editorwidgets/ExternalResource.qml @@ -3,11 +3,9 @@ import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Window 2.14 import QtMultimedia - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 - import "." import ".." @@ -23,38 +21,39 @@ EditorWidgetBase { property string prefixToRelativePath: { if (qgisProject == undefined) return ""; - - var path = "" - if (config["RelativeStorage"] === 1 ) { - path = qgisProject.homePath - if (!path.endsWith("/")) path = path + "/" - } else if (config["RelativeStorage"] === 2 ) { - var collection = config["PropertyCollection"] - var props = collection["properties"] + var path = ""; + if (config["RelativeStorage"] === 1) { + path = qgisProject.homePath; + if (!path.endsWith("/")) + path = path + "/"; + } else if (config["RelativeStorage"] === 2) { + var collection = config["PropertyCollection"]; + var props = collection["properties"]; if (props) { - if(props["propertyRootPath"]) { - var rootPathProps = props["propertyRootPath"] - rootPathEvaluator.expressionText = rootPathProps["expression"] + if (props["propertyRootPath"]) { + var rootPathProps = props["propertyRootPath"]; + rootPathEvaluator.expressionText = rootPathProps["expression"]; } } - rootPathEvaluator.feature = currentFeature - rootPathEvaluator.layer = currentLayer - var evaluatedFilepath = rootPathEvaluator.evaluate().replace("\\", "/") + rootPathEvaluator.feature = currentFeature; + rootPathEvaluator.layer = currentLayer; + var evaluatedFilepath = rootPathEvaluator.evaluate().replace("\\", "/"); if (evaluatedFilepath) { - path = evaluatedFilepath + path = evaluatedFilepath; } else { - path = config["DefaultRoot"] ? config["DefaultRoot"] : qgisProject.homePath - if (!path.endsWith("/")) path = path + "/" + path = config["DefaultRoot"] ? config["DefaultRoot"] : qgisProject.homePath; + if (!path.endsWith("/")) + path = path + "/"; } } // since we've hardcoded the project path by default so far, let's maintain that until we improve things in qfieldsync if (path == "") { - path = qgisProject.homePath - if (!path.endsWith("/")) path = path + "/" + path = qgisProject.homePath; + if (!path.endsWith("/")) + path = path + "/"; } - - return path + return path; } property ResourceSource __resourceSource @@ -77,32 +76,30 @@ EditorWidgetBase { onCurrentValueChanged: { if (currentValue != undefined && currentValue !== '') { const isHttp = value.startsWith('http://') || value.startsWith('https://'); - var fullValue = isHttp ? value : prefixToRelativePath + value - var mimeType = FileUtils.mimeTypeName(fullValue) - isImage = !config.UseLink && mimeType.startsWith("image/") && FileUtils.isImageMimeTypeSupported(mimeType) - isAudio = !config.UseLink && mimeType.startsWith("audio/") - isVideo = !config.UseLink && mimeType.startsWith("video/") - - image.visible = isImage - geoTagBadge.visible = isImage + var fullValue = isHttp ? value : prefixToRelativePath + value; + var mimeType = FileUtils.mimeTypeName(fullValue); + isImage = !config.UseLink && mimeType.startsWith("image/") && FileUtils.isImageMimeTypeSupported(mimeType); + isAudio = !config.UseLink && mimeType.startsWith("audio/"); + isVideo = !config.UseLink && mimeType.startsWith("video/"); + image.visible = isImage; + geoTagBadge.visible = isImage; if (isImage) { - mediaFrame.height = 200 - - image.visible = true - image.hasImage = true - image.opacity = 1 - image.anchors.topMargin = 0 - image.source = (!isHttp ? 'file://' : '') + fullValue - geoTagBadge.hasGeoTag = ExifTools.hasGeoTag(fullValue) + mediaFrame.height = 200; + image.visible = true; + image.hasImage = true; + image.opacity = 1; + image.anchors.topMargin = 0; + image.source = (!isHttp ? 'file://' : '') + fullValue; + geoTagBadge.hasGeoTag = ExifTools.hasGeoTag(fullValue); } else if (isAudio || isVideo) { - player.firstFrameDrawn = false - player.sourceUrl = (!isHttp ? 'file://' : '') + fullValue + player.firstFrameDrawn = false; + player.sourceUrl = (!isHttp ? 'file://' : '') + fullValue; } } else { - image.source = '' - image.visible = documentViewer == document_IMAGE - image.opacity = 0.15 - geoTagBadge.visible = false + image.source = ''; + image.visible = documentViewer == document_IMAGE; + image.opacity = 0.15; + geoTagBadge.visible = false; player.sourceUrl = ''; } } @@ -115,18 +112,18 @@ EditorWidgetBase { var value; if (currentLayer && currentLayer.customProperty('QFieldSync/attachment_naming') !== undefined) { value = JSON.parse(currentLayer.customProperty('QFieldSync/attachment_naming'))[field.name]; - return value !== undefined ? value : '' + return value !== undefined ? value : ''; } else if (currentLayer && currentLayer.customProperty('QFieldSync/photo_naming') !== undefined) { // Fallback to old configuration key value = JSON.parse(currentLayer.customProperty('QFieldSync/photo_naming'))[field.name]; - return value !== undefined ? value : '' + return value !== undefined ? value : ''; } - return '' + return ''; } } function getResourceFilePath() { - var evaluatedFilepath = expressionEvaluator.evaluate() + var evaluatedFilepath = expressionEvaluator.evaluate(); var filepath = evaluatedFilepath; if (FileUtils.fileSuffix(evaluatedFilepath) === '') { // we need an extension for media types (image, audio, video), fallback to hardcoded values @@ -140,7 +137,7 @@ EditorWidgetBase { filepath = 'files/' + (new Date()).toISOString().replace(/[^0-9]/g, '') + '_{filename}'; } } - filepath = filepath.replace('\\', '/') + filepath = filepath.replace('\\', '/'); return filepath; } @@ -159,14 +156,13 @@ EditorWidgetBase { color: FileUtils.fileExists(prefixToRelativePath + value) ? Theme.mainColor : 'gray' text: { - var fieldValue = prefixToRelativePath + currentValue + var fieldValue = prefixToRelativePath + currentValue; if (UrlUtils.isRelativeOrFileUrl(fieldValue)) { - fieldValue = config.FullUrl ? fieldValue : FileUtils.fileName(fieldValue) + fieldValue = config.FullUrl ? fieldValue : FileUtils.fileName(fieldValue); } - fieldValue = StringUtils.insertLinks(fieldValue) - - hasValue = currentValue !== undefined && !!fieldValue - return hasValue ? fieldValue : qsTr('No Value') + fieldValue = StringUtils.insertLinks(fieldValue); + hasValue = currentValue !== undefined && !!fieldValue; + return hasValue ? fieldValue : qsTr('No Value'); } font.pointSize: Theme.defaultFont.pointSize @@ -186,13 +182,13 @@ EditorWidgetBase { anchors.fill: parent onClicked: { - if ( !value ) - return - - if (!UrlUtils.isRelativeOrFileUrl(value)) { // matches `http://...` but not `file://...` paths - Qt.openUrlExternally(value) + if (!value) + return; + if (!UrlUtils.isRelativeOrFileUrl(value)) { + // matches `http://...` but not `file://...` paths + Qt.openUrlExternally(value); } else if (FileUtils.fileExists(prefixToRelativePath + value)) { - __viewStatus = platformUtilities.open(prefixToRelativePath + value, isEnabled, this) + __viewStatus = platformUtilities.open(prefixToRelativePath + value, isEnabled, this); } } } @@ -232,8 +228,8 @@ EditorWidgetBase { cache: false Image { - property bool hasGeoTag: false id: geoTagBadge + property bool hasGeoTag: false visible: false anchors.bottom: image.bottom anchors.right: image.right @@ -279,7 +275,7 @@ EditorWidgetBase { source: player.sourceUrl onHasVideoChanged: { - mediaFrame.height = hasVideo ? 254 : 48 + mediaFrame.height = hasVideo ? 254 : 48; if (!player.firstFrameDrawn && hasVideo) { play(); } @@ -309,9 +305,7 @@ EditorWidgetBase { MouseArea { enabled: mediaFrame.visible width: parent.width - height: playerControls.visible - ? player.height - 54 - : image.height + height: playerControls.visible ? player.height - 54 : image.height onClicked: { if (FileUtils.fileExists(prefixToRelativePath + value)) { @@ -327,14 +321,14 @@ EditorWidgetBase { visible: image.status === Image.Ready && isEnabled round: true - iconSource: Theme.getThemeVectorIcon( "ic_freehand_white_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_freehand_white_24dp") iconColor: "white" bgcolor: Theme.darkGraySemiOpaque onClicked: { - sketcherConnection.enabled = true - sketcher.loadImage(image.source) - sketcher.open() + sketcherConnection.enabled = true; + sketcher.loadImage(image.source); + sketcher.open(); } } @@ -344,18 +338,16 @@ EditorWidgetBase { enabled: false function onFinished(path) { - var filepath = getResourceFilePath() - filepath = filepath.replace('{filename}', FileUtils.fileName(path)) - filepath = filepath.replace('{extension}', FileUtils.fileSuffix(path)) - platformUtilities.renameFile(path, prefixToRelativePath + filepath) - - valueChangeRequested(filepath, false) - - enabled = false + var filepath = getResourceFilePath(); + filepath = filepath.replace('{filename}', FileUtils.fileName(path)); + filepath = filepath.replace('{extension}', FileUtils.fileSuffix(path)); + platformUtilities.renameFile(path, prefixToRelativePath + filepath); + valueChangeRequested(filepath, false); + enabled = false; } function onCancelled() { - enabled = false + enabled = false; } } @@ -373,17 +365,15 @@ EditorWidgetBase { QfToolButton { id: playButton - iconSource: player.active && player.item.playbackState === MediaPlayer.PlayingState - ? Theme.getThemeVectorIcon('ic_pause_black_24dp') - : Theme.getThemeVectorIcon('ic_play_black_24dp') + iconSource: player.active && player.item.playbackState === MediaPlayer.PlayingState ? Theme.getThemeVectorIcon('ic_pause_black_24dp') : Theme.getThemeVectorIcon('ic_play_black_24dp') iconColor: Theme.mainTextColor bgcolor: "transparent" onClicked: { if (player.item.playbackState === MediaPlayer.PlayingState) { - player.item.pause() + player.item.pause(); } else { - player.item.play() + player.item.play(); } } } @@ -398,7 +388,7 @@ EditorWidgetBase { enabled: to > 0 onMoved: { - player.item.seek(value * 1000) + player.item.seek(value * 1000); } } @@ -419,7 +409,7 @@ EditorWidgetBase { seconds -= hours * 60 * 60; var minutes = Math.floor(seconds / 60) + ''; seconds = (seconds - minutes * 60) + ''; - return hours.padStart(2,'0') + ':' + minutes.padStart(2,'0') + ':' + seconds.padStart(2,'0'); + return hours.padStart(2, '0') + ':' + minutes.padStart(2, '0') + ':' + seconds.padStart(2, '0'); } else { return '-'; } @@ -516,7 +506,7 @@ EditorWidgetBase { Loader { id: audioRecorderLoader sourceComponent: audioRecorderComponent - active:false + active: false } Loader { @@ -534,25 +524,24 @@ EditorWidgetBase { visible: false Component.onCompleted: { - open() + open(); } onFinished: { - var filepath = getResourceFilePath() - filepath = filepath.replace('{filename}', FileUtils.fileName(path)) - filepath = filepath.replace('{extension}', FileUtils.fileSuffix(path)) - platformUtilities.renameFile(path, prefixToRelativePath + filepath) - - valueChangeRequested(filepath, false) - close() + var filepath = getResourceFilePath(); + filepath = filepath.replace('{filename}', FileUtils.fileName(path)); + filepath = filepath.replace('{extension}', FileUtils.fileSuffix(path)); + platformUtilities.renameFile(path, prefixToRelativePath + filepath); + valueChangeRequested(filepath, false); + close(); } onCanceled: { - close() + close(); } onClosed: { - audioRecorderLoader.active = false + audioRecorderLoader.active = false; } } } @@ -566,37 +555,35 @@ EditorWidgetBase { Component.onCompleted: { if (isVideo) { - qfieldCamera.state = 'VideoCapture' - open() + qfieldCamera.state = 'VideoCapture'; + open(); } else { - qfieldCamera.state = 'PhotoCapture' - open() + qfieldCamera.state = 'PhotoCapture'; + open(); } } - onFinished: (path) => { - var filepath = getResourceFilePath() - filepath = filepath.replace('{filename}', FileUtils.fileName(path)) - filepath = filepath.replace('{extension}', FileUtils.fileSuffix(path)) - platformUtilities.renameFile(path, prefixToRelativePath + filepath) - + onFinished: path => { + var filepath = getResourceFilePath(); + filepath = filepath.replace('{filename}', FileUtils.fileName(path)); + filepath = filepath.replace('{extension}', FileUtils.fileSuffix(path)); + platformUtilities.renameFile(path, prefixToRelativePath + filepath); if (!cameraLoader.isVideo) { - var maximumWidhtHeight = iface.readProjectNumEntry("qfieldsync", "maximumImageWidthHeight", 0) - if(maximumWidhtHeight > 0) { - FileUtils.restrictImageSize(prefixToRelativePath + filepath, maximumWidhtHeight) + var maximumWidhtHeight = iface.readProjectNumEntry("qfieldsync", "maximumImageWidthHeight", 0); + if (maximumWidhtHeight > 0) { + FileUtils.restrictImageSize(prefixToRelativePath + filepath, maximumWidhtHeight); } } - - valueChangeRequested(filepath, false) - close() + valueChangeRequested(filepath, false); + close(); } onCanceled: { - close() + close(); } onClosed: { - cameraLoader.active = false + cameraLoader.active = false; } } } @@ -604,13 +591,12 @@ EditorWidgetBase { Connections { target: __resourceSource function onResourceReceived(path) { - if( path ) { - var maximumWidhtHeight = iface.readProjectNumEntry("qfieldsync", "maximumImageWidthHeight", 0) - if(maximumWidhtHeight > 0) { - FileUtils.restrictImageSize(prefixToRelativePath + path, maximumWidhtHeight) + if (path) { + var maximumWidhtHeight = iface.readProjectNumEntry("qfieldsync", "maximumImageWidthHeight", 0); + if (maximumWidhtHeight > 0) { + FileUtils.restrictImageSize(prefixToRelativePath + path, maximumWidhtHeight); } - - valueChangeRequested(path, false) + valueChangeRequested(path, false); } } } @@ -629,85 +615,84 @@ EditorWidgetBase { function onStatusReceived(statusText) { if (statusText !== "") { - displayToast( qsTr("Cannot handle this file type"), 'error') + displayToast(qsTr("Cannot handle this file type"), 'error'); } } } function attachFile() { - Qt.inputMethod.hide() - var filepath = getResourceFilePath() + Qt.inputMethod.hide(); + var filepath = getResourceFilePath(); if (documentViewer == document_AUDIO) { - __resourceSource = platformUtilities.getFile(qgisProject.homePath+'/', filepath, PlatformUtilities.AudioFiles, this) + __resourceSource = platformUtilities.getFile(qgisProject.homePath + '/', filepath, PlatformUtilities.AudioFiles, this); } else { - __resourceSource = platformUtilities.getFile(qgisProject.homePath+'/', filepath, this) + __resourceSource = platformUtilities.getFile(qgisProject.homePath + '/', filepath, this); } } function attachGallery() { - Qt.inputMethod.hide() - var filepath = getResourceFilePath() + Qt.inputMethod.hide(); + var filepath = getResourceFilePath(); if (documentViewer == document_VIDEO) { - __resourceSource = platformUtilities.getGalleryVideo(qgisProject.homePath+'/', filepath, this) + __resourceSource = platformUtilities.getGalleryVideo(qgisProject.homePath + '/', filepath, this); } else { - __resourceSource = platformUtilities.getGalleryPicture(qgisProject.homePath+'/', filepath, this) + __resourceSource = platformUtilities.getGalleryPicture(qgisProject.homePath + '/', filepath, this); } } function capturePhoto() { - Qt.inputMethod.hide() - if ( platformUtilities.capabilities & PlatformUtilities.NativeCamera && settings.valueBool("nativeCamera", true) ) { - var filepath = getResourceFilePath() + Qt.inputMethod.hide(); + if (platformUtilities.capabilities & PlatformUtilities.NativeCamera && settings.valueBool("nativeCamera", true)) { + var filepath = getResourceFilePath(); // Pictures taken by cameras will always be JPG - filepath = filepath.replace('{extension}', 'JPG') - __resourceSource = platformUtilities.getCameraPicture(qgisProject.homePath+'/', filepath, FileUtils.fileSuffix(filepath), this) + filepath = filepath.replace('{extension}', 'JPG'); + __resourceSource = platformUtilities.getCameraPicture(qgisProject.homePath + '/', filepath, FileUtils.fileSuffix(filepath), this); } else { - platformUtilities.createDir(qgisProject.homePath, 'DCIM') - cameraLoader.isVideo = false - cameraLoader.active = true + platformUtilities.createDir(qgisProject.homePath, 'DCIM'); + cameraLoader.isVideo = false; + cameraLoader.active = true; } } function captureVideo() { - Qt.inputMethod.hide() - if ( platformUtilities.capabilities & PlatformUtilities.NativeCamera && settings.valueBool("nativeCamera", true) ) { - var filepath = getResourceFilePath() + Qt.inputMethod.hide(); + if (platformUtilities.capabilities & PlatformUtilities.NativeCamera && settings.valueBool("nativeCamera", true)) { + var filepath = getResourceFilePath(); // Video taken by cameras will always be MP4 - filepath = filepath.replace('{extension}', 'MP4') - __resourceSource = platformUtilities.getCameraVideo(qgisProject.homePath+'/', filepath, FileUtils.fileSuffix(filepath), this) + filepath = filepath.replace('{extension}', 'MP4'); + __resourceSource = platformUtilities.getCameraVideo(qgisProject.homePath + '/', filepath, FileUtils.fileSuffix(filepath), this); } else { - platformUtilities.createDir(qgisProject.homePath, 'DCIM') - cameraLoader.isVideo = true - cameraLoader.active = true + platformUtilities.createDir(qgisProject.homePath, 'DCIM'); + cameraLoader.isVideo = true; + cameraLoader.active = true; } } function captureAudio() { - Qt.inputMethod.hide() - audioRecorderLoader.active = true + Qt.inputMethod.hide(); + audioRecorderLoader.active = true; } Component.onCompleted: { - menu.addItem(capturePhotoMenuItem) - menu.addItem(captureVideoMenuItem) - menu.addItem(captureAudioMenuItem) - menu.addItem(separatorGalleryItem) + menu.addItem(capturePhotoMenuItem); + menu.addItem(captureVideoMenuItem); + menu.addItem(captureAudioMenuItem); + menu.addItem(separatorGalleryItem); if (platformUtilities.capabilities & PlatformUtilities.FilePicker) { - menu.addItem(attachFileMenuItem) + menu.addItem(attachFileMenuItem); } - menu.addItem(attachGalleryMenuItem) - menu.addItem(separatorDrawingItem) - menu.addItem(attachDrawingMenuItem) - + menu.addItem(attachGalleryMenuItem); + menu.addItem(separatorDrawingItem); + menu.addItem(attachDrawingMenuItem); hasMenu = true; } MenuItem { id: capturePhotoMenuItem - text: qsTr( 'Take a photo' ) + text: qsTr('Take a photo') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_camera_photo_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_camera_photo_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding @@ -716,10 +701,10 @@ EditorWidgetBase { MenuItem { id: captureVideoMenuItem - text: qsTr( 'Take a video' ) + text: qsTr('Take a video') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_camera_video_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_camera_video_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding @@ -728,24 +713,27 @@ EditorWidgetBase { MenuItem { id: captureAudioMenuItem - text: qsTr( 'Record an audio clip' ) + text: qsTr('Record an audio clip') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_microphone_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_microphone_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: captureAudio() } - MenuSeparator { id: separatorGalleryItem; width: parent.width } + MenuSeparator { + id: separatorGalleryItem + width: parent.width + } MenuItem { id: attachGalleryMenuItem - text: qsTr( 'Attach a gallery item' ) + text: qsTr('Attach a gallery item') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_gallery_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_gallery_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding @@ -754,31 +742,34 @@ EditorWidgetBase { MenuItem { id: attachFileMenuItem - text: qsTr( 'Attach a file' ) + text: qsTr('Attach a file') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_file_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_file_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: attachFile() } - MenuSeparator { id: separatorDrawingItem; width: parent.width } + MenuSeparator { + id: separatorDrawingItem + width: parent.width + } MenuItem { id: attachDrawingMenuItem - text: qsTr( 'Draw a sketch' ) + text: qsTr('Draw a sketch') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_freehand_white_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_freehand_white_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: { - sketcherConnection.enabled = true - sketcher.clear() - sketcher.open() + sketcherConnection.enabled = true; + sketcher.clear(); + sketcher.open(); } } } diff --git a/src/qml/editorwidgets/Range.qml b/src/qml/editorwidgets/Range.qml index 51d2382848..fc323222bd 100644 --- a/src/qml/editorwidgets/Range.qml +++ b/src/qml/editorwidgets/Range.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 import org.qfield 1.0 - import "." EditorWidgetBase { @@ -20,167 +18,164 @@ EditorWidgetBase { height: childrenRect.height Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - visible: widgetStyle != "Slider" - - TextField { - id: textField - height: fontMetrics.height + 20 - topPadding: 10 - bottomPadding: 10 - rightPadding: 0 - leftPadding: enabled ? 5 : 0 - width: parent.width - decreaseButton.width - increaseButton.width - - font: Theme.defaultFont - color: value === undefined || !enabled ? Theme.mainTextDisabledColor : Theme.mainTextColor - - text: value !== undefined ? value : '' - - validator: { - if (LayerUtils.fieldType( field ) === 'double') - { - doubleValidator; - } - else - { - intValidator; - } - } - - inputMethodHints: Qt.ImhFormattedNumbersOnly - - background: Rectangle { - implicitWidth: 120 - color: "transparent" - - Rectangle { - y: textField.height - height - textField.bottomPadding / 2 - width: textField.width - height: textField.activeFocus ? 2 : 1 - color: textField.activeFocus ? Theme.accentColor : Theme.accentLightColor - } - } - - onTextChanged: { - if (text == '' || !isNaN(parseFloat(text))) { - valueChangeRequested( text, text == '' ) - } - } + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + visible: widgetStyle != "Slider" + + TextField { + id: textField + height: fontMetrics.height + 20 + topPadding: 10 + bottomPadding: 10 + rightPadding: 0 + leftPadding: enabled ? 5 : 0 + width: parent.width - decreaseButton.width - increaseButton.width + + font: Theme.defaultFont + color: value === undefined || !enabled ? Theme.mainTextDisabledColor : Theme.mainTextColor + + text: value !== undefined ? value : '' + + validator: { + if (LayerUtils.fieldType(field) === 'double') { + doubleValidator; + } else { + intValidator; + } } - QfToolButton { - id: decreaseButton - width: enabled ? 48 : 0 - height: 48 - - anchors.verticalCenter: textField.verticalCenter - - iconSource: Theme.getThemeVectorIcon("ic_remove_black_24dp") - iconColor: Theme.mainTextColor - bgcolor: "transparent" - visible: enabled - - onClicked: { - decreaseValue(); - } - onDoubleClicked: { - decreaseValue(); - } - onPressAndHold: { - changeValueTimer.increase = false - changeValueTimer.interval = 700 - changeValueTimer.restart() - } - onReleased: { - changeValueTimer.stop() - } - onCanceled: { - changeValueTimer.stop() - } + inputMethodHints: Qt.ImhFormattedNumbersOnly + + background: Rectangle { + implicitWidth: 120 + color: "transparent" + + Rectangle { + y: textField.height - height - textField.bottomPadding / 2 + width: textField.width + height: textField.activeFocus ? 2 : 1 + color: textField.activeFocus ? Theme.accentColor : Theme.accentLightColor + } + } + + onTextChanged: { + if (text == '' || !isNaN(parseFloat(text))) { + valueChangeRequested(text, text == ''); + } + } + } + + QfToolButton { + id: decreaseButton + width: enabled ? 48 : 0 + height: 48 + + anchors.verticalCenter: textField.verticalCenter + + iconSource: Theme.getThemeVectorIcon("ic_remove_black_24dp") + iconColor: Theme.mainTextColor + bgcolor: "transparent" + visible: enabled + + onClicked: { + decreaseValue(); + } + onDoubleClicked: { + decreaseValue(); } + onPressAndHold: { + changeValueTimer.increase = false; + changeValueTimer.interval = 700; + changeValueTimer.restart(); + } + onReleased: { + changeValueTimer.stop(); + } + onCanceled: { + changeValueTimer.stop(); + } + } + + QfToolButton { + id: increaseButton + width: enabled ? 48 : 0 + height: 48 + + anchors.verticalCenter: textField.verticalCenter + + iconSource: Theme.getThemeVectorIcon("ic_add_black_24dp") + iconColor: Theme.mainTextColor + bgcolor: "transparent" + visible: enabled - QfToolButton { - id: increaseButton - width: enabled ? 48 : 0 - height: 48 - - anchors.verticalCenter: textField.verticalCenter - - iconSource: Theme.getThemeVectorIcon("ic_add_black_24dp") - iconColor: Theme.mainTextColor - bgcolor: "transparent" - visible: enabled - - onClicked: { - increaseValue(); - } - onDoubleClicked: { - increaseValue(); - } - onPressAndHold: { - changeValueTimer.increase = true - changeValueTimer.interval = 700 - changeValueTimer.restart() - } - onReleased: { - changeValueTimer.stop() - } - onCanceled: { - changeValueTimer.stop() - } + onClicked: { + increaseValue(); } + onDoubleClicked: { + increaseValue(); + } + onPressAndHold: { + changeValueTimer.increase = true; + changeValueTimer.interval = 700; + changeValueTimer.restart(); + } + onReleased: { + changeValueTimer.stop(); + } + onCanceled: { + changeValueTimer.stop(); + } + } } Timer { - id: changeValueTimer - interval: 700 - repeat: true - - property bool increase: true - - onTriggered: { - var hitBoundary = false; - if ( increase ) { - increaseValue(); - hitBoundary = textField.text == rangeItem.max - } else { - decreaseValue(); - hitBoundary = textField.text == rangeItem.min; - } - - if ( !hitBoundary ) { - if ( interval > 50 ) interval = interval * 0.7; - } else { - stop(); - } + id: changeValueTimer + interval: 700 + repeat: true + + property bool increase: true + + onTriggered: { + var hitBoundary = false; + if (increase) { + increaseValue(); + hitBoundary = textField.text == rangeItem.max; + } else { + decreaseValue(); + hitBoundary = textField.text == rangeItem.min; + } + if (!hitBoundary) { + if (interval > 50) + interval = interval * 0.7; + } else { + stop(); } + } } function decreaseValue() { - var currentValue = Number.parseFloat(textField.text) - var newValue - if (!isNaN(currentValue)) { - newValue = currentValue - rangeItem.step; - valueChangeRequested(Math.max(rangeItem.min, newValue), false) - } else { - newValue = 0; - valueChangeRequested(newValue, false) - } + var currentValue = Number.parseFloat(textField.text); + var newValue; + if (!isNaN(currentValue)) { + newValue = currentValue - rangeItem.step; + valueChangeRequested(Math.max(rangeItem.min, newValue), false); + } else { + newValue = 0; + valueChangeRequested(newValue, false); + } } function increaseValue() { - var currentValue = Number.parseFloat(textField.text) - var newValue + var currentValue = Number.parseFloat(textField.text); + var newValue; if (!isNaN(currentValue)) { - newValue = currentValue + rangeItem.step; - valueChangeRequested(Math.min(rangeItem.max, newValue ), false) - } else { - newValue = 0; - valueChangeRequested(newValue, false) - } + newValue = currentValue + rangeItem.step; + valueChangeRequested(Math.min(rangeItem.max, newValue), false); + } else { + newValue = 0; + valueChangeRequested(newValue, false); + } } Row { @@ -196,9 +191,7 @@ EditorWidgetBase { width: sliderRow.width / 4 height: fontMetrics.height + 20 elide: Text.ElideRight - text: value !== undefined && value != '' - ? Number(slider.value).toFixed(rangeItem.precision).toLocaleString() + rangeItem.suffix - : '' + text: value !== undefined && value != '' ? Number(slider.value).toFixed(rangeItem.precision).toLocaleString() + rangeItem.suffix : '' verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft font: Theme.defaultFont @@ -215,13 +208,11 @@ EditorWidgetBase { to: !Number.isFinite(rangeItem.max) ? Number.MAX_VALUE : rangeItem.max stepSize: !Number.isFinite(rangeItem.step) ? 1 : rangeItem.step // TODO: using `rangeItem.parent.value` makes item reuseability harder. - value: rangeItem.parent.value !== undefined && rangeItem.parent.value !== '' - ? Number(rangeItem.parent.value) - : from + value: rangeItem.parent.value !== undefined && rangeItem.parent.value !== '' ? Number(rangeItem.parent.value) : from onValueChanged: { if (sliderRow.visible) { - rangeItem.valueChangeRequested(slider.value, false) + rangeItem.valueChangeRequested(slider.value, false); } } } diff --git a/src/qml/editorwidgets/RelationReference.qml b/src/qml/editorwidgets/RelationReference.qml index 61abe98837..46e9285263 100644 --- a/src/qml/editorwidgets/RelationReference.qml +++ b/src/qml/editorwidgets/RelationReference.qml @@ -1,17 +1,18 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 - import ".." import "." EditorWidgetBase { height: childrenRect.height - anchors { left: parent.left; right: parent.right; } + anchors { + left: parent.left + right: parent.right + } property bool showOpenFormButton: config['ShowOpenFormButton'] === undefined || config['ShowOpenFormButton'] === true property var _rel: RelationUtils.resolveReferencingRelation(qgisProject, currentLayer, field.name, config['Relation']) @@ -33,25 +34,32 @@ EditorWidgetBase { attributeValue: value !== undefined ? value : '' onListUpdated: { - valueChangeRequested( attributeValue, false ) + valueChangeRequested(attributeValue, false); } } RelationCombobox { id: relationReference featureListModel: listModel - anchors { left: parent.left; right: parent.right; rightMargin: viewButton.width + openFormButton.width + 4 } + anchors { + left: parent.left + right: parent.right + rightMargin: viewButton.width + openFormButton.width + 4 + } enabled: isEnabled useSearch: true allowAddFeature: config['AllowAddFeatures'] !== undefined && config['AllowAddFeatures'] === true relation: _rel } - QfToolButton { + QfToolButton { id: viewButton enabled: relationReference.currentKeyValue !== undefined && relationReference.currentKeyValue !== '' - anchors { right: openFormButton.left; top: parent.top; } + anchors { + right: openFormButton.left + top: parent.top + } property bool isVisible: listModel.currentLayer !== undefined && listModel.currentLayer.geometryType() !== Qgis.GeometryType.Unknown && listModel.currentLayer.geometryType() !== Qgis.GeometryType.Null visible: isVisible @@ -64,23 +72,22 @@ EditorWidgetBase { onClicked: { if (listModel.currentLayer !== undefined) { - var feature = listModel.getFeatureFromKeyValue(relationReference.currentKeyValue) - locatorHighlightItem.geometryWrapper.qgsGeometry = feature.geometry - locatorHighlightItem.geometryWrapper.crs = listModel.currentLayer.crs - mapCanvas.mapSettings.extent = FeatureUtils.extent(mapCanvas.mapSettings, - listModel.currentLayer, - feature, - featureForm.x, - featureForm.y) + var feature = listModel.getFeatureFromKeyValue(relationReference.currentKeyValue); + locatorHighlightItem.geometryWrapper.qgsGeometry = feature.geometry; + locatorHighlightItem.geometryWrapper.crs = listModel.currentLayer.crs; + mapCanvas.mapSettings.extent = FeatureUtils.extent(mapCanvas.mapSettings, listModel.currentLayer, feature, featureForm.x, featureForm.y); } } } - QfToolButton { + QfToolButton { id: openFormButton enabled: showOpenFormButton && relationReference.currentKeyValue !== undefined && relationReference.currentKeyValue !== '' - anchors { right: parent.right; top: parent.top; } + anchors { + right: parent.right + top: parent.top + } width: enabled ? 48 : 0 height: 48 @@ -90,11 +97,11 @@ EditorWidgetBase { bgcolor: "transparent" onClicked: { - if ( relationReference.currentKeyValue !== undefined && relationReference.currentKeyValue !== '' ) { - relationReference.embeddedFeatureForm.state = isEnabled ? 'Edit' : 'ReadOnly' - relationReference.embeddedFeatureForm.currentLayer = listModel.currentLayer - relationReference.embeddedFeatureForm.feature = listModel.getFeatureFromKeyValue(relationReference.currentKeyValue) - relationReference.embeddedFeatureForm.open() + if (relationReference.currentKeyValue !== undefined && relationReference.currentKeyValue !== '') { + relationReference.embeddedFeatureForm.state = isEnabled ? 'Edit' : 'ReadOnly'; + relationReference.embeddedFeatureForm.currentLayer = listModel.currentLayer; + relationReference.embeddedFeatureForm.feature = listModel.getFeatureFromKeyValue(relationReference.currentKeyValue); + relationReference.embeddedFeatureForm.open(); } } } diff --git a/src/qml/editorwidgets/TextEdit.qml b/src/qml/editorwidgets/TextEdit.qml index 2cb0b3e27e..0ab8b86667 100644 --- a/src/qml/editorwidgets/TextEdit.qml +++ b/src/qml/editorwidgets/TextEdit.qml @@ -1,18 +1,13 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 import org.qfield 1.0 - import "." EditorWidgetBase { id: topItem - property bool isEditable: isEnabled && - LayerUtils.fieldType( field ) !== 'QStringList' && - LayerUtils.fieldType( field ) !== 'QVariantList' && - LayerUtils.fieldType( field ) !== 'QVariantMap' + property bool isEditable: isEnabled && LayerUtils.fieldType(field) !== 'QStringList' && LayerUtils.fieldType(field) !== 'QVariantList' && LayerUtils.fieldType(field) !== 'QVariantMap' height: childrenRect.height @@ -29,15 +24,13 @@ EditorWidgetBase { color: Theme.mainTextColor opacity: 0.45 wrapMode: Text.Wrap - textFormat: (config['IsMultiline'] === true && config['UseHtml']) || stringUtilities.hasLinks(value) - ? TextEdit.RichText - : TextEdit.AutoText + textFormat: (config['IsMultiline'] === true && config['UseHtml']) || stringUtilities.hasLinks(value) ? TextEdit.RichText : TextEdit.AutoText - text: value == null ? '' : config['IsMultiline'] === true - ? config['UseHtml'] === true ? value : stringUtilities.insertLinks(value) - : stringUtilities.insertLinks(value).replace('\n','') + text: value == null ? '' : config['IsMultiline'] === true ? config['UseHtml'] === true ? value : stringUtilities.insertLinks(value) : stringUtilities.insertLinks(value).replace('\n', '') - onLinkActivated: (link) => { Qt.openUrlExternally(link) } + onLinkActivated: link => { + Qt.openUrlExternally(link); + } } TextField { @@ -58,14 +51,11 @@ EditorWidgetBase { validator: { if (field && field.isNumeric) - if ( LayerUtils.fieldType( field ) === 'double') - { - doubleValidator; - } - else - { - intValidator; - } + if (LayerUtils.fieldType(field) === 'double') { + doubleValidator; + } else { + intValidator; + } else { null; } @@ -84,13 +74,13 @@ EditorWidgetBase { inputMethodHints: field && field.isNumeric ? Qt.ImhFormattedNumbersOnly : Qt.ImhNone background: Rectangle { - width: parent.width - height: parent.height - color: "transparent"; + width: parent.width + height: parent.height + color: "transparent" } onTextChanged: { - valueChangeRequested( text, text == '' ) + valueChangeRequested(text, text == ''); } } @@ -113,23 +103,23 @@ EditorWidgetBase { textFormat: config['UseHtml'] ? TextEdit.RichText : TextEdit.PlainText background: Rectangle { - width: parent.width - height: parent.height - color: "transparent"; + width: parent.width + height: parent.height + color: "transparent" } onTextChanged: { - valueChangeRequested( text, text == '' ) + valueChangeRequested(text, text == ''); } } Rectangle { - anchors.left: parent.left - anchors.right: parent.right - y: Math.max( textField.height, textArea.height ) - height - textField.bottomPadding / 2 - implicitWidth: 120 - height: textField.activeFocus || textArea.activeFocus ? 2 : 1 - color: textField.activeFocus || textArea.activeFocus ? Theme.accentColor : Theme.accentLightColor + anchors.left: parent.left + anchors.right: parent.right + y: Math.max(textField.height, textArea.height) - height - textField.bottomPadding / 2 + implicitWidth: 120 + height: textField.activeFocus || textArea.activeFocus ? 2 : 1 + color: textField.activeFocus || textArea.activeFocus ? Theme.accentColor : Theme.accentLightColor } FontMetrics { @@ -138,50 +128,51 @@ EditorWidgetBase { } Component.onCompleted: { - menu.addItem( copyTextItem ); - menu.addItem( pasteTextItem ); - menu.addItem( separatorItem ); - menu.addItem( scanCodeItem ); - + menu.addItem(copyTextItem); + menu.addItem(pasteTextItem); + menu.addItem(separatorItem); + menu.addItem(scanCodeItem); hasMenu = true; } - MenuItem { id: copyTextItem - text: qsTr( 'Copy Text' ) + text: qsTr('Copy Text') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_copy_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_copy_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: { - platformUtilities.copyTextToClipboard(value) + platformUtilities.copyTextToClipboard(value); } } MenuItem { id: pasteTextItem - text: qsTr( 'Paste Text' ) + text: qsTr('Paste Text') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_paste_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_paste_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: { var text = platformUtilities.getTextFromClipboard(); - text = text.trim() - valueChangeRequested(text, text == '') + text = text.trim(); + valueChangeRequested(text, text == ''); } } - MenuSeparator { id: separatorItem; width: parent.width } + MenuSeparator { + id: separatorItem + width: parent.width + } MenuItem { id: scanCodeItem - text: qsTr( 'Scan Code' ) + text: qsTr('Scan Code') font: Theme.defaultFont icon.source: withNfc ? Theme.getThemeVectorIcon("ic_qr_nfc_code_black_24dp") : Theme.getThemeVectorIcon("ic_qr_code_black_24dp") @@ -189,11 +180,11 @@ EditorWidgetBase { leftPadding: Theme.menuItemLeftPadding onTriggered: { - requestBarcode(topItem) + requestBarcode(topItem); } } function requestedBarcodeReceived(string) { - valueChangeRequested(string, false) + valueChangeRequested(string, false); } } diff --git a/src/qml/editorwidgets/UuidGenerator.qml b/src/qml/editorwidgets/UuidGenerator.qml index 265d995069..e0c4c84188 100644 --- a/src/qml/editorwidgets/UuidGenerator.qml +++ b/src/qml/editorwidgets/UuidGenerator.qml @@ -1,9 +1,7 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 import org.qfield 1.0 - import "." EditorWidgetBase { @@ -15,36 +13,36 @@ EditorWidgetBase { } Label { - id: uuidLabel - height: fontMetrics.height + 20 - anchors { - left: parent.left - right: parent.right - } - - topPadding: 10 - bottomPadding: 10 - font: Theme.defaultFont - color: Theme.mainTextDisabledColor - text: { - var displayValue = value !== undefined ? value : '' - if (isLoaded && isAdding && (value == undefined || value === '')) { - displayValue = StringUtils.createUuid(); - valueChangeRequested(displayValue ,false); - } - return displayValue; + id: uuidLabel + height: fontMetrics.height + 20 + anchors { + left: parent.left + right: parent.right + } + + topPadding: 10 + bottomPadding: 10 + font: Theme.defaultFont + color: Theme.mainTextDisabledColor + text: { + var displayValue = value !== undefined ? value : ''; + if (isLoaded && isAdding && (value == undefined || value === '')) { + displayValue = StringUtils.createUuid(); + valueChangeRequested(displayValue, false); } - elide: Text.ElideMiddle + return displayValue; + } + elide: Text.ElideMiddle } Rectangle { - id: backgroundRect - anchors.left: parent.left - anchors.right: parent.right - y: uuidLabel.height - height - uuidLabel.bottomPadding / 2 - implicitWidth: 120 - height: 1 - color: Theme.accentLightColor + id: backgroundRect + anchors.left: parent.left + anchors.right: parent.right + y: uuidLabel.height - height - uuidLabel.bottomPadding / 2 + implicitWidth: 120 + height: 1 + color: Theme.accentLightColor } FontMetrics { diff --git a/src/qml/editorwidgets/ValueMap.qml b/src/qml/editorwidgets/ValueMap.qml index 7378f3c784..44ee19c678 100644 --- a/src/qml/editorwidgets/ValueMap.qml +++ b/src/qml/editorwidgets/ValueMap.qml @@ -3,11 +3,9 @@ import QtQuick.Controls 2.14 import QtQuick.Layouts import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 - import "." import ".." @@ -23,7 +21,7 @@ EditorWidgetBase { // Workaround to get a signal when the value has changed onCurrentKeyValueChanged: { - comboBox.currentIndex = comboBox.model.keyToIndex(currentKeyValue) + comboBox.currentIndex = comboBox.model.keyToIndex(currentKeyValue); } height: childrenRect.height @@ -66,9 +64,7 @@ EditorWidgetBase { // Using the search and comboBox when there are less than X items in the dropdown proves to be poor UI on normally // sized and oriented phones. Some empirical tests proved 6 to be a good number for now. - readonly property int toggleButtonsThreshold: currentLayer && currentLayer.customProperty('QFieldSync/value_map_button_interface_threshold') !== undefined - ? currentLayer.customProperty('QFieldSync/value_map_button_interface_threshold') - : 0 + readonly property int toggleButtonsThreshold: currentLayer && currentLayer.customProperty('QFieldSync/value_map_button_interface_threshold') !== undefined ? currentLayer.customProperty('QFieldSync/value_map_button_interface_threshold') : 0 state: currentItemCount < toggleButtonsThreshold ? "toggleButtonsView" : "comboBoxItemView" property real currentItemCount: comboBox.count @@ -77,7 +73,7 @@ EditorWidgetBase { id: listModel filterCaseSensitivity: Qt.CaseInsensitive onMapChanged: { - comboBox.currentIndex = keyToIndex(valueMap.currentKeyValue) + comboBox.currentIndex = keyToIndex(valueMap.currentKeyValue); } } @@ -122,12 +118,12 @@ EditorWidgetBase { Component.onCompleted: { if (selected) { - toggleButtons.currentSelectedKey = key - toggleButtons.currentSelectedValue = value + toggleButtons.currentSelectedKey = key; + toggleButtons.currentSelectedValue = value; } } - Behavior on color { + Behavior on color { ColorAnimation { duration: 150 } @@ -135,7 +131,7 @@ EditorWidgetBase { Text { id: innerText - width: Math.min(flow.width - 32 , implicitWidth) + width: Math.min(flow.width - 32, implicitWidth) text: value elide: Text.ElideRight anchors.centerIn: parent @@ -148,15 +144,15 @@ EditorWidgetBase { anchors.fill: parent onClicked: { if (toggleButtons.selectedIndex != index) { - comboBox.currentIndex = index - toggleButtons.currentSelectedKey = key - toggleButtons.currentSelectedValue = value + comboBox.currentIndex = index; + toggleButtons.currentSelectedKey = key; + toggleButtons.currentSelectedValue = value; } else { - comboBox.currentIndex = -1 - toggleButtons.currentSelectedKey = "" - toggleButtons.currentSelectedValue = "" + comboBox.currentIndex = -1; + toggleButtons.currentSelectedKey = ""; + toggleButtons.currentSelectedValue = ""; } - valueChangeRequested(toggleButtons.currentSelectedKey, false) + valueChangeRequested(toggleButtons.currentSelectedKey, false); } Ripple { @@ -172,7 +168,6 @@ EditorWidgetBase { } } - Rectangle { y: flow.height + flow.anchors.topMargin + flow.anchors.bottomMargin - 1 visible: !isEnabled @@ -194,14 +189,14 @@ EditorWidgetBase { textRole: 'value' Component.onCompleted: { - comboBox.popup.z = 10000 // 1000s are embedded feature forms, use a higher value to insure popups always show above embedded feature formes - model.valueMap = config['map'] + comboBox.popup.z = 10000; // 1000s are embedded feature forms, use a higher value to insure popups always show above embedded feature formes + model.valueMap = config['map']; } onCurrentTextChanged: { if (valueMap.state === "comboBoxItemView") { - var key = model.keyForValue(currentText) - valueChangeRequested(key, false) + var key = model.keyForValue(currentText); + valueChangeRequested(key, false); } } @@ -210,11 +205,14 @@ EditorWidgetBase { propagateComposedEvents: true onClicked: mouse.accepted = false - onPressed: (mouse)=> { forceActiveFocus(); mouse.accepted = false; } - onReleased: mouse.accepted = false; - onDoubleClicked: mouse.accepted = false; - onPositionChanged: mouse.accepted = false; - onPressAndHold: mouse.accepted = false; + onPressed: mouse => { + forceActiveFocus(); + mouse.accepted = false; + } + onReleased: mouse.accepted = false + onDoubleClicked: mouse.accepted = false + onPositionChanged: mouse.accepted = false + onPressAndHold: mouse.accepted = false } contentItem: Text { @@ -241,9 +239,9 @@ EditorWidgetBase { } Rectangle { + id: backgroundRect visible: enabled anchors.fill: parent - id: backgroundRect border.color: comboBox.pressed ? Theme.accentColor : Theme.accentLightColor border.width: comboBox.visualFocus ? 2 : 1 color: Theme.controlBackgroundAlternateColor @@ -268,7 +266,7 @@ EditorWidgetBase { iconColor: Theme.mainTextColor onClicked: { - searchFeaturePopup.open() + searchFeaturePopup.open(); } } @@ -288,12 +286,12 @@ EditorWidgetBase { onOpened: { if (resultsList.contentHeight > resultsList.height) { - searchField.forceActiveFocus() + searchField.forceActiveFocus(); } } onClosed: { - searchField.text = '' + searchField.text = ''; } Page { @@ -308,8 +306,8 @@ EditorWidgetBase { } TextField { - z: 1 id: searchField + z: 1 anchors.left: parent.left anchors.right: parent.right @@ -327,11 +325,11 @@ EditorWidgetBase { onDisplayTextChanged: listModel.setFilterFixedString(displayText) - Keys.onPressed: (event)=> { + Keys.onPressed: event => { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (listModel.rowCount() === 1) { - resultsList.itemAtIndex(0).performClick() - searchFeaturePopup.close() + resultsList.itemAtIndex(0).performClick(); + searchFeaturePopup.close(); } } } @@ -342,7 +340,12 @@ EditorWidgetBase { z: 1 width: fontMetrics.height height: fontMetrics.height - anchors { top: searchField.top; right: searchField.right; topMargin: height - 7; rightMargin: height - 7 } + anchors { + top: searchField.top + right: searchField.right + topMargin: height - 7 + rightMargin: height - 7 + } padding: 0 iconSource: Theme.getThemeIcon("ic_clear_black_18dp") @@ -400,12 +403,12 @@ EditorWidgetBase { font.italic: value ? false : true checked: itemChecked - indicator: Rectangle {} + indicator: Rectangle { + } - text: searchField.displayText !== '' - ? itemText.replace(new RegExp('('+searchField.displayText+')', "i"), - '$1') - : itemText + text: searchField.displayText !== '' ? itemText.replace(new RegExp('(' + searchField.displayText + ')', "i"), '$1') : itemText contentItem: Text { text: parent.text @@ -429,10 +432,9 @@ EditorWidgetBase { function performClick() { if (key === currentKeyValue) - return - - valueChangeRequested(key, false) - searchFeaturePopup.close() + return; + valueChangeRequested(key, false); + searchFeaturePopup.close(); } } @@ -440,17 +442,16 @@ EditorWidgetBase { anchors.fill: parent propagateComposedEvents: true - onClicked: (mouse)=> { - var item = resultsList.itemAt(resultsList.contentX + mouse.x, resultsList.contentY + mouse.y) + onClicked: mouse => { + var item = resultsList.itemAt(resultsList.contentX + mouse.x, resultsList.contentY + mouse.y); if (!item) return; - - item.performClick() + item.performClick(); } } onMovementStarted: { - Qt.inputMethod.hide() + Qt.inputMethod.hide(); } } } diff --git a/src/qml/editorwidgets/ValueRelation.qml b/src/qml/editorwidgets/ValueRelation.qml index 7890d91b7d..20d01d4497 100644 --- a/src/qml/editorwidgets/ValueRelation.qml +++ b/src/qml/editorwidgets/ValueRelation.qml @@ -1,11 +1,9 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 - import ".." import "." @@ -16,16 +14,15 @@ EditorWidgetBase { enabled: true LayerResolver { - id: layerResolver + id: layerResolver - layerId: config['Layer'] - layerName: config['LayerName'] - layerSource: config['LayerSource'] - layerProviderName: config['LayerProviderName'] - project: qgisProject + layerId: config['Layer'] + layerName: config['LayerName'] + layerSource: config['LayerSource'] + layerProviderName: config['LayerProviderName'] + project: qgisProject } - FeatureCheckListModel { id: listModel allowMulti: Number(config['AllowMulti']) === 1 @@ -45,7 +42,7 @@ EditorWidgetBase { attributeValue: value !== undefined ? value : "" onListUpdated: { - valueChangeRequested( attributeValue, false ) + valueChangeRequested(attributeValue, false); } } @@ -66,7 +63,7 @@ EditorWidgetBase { visible: Number(config['AllowMulti']) === 1 width: parent.width - height: Math.max( valueListView.height, itemHeight) + height: Math.max(valueListView.height, itemHeight) color: Theme.controlBackgroundColor border.color: Theme.controlBorderColor @@ -76,7 +73,7 @@ EditorWidgetBase { id: valueListView model: listModel width: parent.width - height: Math.min( 5 * valueRelationList.itemHeight, valueListView.count * valueRelationList.itemHeight ) + height: Math.min(5 * valueRelationList.itemHeight, valueListView.count * valueRelationList.itemHeight) delegate: listComponent focus: true clip: true @@ -84,10 +81,8 @@ EditorWidgetBase { property int storedIndex - onModelChanged: - currentIndex = storedIndex - onCurrentIndexChanged: - storedIndex = currentIndex + onModelChanged: currentIndex = storedIndex + onCurrentIndexChanged: storedIndex = currentIndex } Component { @@ -95,8 +90,11 @@ EditorWidgetBase { Item { id: listItem - anchors { left: parent ? parent.left : undefined; right: parent ? parent.right : undefined } - height: Math.max( valueRelationList.itemHeight, valueText.height ) + anchors { + left: parent ? parent.left : undefined + right: parent ? parent.right : undefined + } + height: Math.max(valueRelationList.itemHeight, valueText.height) focus: true @@ -143,7 +141,7 @@ EditorWidgetBase { onClicked: { if (isEnabled) { - model.checked = !model.checked + model.checked = !model.checked; } } } @@ -160,7 +158,6 @@ EditorWidgetBase { } function siblingValueChanged(field, feature) { - listModel.currentFormFeature = feature + listModel.currentFormFeature = feature; } } - diff --git a/src/qml/editorwidgets/relationeditors/ordered_relation_editor.qml b/src/qml/editorwidgets/relationeditors/ordered_relation_editor.qml index 20fb7422a6..7fef587962 100644 --- a/src/qml/editorwidgets/relationeditors/ordered_relation_editor.qml +++ b/src/qml/editorwidgets/relationeditors/ordered_relation_editor.qml @@ -4,11 +4,9 @@ import QtQml.Models 2.14 import QtQuick.Layouts 1.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 - import "../.." import ".." @@ -18,8 +16,7 @@ EditorWidgetBase { property int itemHeight: 40 // because no additional addEntry item on readOnly (isEnabled false) - height: listView.contentHeight - + (isEnabled ? addEntry.height : 0) + height: listView.contentHeight + (isEnabled ? addEntry.height : 0) enabled: true Rectangle { @@ -42,7 +39,7 @@ EditorWidgetBase { property int featureFocus: -1 onFailedReorder: { - displayToast( "Failed to reorder features.", "error" ) + displayToast("Failed to reorder features.", "error"); } } @@ -72,7 +69,7 @@ EditorWidgetBase { focus: true - Rectangle{ + Rectangle { anchors.fill: parent color: Theme.controlBorderColor visible: isEnabled @@ -80,8 +77,13 @@ EditorWidgetBase { Text { visible: isEnabled color: Theme.secondaryTextColor - text: isEnabled && !constraintsHardValid ? qsTr( 'Ensure contraints') : '' - anchors { leftMargin: 10; left: parent.left; right: addButtonRow.left; verticalCenter: parent.verticalCenter } + text: isEnabled && !constraintsHardValid ? qsTr('Ensure contraints') : '' + anchors { + leftMargin: 10 + left: parent.left + right: addButtonRow.left + verticalCenter: parent.verticalCenter + } font.bold: true font.italic: true font.pointSize: Theme.tipFont.pointSize @@ -89,7 +91,11 @@ EditorWidgetBase { Row { id: addButtonRow - anchors { top: parent.top; right: parent.right; rightMargin: 10 } + anchors { + top: parent.top + right: parent.right + rightMargin: 10 + } height: parent.height QfToolButton { @@ -99,14 +105,18 @@ EditorWidgetBase { enabled: constraintsHardValid round: false - iconSource: Theme.getThemeIcon( 'ic_add_white_24dp' ) + iconSource: Theme.getThemeIcon('ic_add_white_24dp') bgcolor: parent.enabled ? nmRelationId ? 'blue' : 'black' : 'grey' } } BusyIndicator { id: addingIndicator - anchors { top: parent.top; right: parent.right; rightMargin: 10 } + anchors { + top: parent.top + right: parent.right + rightMargin: 10 + } width: parent.height height: parent.height running: false @@ -124,21 +134,21 @@ EditorWidgetBase { if (ProjectUtils.transactionMode(qgisProject) !== Qgis.TransactionMode.Disabled) { // When a transaction mode is enabled, we must fallback to saving the parent feature to have provider-side issues if (!save()) { - displayToast(qsTr('Cannot add child feature: insure the parent feature meets all constraints and can be saved'), 'warning') - return + displayToast(qsTr('Cannot add child feature: insure the parent feature meets all constraints and can be saved'), 'warning'); + return; } } //this has to be checked after buffering because the primary could be a value that has been created on creating featurer (e.g. fid) - if(orderedRelationModel.parentPrimariesAvailable) { - displayToast(qsTr('Adding child feature in layer %1').arg(orderedRelationModel.relation.referencingLayer.name)) + if (orderedRelationModel.parentPrimariesAvailable) { + displayToast(qsTr('Adding child feature in layer %1').arg(orderedRelationModel.relation.referencingLayer.name)); if (orderedRelationModel.relation.referencingLayer.geometryType() !== Qgis.GeometryType.Null) { requestGeometry(relationEditor, orderedRelationModel.relation.referencingLayer); return; } - showAddFeaturePopup() + showAddFeaturePopup(); } else { - displayToast(qsTr('Cannot add child feature: attribute value linking parent and children is not set'), 'warning') + displayToast(qsTr('Cannot add child feature: attribute value linking parent and children is not set'), 'warning'); } } } @@ -146,7 +156,7 @@ EditorWidgetBase { MouseArea { anchors.fill: parent onClicked: { - addingTimer.restart() + addingTimer.restart(); } } } @@ -173,28 +183,24 @@ EditorWidgetBase { onPressAndHold: { if (isEnabled) { - held = true + held = true; } } onReleased: { if (held === true) { - held = false - orderedRelationModel.moveItems(indexFrom, indexTo) + held = false; + orderedRelationModel.moveItems(indexFrom, indexTo); } else if (listView.currentIndex !== dragArea.DelegateModel.itemsIndex) { - listView.currentIndex = dragArea.DelegateModel.itemsIndex - orderedRelationModel.triggerViewCurrentFeatureChange(listView.currentIndex) + listView.currentIndex = dragArea.DelegateModel.itemsIndex; + orderedRelationModel.triggerViewCurrentFeatureChange(listView.currentIndex); } } onClicked: { if (orderedRelationModel.relation.referencingLayer !== undefined) { - locatorHighlightItem.geometryWrapper.qgsGeometry = nmRelationId ? model.nmReferencingFeature.geometry : model.referencingFeature.geometry - locatorHighlightItem.geometryWrapper.crs = orderedRelationModel.relation.referencingLayer.crs - mapCanvas.mapSettings.extent = FeatureUtils.extent(mapCanvas.mapSettings, - orderedRelationModel.relation.referencingLayer, - nmRelationId ? model.nmReferencingFeature : model.referencingFeature, - featureForm.x, - featureForm.y) + locatorHighlightItem.geometryWrapper.qgsGeometry = nmRelationId ? model.nmReferencingFeature.geometry : model.referencingFeature.geometry; + locatorHighlightItem.geometryWrapper.crs = orderedRelationModel.relation.referencingLayer.crs; + mapCanvas.mapSettings.extent = FeatureUtils.extent(mapCanvas.mapSettings, orderedRelationModel.relation.referencingLayer, nmRelationId ? model.nmReferencingFeature : model.referencingFeature, featureForm.x, featureForm.y); } } @@ -240,13 +246,11 @@ EditorWidgetBase { anchors.fill: parent anchors.margins: 2 - height: Math.max( itemHeight, featureText.height ) + height: Math.max(itemHeight, featureText.height) Image { id: featureImage - source: ImagePath - ? ('file://' + ImagePath) - : Theme.getThemeIcon("ic_photo_notavailable_black_24dp") + source: ImagePath ? ('file://' + ImagePath) : Theme.getThemeIcon("ic_photo_notavailable_black_24dp") width: parent.height height: parent.height fillMode: Image.PreserveAspectFit @@ -261,13 +265,7 @@ EditorWidgetBase { verticalAlignment: Text.AlignVCenter padding: 4 elide: Text.ElideRight - width: parent.width - - 8 - - (featureImage.visible ? featureImage.width : 0) - - viewButton.width - - moveDownButton.width - - moveUpButton.width - - deleteButton.width + width: parent.width - 8 - (featureImage.visible ? featureImage.width : 0) - viewButton.width - moveDownButton.width - moveUpButton.width - deleteButton.width } QfToolButton { @@ -281,13 +279,13 @@ EditorWidgetBase { bgcolor: 'transparent' onClicked: { - embeddedPopup.state = isEnabled ? 'Edit' : 'ReadOnly' - embeddedPopup.currentLayer = orderedRelationModel.relation.referencingLayer - embeddedPopup.linkedRelation = orderedRelationModel.relation - embeddedPopup.linkedRelationOrderingField = orderedRelationModel.orderingField - embeddedPopup.linkedParentFeature = orderedRelationModel.feature - embeddedPopup.feature = model.referencingFeature - embeddedPopup.open() + embeddedPopup.state = isEnabled ? 'Edit' : 'ReadOnly'; + embeddedPopup.currentLayer = orderedRelationModel.relation.referencingLayer; + embeddedPopup.linkedRelation = orderedRelationModel.relation; + embeddedPopup.linkedRelationOrderingField = orderedRelationModel.orderingField; + embeddedPopup.linkedParentFeature = orderedRelationModel.feature; + embeddedPopup.feature = model.referencingFeature; + embeddedPopup.open(); } } @@ -299,19 +297,15 @@ EditorWidgetBase { opacity: (index === listView.count - 1) ? 0.3 : 1 round: false - iconSource: Theme.getThemeVectorIcon( 'ic_chevron_down' ) + iconSource: Theme.getThemeVectorIcon('ic_chevron_down') iconColor: Theme.mainTextColor bgcolor: 'transparent' onClicked: { if (index === listView.count - 1) { - return + return; } - - orderedRelationModel.moveItems( - index, - index + 1 - ) + orderedRelationModel.moveItems(index, index + 1); } } @@ -323,19 +317,15 @@ EditorWidgetBase { opacity: (index === 0) ? 0.3 : 1 round: false - iconSource: Theme.getThemeVectorIcon( 'ic_chevron_up' ) + iconSource: Theme.getThemeVectorIcon('ic_chevron_up') iconColor: Theme.mainTextColor bgcolor: 'transparent' onClicked: { if (index === 0) { - return + return; } - - orderedRelationModel.moveItems( - index, - index - 1 - ) + orderedRelationModel.moveItems(index, index - 1); } } @@ -346,16 +336,16 @@ EditorWidgetBase { height: 40 round: false - iconSource: Theme.getThemeIcon( 'ic_delete_forever_white_24dp' ) + iconSource: Theme.getThemeIcon('ic_delete_forever_white_24dp') iconColor: Theme.mainTextColor bgcolor: 'transparent' onClicked: { - deleteDialog.referencingFeatureId = model.referencingFeature.id - deleteDialog.referencingFeatureDisplayMessage = model.displayString - deleteDialog.nmReferencedFeatureId = nmRelationId ? model.model.nmReferencedFeature.id : 0 - deleteDialog.nmReferencedFeatureDisplayMessage = nmRelationId ? model.nmDisplayString : '' - deleteDialog.visible = true + deleteDialog.referencingFeatureId = model.referencingFeature.id; + deleteDialog.referencingFeatureDisplayMessage = model.displayString; + deleteDialog.nmReferencedFeatureId = nmRelationId ? model.model.nmReferencedFeature.id : 0; + deleteDialog.nmReferencedFeatureDisplayMessage = nmRelationId ? model.nmDisplayString : ''; + deleteDialog.visible = true; } } } @@ -375,14 +365,10 @@ EditorWidgetBase { onEntered: { if (dragArea.indexFrom === -1) { - dragArea.indexFrom = drag.source.DelegateModel.itemsIndex + dragArea.indexFrom = drag.source.DelegateModel.itemsIndex; } - - dragArea.indexTo = dragArea.DelegateModel.itemsIndex - visualModel.items.move( - drag.source.DelegateModel.itemsIndex, - dragArea.DelegateModel.itemsIndex - ) + dragArea.indexTo = dragArea.DelegateModel.itemsIndex; + visualModel.items.move(drag.source.DelegateModel.itemsIndex, dragArea.DelegateModel.itemsIndex); } } } @@ -403,47 +389,28 @@ EditorWidgetBase { visible: false modal: true z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature forms - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 font: Theme.defaultFont - title: nmRelationId - ? qsTr( 'Unlink feature %1 (%2) of %3' ) - .arg( nmReferencedFeatureDisplayMessage ) - .arg( nmReferencedFeatureId ) - .arg( nmReferencedLayerName ) - : qsTr( 'Delete feature %1 (%2) on %3' ) - .arg( referencingFeatureDisplayMessage ) - .arg( referencingFeatureId ) - .arg( referencingLayerName ) + title: nmRelationId ? qsTr('Unlink feature %1 (%2) of %3').arg(nmReferencedFeatureDisplayMessage).arg(nmReferencedFeatureId).arg(nmReferencedLayerName) : qsTr('Delete feature %1 (%2) on %3').arg(referencingFeatureDisplayMessage).arg(referencingFeatureId).arg(referencingLayerName) Label { width: parent.width wrapMode: Text.WordWrap - text: nmRelationId - ? qsTr( 'Should the feature %1 (%2) of layer %3 be unlinked?
(The connection will be deleted on layer %4)') - .arg( nmReferencedFeatureDisplayMessage ) - .arg( deleteDialog.nmReferencedFeatureId ) - .arg( deleteDialog.nmReferencedLayerName ) - .arg( deleteDialog.referencingLayerName ) - : qsTr( 'Should the feature %1 (%2) on layer %3 be deleted?') - .arg( deleteDialog.referencingFeatureDisplayMessage ) - .arg( deleteDialog.referencingFeatureId ) - .arg( deleteDialog.referencingLayerName ) + text: nmRelationId ? qsTr('Should the feature %1 (%2) of layer %3 be unlinked?
(The connection will be deleted on layer %4)').arg(nmReferencedFeatureDisplayMessage).arg(deleteDialog.nmReferencedFeatureId).arg(deleteDialog.nmReferencedLayerName).arg(deleteDialog.referencingLayerName) : qsTr('Should the feature %1 (%2) on layer %3 be deleted?').arg(deleteDialog.referencingFeatureDisplayMessage).arg(deleteDialog.referencingFeatureId).arg(deleteDialog.referencingLayerName) } standardButtons: Dialog.Ok | Dialog.Cancel onAccepted: { - if ( ! orderedRelationModel.deleteFeature( referencingFeatureId ) ) { - displayToast( qsTr( "Failed to delete referencing feature" ), 'error' ) + if (!orderedRelationModel.deleteFeature(referencingFeatureId)) { + displayToast(qsTr("Failed to delete referencing feature"), 'error'); } - - visible = false + visible = false; } onRejected: { - visible = false + visible = false; } - } BusyIndicator { @@ -462,35 +429,35 @@ EditorWidgetBase { codeReader: form.codeReader onFeatureCancelled: { - if( autoSave ) { - orderedRelationModel.reload() + if (autoSave) { + orderedRelationModel.reload(); } } - onFeatureSaved: (id) => { - orderedRelationModel.featureFocus = id - orderedRelationModel.reload() + onFeatureSaved: id => { + orderedRelationModel.featureFocus = id; + orderedRelationModel.reload(); } onOpened: { - addingIndicator.running = false + addingIndicator.running = false; } } function requestedGeometryReceived(geometry) { - showAddFeaturePopup(geometry) + showAddFeaturePopup(geometry); } function showAddFeaturePopup(geometry) { - embeddedPopup.state = 'Add' - embeddedPopup.currentLayer = orderedRelationModel.relation.referencingLayer - embeddedPopup.linkedParentFeature = orderedRelationModel.feature - embeddedPopup.linkedRelation = orderedRelationModel.relation - embeddedPopup.linkedRelationOrderingField = orderedRelationModel.orderingField - if ( geometry !== undefined ) { - embeddedPopup.applyGeometry(geometry) + embeddedPopup.state = 'Add'; + embeddedPopup.currentLayer = orderedRelationModel.relation.referencingLayer; + embeddedPopup.linkedParentFeature = orderedRelationModel.feature; + embeddedPopup.linkedRelation = orderedRelationModel.relation; + embeddedPopup.linkedRelationOrderingField = orderedRelationModel.orderingField; + if (geometry !== undefined) { + embeddedPopup.applyGeometry(geometry); } - embeddedPopup.open() - embeddedPopup.attributeFormModel.applyParentDefaultValues() + embeddedPopup.open(); + embeddedPopup.attributeFormModel.applyParentDefaultValues(); } } diff --git a/src/qml/editorwidgets/relationeditors/relation_editor.qml b/src/qml/editorwidgets/relationeditors/relation_editor.qml index 6d5b034066..0481dd21f4 100644 --- a/src/qml/editorwidgets/relationeditors/relation_editor.qml +++ b/src/qml/editorwidgets/relationeditors/relation_editor.qml @@ -3,411 +3,387 @@ import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import org.qfield 1.0 import org.qgis 1.0 import Theme 1.0 - import "../.." import ".." EditorWidgetBase { - id: relationEditor - - property int itemHeight: 40 - property int bottomMargin: 10 - property int maximumVisibleItems: 4 - - Component.onCompleted: { - if ( currentLayer && currentLayer.customProperty('QFieldSync/relationship_maximum_visible') !== undefined ) { - var value = JSON.parse(currentLayer.customProperty('QFieldSync/relationship_maximum_visible'))[relationId] - maximumVisibleItems = value !== undefined ? value : 4 - } else { - maximumVisibleItems = 4 + id: relationEditor + + property int itemHeight: 40 + property int bottomMargin: 10 + property int maximumVisibleItems: 4 + + Component.onCompleted: { + if (currentLayer && currentLayer.customProperty('QFieldSync/relationship_maximum_visible') !== undefined) { + var value = JSON.parse(currentLayer.customProperty('QFieldSync/relationship_maximum_visible'))[relationId]; + maximumVisibleItems = value !== undefined ? value : 4; + } else { + maximumVisibleItems = 4; + } + } + + // because no additional addEntry item on readOnly (isEnabled false) + height: (isEnabled ? referencingFeatureListView.height + itemHeight : Math.max(referencingFeatureListView.height, itemHeight)) + relationEditor.bottomMargin + enabled: true + + ReferencingFeatureListModel { + //containing the current (parent) feature, the relation to the children + //and the relation from the children to the other parent (if it's nm and cardinality is set) + //if cardinality is not set, the nmRelationId is empty + id: relationEditorModel + currentRelationId: relationId + currentNmRelationId: nmRelationId + feature: currentFeature + + property int featureFocus: -1 + onModelUpdated: { + if (featureFocus > -1) { + referencingFeatureListView.currentIndex = relationEditorModel.getFeatureIdRow(featureFocus); + featureFocus = -1; } } - - // because no additional addEntry item on readOnly (isEnabled false) - height: (isEnabled - ? referencingFeatureListView.height + itemHeight - : Math.max( referencingFeatureListView.height, itemHeight)) + relationEditor.bottomMargin - enabled: true - - ReferencingFeatureListModel { - //containing the current (parent) feature, the relation to the children - //and the relation from the children to the other parent (if it's nm and cardinality is set) - //if cardinality is not set, the nmRelationId is empty - id: relationEditorModel - currentRelationId: relationId - currentNmRelationId: nmRelationId - feature: currentFeature - - property int featureFocus: -1 - onModelUpdated: { - if (featureFocus > -1) { - referencingFeatureListView.currentIndex = relationEditorModel.getFeatureIdRow(featureFocus) - featureFocus = -1 + } + + Rectangle { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: relationEditor.bottomMargin + width: parent.width + color: "transparent" + border.color: Theme.controlBorderColor + border.width: 1 + clip: true + + ListView { + id: referencingFeatureListView + model: relationEditorModel + width: parent.width + height: maximumVisibleItems > 0 ? Math.min(maximumVisibleItems * itemHeight, referencingFeatureListView.count * itemHeight) + (referencingFeatureListView.count > maximumVisibleItems ? itemHeight / 2 : 0) : referencingFeatureListView.count * itemHeight + delegate: referencingFeatureDelegate + focus: true + clip: true + highlightRangeMode: ListView.ApplyRange + + ScrollBar.vertical: ScrollBar { + width: 6 + policy: ScrollBar.AlwaysOn + + contentItem: Rectangle { + implicitWidth: 6 + implicitHeight: itemHeight + color: Theme.mainColor } } } - Rectangle { - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.bottomMargin: relationEditor.bottomMargin - width: parent.width - color: "transparent" - border.color: Theme.controlBorderColor - border.width: 1 - clip: true - - ListView { - id: referencingFeatureListView - model: relationEditorModel - width: parent.width - height: maximumVisibleItems > 0 - ? Math.min(maximumVisibleItems * itemHeight, - referencingFeatureListView.count * itemHeight) - + (referencingFeatureListView.count > maximumVisibleItems ? itemHeight / 2 : 0) - : referencingFeatureListView.count * itemHeight - delegate: referencingFeatureDelegate - focus: true - clip: true - highlightRangeMode: ListView.ApplyRange - - ScrollBar.vertical: ScrollBar { - width: 6 - policy: ScrollBar.AlwaysOn - - contentItem: Rectangle { - implicitWidth: 6 - implicitHeight: itemHeight - color: Theme.mainColor - } + Item { + id: addEntry + anchors.bottom: parent.bottom + height: itemHeight + width: parent.width + visible: isButtonEnabled('AddChildFeature') + + focus: true + + Rectangle { + anchors.fill: parent + color: Theme.controlBorderColor + visible: isEnabled + + Text { + visible: isEnabled + color: Theme.secondaryTextColor + text: isEnabled && !constraintsHardValid ? qsTr('Ensure contraints') : '' + anchors { + leftMargin: 10 + left: parent.left + right: addButtonRow.left + verticalCenter: parent.verticalCenter } + font.bold: true + font.italic: true + font.pointSize: Theme.tipFont.pointSize } - Item { - id: addEntry - anchors.bottom: parent.bottom - height: itemHeight - width: parent.width - visible: isButtonEnabled('AddChildFeature') - - focus: true - - Rectangle { - anchors.fill: parent - color: Theme.controlBorderColor - visible: isEnabled - - Text { - visible: isEnabled - color: Theme.secondaryTextColor - text: isEnabled && !constraintsHardValid ? qsTr( 'Ensure contraints') : '' - anchors { leftMargin: 10; left: parent.left; right: addButtonRow.left; verticalCenter: parent.verticalCenter } - font.bold: true - font.italic: true - font.pointSize: Theme.tipFont.pointSize - } - - Row { - id: addButtonRow - anchors { top: parent.top; right: parent.right; rightMargin: 10 } - height: parent.height - - QfToolButton { - id: addButton - width: parent.height - height: parent.height - enabled: constraintsHardValid - - round: false - iconSource: Theme.getThemeIcon( 'ic_add_white_24dp' ) - bgcolor: parent.enabled ? nmRelationId ? 'blue' : 'black' : 'grey' - } - } - - BusyIndicator { - id: addingIndicator - anchors { top: parent.top; right: parent.right; rightMargin: 10 } - width: parent.height - height: parent.height - running: false - } + Row { + id: addButtonRow + anchors { + top: parent.top + right: parent.right + rightMargin: 10 + } + height: parent.height - Timer { - id: addingTimer - - property string printName: '' - - interval: 50 - repeat: false - - onTriggered: { - if (ProjectUtils.transactionMode(qgisProject) !== Qgis.TransactionMode.Disabled) { - // When a transaction mode is enabled, we must fallback to saving the parent feature to have provider-side issues - if (!save()) { - addingIndicator.running = false - displayToast(qsTr('Cannot add child feature: insure the parent feature meets all constraints and can be saved'), 'warning') - return - } - } - - //this has to be checked after buffering because the primary could be a value that has been created on creating featurer (e.g. fid) - if(relationEditorModel.parentPrimariesAvailable ) { - displayToast(qsTr('Adding child feature in layer %1').arg(relationEditorModel.relation.referencingLayer.name)) - if (relationEditorModel.relation.referencingLayer.geometryType() !== Qgis.GeometryType.Null) - { - requestGeometry(relationEditor, relationEditorModel.relation.referencingLayer); - return; - } - showAddFeaturePopup() - } - else - { - addingIndicator.running = false - displayToast(qsTr('Cannot add child feature: attribute value linking parent and children is not set'), 'warning') - } - } - } + QfToolButton { + id: addButton + width: parent.height + height: parent.height + enabled: constraintsHardValid - MouseArea { - anchors.fill: parent - onClicked: { - addingIndicator.running = true - addingTimer.restart() - } - } + round: false + iconSource: Theme.getThemeIcon('ic_add_white_24dp') + bgcolor: parent.enabled ? nmRelationId ? 'blue' : 'black' : 'grey' } } - } - - Component { - id: referencingFeatureDelegate - Item { - id: listitem - anchors.left: parent ? parent.left : undefined - anchors.right: parent ? parent.right : undefined - - focus: true - - height: Math.max(itemHeight, featureText.height) - - Ripple { - clip: true - width: parent.width - height: parent.height - pressed: mouseArea.pressed - anchor: listitem - active: mouseArea.pressed - color: Material.rippleColor + BusyIndicator { + id: addingIndicator + anchors { + top: parent.top + right: parent.right + rightMargin: 10 } + width: parent.height + height: parent.height + running: false + } - MouseArea { - id: mouseArea - anchors.fill: parent - - onClicked: { - if (relationEditorModel.relation.referencingLayer !== undefined) { - locatorHighlightItem.geometryWrapper.qgsGeometry = nmRelationId ? model.nmReferencingFeature.geometry : model.referencingFeature.geometry - locatorHighlightItem.geometryWrapper.crs = relationEditorModel.relation.referencingLayer.crs - mapCanvas.mapSettings.extent = FeatureUtils.extent(mapCanvas.mapSettings, - relationEditorModel.relation.referencingLayer, - nmRelationId ? model.nmReferencingFeature : model.referencingFeature, - featureForm.x, - featureForm.y) - } - } - } + Timer { + id: addingTimer - Row { - id: itemRow - anchors.fill: parent - anchors.rightMargin: 10 - anchors.leftMargin: 10 - height: listitem.height - - Text { - id: featureText - anchors.verticalCenter: parent.verticalCenter - width: parent.width - viewButton.width - deleteButton.width - font: Theme.defaultFont - color: !isEnabled ? Theme.mainTextDisabledColor : Theme.mainTextColor - elide: Text.ElideRight - text: nmRelationId ? model.nmDisplayString : model.displayString - } + property string printName: '' + + interval: 50 + repeat: false - QfToolButton { - id: viewButton - width: 40 - height: 40 - - round: false - iconSource: isEnabled ? Theme.getThemeVectorIcon('ic_edit_attributes_white-24dp') : Theme.getThemeVectorIcon('ic_baseline-list_alt-24dp') - iconColor: Theme.mainTextColor - bgcolor: 'transparent' - - onClicked: { - embeddedPopup.state = isEnabled ? 'Edit' : 'ReadOnly' - embeddedPopup.currentLayer = nmRelationId ? relationEditorModel.nmRelation.referencedLayer : relationEditorModel.relation.referencingLayer - embeddedPopup.linkedRelation = relationEditorModel.relation - embeddedPopup.linkedParentFeature = relationEditorModel.feature - embeddedPopup.feature = nmRelationId ? model.nmReferencedFeature : model.referencingFeature - embeddedPopup.open() + onTriggered: { + if (ProjectUtils.transactionMode(qgisProject) !== Qgis.TransactionMode.Disabled) { + // When a transaction mode is enabled, we must fallback to saving the parent feature to have provider-side issues + if (!save()) { + addingIndicator.running = false; + displayToast(qsTr('Cannot add child feature: insure the parent feature meets all constraints and can be saved'), 'warning'); + return; } } - QfToolButton { - id: deleteButton - visible: isEnabled && isButtonEnabled('DeleteChildFeature') - width: visible ? 40 : 0 - height: 40 - - round: false - iconSource: Theme.getThemeIcon( 'ic_delete_forever_white_24dp' ) - iconColor: Theme.mainTextColor - bgcolor: 'transparent' - - onClicked: { - deleteDialog.referencingFeatureId = model.referencingFeature.id - deleteDialog.referencingFeatureDisplayMessage = model.displayString - deleteDialog.nmReferencedFeatureId = nmRelationId ? model.model.nmReferencedFeature.id : 0 - deleteDialog.nmReferencedFeatureDisplayMessage = nmRelationId ? model.nmDisplayString : '' - deleteDialog.visible = true + //this has to be checked after buffering because the primary could be a value that has been created on creating featurer (e.g. fid) + if (relationEditorModel.parentPrimariesAvailable) { + displayToast(qsTr('Adding child feature in layer %1').arg(relationEditorModel.relation.referencingLayer.name)); + if (relationEditorModel.relation.referencingLayer.geometryType() !== Qgis.GeometryType.Null) { + requestGeometry(relationEditor, relationEditorModel.relation.referencingLayer); + return; } + showAddFeaturePopup(); + } else { + addingIndicator.running = false; + displayToast(qsTr('Cannot add child feature: attribute value linking parent and children is not set'), 'warning'); } } + } - //bottom line - Rectangle { - id: bottomLine - anchors.bottom: parent.bottom - height: 1 - color: Theme.controlBorderColor - width: parent.width + MouseArea { + anchors.fill: parent + onClicked: { + addingIndicator.running = true; + addingTimer.restart(); } } - } - - Dialog { - id: deleteDialog - parent: mainWindow.contentItem - - property int referencingFeatureId - property string referencingFeatureDisplayMessage - property string referencingLayerName: relationEditorModel.relation.referencingLayer ? relationEditorModel.relation.referencingLayer.name : '' - property int nmReferencedFeatureId - property string nmReferencedFeatureDisplayMessage - property string nmReferencedLayerName: relationEditorModel.nmRelation.referencedLayer ? relationEditorModel.nmRelation.referencedLayer.name : '' - property string nmReferencingLayerName - - visible: false - modal: true - z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature forms - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 - - font: Theme.defaultFont - - title: nmRelationId - ? qsTr( 'Unlink feature %1 (%2) of %3' ) - .arg( nmReferencedFeatureDisplayMessage ) - .arg( nmReferencedFeatureId ) - .arg( nmReferencedLayerName ) - : qsTr( 'Delete feature %1 (%2) on %3' ) - .arg( referencingFeatureDisplayMessage ) - .arg( referencingFeatureId ) - .arg( referencingLayerName ) - Label { - width: parent.width - wrapMode: Text.WordWrap - text: nmRelationId - ? qsTr( 'Should the feature %1 (%2) of layer %3 be unlinked?
(The connection will be deleted on layer %4)') - .arg( nmReferencedFeatureDisplayMessage ) - .arg( deleteDialog.nmReferencedFeatureId ) - .arg( deleteDialog.nmReferencedLayerName ) - .arg( deleteDialog.referencingLayerName ) - : qsTr( 'Should the feature %1 (%2) on layer %3 be deleted?') - .arg( deleteDialog.referencingFeatureDisplayMessage ) - .arg( deleteDialog.referencingFeatureId ) - .arg( deleteDialog.referencingLayerName ) } + } + } - standardButtons: Dialog.Ok | Dialog.Cancel - onAccepted: { - if ( ! referencingFeatureListView.model.deleteFeature( referencingFeatureId ) ) { - displayToast( qsTr( "Failed to delete referencing feature" ), 'error' ) - } + Component { + id: referencingFeatureDelegate - visible = false - } - onRejected: { - visible = false - } + Item { + id: listitem + anchors.left: parent ? parent.left : undefined + anchors.right: parent ? parent.right : undefined - } + focus: true - BusyIndicator { - id: busyIndicator - anchors.centerIn: parent - width: 36 - height: 36 - running: relationEditorModel.isLoading - } + height: Math.max(itemHeight, featureText.height) - EmbeddedFeatureForm { - id: embeddedPopup + Ripple { + clip: true + width: parent.width + height: parent.height + pressed: mouseArea.pressed + anchor: listitem + active: mouseArea.pressed + color: Material.rippleColor + } - embeddedLevel: form.embeddedLevel + 1 - digitizingToolbar: form.digitizingToolbar - codeReader: form.codeReader + MouseArea { + id: mouseArea + anchors.fill: parent - onFeatureCancelled: { - if( autoSave ) - relationEditorModel.reload() + onClicked: { + if (relationEditorModel.relation.referencingLayer !== undefined) { + locatorHighlightItem.geometryWrapper.qgsGeometry = nmRelationId ? model.nmReferencingFeature.geometry : model.referencingFeature.geometry; + locatorHighlightItem.geometryWrapper.crs = relationEditorModel.relation.referencingLayer.crs; + mapCanvas.mapSettings.extent = FeatureUtils.extent(mapCanvas.mapSettings, relationEditorModel.relation.referencingLayer, nmRelationId ? model.nmReferencingFeature : model.referencingFeature, featureForm.x, featureForm.y); + } } + } - onFeatureSaved: (id) => { - relationEditorModel.featureFocus = id - relationEditorModel.reload() + Row { + id: itemRow + anchors.fill: parent + anchors.rightMargin: 10 + anchors.leftMargin: 10 + height: listitem.height + + Text { + id: featureText + anchors.verticalCenter: parent.verticalCenter + width: parent.width - viewButton.width - deleteButton.width + font: Theme.defaultFont + color: !isEnabled ? Theme.mainTextDisabledColor : Theme.mainTextColor + elide: Text.ElideRight + text: nmRelationId ? model.nmDisplayString : model.displayString } - onOpened: { - addingIndicator.running = false + QfToolButton { + id: viewButton + width: 40 + height: 40 + + round: false + iconSource: isEnabled ? Theme.getThemeVectorIcon('ic_edit_attributes_white-24dp') : Theme.getThemeVectorIcon('ic_baseline-list_alt-24dp') + iconColor: Theme.mainTextColor + bgcolor: 'transparent' + + onClicked: { + embeddedPopup.state = isEnabled ? 'Edit' : 'ReadOnly'; + embeddedPopup.currentLayer = nmRelationId ? relationEditorModel.nmRelation.referencedLayer : relationEditorModel.relation.referencingLayer; + embeddedPopup.linkedRelation = relationEditorModel.relation; + embeddedPopup.linkedParentFeature = relationEditorModel.feature; + embeddedPopup.feature = nmRelationId ? model.nmReferencedFeature : model.referencingFeature; + embeddedPopup.open(); + } } - } - function isButtonEnabled(buttonType) { - const buttons = relationEditorWidgetConfig.buttons - if (buttons === undefined) - return true + QfToolButton { + id: deleteButton + visible: isEnabled && isButtonEnabled('DeleteChildFeature') + width: visible ? 40 : 0 + height: 40 + + round: false + iconSource: Theme.getThemeIcon('ic_delete_forever_white_24dp') + iconColor: Theme.mainTextColor + bgcolor: 'transparent' + + onClicked: { + deleteDialog.referencingFeatureId = model.referencingFeature.id; + deleteDialog.referencingFeatureDisplayMessage = model.displayString; + deleteDialog.nmReferencedFeatureId = nmRelationId ? model.model.nmReferencedFeature.id : 0; + deleteDialog.nmReferencedFeatureDisplayMessage = nmRelationId ? model.nmDisplayString : ''; + deleteDialog.visible = true; + } + } + } - if (buttons === 'NoButton') - return false; - if (buttons === 'AllButtons') - return true - if (buttons.split('|').indexOf(buttonType) >= 0) - return true + //bottom line + Rectangle { + id: bottomLine + anchors.bottom: parent.bottom + height: 1 + color: Theme.controlBorderColor + width: parent.width + } + } + } + + Dialog { + id: deleteDialog + parent: mainWindow.contentItem + + property int referencingFeatureId + property string referencingFeatureDisplayMessage + property string referencingLayerName: relationEditorModel.relation.referencingLayer ? relationEditorModel.relation.referencingLayer.name : '' + property int nmReferencedFeatureId + property string nmReferencedFeatureDisplayMessage + property string nmReferencedLayerName: relationEditorModel.nmRelation.referencedLayer ? relationEditorModel.nmRelation.referencedLayer.name : '' + property string nmReferencingLayerName + + visible: false + modal: true + z: 10000 // 1000s are embedded feature forms, use a higher value to insure feature form popups always show above embedded feature forms + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 + + font: Theme.defaultFont + + title: nmRelationId ? qsTr('Unlink feature %1 (%2) of %3').arg(nmReferencedFeatureDisplayMessage).arg(nmReferencedFeatureId).arg(nmReferencedLayerName) : qsTr('Delete feature %1 (%2) on %3').arg(referencingFeatureDisplayMessage).arg(referencingFeatureId).arg(referencingLayerName) + Label { + width: parent.width + wrapMode: Text.WordWrap + text: nmRelationId ? qsTr('Should the feature %1 (%2) of layer %3 be unlinked?
(The connection will be deleted on layer %4)').arg(nmReferencedFeatureDisplayMessage).arg(deleteDialog.nmReferencedFeatureId).arg(deleteDialog.nmReferencedLayerName).arg(deleteDialog.referencingLayerName) : qsTr('Should the feature %1 (%2) on layer %3 be deleted?').arg(deleteDialog.referencingFeatureDisplayMessage).arg(deleteDialog.referencingFeatureId).arg(deleteDialog.referencingLayerName) + } - return false + standardButtons: Dialog.Ok | Dialog.Cancel + onAccepted: { + if (!referencingFeatureListView.model.deleteFeature(referencingFeatureId)) { + displayToast(qsTr("Failed to delete referencing feature"), 'error'); + } + visible = false; + } + onRejected: { + visible = false; + } + } + + BusyIndicator { + id: busyIndicator + anchors.centerIn: parent + width: 36 + height: 36 + running: relationEditorModel.isLoading + } + + EmbeddedFeatureForm { + id: embeddedPopup + + embeddedLevel: form.embeddedLevel + 1 + digitizingToolbar: form.digitizingToolbar + codeReader: form.codeReader + + onFeatureCancelled: { + if (autoSave) + relationEditorModel.reload(); } - function requestedGeometryReceived(geometry) { - showAddFeaturePopup(geometry) + onFeatureSaved: id => { + relationEditorModel.featureFocus = id; + relationEditorModel.reload(); } - function showAddFeaturePopup(geometry) { - embeddedPopup.state = 'Add' - embeddedPopup.currentLayer = relationEditorModel.relation.referencingLayer - embeddedPopup.linkedParentFeature = relationEditorModel.feature - embeddedPopup.linkedRelation = relationEditorModel.relation - if ( geometry !== undefined ) - { - embeddedPopup.applyGeometry(geometry) - } - embeddedPopup.open() - embeddedPopup.attributeFormModel.applyParentDefaultValues() + onOpened: { + addingIndicator.running = false; + } + } + + function isButtonEnabled(buttonType) { + const buttons = relationEditorWidgetConfig.buttons; + if (buttons === undefined) + return true; + if (buttons === 'NoButton') + return false; + if (buttons === 'AllButtons') + return true; + if (buttons.split('|').indexOf(buttonType) >= 0) + return true; + return false; + } + + function requestedGeometryReceived(geometry) { + showAddFeaturePopup(geometry); + } + + function showAddFeaturePopup(geometry) { + embeddedPopup.state = 'Add'; + embeddedPopup.currentLayer = relationEditorModel.relation.referencingLayer; + embeddedPopup.linkedParentFeature = relationEditorModel.feature; + embeddedPopup.linkedRelation = relationEditorModel.relation; + if (geometry !== undefined) { + embeddedPopup.applyGeometry(geometry); } + embeddedPopup.open(); + embeddedPopup.attributeFormModel.applyParentDefaultValues(); + } } diff --git a/src/qml/geometryeditors/Erase.qml b/src/qml/geometryeditors/Erase.qml index eafec550c2..f135635379 100644 --- a/src/qml/geometryeditors/Erase.qml +++ b/src/qml/geometryeditors/Erase.qml @@ -1,15 +1,13 @@ import QtQuick 2.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 - import ".." VisibilityFadingRow { id: eraseToolbar - signal finished() + signal finished property FeatureModel featureModel property GeometryRenderer editorRenderer @@ -21,38 +19,34 @@ VisibilityFadingRow { spacing: 4 - function canvasClicked(point, type) - { + function canvasClicked(point, type) { if (type === "stylus") { - drawPolygonToolbar.addVertex() - return true + drawPolygonToolbar.addVertex(); + return true; } - return false + return false; } - function canvasLongPressed(point, type) - { + function canvasLongPressed(point, type) { if (type === "stylus") { - drawPolygonToolbar.confirm() - return true + drawPolygonToolbar.confirm(); + return true; } - return false + return false; } - function canvasFreehandBegin() - { - geometryEditorsRubberband.visible = false - drawPolygonToolbar.rubberbandModel.measureValue = 0.0 - drawPolygonToolbar.addVertex() - adjustSize() - return true // handled + function canvasFreehandBegin() { + geometryEditorsRubberband.visible = false; + drawPolygonToolbar.rubberbandModel.measureValue = 0.0; + drawPolygonToolbar.addVertex(); + adjustSize(); + return true; // handled } - function canvasFreehandEnd() - { - drawPolygonToolbar.rubberbandModel.measureValue = 0.0 - drawPolygonToolbar.addVertex() - return true // handled + function canvasFreehandEnd() { + drawPolygonToolbar.rubberbandModel.measureValue = 0.0; + drawPolygonToolbar.addVertex(); + return true; // handled } DigitizingToolbar { @@ -63,46 +57,44 @@ VisibilityFadingRow { digitizingLogger.type: 'edit_erase' function addVertex() { - digitizingLogger.addCoordinate( coordinateLocator.currentCoordinate ) - coordinateLocator.flash() - - rubberbandModel.addVertex() + digitizingLogger.addCoordinate(coordinateLocator.currentCoordinate); + coordinateLocator.flash(); + rubberbandModel.addVertex(); } onConfirmed: { - digitizingLogger.writeCoordinates() - - rubberbandModel.frozen = true + digitizingLogger.writeCoordinates(); + rubberbandModel.frozen = true; if (!featureModel.currentLayer.editBuffer()) { - featureModel.currentLayer.startEditing() + featureModel.currentLayer.startEditing(); } - var result = GeometryUtils.eraseFromRubberband(featureModel.currentLayer, featureModel.feature.id, rubberbandModel) - if ( result !== GeometryUtils.Success ) { - if ( result === GeometryUtils.AddPartNotMultiGeometry ) { - displayToast( qsTr( 'The geometry could not be modified into multiple parts' ), 'error' ); - } else { - displayToast( qsTr( 'The geometry could not be modified' ), 'error' ); - } - featureModel.currentLayer.rollBack() - rubberbandModel.reset() + var result = GeometryUtils.eraseFromRubberband(featureModel.currentLayer, featureModel.feature.id, rubberbandModel); + if (result !== GeometryUtils.Success) { + if (result === GeometryUtils.AddPartNotMultiGeometry) { + displayToast(qsTr('The geometry could not be modified into multiple parts'), 'error'); + } else { + displayToast(qsTr('The geometry could not be modified'), 'error'); + } + featureModel.currentLayer.rollBack(); + rubberbandModel.reset(); } else { - featureModel.currentLayer.commitChanges() - rubberbandModel.reset() - featureModel.refresh() - featureModel.applyGeometryToVertexModel() + featureModel.currentLayer.commitChanges(); + rubberbandModel.reset(); + featureModel.refresh(); + featureModel.applyGeometryToVertexModel(); } - rubberbandModel.reset() - eraseToolbar.editorRenderer.geometryWrapper.clear() + rubberbandModel.reset(); + eraseToolbar.editorRenderer.geometryWrapper.clear(); } onCancel: { - rubberbandModel.reset() - eraseToolbar.editorRenderer.geometryWrapper.clear() + rubberbandModel.reset(); + eraseToolbar.editorRenderer.geometryWrapper.clear(); } onVertexCountChanged: { - editorRenderer.geometryWrapper.crs = featureModel.currentLayer.crs - editorRenderer.geometryWrapper.qgsGeometry = GeometryUtils.variableWidthBufferByMFromRubberband(drawPolygonToolbar.rubberbandModel, featureModel.currentLayer.crs) + editorRenderer.geometryWrapper.crs = featureModel.currentLayer.crs; + editorRenderer.geometryWrapper.qgsGeometry = GeometryUtils.variableWidthBufferByMFromRubberband(drawPolygonToolbar.rubberbandModel, featureModel.currentLayer.crs); } } @@ -121,11 +113,7 @@ VisibilityFadingRow { property int sizeMedium: 6 property int sizeLarge: 12 - iconSource: eraseToolbar.size == sizeSmall - ? Theme.getThemeVectorIcon("ic_size_small_white_24dp") - : eraseToolbar.size == sizeMedium - ? Theme.getThemeVectorIcon("ic_size_medium_white_24dp") - : Theme.getThemeVectorIcon("ic_size_large_white_24dp") + iconSource: eraseToolbar.size == sizeSmall ? Theme.getThemeVectorIcon("ic_size_small_white_24dp") : eraseToolbar.size == sizeMedium ? Theme.getThemeVectorIcon("ic_size_medium_white_24dp") : Theme.getThemeVectorIcon("ic_size_large_white_24dp") iconColor: "white" round: true visible: true @@ -133,37 +121,34 @@ VisibilityFadingRow { onClicked: { if (eraseToolbar.size == sizeSmall) { - eraseToolbar.size = sizeMedium + eraseToolbar.size = sizeMedium; } else if (eraseToolbar.size == sizeMedium) { - eraseToolbar.size = sizeLarge + eraseToolbar.size = sizeLarge; } else { - eraseToolbar.size = sizeSmall + eraseToolbar.size = sizeSmall; } adjustSize(); } } - function adjustSize() - { - drawPolygonToolbar.rubberbandModel.measureValue = drawPolygonToolbar.mapSettings.mapUnitsPerPoint * 5 * eraseToolbar.size + function adjustSize() { + drawPolygonToolbar.rubberbandModel.measureValue = drawPolygonToolbar.mapSettings.mapUnitsPerPoint * 5 * eraseToolbar.size; } - function init(featureModel, mapSettings, editorRubberbandModel, editorRenderer) - { - eraseToolbar.featureModel = featureModel - eraseToolbar.editorRenderer = editorRenderer - eraseToolbar.editorRenderer.mapSettings = mapSettings - drawPolygonToolbar.digitizingLogger.digitizingLayer = featureModel.currentLayer - drawPolygonToolbar.mapSettings = mapSettings - drawPolygonToolbar.rubberbandModel = editorRubberbandModel - drawPolygonToolbar.rubberbandModel.geometryType = Qgis.GeometryType.Line - adjustSize() - drawPolygonToolbar.stateVisible = true + function init(featureModel, mapSettings, editorRubberbandModel, editorRenderer) { + eraseToolbar.featureModel = featureModel; + eraseToolbar.editorRenderer = editorRenderer; + eraseToolbar.editorRenderer.mapSettings = mapSettings; + drawPolygonToolbar.digitizingLogger.digitizingLayer = featureModel.currentLayer; + drawPolygonToolbar.mapSettings = mapSettings; + drawPolygonToolbar.rubberbandModel = editorRubberbandModel; + drawPolygonToolbar.rubberbandModel.geometryType = Qgis.GeometryType.Line; + adjustSize(); + drawPolygonToolbar.stateVisible = true; } - function cancel() - { - drawPolygonToolbar.cancel() - geometryEditorsRubberband.visible = true + function cancel() { + drawPolygonToolbar.cancel(); + geometryEditorsRubberband.visible = true; } } diff --git a/src/qml/geometryeditors/FillRing.qml b/src/qml/geometryeditors/FillRing.qml index da462afb47..70c233d340 100644 --- a/src/qml/geometryeditors/FillRing.qml +++ b/src/qml/geometryeditors/FillRing.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import org.qgis 1.0 import org.qfield 1.0 import Theme 1.0 @@ -9,7 +8,7 @@ import ".." VisibilityFadingRow { id: fillRingToolbar - signal finished() + signal finished property FeatureModel featureModel property bool screenHovering: false // 100) + interval = interval * 0.8; + } + } + + ColumnLayout { + Rectangle { + width: 350 + height: childrenRect.height + color: "transparent" + + MouseArea { + anchors.fill: parent + onClicked: mouse => { + mouse.accepted = true; + } + onWheel: wheel => { + wheel.accepted = true; + } + } + + GridLayout { + anchors.left: parent.left + anchors.right: parent.right + columns: 3 + + Row { + Layout.column: 0 + Layout.row: 0 + + QfToolButton { + enabled: true + iconSource: Theme.getThemeIcon('ic_doublearrow_left_black_24dp') + iconColor: Theme.mainTextColor + bgcolor: "transparent" + roundborder: true + + onPressed: { + calendar.decreaseYear(); + changeCalendarTimer.action = 'decreaseYear'; + changeCalendarTimer.interval = 700; + changeCalendarTimer.restart(); + } + onReleased: { + changeCalendarTimer.stop(); + } + onCanceled: { + changeCalendarTimer.stop(); + } + } - Timer { - id: changeCalendarTimer - interval: 700 - repeat: true - - property string action: '' - - onTriggered: { - switch(action) { - case 'decreaseYear': - calendar.decreaseYear(); - break; - case 'decreaseMonth': - calendar.decreaseMonth(); - break; - case 'increaseYear': - calendar.increaseYear(); - break; - case 'increaseMonth': - calendar.increaseMonth(); - break; + QfToolButton { + enabled: true + iconSource: Theme.getThemeIcon('ic_arrow_left_black_24dp') + iconColor: Theme.mainTextColor + bgcolor: "transparent" + roundborder: true + + onPressed: { + calendar.decreaseMonth(); + changeCalendarTimer.action = 'decreaseMonth'; + changeCalendarTimer.interval = 700; + changeCalendarTimer.restart(); + } + onReleased: { + changeCalendarTimer.stop(); + } + onCanceled: { + changeCalendarTimer.stop(); + } } - if ( interval > 100 ) interval = interval * 0.8; } - } - ColumnLayout { - Rectangle { - width: 350 - height: childrenRect.height - color: "transparent" + Text { + text: calendar.title + horizontalAlignment: Text.AlignHCenter + Layout.column: 1 + Layout.row: 0 + Layout.fillWidth: true + font: Theme.tipFont + color: Theme.mainTextColor + } - MouseArea { - anchors.fill: parent - onClicked: (mouse) => { mouse.accepted = true } - onWheel: (wheel) => { wheel.accepted = true } + Row { + Layout.column: 2 + Layout.row: 0 + + QfToolButton { + enabled: true + iconSource: Theme.getThemeIcon('ic_arrow_right_black_24dp') + iconColor: Theme.mainTextColor + bgcolor: "transparent" + roundborder: true + + onPressed: { + calendar.increaseMonth(); + changeCalendarTimer.action = 'increaseMonth'; + changeCalendarTimer.interval = 700; + changeCalendarTimer.restart(); } - - GridLayout { - anchors.left: parent.left - anchors.right: parent.right - columns: 3 - - Row { - Layout.column: 0 - Layout.row: 0 - - QfToolButton { - enabled: true - iconSource: Theme.getThemeIcon( 'ic_doublearrow_left_black_24dp' ) - iconColor: Theme.mainTextColor - bgcolor: "transparent" - roundborder: true - - onPressed: { - calendar.decreaseYear(); - changeCalendarTimer.action = 'decreaseYear'; - changeCalendarTimer.interval = 700; - changeCalendarTimer.restart(); - } - onReleased: { - changeCalendarTimer.stop() - } - onCanceled: { - changeCalendarTimer.stop() - } - } - - QfToolButton { - enabled: true - iconSource: Theme.getThemeIcon( 'ic_arrow_left_black_24dp' ) - iconColor: Theme.mainTextColor - bgcolor: "transparent" - roundborder: true - - onPressed: { - calendar.decreaseMonth(); - changeCalendarTimer.action = 'decreaseMonth'; - changeCalendarTimer.interval = 700; - changeCalendarTimer.restart(); - } - onReleased: { - changeCalendarTimer.stop() - } - onCanceled: { - changeCalendarTimer.stop() - } - } - } - - Text { - text: calendar.title - horizontalAlignment: Text.AlignHCenter - Layout.column: 1 - Layout.row: 0 - Layout.fillWidth: true - font: Theme.tipFont - color: Theme.mainTextColor - } - - Row { - Layout.column: 2 - Layout.row: 0 - - QfToolButton { - enabled: true - iconSource: Theme.getThemeIcon( 'ic_arrow_right_black_24dp' ) - iconColor: Theme.mainTextColor - bgcolor: "transparent" - roundborder: true - - onPressed: { - calendar.increaseMonth(); - changeCalendarTimer.action = 'increaseMonth'; - changeCalendarTimer.interval = 700; - changeCalendarTimer.restart(); - } - onReleased: { - changeCalendarTimer.stop() - } - onCanceled: { - changeCalendarTimer.stop() - } - } - QfToolButton { - enabled: true - iconSource: Theme.getThemeIcon( 'ic_doublearrow_right_black_24dp' ) - iconColor: Theme.mainTextColor - bgcolor: "transparent" - roundborder: true - - onPressed: { - calendar.increaseYear(); - changeCalendarTimer.action = 'increaseYear'; - changeCalendarTimer.interval = 700; - changeCalendarTimer.restart(); - } - onReleased: { - changeCalendarTimer.stop() - } - onCanceled: { - changeCalendarTimer.stop() - } - } - } - - DayOfWeekRow { - locale: calendar.locale - - Layout.column: 0 - Layout.columnSpan: 3 - Layout.row: 1 - Layout.fillWidth: true - - delegate: Text { - text: model.shortName - font: Theme.tipFont - color: Theme.secondaryTextColor - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - } - - MonthGrid { - id: calendar - - property date today: new Date() - - function decreaseYear() { - year -= 1; - } - function increaseYear() { - year += 1; - } - function decreaseMonth() { - if (month !== Calendar.January) { - month -= 1; - } else { - year -= 1; - month = Calendar.December; - } - } - function increaseMonth() { - if (month !== Calendar.December) { - month += 1; - } else { - month = Calendar.January - year += 1; - } - } - - month: Calendar.January - year: 2020 - Layout.row: 2 - Layout.column: 0 - Layout.columnSpan: 3 - Layout.fillWidth: true - Layout.preferredHeight: 40 * 6 - - delegate: Rectangle { - property bool isSelectedDate: calendarPopup.selectedDate.getFullYear() === model.date.getFullYear() && calendarPopup.selectedDate.getMonth() === model.date.getMonth() && calendarPopup.selectedDate.getDate() === model.date.getDate() - property bool isNow: calendar.today.getFullYear() === model.date.getFullYear() && calendar.today.getMonth() === model.date.getMonth() && calendar.today.getDate() === model.date.getDate() - color: isSelectedDate ? Theme.mainColor : "transparent" - width: 18 - height: 18 - radius: 10 - - Text { - anchors.centerIn: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - opacity: model.month !== calendar.month ? 0.5 : 1 - text: model.day - font.pointSize: Theme.tipFont.pointSize - font.bold: parent.isSelectedDate ? true : false - font.underline: parent.isNow ? true : false - color: parent.isSelectedDate ? "white" : Theme.mainTextColor - } - } - - onClicked: (date) => { - if (calendarPopup.selectedDate.getFullYear() !== date.getFullYear() || - calendarPopup.selectedDate.getMonth() !== date.getMonth() || - calendarPopup.selectedDate.getDate() !== date.getDate()) { - calendarPopup.selectedDate = date; - } else { - calendarPopup.selectDate(); - } - } - - function resetDate() { - calendarPopup.selectedDate = new Date() - } - } + onReleased: { + changeCalendarTimer.stop(); + } + onCanceled: { + changeCalendarTimer.stop(); + } + } + QfToolButton { + enabled: true + iconSource: Theme.getThemeIcon('ic_doublearrow_right_black_24dp') + iconColor: Theme.mainTextColor + bgcolor: "transparent" + roundborder: true + + onPressed: { + calendar.increaseYear(); + changeCalendarTimer.action = 'increaseYear'; + changeCalendarTimer.interval = 700; + changeCalendarTimer.restart(); + } + onReleased: { + changeCalendarTimer.stop(); + } + onCanceled: { + changeCalendarTimer.stop(); } + } } - RowLayout { - GridLayout { - id: timeGrid - visible: calendarPanel.isDateTime - Layout.alignment: Qt.AlignHCenter - Layout.leftMargin: 20 - rows: 3 - columns: 2 - - Label { - Layout.alignment: Qt.AlignRight - Layout.row: 0 - Layout.column: 0 - text: qsTr( "Hours" ) - font: Theme.tipFont - } - SpinBox { - id: hoursSpinBox - Layout.row: 0 - Layout.column: 1 - editable: true - from: 0 - to: 23 - value: 12 - inputMethodHints: Qt.ImhTime - font: Theme.tipFont - } - Label { - Layout.alignment: Qt.AlignRight - Layout.row: 1 - Layout.column: 0 - text: qsTr( "Minutes" ) - font: Theme.tipFont - } - SpinBox { - id: minutesSpinBox - Layout.row: 1 - Layout.column: 1 - editable: true - from: 0 - to: 59 - value: 30 - inputMethodHints: Qt.ImhTime - font: Theme.tipFont - } - Label { - Layout.alignment: Qt.AlignRight - Layout.row: 2 - Layout.column: 0 - text: qsTr( "Seconds" ) - font: Theme.tipFont - } - SpinBox { - id: secondsSpinBox - Layout.row: 2 - Layout.column: 1 - editable: true - from: 0 - to: 59 - value: 30 - inputMethodHints: Qt.ImhTime - font: Theme.tipFont - } - } + DayOfWeekRow { + locale: calendar.locale + + Layout.column: 0 + Layout.columnSpan: 3 + Layout.row: 1 + Layout.fillWidth: true + + delegate: Text { + text: model.shortName + font: Theme.tipFont + color: Theme.secondaryTextColor + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } } - RowLayout { - QfButton { - id: okButton - text: qsTr( "OK" ) - font: Theme.tipFont - Layout.fillWidth: true + MonthGrid { + id: calendar + + property date today: new Date() + + function decreaseYear() { + year -= 1; + } + function increaseYear() { + year += 1; + } + function decreaseMonth() { + if (month !== Calendar.January) { + month -= 1; + } else { + year -= 1; + month = Calendar.December; + } + } + function increaseMonth() { + if (month !== Calendar.December) { + month += 1; + } else { + month = Calendar.January; + year += 1; + } + } + + month: Calendar.January + year: 2020 + Layout.row: 2 + Layout.column: 0 + Layout.columnSpan: 3 + Layout.fillWidth: true + Layout.preferredHeight: 40 * 6 + + delegate: Rectangle { + property bool isSelectedDate: calendarPopup.selectedDate.getFullYear() === model.date.getFullYear() && calendarPopup.selectedDate.getMonth() === model.date.getMonth() && calendarPopup.selectedDate.getDate() === model.date.getDate() + property bool isNow: calendar.today.getFullYear() === model.date.getFullYear() && calendar.today.getMonth() === model.date.getMonth() && calendar.today.getDate() === model.date.getDate() + color: isSelectedDate ? Theme.mainColor : "transparent" + width: 18 + height: 18 + radius: 10 + + Text { + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + opacity: model.month !== calendar.month ? 0.5 : 1 + text: model.day + font.pointSize: Theme.tipFont.pointSize + font.bold: parent.isSelectedDate ? true : false + font.underline: parent.isNow ? true : false + color: parent.isSelectedDate ? "white" : Theme.mainTextColor + } + } - onClicked: selectDate(); + onClicked: date => { + if (calendarPopup.selectedDate.getFullYear() !== date.getFullYear() || calendarPopup.selectedDate.getMonth() !== date.getMonth() || calendarPopup.selectedDate.getDate() !== date.getDate()) { + calendarPopup.selectedDate = date; + } else { + calendarPopup.selectDate(); } + } + + function resetDate() { + calendarPopup.selectedDate = new Date(); + } } + } } - function selectDate() { - var newDate = calendarPopup.selectedDate - if (calendarPanel.isDateTime) { - newDate.setHours(hoursSpinBox.value); - newDate.setMinutes(minutesSpinBox.value); - newDate.setSeconds(secondsSpinBox.value); + RowLayout { + GridLayout { + id: timeGrid + visible: calendarPanel.isDateTime + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: 20 + rows: 3 + columns: 2 + + Label { + Layout.alignment: Qt.AlignRight + Layout.row: 0 + Layout.column: 0 + text: qsTr("Hours") + font: Theme.tipFont + } + SpinBox { + id: hoursSpinBox + Layout.row: 0 + Layout.column: 1 + editable: true + from: 0 + to: 23 + value: 12 + inputMethodHints: Qt.ImhTime + font: Theme.tipFont + } + Label { + Layout.alignment: Qt.AlignRight + Layout.row: 1 + Layout.column: 0 + text: qsTr("Minutes") + font: Theme.tipFont + } + SpinBox { + id: minutesSpinBox + Layout.row: 1 + Layout.column: 1 + editable: true + from: 0 + to: 59 + value: 30 + inputMethodHints: Qt.ImhTime + font: Theme.tipFont } - dateTimePicked(newDate); - calendarPanel.close() + Label { + Layout.alignment: Qt.AlignRight + Layout.row: 2 + Layout.column: 0 + text: qsTr("Seconds") + font: Theme.tipFont + } + SpinBox { + id: secondsSpinBox + Layout.row: 2 + Layout.column: 1 + editable: true + from: 0 + to: 59 + value: 30 + inputMethodHints: Qt.ImhTime + font: Theme.tipFont + } + } } -} + RowLayout { + QfButton { + id: okButton + text: qsTr("OK") + font: Theme.tipFont + Layout.fillWidth: true + onClicked: selectDate() + } + } + } + + function selectDate() { + var newDate = calendarPopup.selectedDate; + if (calendarPanel.isDateTime) { + newDate.setHours(hoursSpinBox.value); + newDate.setMinutes(minutesSpinBox.value); + newDate.setSeconds(secondsSpinBox.value); + } + dateTimePicked(newDate); + calendarPanel.close(); + } +} diff --git a/src/qml/imports/Theme/QfCloseButton.qml b/src/qml/imports/Theme/QfCloseButton.qml index 8c8ce932cd..b12210bf84 100644 --- a/src/qml/imports/Theme/QfCloseButton.qml +++ b/src/qml/imports/Theme/QfCloseButton.qml @@ -2,7 +2,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import Theme 1.0 ToolButton { @@ -11,7 +10,7 @@ ToolButton { property string toolImage: '' property string toolText: qsTr("close") - signal close() + signal close height: 48 width: height + buttonText.width + 32 + 24 @@ -43,7 +42,7 @@ ToolButton { pressed: button.down anchor: parent active: button.down - color: "#22aaaaaa" + color: "#22aaaaaa" } } @@ -69,14 +68,13 @@ ToolButton { fillMode: Image.PreserveAspectFit horizontalAlignment: Image.AlignHCenter verticalAlignment: Image.AlignVCenter - source: Theme.getThemeIcon( "ic_close_white_24dp" ) + source: Theme.getThemeIcon("ic_close_white_24dp") sourceSize.width: 24 * screen.devicePixelRatio sourceSize.height: 24 * screen.devicePixelRatio } } onClicked: { - close() + close(); } } - diff --git a/src/qml/imports/Theme/QfCollapsibleMessage.qml b/src/qml/imports/Theme/QfCollapsibleMessage.qml index 0b97265fdf..d1b65b55ec 100644 --- a/src/qml/imports/Theme/QfCollapsibleMessage.qml +++ b/src/qml/imports/Theme/QfCollapsibleMessage.qml @@ -2,90 +2,92 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import Theme 1.0 Item { - property bool collapsed: true - property alias color: titleText.color - property alias detailsColor: detailsText.color - property alias font: titleText.font - property alias titleText: titleText.text - property alias detailsText: detailsText.text - - clip: true - height: collapsed ? titleText.height + 1 : titleText.height + detailsText.height + 1 - implicitHeight: height - - Behavior on height { - NumberAnimation { duration: 100; easing.type: Easing.InQuad; } - } - - Rectangle { - id: background - anchors.fill: parent - - color: "transparent" - border.color: titleText.color - border.width: 1 - opacity: 0.25 - radius: 12 + property bool collapsed: true + property alias color: titleText.color + property alias detailsColor: detailsText.color + property alias font: titleText.font + property alias titleText: titleText.text + property alias detailsText: detailsText.text + + clip: true + height: collapsed ? titleText.height + 1 : titleText.height + detailsText.height + 1 + implicitHeight: height + + Behavior on height { + NumberAnimation { + duration: 100 + easing.type: Easing.InQuad } + } + + Rectangle { + id: background + anchors.fill: parent + + color: "transparent" + border.color: titleText.color + border.width: 1 + opacity: 0.25 + radius: 12 + } + + Text { + id: titleText + + width: parent.width - 5 + anchors.top: parent.top + anchors.left: parent.left + padding: 5 + clip: true - Text { - id: titleText - - width: parent.width - 5 - anchors.top: parent.top - anchors.left: parent.left - padding: 5 - clip: true + font: Theme.defaultFont + color: "black" - font: Theme.defaultFont - color: "black" + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } + Rectangle { + id: separator - Rectangle { - id: separator + width: parent.width - 24 + anchors.top: titleText.bottom + anchors.left: parent.left + anchors.leftMargin: 12 - width: parent.width - 24 - anchors.top: titleText.bottom - anchors.left: parent.left - anchors.leftMargin: 12 + height: 1 + color: titleText.color + opacity: 0.25 + } - height: 1 - color: titleText.color - opacity: 0.25 - } + Text { + id: detailsText - Text { - id: detailsText - - width: parent.width - 5 - anchors.top: separator.bottom - anchors.left: parent.left - padding: 5 - clip: true + width: parent.width - 5 + anchors.top: separator.bottom + anchors.left: parent.left + padding: 5 + clip: true - font.pointSize: titleText.font.pointSize / 1.5 - font.weight: titleText.font.weight - font.italic: titleText.font.italic - font.family: titleText.font.family + font.pointSize: titleText.font.pointSize / 1.5 + font.weight: titleText.font.weight + font.italic: titleText.font.italic + font.family: titleText.font.family - color: titleText.color + color: titleText.color - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } - MouseArea { - anchors.fill: parent + MouseArea { + anchors.fill: parent - onClicked: { - parent.collapsed = !parent.collapsed - } + onClicked: { + parent.collapsed = !parent.collapsed; } + } } diff --git a/src/qml/imports/Theme/QfPageHeader.qml b/src/qml/imports/Theme/QfPageHeader.qml index 20f866a375..214dc2bb0e 100644 --- a/src/qml/imports/Theme/QfPageHeader.qml +++ b/src/qml/imports/Theme/QfPageHeader.qml @@ -2,7 +2,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Layouts 1.14 - import Theme 1.0 ToolBar { @@ -50,25 +49,45 @@ ToolBar { visible: opacity > 0 states: [ - State { name: 'on' - PropertyChanges { target: busyIndicator; opacity: 1.0 }}, - State { name: 'off' - PropertyChanges { target: busyIndicator; opacity: 0.0 }} + State { + name: 'on' + PropertyChanges { + target: busyIndicator + opacity: 1.0 + } + }, + State { + name: 'off' + PropertyChanges { + target: busyIndicator + opacity: 0.0 + } + } ] transitions: [ Transition { from: "off" to: "on" SequentialAnimation { - NumberAnimation { target: busyIndicator; property: 'opacity'; duration: 100; } + NumberAnimation { + target: busyIndicator + property: 'opacity' + duration: 100 + } } }, Transition { from: "on" to: "off" SequentialAnimation { - PauseAnimation { duration: 100 } - NumberAnimation { target: busyIndicator; property: 'opacity'; duration: 200; } + PauseAnimation { + duration: 100 + } + NumberAnimation { + target: busyIndicator + property: 'opacity' + duration: 200 + } } } ] @@ -86,13 +105,12 @@ ToolBar { Layout.alignment: Qt.AlignTop | Qt.AlignLeft clip: true - iconSource: Theme.getThemeVectorIcon( 'ic_arrow_left_white_24dp' ) + iconSource: Theme.getThemeVectorIcon('ic_arrow_left_white_24dp') iconColor: backgroundFill ? Theme.light : Theme.mainTextColor - onClicked: - { - back() - finished() + onClicked: { + back(); + finished(); } } @@ -101,20 +119,19 @@ ToolBar { Layout.alignment: Qt.AlignTop | Qt.AlignLeft clip: true - iconSource: Theme.getThemeIcon( 'ic_check_white_48dp' ) + iconSource: Theme.getThemeIcon('ic_check_white_48dp') iconColor: backgroundFill ? Theme.light : Theme.mainTextColor - onClicked: - { - apply() - finished() + onClicked: { + apply(); + finished(); } } Label { id: titleLabel - leftPadding: !showApplyButton && showCancelButton ? 48: 0 - rightPadding: (showApplyButton || showBackButton) && !showCancelButton ? 48: 0 + leftPadding: !showApplyButton && showCancelButton ? 48 : 0 + rightPadding: (showApplyButton || showBackButton) && !showCancelButton ? 48 : 0 font: Theme.strongFont color: backgroundFill ? Theme.light : Theme.mainColor elide: Label.ElideRight @@ -128,12 +145,12 @@ ToolBar { Layout.alignment: Qt.AlignTop | Qt.AlignRight clip: true - iconSource: Theme.getThemeIcon( 'ic_close_white_24dp' ) + iconSource: Theme.getThemeIcon('ic_close_white_24dp') iconColor: backgroundFill ? Theme.light : Theme.mainTextColor onClicked: { - cancel() - finished() + cancel(); + finished(); } } } diff --git a/src/qml/imports/Theme/QfSlider.qml b/src/qml/imports/Theme/QfSlider.qml index ce211159df..900aa6d1c9 100644 --- a/src/qml/imports/Theme/QfSlider.qml +++ b/src/qml/imports/Theme/QfSlider.qml @@ -5,7 +5,7 @@ import QtQuick.Layouts 1.14 Item { id: wrapper - property alias from: slider.from; + property alias from: slider.from property alias to: slider.to property alias stepSize: slider.stepSize property alias value: slider.value @@ -54,7 +54,7 @@ Item { text: prefixText + getSampleOfNumberOfLength(Math.min(slider.to, 999)) + suffixText function getSampleOfNumberOfLength(number) { - return new Array(number.toString().length + 1).join(9) + return new Array(number.toString().length + 1).join(9); } } } diff --git a/src/qml/imports/Theme/QfSwipeAnimator.qml b/src/qml/imports/Theme/QfSwipeAnimator.qml index 8b769a1612..7eb7b059c2 100644 --- a/src/qml/imports/Theme/QfSwipeAnimator.qml +++ b/src/qml/imports/Theme/QfSwipeAnimator.qml @@ -48,9 +48,9 @@ Flickable { // handle text selection and showing cursor rectangle function ensureCursorVisible(cursorRectangle) { if (contentX >= cursorRectangle.x) { - contentX = cursorRectangle.x + contentX = cursorRectangle.x; } else if (contentX + width <= cursorRectangle.x + cursorRectangle.width) { - contentX = cursorRectangle.x + cursorRectangle.width - width + contentX = cursorRectangle.x + cursorRectangle.width - width; } } } diff --git a/src/qml/imports/Theme/QfSwitch.qml b/src/qml/imports/Theme/QfSwitch.qml index 7fe70ee069..f7d805d4ed 100644 --- a/src/qml/imports/Theme/QfSwitch.qml +++ b/src/qml/imports/Theme/QfSwitch.qml @@ -2,40 +2,40 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 SwitchDelegate { - property bool small: false + property bool small: false - width: small ? 34 : 48 - padding: 10 - indicator: Rectangle { - implicitWidth: small ? 34 : 48 - implicitHeight: small ? 16 : 26 - x: parent.leftPadding - y: ( parent.height + parent.topPadding - 6 ) / 2 - height / 2 - radius: implicitHeight / 2 - color: parent.checked ? Theme.mainColor : Theme.controlBorderColor - border.color: parent.checked ? Theme.mainColor : Theme.controlBorderColor + width: small ? 34 : 48 + padding: 10 + indicator: Rectangle { + implicitWidth: small ? 34 : 48 + implicitHeight: small ? 16 : 26 + x: parent.leftPadding + y: (parent.height + parent.topPadding - 6) / 2 - height / 2 + radius: implicitHeight / 2 + color: parent.checked ? Theme.mainColor : Theme.controlBorderColor + border.color: parent.checked ? Theme.mainColor : Theme.controlBorderColor - Rectangle { - x: parent.parent.checked ? parent.width - width : 0 - width: parent.implicitHeight - height: parent.implicitHeight - radius: parent.implicitHeight / 2 - opacity: parent.parent.down ? 0.85 : 1 - color: Theme.mainBackgroundColor - border.color: parent.parent.checked ? Theme.mainColor : Theme.controlBorderColor - Behavior on x { - PropertyAnimation { - duration: 150 - easing.type: Easing.Linear - } - } + Rectangle { + x: parent.parent.checked ? parent.width - width : 0 + width: parent.implicitHeight + height: parent.implicitHeight + radius: parent.implicitHeight / 2 + opacity: parent.parent.down ? 0.85 : 1 + color: Theme.mainBackgroundColor + border.color: parent.parent.checked ? Theme.mainColor : Theme.controlBorderColor + Behavior on x { + PropertyAnimation { + duration: 150 + easing.type: Easing.Linear } + } } + } - background: Rectangle { - implicitWidth: 100 - implicitHeight: 40 - visible: false - color: "transparent" - } + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + visible: false + color: "transparent" + } } diff --git a/src/qml/imports/Theme/QfTabBar.qml b/src/qml/imports/Theme/QfTabBar.qml index a5fddec460..4f04a1c5ee 100644 --- a/src/qml/imports/Theme/QfTabBar.qml +++ b/src/qml/imports/Theme/QfTabBar.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 ListView { @@ -26,12 +25,12 @@ ListView { font: Theme.defaultFont checked: tabRow.currentIndex === index onClicked: { - tabRow.currentIndex = index + tabRow.currentIndex = index; } } onCurrentIndexChanged: { - tabRow.positionViewAtIndex(currentIndex, ListView.Contain) + tabRow.positionViewAtIndex(currentIndex, ListView.Contain); } property real defaultHeight: 48 diff --git a/src/qml/imports/Theme/QfTextField.qml b/src/qml/imports/Theme/QfTextField.qml index 387b10b562..96f742e78d 100644 --- a/src/qml/imports/Theme/QfTextField.qml +++ b/src/qml/imports/Theme/QfTextField.qml @@ -50,27 +50,27 @@ Item { } onActiveFocusChanged: { - if ( !activeFocus ) { - echoMode = textFieldWrapper.echoMode + if (!activeFocus) { + echoMode = textFieldWrapper.echoMode; } } onTextEdited: { - textFieldWrapper.textEdited() + textFieldWrapper.textEdited(); } onEditingFinished: { - textFieldWrapper.editingFinished(); + textFieldWrapper.editingFinished(); } onFocusChanged: { - if (focus) { - Qt.inputMethod.show() - } + if (focus) { + Qt.inputMethod.show(); + } } Keys.onReturnPressed: { - textFieldWrapper.returnPressed() + textFieldWrapper.returnPressed(); } } @@ -78,17 +78,13 @@ Item { id: showPasswordButton z: 1 visible: !!textFieldWrapper.echoMode && textFieldWrapper.echoMode !== TextInput.Normal - iconSource: textField.echoMode === TextInput.Normal - ? Theme.getThemeVectorIcon('ic_hide_green_48dp') - : Theme.getThemeVectorIcon('ic_show_green_48dp') + iconSource: textField.echoMode === TextInput.Normal ? Theme.getThemeVectorIcon('ic_hide_green_48dp') : Theme.getThemeVectorIcon('ic_show_green_48dp') anchors.right: textField.right anchors.verticalCenter: textField.verticalCenter opacity: textField.text.length > 0 ? 1 : 0.25 onClicked: { - textField.echoMode = textField.echoMode === TextInput.Normal - ? textFieldWrapper.echoMode - : TextInput.Normal + textField.echoMode = textField.echoMode === TextInput.Normal ? textFieldWrapper.echoMode : TextInput.Normal; } } } diff --git a/src/qml/imports/Theme/QfToolButton.qml b/src/qml/imports/Theme/QfToolButton.qml index cf672d887c..e4b65626fb 100644 --- a/src/qml/imports/Theme/QfToolButton.qml +++ b/src/qml/imports/Theme/QfToolButton.qml @@ -2,7 +2,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 import QtQuick.Controls.Material.impl 2.14 - import Theme 1.0 RoundButton { @@ -23,11 +22,11 @@ RoundButton { implicitWidth: width implicitHeight: height - topInset:0 - bottomInset:0 - leftInset:0 - rightInset:0 - padding:10 + topInset: 0 + bottomInset: 0 + leftInset: 0 + rightInset: 0 + padding: 10 background: Rectangle { id: backgroundRectangle @@ -39,7 +38,7 @@ RoundButton { radius: round ? height / 2 : 0 clip: true - Behavior on color { + Behavior on color { ColorAnimation { duration: 200 } @@ -54,9 +53,7 @@ RoundButton { pressed: button.down anchor: parent active: button.down - color: Theme.darkTheme - ? bgcolor == "#ffffff" ? "#10000000" : "#10ffffff" - : bgcolor == "#ffffff" || bgcolor == "#00000000" ? "#10000000" : "#22ffffff" + color: Theme.darkTheme ? bgcolor == "#ffffff" ? "#10000000" : "#10ffffff" : bgcolor == "#ffffff" || bgcolor == "#00000000" ? "#10000000" : "#22ffffff" } } @@ -85,9 +82,7 @@ RoundButton { anchors.fill: parent color: bottomRightIndicatorFgColor text: bottomRightIndicatorText - font.pixelSize: bottomRightIndicatorText.length == 1 - ? height / 1.6 - : height / 1.8 + font.pixelSize: bottomRightIndicatorText.length == 1 ? height / 1.6 : height / 1.8 horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter } diff --git a/src/qml/imports/Theme/QfToolButtonDrawer.qml b/src/qml/imports/Theme/QfToolButtonDrawer.qml index 4ab66e61e7..bae54e3a07 100644 --- a/src/qml/imports/Theme/QfToolButtonDrawer.qml +++ b/src/qml/imports/Theme/QfToolButtonDrawer.qml @@ -1,6 +1,5 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 Container { @@ -23,40 +22,44 @@ Container { property alias iconColor: toggleButton.iconColor onNameChanged: { - collapsed = settings.valueBool("QField/QfToolButtonContainer/"+name+"/collapsed", true) + collapsed = settings.valueBool("QField/QfToolButtonContainer/" + name + "/collapsed", true); } width: { - switch(container.direction) { - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Down: - return size - case QfToolButtonDrawer.Direction.Left: - case QfToolButtonDrawer.Direction.Right: - return collapsed ? size : size + content.contentWidth + container.spacing * 2 + switch (container.direction) { + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Down: + return size; + case QfToolButtonDrawer.Direction.Left: + case QfToolButtonDrawer.Direction.Right: + return collapsed ? size : size + content.contentWidth + container.spacing * 2; } } height: { - switch(container.direction) { - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Down: - return collapsed ? size : size + content.contentHeight + container.spacing * 2 - case QfToolButtonDrawer.Direction.Left: - case QfToolButtonDrawer.Direction.Right: - return size + switch (container.direction) { + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Down: + return collapsed ? size : size + content.contentHeight + container.spacing * 2; + case QfToolButtonDrawer.Direction.Left: + case QfToolButtonDrawer.Direction.Right: + return size; } } spacing: 4 clip: true - Behavior on width { + Behavior on width { enabled: true - NumberAnimation { duration: 200 } + NumberAnimation { + duration: 200 + } } - Behavior on height { + Behavior on height { enabled: true - NumberAnimation { duration: 200 } + NumberAnimation { + duration: 200 + } } contentItem: Rectangle { @@ -67,50 +70,48 @@ Container { ListView { id: content width: { - switch(container.direction) { - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Down: - return container.size - case QfToolButtonDrawer.Direction.Left: - case QfToolButtonDrawer.Direction.Right: - return content.contentWidth + switch (container.direction) { + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Down: + return container.size; + case QfToolButtonDrawer.Direction.Left: + case QfToolButtonDrawer.Direction.Right: + return content.contentWidth; } } height: { - switch(container.direction) { - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Down: - return content.contentHeight - case QfToolButtonDrawer.Direction.Left: - case QfToolButtonDrawer.Direction.Right: - return container.size + switch (container.direction) { + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Down: + return content.contentHeight; + case QfToolButtonDrawer.Direction.Left: + case QfToolButtonDrawer.Direction.Right: + return container.size; } } x: { switch (container.direction) { - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Down: - case QfToolButtonDrawer.Direction.Left: - return container.spacing - case QfToolButtonDrawer.Direction.Right: - return container.size + container.spacing + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Down: + case QfToolButtonDrawer.Direction.Left: + return container.spacing; + case QfToolButtonDrawer.Direction.Right: + return container.size + container.spacing; } } y: { switch (container.direction) { - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Left: - case QfToolButtonDrawer.Direction.Right: - return container.spacing - case QfToolButtonDrawer.Direction.Down: - return container.size + container.spacing + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Left: + case QfToolButtonDrawer.Direction.Right: + return container.spacing; + case QfToolButtonDrawer.Direction.Down: + return container.size + container.spacing; } } model: container.contentModel snapMode: ListView.SnapToItem - orientation: container.direction === QfToolButtonDrawer.Direction.Up || container.direction === QfToolButtonDrawer.Direction.Down - ? ListView.Vertical - : ListView.Horizontal + orientation: container.direction === QfToolButtonDrawer.Direction.Up || container.direction === QfToolButtonDrawer.Direction.Down ? ListView.Vertical : ListView.Horizontal spacing: container.spacing } @@ -119,31 +120,31 @@ Container { width: container.size height: container.size x: { - switch(direction) { - case QfToolButtonDrawer.Direction.Down: - case QfToolButtonDrawer.Direction.Right: - return 0 - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Left: - return container.width - container.size + switch (direction) { + case QfToolButtonDrawer.Direction.Down: + case QfToolButtonDrawer.Direction.Right: + return 0; + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Left: + return container.width - container.size; } } y: { - switch(direction) { - case QfToolButtonDrawer.Direction.Down: - case QfToolButtonDrawer.Direction.Right: - return 0 - case QfToolButtonDrawer.Direction.Up: - case QfToolButtonDrawer.Direction.Left: - return container.height - container.size + switch (direction) { + case QfToolButtonDrawer.Direction.Down: + case QfToolButtonDrawer.Direction.Right: + return 0; + case QfToolButtonDrawer.Direction.Up: + case QfToolButtonDrawer.Direction.Left: + return container.height - container.size; } } round: true onClicked: { - container.collapsed = !container.collapsed + container.collapsed = !container.collapsed; if (name != "") { - settings.setValue("QField/QfToolButtonContainer/" + name + "/collapsed", container.collapsed) + settings.setValue("QField/QfToolButtonContainer/" + name + "/collapsed", container.collapsed); } } } diff --git a/src/qml/imports/Theme/Theme.qml b/src/qml/imports/Theme/Theme.qml index e829fe9cf3..6d8fb7cb98 100644 --- a/src/qml/imports/Theme/Theme.qml +++ b/src/qml/imports/Theme/Theme.qml @@ -1,156 +1,172 @@ pragma Singleton - import QtQuick 2.14 import QtQuick.Controls.Material 2.14 QtObject { - property bool darkTheme: false - - property color mainBackgroundColor: darkTheme ? "#303030" : "#fafafa" - property color mainBackgroundColorSemiOpaque: darkTheme ? "#bb303030" : "#bbfafafa" - - property color mainTextColor: darkTheme ? "#EEEEEE" : "#000000" - readonly property color mainTextDisabledColor: darkTheme ? "#73EEEEEE" : "#73000000" - readonly property color mainColor: "#80cc28" - - readonly property color secondaryTextColor: darkTheme? "#AAAAAA" : "#999999" - - readonly property color controlBackgroundColor: darkTheme ? "#202020" : "#ffffff" - readonly property color controlBackgroundAlternateColor: darkTheme ? "#202020" : "#e6e6e6" // used by feature form editor widgets - readonly property color controlBackgroundDisabledColor: "#33555555" - readonly property color controlBorderColor: darkTheme ? "#404040" : "#e6e6e6" - - readonly property color darkRed: "#c0392b" - readonly property color darkGray: "#212121" - readonly property color darkGraySemiOpaque: "#4D212121" - readonly property color gray: "#888888" - readonly property color lightGray: "#dddddd" - readonly property color lightestGray: "#eeeeee" - readonly property color light: "#ffffff" - readonly property color hyperlinkBlue: '#0000EE' - - readonly property color errorColor: darkTheme ? "#df3422" : "#c0392b" - readonly property color warningColor: "orange" - readonly property color cloudColor: "#4c6dac" - - readonly property color positionColor: "#64b5f6" - readonly property color positionColorSemiOpaque: "#3364b5f6" - readonly property color positionBackgroundColor: "#3364b5f6" - readonly property color darkPositionColor: "#2374b5" - readonly property color darkPositionColorSemiOpaque: "#882374b5" - - readonly property color accuracyBad: "#c0392b" - readonly property color accuracyTolerated: "orange" - readonly property color accuracyExcellent: "#80cc28" - - readonly property color navigationColor: "#984ea3" - readonly property color navigationColorSemiOpaque: "#99984ea3" - readonly property color navigationBackgroundColor: "#33984ea3" - - readonly property color sensorBackgroundColor: "#33999999" - - readonly property color bookmarkDefault: "#80cc28" - readonly property color bookmarkOrange: "orange" - readonly property color bookmarkRed: "#c0392b" - readonly property color bookmarkBlue: "#64b5f6" - - readonly property color vertexColor: "#FF0000" - readonly property color vertexColorSemiOpaque: "#40FF0000" - readonly property color vertexSelectedColor: "#0000FF" - readonly property color vertexSelectedColorSemiOpaque: "#200000FF" - readonly property color vertexNewColor: "#4CAF50" - readonly property color vertexNewColorSemiOpaque: "#404CAF50" - - readonly property color processingPreview: '#99000000' - - readonly property color accentColor: '#4CAF50' - readonly property color accentLightColor: '#994CAF50' - - property real fontScale: 1.0 - - property font defaultFont: Qt.font({pointSize: systemFontPointSize * fontScale, weight: Font.Normal}) - property font tinyFont: Qt.font({pointSize: systemFontPointSize * fontScale * 0.75, weight: Font.Normal}) - property font tipFont: Qt.font({pointSize: systemFontPointSize * fontScale * 0.875, weight: Font.Normal}) - property font resultFont: Qt.font({pointSize: systemFontPointSize * fontScale * 0.8125, weight: Font.Normal}) - property font strongFont: Qt.font({pointSize: systemFontPointSize * fontScale, bold: true, weight: Font.Bold}) - property font strongTipFont: Qt.font({pointSize: systemFontPointSize * fontScale * 0.875, bold: true, weight: Font.Bold}) - property font secondaryTitleFont: Qt.font({pointSize: systemFontPointSize * fontScale * 1.125, weight: Font.Normal}) - property font titleFont: Qt.font({pointSize: systemFontPointSize * fontScale * 1.25, weight: Font.Normal}) - - readonly property int popupScreenEdgeMargin: 40 - - readonly property int menuItemIconlessLeftPadding: 52 - readonly property int menuItemLeftPadding: 12 - readonly property int menuItemCheckLeftPadding: 16 - - function getThemeIcon(name) { - var ppiName - if ( ppi >= 360 ) - ppiName = "xxxhdpi"; - else if ( ppi >= 270 ) - ppiName = "xxhdpi"; - else if ( ppi >= 180 ) - ppiName = "xhdpi"; - else if ( ppi >= 135 ) - ppiName = "hdpi"; - else - ppiName = "mdpi"; - - var theme = 'qfield'; - - var path = 'qrc:/themes/' + theme + '/' + ppiName + '/' + name + '.png'; - return path; + property bool darkTheme: false + + property color mainBackgroundColor: darkTheme ? "#303030" : "#fafafa" + property color mainBackgroundColorSemiOpaque: darkTheme ? "#bb303030" : "#bbfafafa" + + property color mainTextColor: darkTheme ? "#EEEEEE" : "#000000" + readonly property color mainTextDisabledColor: darkTheme ? "#73EEEEEE" : "#73000000" + readonly property color mainColor: "#80cc28" + + readonly property color secondaryTextColor: darkTheme ? "#AAAAAA" : "#999999" + + readonly property color controlBackgroundColor: darkTheme ? "#202020" : "#ffffff" + readonly property color controlBackgroundAlternateColor: darkTheme ? "#202020" : "#e6e6e6" // used by feature form editor widgets + readonly property color controlBackgroundDisabledColor: "#33555555" + readonly property color controlBorderColor: darkTheme ? "#404040" : "#e6e6e6" + + readonly property color darkRed: "#c0392b" + readonly property color darkGray: "#212121" + readonly property color darkGraySemiOpaque: "#4D212121" + readonly property color gray: "#888888" + readonly property color lightGray: "#dddddd" + readonly property color lightestGray: "#eeeeee" + readonly property color light: "#ffffff" + readonly property color hyperlinkBlue: '#0000EE' + + readonly property color errorColor: darkTheme ? "#df3422" : "#c0392b" + readonly property color warningColor: "orange" + readonly property color cloudColor: "#4c6dac" + + readonly property color positionColor: "#64b5f6" + readonly property color positionColorSemiOpaque: "#3364b5f6" + readonly property color positionBackgroundColor: "#3364b5f6" + readonly property color darkPositionColor: "#2374b5" + readonly property color darkPositionColorSemiOpaque: "#882374b5" + + readonly property color accuracyBad: "#c0392b" + readonly property color accuracyTolerated: "orange" + readonly property color accuracyExcellent: "#80cc28" + + readonly property color navigationColor: "#984ea3" + readonly property color navigationColorSemiOpaque: "#99984ea3" + readonly property color navigationBackgroundColor: "#33984ea3" + + readonly property color sensorBackgroundColor: "#33999999" + + readonly property color bookmarkDefault: "#80cc28" + readonly property color bookmarkOrange: "orange" + readonly property color bookmarkRed: "#c0392b" + readonly property color bookmarkBlue: "#64b5f6" + + readonly property color vertexColor: "#FF0000" + readonly property color vertexColorSemiOpaque: "#40FF0000" + readonly property color vertexSelectedColor: "#0000FF" + readonly property color vertexSelectedColorSemiOpaque: "#200000FF" + readonly property color vertexNewColor: "#4CAF50" + readonly property color vertexNewColorSemiOpaque: "#404CAF50" + + readonly property color processingPreview: '#99000000' + + readonly property color accentColor: '#4CAF50' + readonly property color accentLightColor: '#994CAF50' + + property real fontScale: 1.0 + + property font defaultFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale, + "weight": Font.Normal + }) + property font tinyFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale * 0.75, + "weight": Font.Normal + }) + property font tipFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale * 0.875, + "weight": Font.Normal + }) + property font resultFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale * 0.8125, + "weight": Font.Normal + }) + property font strongFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale, + "bold": true, + "weight": Font.Bold + }) + property font strongTipFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale * 0.875, + "bold": true, + "weight": Font.Bold + }) + property font secondaryTitleFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale * 1.125, + "weight": Font.Normal + }) + property font titleFont: Qt.font({ + "pointSize": systemFontPointSize * fontScale * 1.25, + "weight": Font.Normal + }) + + readonly property int popupScreenEdgeMargin: 40 + + readonly property int menuItemIconlessLeftPadding: 52 + readonly property int menuItemLeftPadding: 12 + readonly property int menuItemCheckLeftPadding: 16 + + function getThemeIcon(name) { + var ppiName; + if (ppi >= 360) + ppiName = "xxxhdpi"; + else if (ppi >= 270) + ppiName = "xxhdpi"; + else if (ppi >= 180) + ppiName = "xhdpi"; + else if (ppi >= 135) + ppiName = "hdpi"; + else + ppiName = "mdpi"; + var theme = 'qfield'; + var path = 'qrc:/themes/' + theme + '/' + ppiName + '/' + name + '.png'; + return path; + } + + function getThemeVectorIcon(name) { + var theme = 'qfield'; + var path = 'qrc:/themes/' + theme + '/nodpi/' + name + '.svg'; + return path; + } + + function colorToHtml(color) { + return "rgba(%1,%2,%3,%4)".arg(Math.floor(Theme.errorColor.r * 255)).arg(Math.floor(Theme.errorColor.g * 255)).arg(Math.floor(Theme.errorColor.b * 255)).arg(Math.floor(Theme.errorColor.a * 255)); + } + + function toInlineStyles(styleProperties) { + var styles = ''; + for (var property in styleProperties) { + var value = styleProperties[property]; + styles += property; + styles += ': '; + styles += typeof value == 'color' ? colorToHtml(value) : value; + styles += ';'; } - - function getThemeVectorIcon(name) { - var theme = 'qfield'; - - var path = 'qrc:/themes/' + theme + '/nodpi/' + name + '.svg'; - return path; - } - - function colorToHtml(color) { - return "rgba(%1,%2,%3,%4)".arg(Math.floor(Theme.errorColor.r * 255)).arg(Math.floor(Theme.errorColor.g * 255)).arg(Math.floor(Theme.errorColor.b * 255)).arg(Math.floor(Theme.errorColor.a * 255)); - - } - - function toInlineStyles(styleProperties) { - var styles = '' - - for (var property in styleProperties) { - var value = styleProperties[property]; - styles += property - styles += ': ' - styles += typeof value == 'color' - ? colorToHtml(value) - : value - styles += ';' - } - - return styles; - } - - function applyAppearance() { - var appearance = settings.value('appearance', 'system') - if (appearance === undefined || appearance === 'system') { - darkTheme = platformUtilities.isSystemDarkTheme() - } else if (appearance === 'light') { - darkTheme = false - } else if (appearance === 'dark') { - darkTheme = true - } - Material.theme = darkTheme ? "Dark" : "Light" - mainBackgroundColor = Material.backgroundColor - mainTextColor = Material.foreground - } - - function applyFontScale() { - fontScale = settings.value('fontScale', 1.0) - } - - Component.onCompleted: { - applyAppearance() - applyFontScale() + return styles; + } + + function applyAppearance() { + var appearance = settings.value('appearance', 'system'); + if (appearance === undefined || appearance === 'system') { + darkTheme = platformUtilities.isSystemDarkTheme(); + } else if (appearance === 'light') { + darkTheme = false; + } else if (appearance === 'dark') { + darkTheme = true; } + Material.theme = darkTheme ? "Dark" : "Light"; + mainBackgroundColor = Material.backgroundColor; + mainTextColor = Material.foreground; + } + + function applyFontScale() { + fontScale = settings.value('fontScale', 1.0); + } + + Component.onCompleted: { + applyAppearance(); + applyFontScale(); + } } - diff --git a/src/qml/processingparameterwidgets/number.qml b/src/qml/processingparameterwidgets/number.qml index c2066a31ab..4187d2a38d 100644 --- a/src/qml/processingparameterwidgets/number.qml +++ b/src/qml/processingparameterwidgets/number.qml @@ -1,10 +1,8 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 - import Theme 1.0 import org.qfield 1.0 import org.qgis 1.0 - import "." ProcessingParameterWidgetBase { @@ -37,12 +35,9 @@ ProcessingParameterWidgetBase { text: value !== undefined ? value : '' validator: { - if (isDouble) - { + if (isDouble) { doubleValidator; - } - else - { + } else { intValidator; } } @@ -64,8 +59,8 @@ ProcessingParameterWidgetBase { onTextChanged: { if (text != value) { if (!isNaN(parseFloat(text))) { - let numberValue = Math.max(numberItem.min, Math.min(numberItem.max, text)) - valueChangeRequested(numberValue) + let numberValue = Math.max(numberItem.min, Math.min(numberItem.max, text)); + valueChangeRequested(numberValue); } } } @@ -90,15 +85,15 @@ ProcessingParameterWidgetBase { decreaseValue(); } onPressAndHold: { - changeValueTimer.increase = false - changeValueTimer.interval = 700 - changeValueTimer.restart() + changeValueTimer.increase = false; + changeValueTimer.interval = 700; + changeValueTimer.restart(); } onReleased: { - changeValueTimer.stop() + changeValueTimer.stop(); } onCanceled: { - changeValueTimer.stop() + changeValueTimer.stop(); } } @@ -121,15 +116,15 @@ ProcessingParameterWidgetBase { increaseValue(); } onPressAndHold: { - changeValueTimer.increase = true - changeValueTimer.interval = 700 - changeValueTimer.restart() + changeValueTimer.increase = true; + changeValueTimer.interval = 700; + changeValueTimer.restart(); } onReleased: { - changeValueTimer.stop() + changeValueTimer.stop(); } onCanceled: { - changeValueTimer.stop() + changeValueTimer.stop(); } } } @@ -143,16 +138,16 @@ ProcessingParameterWidgetBase { onTriggered: { var hitBoundary = false; - if ( increase ) { + if (increase) { increaseValue(); - hitBoundary = textField.text == numberItem.max + hitBoundary = textField.text == numberItem.max; } else { decreaseValue(); hitBoundary = textField.text == numberItem.min; } - - if ( !hitBoundary ) { - if ( interval > 50 ) interval = interval * 0.7; + if (!hitBoundary) { + if (interval > 50) + interval = interval * 0.7; } else { stop(); } @@ -160,26 +155,26 @@ ProcessingParameterWidgetBase { } function decreaseValue() { - var currentValue = Number.parseFloat(textField.text) - var newValue + var currentValue = Number.parseFloat(textField.text); + var newValue; if (!isNaN(currentValue)) { newValue = currentValue - numberItem.step; - valueChangeRequested(Math.max(numberItem.min, newValue)) + valueChangeRequested(Math.max(numberItem.min, newValue)); } else { newValue = 0; - valueChangeRequested(newValue, false) + valueChangeRequested(newValue, false); } } function increaseValue() { - var currentValue = Number.parseFloat(textField.text) - var newValue + var currentValue = Number.parseFloat(textField.text); + var newValue; if (!isNaN(currentValue)) { newValue = currentValue + numberItem.step; - valueChangeRequested(Math.min(numberItem.max, newValue )) + valueChangeRequested(Math.min(numberItem.max, newValue)); } else { newValue = 0; - valueChangeRequested(newValue) + valueChangeRequested(newValue); } } diff --git a/src/qml/qgismobileapp.qml b/src/qml/qgismobileapp.qml index c565915e69..6abac0d6bf 100644 --- a/src/qml/qgismobileapp.qml +++ b/src/qml/qgismobileapp.qml @@ -14,7 +14,6 @@ * (at your option) any later version. * * * ***************************************************************************/ - import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Controls.Material 2.14 @@ -23,19 +22,15 @@ import QtQuick.Window 2.14 import QtQml 2.14 import QtSensors 5.14 import QtCore - import org.qgis 1.0 import org.qfield 1.0 - import Theme 1.0 ApplicationWindow { id: mainWindow objectName: 'mainWindow' visible: true - flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | - (Qt.platform.os === "ios" ? Qt.MaximizeUsingFullscreenGeometryHint : 0) | - (Qt.platform.os !== "ios" && Qt.platform.os !== "android" ? Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint : 0) + flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | (Qt.platform.os === "ios" ? Qt.MaximizeUsingFullscreenGeometryHint : 0) | (Qt.platform.os !== "ios" && Qt.platform.os !== "android" ? Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint : 0) Material.theme: Theme.darkTheme ? "Dark" : "Light" Material.accent: Theme.mainColor @@ -49,10 +44,9 @@ ApplicationWindow { repeat: false interval: 50 - readonly property bool screenIsPortrait: (Screen.primaryOrientation === Qt.PortraitOrientation || - Screen.primaryOrientation === Qt.InvertedPortraitOrientation) - onScreenIsPortraitChanged:{ - start() + readonly property bool screenIsPortrait: (Screen.primaryOrientation === Qt.PortraitOrientation || Screen.primaryOrientation === Qt.InvertedPortraitOrientation) + onScreenIsPortraitChanged: { + start(); } onTriggered: { @@ -71,15 +65,15 @@ ApplicationWindow { Component.onCompleted: { if (Qt.platform.os !== "ios" && Qt.platform.os !== "android") { - width = Math.max(width, minimumSize) - height = Math.max(height, minimumSize) - x = Math.min(x, mainWindow.screen.width - width) - y = Math.min(y, mainWindow.screen.height - height) + width = Math.max(width, minimumSize); + height = Math.max(height, minimumSize); + x = Math.min(x, mainWindow.screen.width - width); + y = Math.min(y, mainWindow.screen.height - height); } } } - FocusStack{ + FocusStack { id: focusstack } @@ -93,17 +87,17 @@ ApplicationWindow { property int previousVisibilityState: Window.Windowed - Keys.onReleased: (event) => { - if ( event.key === Qt.Key_Back || event.key === Qt.Key_Escape ) { - if ( featureForm.visible ) { - featureForm.hide(); - } else if ( stateMachine.state === 'measure' ) { - mainWindow.closeMeasureTool() + Keys.onReleased: event => { + if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { + if (featureForm.visible) { + featureForm.hide(); + } else if (stateMachine.state === 'measure') { + mainWindow.closeMeasureTool(); } else { mainWindow.close(); } - event.accepted = true - } else if ( event.key === Qt.Key_F11 ) { + event.accepted = true; + } else if (event.key === Qt.Key_F11) { if (Qt.platform.os !== "android" && Qt.platform.os !== "ios") { if (mainWindow.visibility !== Window.FullScreen) { previousVisibilityState = mainWindow.visibility; @@ -118,7 +112,7 @@ ApplicationWindow { } } - Component.onCompleted: focusstack.addFocusTaker( this ) + Component.onCompleted: focusstack.addFocusTaker(this) } //currentRubberband provides the rubberband depending on the current state (digitize or measure) @@ -126,8 +120,8 @@ ApplicationWindow { property LayerObserver layerObserverAlias: layerObserver property QgsGpkgFlusher gpkgFlusherAlias: gpkgFlusher - signal closeMeasureTool() - signal changeMode( string mode ) + signal closeMeasureTool + signal changeMode(string mode) Item { id: stateMachine @@ -137,62 +131,73 @@ ApplicationWindow { states: [ State { name: "browse" - PropertyChanges { target: identifyTool; deactivated: false } + PropertyChanges { + target: identifyTool + deactivated: false + } }, - State { name: "digitize" - PropertyChanges { target: identifyTool; deactivated: false } - PropertyChanges { target: mainWindow; currentRubberband: digitizingRubberband } + PropertyChanges { + target: identifyTool + deactivated: false + } + PropertyChanges { + target: mainWindow + currentRubberband: digitizingRubberband + } }, - State { name: 'measure' - PropertyChanges { target: identifyTool; deactivated: true } - PropertyChanges { target: mainWindow; currentRubberband: measuringTool.measuringRubberband } - PropertyChanges { target: featureForm; state: "Hidden" } + PropertyChanges { + target: identifyTool + deactivated: true + } + PropertyChanges { + target: mainWindow + currentRubberband: measuringTool.measuringRubberband + } + PropertyChanges { + target: featureForm + state: "Hidden" + } } ] state: "browse" } - onChangeMode: (mode) => { - if ( stateMachine.state === mode ) - return - - stateMachine.lastState = stateMachine.state - stateMachine.state = mode - switch ( stateMachine.state ) - { - case 'browse': - projectInfo.stateMode = mode - platformUtilities.setHandleVolumeKeys(false) - displayToast( qsTr( 'You are now in browse mode' ) ); - break; - case 'digitize': - projectInfo.stateMode = mode - platformUtilities.setHandleVolumeKeys(qfieldSettings.digitizingVolumeKeys) - dashBoard.ensureEditableLayerSelected(); - if (dashBoard.activeLayer) - { - displayToast( qsTr( 'You are now in digitize mode on layer %1' ).arg( dashBoard.activeLayer.name ) ); - } - else - { - displayToast( qsTr( 'You are now in digitize mode' ) ); - } - break; - case 'measure': - platformUtilities.setHandleVolumeKeys(qfieldSettings.digitizingVolumeKeys) - informationDrawer.elevationProfile.populateLayersFromProject(); - displayToast( qsTr( 'You are now in measure mode' ) ); - break; + onChangeMode: mode => { + if (stateMachine.state === mode) + return; + stateMachine.lastState = stateMachine.state; + stateMachine.state = mode; + switch (stateMachine.state) { + case 'browse': + projectInfo.stateMode = mode; + platformUtilities.setHandleVolumeKeys(false); + displayToast(qsTr('You are now in browse mode')); + break; + case 'digitize': + projectInfo.stateMode = mode; + platformUtilities.setHandleVolumeKeys(qfieldSettings.digitizingVolumeKeys); + dashBoard.ensureEditableLayerSelected(); + if (dashBoard.activeLayer) { + displayToast(qsTr('You are now in digitize mode on layer %1').arg(dashBoard.activeLayer.name)); + } else { + displayToast(qsTr('You are now in digitize mode')); + } + break; + case 'measure': + platformUtilities.setHandleVolumeKeys(qfieldSettings.digitizingVolumeKeys); + informationDrawer.elevationProfile.populateLayersFromProject(); + displayToast(qsTr('You are now in measure mode')); + break; } } onCloseMeasureTool: { - overlayFeatureFormDrawer.close() - changeMode( stateMachine.lastState) + overlayFeatureFormDrawer.close(); + changeMode(stateMachine.lastState); } /** @@ -204,7 +209,7 @@ ApplicationWindow { deviceId: positioningSettings.positioningDevice - property bool currentness: false; + property bool currentness: false property alias destinationCrs: positionSource.coordinateTransformer.destinationCrs property real bearingTrueNorth: 0.0 @@ -222,7 +227,7 @@ ApplicationWindow { onProjectedPositionChanged: { if (active) { - bearingTrueNorth = PositioningUtils.bearingTrueNorth(positionSource.projectedPosition, mapCanvas.mapSettings.destinationCrs) + bearingTrueNorth = PositioningUtils.bearingTrueNorth(positionSource.projectedPosition, mapCanvas.mapSettings.destinationCrs); if (gnssButton.followActive) { gnssButton.followLocation(false); } @@ -241,10 +246,10 @@ ApplicationWindow { onPositioningActivatedChanged: { if (positioningActivated) { - displayToast( qsTr( "Activating positioning service" ) ) - positionSource.active = true + displayToast(qsTr("Activating positioning service")); + positionSource.active = true; } else { - positionSource.active = false + positionSource.active = false; } } } @@ -253,21 +258,21 @@ ApplicationWindow { target: positionSource.device function onLastErrorChanged() { - displayToast(qsTr('Positioning device error: %1').arg(positionSource.device.lastError), 'error') + displayToast(qsTr('Positioning device error: %1').arg(positionSource.device.lastError), 'error'); } } Timer { id: positionTimer - property bool geocoderLocatorFiltersChecked: false; + property bool geocoderLocatorFiltersChecked: false interval: 2500 repeat: true running: positionSource.active triggeredOnStart: true onTriggered: { - if ( positionSource.positionInformation ) { + if (positionSource.positionInformation) { positionSource.currentness = ((Date.now() - positionSource.positionInformation.utcDateTime.getTime()) / 1000) < 30; if (!geocoderLocatorFiltersChecked && positionSource.valid) { locatorItem.locatorFiltersModel.setGeocoderLocatorFiltersDefaulByPosition(positionSource.positionInformation); @@ -283,106 +288,100 @@ ApplicationWindow { clip: true DragHandler { - id: freehandHandler - property bool isDigitizing: false - enabled: freehandButton.visible && freehandButton.freehandDigitizing && !digitizingToolbar.rubberbandModel.frozen && (!featureForm.visible || digitizingToolbar.geometryRequested) - acceptedDevices: !qfieldSettings.mouseAsTouchScreen ? PointerDevice.Stylus | PointerDevice.Mouse : PointerDevice.Stylus - grabPermissions: PointerHandler.CanTakeOverFromHandlersOfSameType | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything - - onActiveChanged: { - if (active) { - geometryEditorsToolbar.canvasFreehandBegin(); - } else { - geometryEditorsToolbar.canvasFreehandEnd(); - var screenLocation = centroid.position; - var screenFraction = settings.value( "/QField/Digitizing/FreehandRecenterScreenFraction", 5 ); - var threshold = Math.min( mainWindow.width, mainWindow.height ) / screenFraction; - if ( screenLocation.x < threshold || screenLocation.x > mainWindow.width - threshold || - screenLocation.y < threshold || screenLocation.y > mainWindow.height - threshold ) - { - mapCanvas.mapSettings.setCenter(mapCanvas.mapSettings.screenToCoordinate(screenLocation)); - } - } + id: freehandHandler + property bool isDigitizing: false + enabled: freehandButton.visible && freehandButton.freehandDigitizing && !digitizingToolbar.rubberbandModel.frozen && (!featureForm.visible || digitizingToolbar.geometryRequested) + acceptedDevices: !qfieldSettings.mouseAsTouchScreen ? PointerDevice.Stylus | PointerDevice.Mouse : PointerDevice.Stylus + grabPermissions: PointerHandler.CanTakeOverFromHandlersOfSameType | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything + + onActiveChanged: { + if (active) { + geometryEditorsToolbar.canvasFreehandBegin(); + } else { + geometryEditorsToolbar.canvasFreehandEnd(); + var screenLocation = centroid.position; + var screenFraction = settings.value("/QField/Digitizing/FreehandRecenterScreenFraction", 5); + var threshold = Math.min(mainWindow.width, mainWindow.height) / screenFraction; + if (screenLocation.x < threshold || screenLocation.x > mainWindow.width - threshold || screenLocation.y < threshold || screenLocation.y > mainWindow.height - threshold) { + mapCanvas.mapSettings.setCenter(mapCanvas.mapSettings.screenToCoordinate(screenLocation)); + } } + } - onCentroidChanged: { - if (active) { - if (centroid.position !== Qt.point(0, 0)) { - coordinateLocator.sourceLocation = centroid.position - if (!geometryEditorsToolbar.canvasClicked(centroid.position)) { - digitizingToolbar.addVertex(); - } - } + onCentroidChanged: { + if (active) { + if (centroid.position !== Qt.point(0, 0)) { + coordinateLocator.sourceLocation = centroid.position; + if (!geometryEditorsToolbar.canvasClicked(centroid.position)) { + digitizingToolbar.addVertex(); } + } } + } } HoverHandler { - id: hoverHandler - enabled: !(positionSource.active && positioningSettings.positioningCoordinateLock) - && (!digitizingToolbar.rubberbandModel || !digitizingToolbar.rubberbandModel.frozen) - acceptedDevices: !qfieldSettings.mouseAsTouchScreen ? PointerDevice.Stylus | PointerDevice.Mouse : PointerDevice.Stylus - grabPermissions: PointerHandler.TakeOverForbidden - - property bool hasBeenHovered: false - property bool skipHover: false - - function pointInItem(point, item) { - var itemCoordinates = item.mapToItem(mainWindow.contentItem, 0, 0); - return point.position.x >= itemCoordinates.x && point.position.x <= itemCoordinates.x + item.width && - point.position.y >= itemCoordinates.y && point.position.y <= itemCoordinates.y + item.height; - } + id: hoverHandler + enabled: !(positionSource.active && positioningSettings.positioningCoordinateLock) && (!digitizingToolbar.rubberbandModel || !digitizingToolbar.rubberbandModel.frozen) + acceptedDevices: !qfieldSettings.mouseAsTouchScreen ? PointerDevice.Stylus | PointerDevice.Mouse : PointerDevice.Stylus + grabPermissions: PointerHandler.TakeOverForbidden - onPointChanged: { - if (skipHover || !mapCanvasMap.hovered) { - return - } + property bool hasBeenHovered: false + property bool skipHover: false - // when hovering various toolbars, reset coordinate locator position for nicer UX - if ( !freehandHandler.active && ( pointInItem( point, digitizingToolbar ) || pointInItem( point, elevationProfileButton ) ) ) { - coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen( digitizingToolbar.rubberbandModel.lastCoordinate ) - } else if ( !freehandHandler.active && pointInItem( point, geometryEditorsToolbar ) ) { - coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen( geometryEditorsToolbar.editorRubberbandModel.lastCoordinate ) - } else if ( !freehandHandler.active ) { - // after a click, it seems that the position is sent once at 0,0 => weird) - if (point.position !== Qt.point(0, 0)) { - coordinateLocator.sourceLocation = point.position - } - } - } + function pointInItem(point, item) { + var itemCoordinates = item.mapToItem(mainWindow.contentItem, 0, 0); + return point.position.x >= itemCoordinates.x && point.position.x <= itemCoordinates.x + item.width && point.position.y >= itemCoordinates.y && point.position.y <= itemCoordinates.y + item.height; + } - onActiveChanged: { - if ( !active ) { - coordinateLocator.sourceLocation = undefined - } + onPointChanged: { + if (skipHover || !mapCanvasMap.hovered) { + return; } - onHoveredChanged: { - if ( mapCanvasMap.pinched ) { - return - } + // when hovering various toolbars, reset coordinate locator position for nicer UX + if (!freehandHandler.active && (pointInItem(point, digitizingToolbar) || pointInItem(point, elevationProfileButton))) { + coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen(digitizingToolbar.rubberbandModel.lastCoordinate); + } else if (!freehandHandler.active && pointInItem(point, geometryEditorsToolbar)) { + coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen(geometryEditorsToolbar.editorRubberbandModel.lastCoordinate); + } else if (!freehandHandler.active) { + // after a click, it seems that the position is sent once at 0,0 => weird) + if (point.position !== Qt.point(0, 0)) { + coordinateLocator.sourceLocation = point.position; + } + } + } - if ( skipHover ) { - if ( !hovered ) { - mapCanvasMap.hovered = false - dummyHoverTimer.restart() - } - return - } + onActiveChanged: { + if (!active) { + coordinateLocator.sourceLocation = undefined; + } + } - mapCanvasMap.hovered = hovered - if ( hovered ) { - hasBeenHovered = true; - } else { - if ( currentRubberband && currentRubberband.model.vertexCount > 1 ) { - coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen( currentRubberband.model.lastCoordinate ) - } else if ( geometryEditorsToolbar.editorRubberbandModel && geometryEditorsToolbar.editorRubberbandModel.vertexCount > 1 ) { - coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen( geometryEditorsToolbar.editorRubberbandModel.lastCoordinate ) - } else { - coordinateLocator.sourceLocation = undefined - } - } + onHoveredChanged: { + if (mapCanvasMap.pinched) { + return; } + if (skipHover) { + if (!hovered) { + mapCanvasMap.hovered = false; + dummyHoverTimer.restart(); + } + return; + } + mapCanvasMap.hovered = hovered; + if (hovered) { + hasBeenHovered = true; + } else { + if (currentRubberband && currentRubberband.model.vertexCount > 1) { + coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen(currentRubberband.model.lastCoordinate); + } else if (geometryEditorsToolbar.editorRubberbandModel && geometryEditorsToolbar.editorRubberbandModel.vertexCount > 1) { + coordinateLocator.sourceLocation = mapCanvas.mapSettings.coordinateToScreen(geometryEditorsToolbar.editorRubberbandModel.lastCoordinate); + } else { + coordinateLocator.sourceLocation = undefined; + } + } + } } /* The second hover handler is a workaround what appears to be an issue with @@ -397,30 +396,29 @@ ApplicationWindow { repeat: false onTriggered: { - hoverHandler.skipHover = false + hoverHandler.skipHover = false; } } HoverHandler { - id: dummyHoverHandler - enabled: !qfieldSettings.mouseAsTouchScreen - && !(positionSource.active && positioningSettings.positioningCoordinateLock) - acceptedDevices: PointerDevice.TouchScreen - grabPermissions: PointerHandler.TakeOverForbidden - - onHoveredChanged: { - if ( hovered ) { - dummyHoverTimer.stop() - hoverHandler.skipHover = true - - // Unfortunately, Qt fails to set the hovered property to false when stylus leaves proximity - // of the screen, we've got to compensate for that - mapCanvasMap.hovered = false - if ( !qfieldSettings.fingerTapDigitizing ) { - coordinateLocator.sourceLocation = undefined - } - } + id: dummyHoverHandler + enabled: !qfieldSettings.mouseAsTouchScreen && !(positionSource.active && positioningSettings.positioningCoordinateLock) + acceptedDevices: PointerDevice.TouchScreen + grabPermissions: PointerHandler.TakeOverForbidden + + onHoveredChanged: { + if (hovered) { + dummyHoverTimer.stop(); + hoverHandler.skipHover = true; + + // Unfortunately, Qt fails to set the hovered property to false when stylus leaves proximity + // of the screen, we've got to compensate for that + mapCanvasMap.hovered = false; + if (!qfieldSettings.fingerTapDigitizing) { + coordinateLocator.sourceLocation = undefined; + } } + } } /* Initialize a MapSettings object. This will contain information about @@ -448,15 +446,7 @@ ApplicationWindow { MapCanvas { id: mapCanvasMap - property bool isEnabled: !dashBoard.opened && - !welcomeScreen.visible && - !qfieldSettings.visible && - !qfieldLocalDataPickerScreen.visible && - !qfieldCloudScreen.visible && - !qfieldCloudPopup.visible && - !codeReader.visible && - !sketcher.visible && - !overlayFeatureFormDrawer.visible + property bool isEnabled: !dashBoard.opened && !welcomeScreen.visible && !qfieldSettings.visible && !qfieldLocalDataPickerScreen.visible && !qfieldCloudScreen.visible && !qfieldCloudPopup.visible && !codeReader.visible && !sketcher.visible && !overlayFeatureFormDrawer.visible interactive: isEnabled && !screenLocker.enabled isMapRotationEnabled: qfieldSettings.enableMapRotation incrementalRendering: true @@ -470,144 +460,125 @@ ApplicationWindow { anchors.fill: parent function pointInItem(point, item) { - var itemCoordinates = item.mapToItem(mainWindow.contentItem, 0, 0); - return point.x >= itemCoordinates.x && point.x <= itemCoordinates.x + item.width && - point.y >= itemCoordinates.y && point.y <= itemCoordinates.y + item.height; + var itemCoordinates = item.mapToItem(mainWindow.contentItem, 0, 0); + return point.x >= itemCoordinates.x && point.x <= itemCoordinates.x + item.width && point.y >= itemCoordinates.y && point.y <= itemCoordinates.y + item.height; } onClicked: (point, type) => { - if (type === "stylus" && - ( overlayFeatureFormDrawer.opened || ( featureForm.visible && pointInItem( point, featureForm ) ) ) ) { - return; - } - - if (!digitizingToolbar.geometryRequested && featureForm.state == "FeatureFormEdit") { - return; + if (type === "stylus" && (overlayFeatureFormDrawer.opened || (featureForm.visible && pointInItem(point, featureForm)))) { + return; + } + if (!digitizingToolbar.geometryRequested && featureForm.state == "FeatureFormEdit") { + return; + } + if (locatorItem.state == "on") { + locatorItem.state = "off"; + return; + } + if (type === "stylus") { + if (pointInItem(point, digitizingToolbar) || pointInItem(point, zoomToolbar) || pointInItem(point, mainToolbar) || pointInItem(point, mainMenuBar) || pointInItem(point, geometryEditorsToolbar) || pointInItem(point, locationToolbar) || pointInItem(point, digitizingToolbarContainer) || pointInItem(point, locatorItem)) { + return; } - if (locatorItem.state == "on") { - locatorItem.state = "off" - return; + // Check if geometry editor is taking over + const positionLocked = positionSource.active && positioningSettings.positioningCoordinateLock; + if (geometryEditorsToolbar.stateVisible) { + if (!positionLocked) { + geometryEditorsToolbar.canvasClicked(point, type); + } + return; } - - if ( type === "stylus" ) { - if ( pointInItem( point, digitizingToolbar ) || - pointInItem( point, zoomToolbar ) || - pointInItem( point, mainToolbar ) || - pointInItem( point, mainMenuBar ) || - pointInItem( point, geometryEditorsToolbar ) || - pointInItem( point, locationToolbar ) || - pointInItem( point, digitizingToolbarContainer ) || - pointInItem( point, locatorItem ) ) { - return; - } - - // Check if geometry editor is taking over - const positionLocked = positionSource.active && positioningSettings.positioningCoordinateLock - if ( geometryEditorsToolbar.stateVisible ) { - if ( !positionLocked ) { - geometryEditorsToolbar.canvasClicked( point, type ) - } - return - } - - if ( ( stateMachine.state === "digitize" && digitizingFeature.currentLayer ) || stateMachine.state === "measure" ) { - if ( !positionLocked && ( !featureForm.visible || digitizingToolbar.geometryRequested ) ) { - if ( Number( currentRubberband.model.geometryType ) === Qgis.GeometryType.Point || - Number( currentRubberband.model.geometryType ) === Qgis.GeometryType.Null ) { - digitizingToolbar.confirm() - } else { - digitizingToolbar.addVertex() - } - } + if ((stateMachine.state === "digitize" && digitizingFeature.currentLayer) || stateMachine.state === "measure") { + if (!positionLocked && (!featureForm.visible || digitizingToolbar.geometryRequested)) { + if (Number(currentRubberband.model.geometryType) === Qgis.GeometryType.Point || Number(currentRubberband.model.geometryType) === Qgis.GeometryType.Null) { + digitizingToolbar.confirm(); } else { - if (!featureForm.canvasOperationRequested && !overlayFeatureFormDrawer.visible && featureForm.state !== "FeatureFormEdit" ) { - identifyTool.isMenuRequest = false - identifyTool.identify(point) - } + digitizingToolbar.addVertex(); } + } + } else { + if (!featureForm.canvasOperationRequested && !overlayFeatureFormDrawer.visible && featureForm.state !== "FeatureFormEdit") { + identifyTool.isMenuRequest = false; + identifyTool.identify(point); + } } + } } - onConfirmedClicked: (point) => { - // Check if geometry editor is taking over - const positionLocked = positionSource.active && positioningSettings.positioningCoordinateLock - if ( geometryEditorsToolbar.stateVisible ) { - if ( !positionLocked ) { - geometryEditorsToolbar.canvasClicked( point, '' ) - } - return + onConfirmedClicked: point => { + // Check if geometry editor is taking over + const positionLocked = positionSource.active && positioningSettings.positioningCoordinateLock; + if (geometryEditorsToolbar.stateVisible) { + if (!positionLocked) { + geometryEditorsToolbar.canvasClicked(point, ''); } - - if ( qfieldSettings.fingerTapDigitizing && ( ( stateMachine.state === "digitize" && digitizingFeature.currentLayer ) || stateMachine.state === "measure" ) ) { - if ( !positionLocked && ( !featureForm.visible || digitizingToolbar.geometryRequested ) ) { - coordinateLocator.sourceLocation = point - } - } else if (!featureForm.canvasOperationRequested && !overlayFeatureFormDrawer.visible && featureForm.state !== "FeatureFormEdit") { - identifyTool.isMenuRequest = false - identifyTool.identify(point) + return; + } + if (qfieldSettings.fingerTapDigitizing && ((stateMachine.state === "digitize" && digitizingFeature.currentLayer) || stateMachine.state === "measure")) { + if (!positionLocked && (!featureForm.visible || digitizingToolbar.geometryRequested)) { + coordinateLocator.sourceLocation = point; } + } else if (!featureForm.canvasOperationRequested && !overlayFeatureFormDrawer.visible && featureForm.state !== "FeatureFormEdit") { + identifyTool.isMenuRequest = false; + identifyTool.identify(point); + } } onLongPressed: (point, type) => { - if ( type === "stylus" ) { - if ( overlayFeatureFormDrawer.opened || ( featureForm.visible && pointInItem( point, featureForm ) ) ) { - return + if (type === "stylus") { + if (overlayFeatureFormDrawer.opened || (featureForm.visible && pointInItem(point, featureForm))) { + return; } // Check if geometry editor is taking over - if ( geometryEditorsToolbar.canvasLongPressed( point, type ) ) { - return + if (geometryEditorsToolbar.canvasLongPressed(point, type)) { + return; } - - if ( stateMachine.state === "digitize" && dashBoard.activeLayer ) { // the sourceLocation test checks if a (stylus) hover is active - if ( ( Number( currentRubberband.model.geometryType ) === Qgis.GeometryType.Line && currentRubberband.model.vertexCount >= 2 ) - || ( Number( currentRubberband.model.geometryType ) === Qgis.GeometryType.Polygon && currentRubberband.model.vertexCount >= 2 ) ) { - digitizingToolbar.addVertex(); - - // When it's released, it will normally cause a release event to close the attribute form. - // We get around this by temporarily switching the closePolicy. - overlayFeatureFormDrawer.closePolicy = Popup.CloseOnEscape - - digitizingToolbar.confirm() - return + if (stateMachine.state === "digitize" && dashBoard.activeLayer) { + // the sourceLocation test checks if a (stylus) hover is active + if ((Number(currentRubberband.model.geometryType) === Qgis.GeometryType.Line && currentRubberband.model.vertexCount >= 2) || (Number(currentRubberband.model.geometryType) === Qgis.GeometryType.Polygon && currentRubberband.model.vertexCount >= 2)) { + digitizingToolbar.addVertex(); + + // When it's released, it will normally cause a release event to close the attribute form. + // We get around this by temporarily switching the closePolicy. + overlayFeatureFormDrawer.closePolicy = Popup.CloseOnEscape; + digitizingToolbar.confirm(); + return; } } // do not use else, as if it was catch it has return before - identifyTool.isMenuRequest = false - identifyTool.identify(point) + identifyTool.isMenuRequest = false; + identifyTool.identify(point); } else { // Check if geometry editor is taking over - if ( geometryEditorsToolbar.canvasLongPressed(point) ) { - return + if (geometryEditorsToolbar.canvasLongPressed(point)) { + return; } - - canvasMenu.point = mapCanvas.mapSettings.screenToCoordinate(point) - canvasMenu.popup(point.x, point.y) - identifyTool.isMenuRequest = true - identifyTool.identify(point) + canvasMenu.point = mapCanvas.mapSettings.screenToCoordinate(point); + canvasMenu.popup(point.x, point.y); + identifyTool.isMenuRequest = true; + identifyTool.identify(point); } } onRightClicked: (point, type) => { - canvasMenu.point = mapCanvas.mapSettings.screenToCoordinate(point) - canvasMenu.popup(point.x, point.y) - identifyTool.isMenuRequest = true - identifyTool.identify(point) + canvasMenu.point = mapCanvas.mapSettings.screenToCoordinate(point); + canvasMenu.popup(point.x, point.y); + identifyTool.isMenuRequest = true; + identifyTool.identify(point); } - onLongPressReleased: (type) => { - if ( type === "stylus" ) { + onLongPressReleased: type => { + if (type === "stylus") { // The user has released the long press. We can re-enable the default close behavior for the feature form. // The next press will be intentional to close the form. - overlayFeatureFormDrawer.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside + overlayFeatureFormDrawer.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside; } } } - - /************************************************** + /************************************************** * Overlays, including: * - Coordinate Locator * - Location Marker @@ -622,7 +593,7 @@ ApplicationWindow { property bool isMenuRequest: false mapSettings: mapCanvas.mapSettings - model: isMenuRequest ? canvasMenuFeatureListModel : featureForm.model + model: isMenuRequest ? canvasMenuFeatureListModel : featureForm.model searchRadiusMm: 3 } @@ -638,19 +609,20 @@ ApplicationWindow { /** Tracking sessions **/ Repeater { - id: trackings - model: trackingModel - - onCountChanged: { - if (count > 0) { - // Start positioning if not yet active - if (!positionSource.active) { - positioningSettings.positioningActivated = true - } + id: trackings + model: trackingModel + + onCountChanged: { + if (count > 0) { + // Start positioning if not yet active + if (!positionSource.active) { + positioningSettings.positioningActivated = true; } } + } - TrackingSession {} + TrackingSession { + } } /** A rubberband for ditizing **/ @@ -664,23 +636,23 @@ ApplicationWindow { currentCoordinate: coordinateLocator.currentCoordinate measureValue: { if (coordinateLocator.positionLocked) { - switch(positioningSettings.digitizingMeasureType) { - case Tracker.Timestamp: - return coordinateLocator.positionInformation.utcDateTime.getTime() - case Tracker.GroundSpeed: - return coordinateLocator.positionInformation.speed - case Tracker.Bearing: - return coordinateLocator.positionInformation.direction - case Tracker.HorizontalAccuracy: - return coordinateLocator.positionInformation.hacc - case Tracker.VerticalAccuracy: - return coordinateLocator.positionInformation.vacc - case Tracker.PDOP: - return coordinateLocator.positionInformation.pdop - case Tracker.HDOP: - return coordinateLocator.positionInformation.hdop - case Tracker.VDOP: - return coordinateLocator.positionInformation.vdop + switch (positioningSettings.digitizingMeasureType) { + case Tracker.Timestamp: + return coordinateLocator.positionInformation.utcDateTime.getTime(); + case Tracker.GroundSpeed: + return coordinateLocator.positionInformation.speed; + case Tracker.Bearing: + return coordinateLocator.positionInformation.direction; + case Tracker.HorizontalAccuracy: + return coordinateLocator.positionInformation.hacc; + case Tracker.VerticalAccuracy: + return coordinateLocator.positionInformation.vacc; + case Tracker.PDOP: + return coordinateLocator.positionInformation.pdop; + case Tracker.HDOP: + return coordinateLocator.positionInformation.hdop; + case Tracker.VDOP: + return coordinateLocator.positionInformation.vdop; } } else { return Number.NaN; @@ -713,8 +685,8 @@ ApplicationWindow { } BookmarkHighlight { - id: bookmarkHighlight - mapSettings: mapCanvas.mapSettings + id: bookmarkHighlight + mapSettings: mapCanvas.mapSettings } Navigation { @@ -722,10 +694,7 @@ ApplicationWindow { mapSettings: mapCanvas.mapSettings location: positionSource.active ? positionSource.projectedPosition : GeometryUtils.emptyPoint() - proximityAlarm: positioningSettings.preciseViewProximityAlarm - && informationDrawer.positioningPreciseView.visible - && informationDrawer.positioningPreciseView.hasAcceptableAccuracy - && !informationDrawer.positioningPreciseView.hasAlarmSnoozed + proximityAlarm: positioningSettings.preciseViewProximityAlarm && informationDrawer.positioningPreciseView.visible && informationDrawer.positioningPreciseView.hasAcceptableAccuracy && !informationDrawer.positioningPreciseView.hasAlarmSnoozed proximityAlarmThreshold: positioningSettings.preciseViewPrecision } @@ -739,7 +708,7 @@ ApplicationWindow { visible: informationDrawer.elevationProfile.visible mapSettings: mapCanvas.mapSettings - geometry: QgsGeometryWrapper { + geometry: QgsGeometryWrapper { qgsGeometry: informationDrawer.elevationProfile.profileCurve crs: informationDrawer.elevationProfile.crs } @@ -773,19 +742,9 @@ ApplicationWindow { location: positionSource.projectedPosition accuracy: positionSource.projectedHorizontalAccuracy - direction: positionSource.positionInformation - && positionSource.positionInformation.directionValid - ? positionSource.positionInformation.direction - : -1 - speed: positionSource.positionInformation - && positionSource.positionInformation.speedValid - ? positionSource.positionInformation.speed - : -1 - orientation: !isNaN(positionSource.orientation) - ? positionSource.orientation + positionSource.bearingTrueNorth < 0 - ? 360 + positionSource.orientation + positionSource.bearingTrueNorth - : positionSource.orientation + positionSource.bearingTrueNorth - : -1 + direction: positionSource.positionInformation && positionSource.positionInformation.directionValid ? positionSource.positionInformation.direction : -1 + speed: positionSource.positionInformation && positionSource.positionInformation.speedValid ? positionSource.positionInformation.speed : -1 + orientation: !isNaN(positionSource.orientation) ? positionSource.orientation + positionSource.bearingTrueNorth < 0 ? 360 + positionSource.orientation + positionSource.bearingTrueNorth : positionSource.orientation + positionSource.bearingTrueNorth : -1 } /* Rubberband for vertices */ @@ -830,8 +789,8 @@ ApplicationWindow { // take rotation into account property double rotationRadians: -mapSettings.rotation * Math.PI / 180 - translateX: mapToScreenTranslateX.screenDistance * Math.cos( rotationRadians ) - mapToScreenTranslateY.screenDistance * Math.sin( rotationRadians ) - translateY: mapToScreenTranslateY.screenDistance * Math.cos( rotationRadians ) + mapToScreenTranslateX.screenDistance * Math.sin( rotationRadians ) + translateX: mapToScreenTranslateX.screenDistance * Math.cos(rotationRadians) - mapToScreenTranslateY.screenDistance * Math.sin(rotationRadians) + translateY: mapToScreenTranslateY.screenDistance * Math.cos(rotationRadians) + mapToScreenTranslateX.screenDistance * Math.sin(rotationRadians) color: "yellow" focusedColor: "#ff7777" @@ -873,18 +832,18 @@ ApplicationWindow { onIsWithinChanged: { if (behavior == Geofencer.AlertWhenInsideGeofencedArea && geofencer.isWithin) { - platformUtilities.vibrate(longVibration) - displayToast(qsTr("Position has trespassed into ‘%1’").arg(isWithinAreaName), 'error') + platformUtilities.vibrate(longVibration); + displayToast(qsTr("Position has trespassed into ‘%1’").arg(isWithinAreaName), 'error'); } else if (behavior == Geofencer.AlertWhenOutsideGeofencedArea && !geofencer.isWithin) { - platformUtilities.vibrate(longVibration) - displayToast(qsTr("Position outside areas after leaving ‘%1’").arg(lastWithinAreaName), 'error') + platformUtilities.vibrate(longVibration); + displayToast(qsTr("Position outside areas after leaving ‘%1’").arg(lastWithinAreaName), 'error'); } else if (behavior == Geofencer.InformWhenEnteringLeavingGeofencedArea) { if (isWithin) { - platformUtilities.vibrate(shortVibration) - displayToast(qsTr("Position entered into ‘%1’").arg(isWithinAreaName)) + platformUtilities.vibrate(shortVibration); + displayToast(qsTr("Position entered into ‘%1’").arg(isWithinAreaName)); } else if (lastWithinAreaName != '') { - platformUtilities.vibrate(shortVibration) - displayToast(qsTr("Position left from ‘%1’").arg(lastWithinAreaName)) + platformUtilities.vibrate(shortVibration); + displayToast(qsTr("Position left from ‘%1’").arg(lastWithinAreaName)); } } } @@ -907,20 +866,20 @@ ApplicationWindow { onRunningChanged: { if (!running) { - geofencerFeedback.opacity = 0 + geofencerFeedback.opacity = 0; } } OpacityAnimator { target: geofencerFeedback - from: 0; - to: 0.75; + from: 0 + to: 0.75 duration: 1000 } OpacityAnimator { target: geofencerFeedback - from: 0.75; - to: 0; + from: 0.75 + to: 0 duration: 1000 } } @@ -953,7 +912,6 @@ ApplicationWindow { * - Scale Bar * - UI elements such as QfToolButtons **************************************************/ - Item { id: mapCanvasOverlays anchors.fill: mapCanvas @@ -973,7 +931,7 @@ ApplicationWindow { height: 48 radius: 4 - color:'#55000000' + color: '#55000000' Text { id: titleDecoration @@ -1010,7 +968,7 @@ ApplicationWindow { radius: 4 clip: true - color:'#55000000' + color: '#55000000' Text { id: copyrightDecoration @@ -1072,7 +1030,7 @@ ApplicationWindow { return newX; } y: { - var newY = coordinateLocator.displayPosition.y + 14 + var newY = coordinateLocator.displayPosition.y + 14; if (newY + height > mapCanvas.y + mapCanvas.height) newY -= height - 28; return newY; @@ -1080,61 +1038,15 @@ ApplicationWindow { textFormat: Text.PlainText text: { - if ((qfieldSettings.numericalDigitizingInformation && stateMachine.state === "digitize" ) || stateMachine.state === 'measure') { - var point = GeometryUtils.reprojectPoint(coordinateLocator.currentCoordinate, coordinateLocator.mapSettings.destinationCrs, projectInfo.coordinateDisplayCrs) + if ((qfieldSettings.numericalDigitizingInformation && stateMachine.state === "digitize") || stateMachine.state === 'measure') { + var point = GeometryUtils.reprojectPoint(coordinateLocator.currentCoordinate, coordinateLocator.mapSettings.destinationCrs, projectInfo.coordinateDisplayCrs); var coordinates; if (coordinatesIsXY) { - coordinates = '%1: %2\n%3: %4\n' - .arg(coordinatesIsGeographic ? qsTr( 'Lon' ) : 'X') - .arg(point.x.toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2 )) - .arg(coordinatesIsGeographic ? qsTr( 'Lat' ) : 'Y') - .arg(point.y.toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2 )); + coordinates = '%1: %2\n%3: %4\n'.arg(coordinatesIsGeographic ? qsTr('Lon') : 'X').arg(point.x.toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2)).arg(coordinatesIsGeographic ? qsTr('Lat') : 'Y').arg(point.y.toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2)); } else { - coordinates = '%1: %2\n%3: %4\n' - .arg(coordinatesIsGeographic ? qsTr( 'Lat' ) : 'Y') - .arg(point.y.toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2 )) - .arg(coordinatesIsGeographic ? qsTr( 'Lon' ) : 'X') - .arg(point.x.toLocaleString( Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2 )); + coordinates = '%1: %2\n%3: %4\n'.arg(coordinatesIsGeographic ? qsTr('Lat') : 'Y').arg(point.y.toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2)).arg(coordinatesIsGeographic ? qsTr('Lon') : 'X').arg(point.x.toLocaleString(Qt.locale(), 'f', coordinatesIsGeographic ? 5 : 2)); } - - return '%1%2%3%4%5%6' - .arg(stateMachine.state === 'digitize' || !digitizingToolbar.isDigitizing - ? coordinates - : '') - - .arg(digitizingGeometryMeasure.lengthValid && digitizingGeometryMeasure.segmentLength != 0.0 - ? '%1: %2\n' - .arg( digitizingGeometryMeasure.segmentLength != digitizingGeometryMeasure.length ? qsTr( 'Segment') : qsTr( 'Length' ) ) - .arg(UnitTypes.formatDistance( digitizingGeometryMeasure.convertLengthMeansurement( digitizingGeometryMeasure.segmentLength, projectInfo.distanceUnits ) , 3, projectInfo.distanceUnits ) ) - : '') - - .arg(digitizingGeometryMeasure.lengthValid && digitizingGeometryMeasure.segmentLength != 0.0 - ? '%1: %2\n' - .arg( qsTr( 'Azimuth') ) - .arg( UnitTypes.formatAngle( digitizingGeometryMeasure.azimuth < 0 ? digitizingGeometryMeasure.azimuth + 360 : digitizingGeometryMeasure.azimuth, 2, Qgis.AngleUnit.Degrees ) ) - : '') - - .arg(currentRubberband && currentRubberband.model && currentRubberband.model.geometryType === Qgis.GeometryType.Polygon - ? digitizingGeometryMeasure.perimeterValid - ? '%1: %2\n' - .arg( qsTr( 'Perimeter') ) - .arg(UnitTypes.formatDistance( digitizingGeometryMeasure.convertLengthMeansurement( digitizingGeometryMeasure.perimeter, projectInfo.distanceUnits ), 3, projectInfo.distanceUnits ) ) - : '' - : digitizingGeometryMeasure.lengthValid && digitizingGeometryMeasure.segmentLength != digitizingGeometryMeasure.length - ? '%1: %2\n' - .arg( qsTr( 'Length') ) - .arg(UnitTypes.formatDistance( digitizingGeometryMeasure.convertLengthMeansurement( digitizingGeometryMeasure.length, projectInfo.distanceUnits ),3, projectInfo.distanceUnits ) ) - : '') - - .arg(digitizingGeometryMeasure.areaValid - ? '%1: %2\n' - .arg( qsTr( 'Area') ) - .arg(UnitTypes.formatArea( digitizingGeometryMeasure.convertAreaMeansurement( digitizingGeometryMeasure.area, projectInfo.areaUnits ), 3, projectInfo.areaUnits ) ) - : '') - - .arg(stateMachine.state === 'measure' && digitizingToolbar.isDigitizing - ? coordinates - : '') + return '%1%2%3%4%5%6'.arg(stateMachine.state === 'digitize' || !digitizingToolbar.isDigitizing ? coordinates : '').arg(digitizingGeometryMeasure.lengthValid && digitizingGeometryMeasure.segmentLength != 0.0 ? '%1: %2\n'.arg(digitizingGeometryMeasure.segmentLength != digitizingGeometryMeasure.length ? qsTr('Segment') : qsTr('Length')).arg(UnitTypes.formatDistance(digitizingGeometryMeasure.convertLengthMeansurement(digitizingGeometryMeasure.segmentLength, projectInfo.distanceUnits), 3, projectInfo.distanceUnits)) : '').arg(digitizingGeometryMeasure.lengthValid && digitizingGeometryMeasure.segmentLength != 0.0 ? '%1: %2\n'.arg(qsTr('Azimuth')).arg(UnitTypes.formatAngle(digitizingGeometryMeasure.azimuth < 0 ? digitizingGeometryMeasure.azimuth + 360 : digitizingGeometryMeasure.azimuth, 2, Qgis.AngleUnit.Degrees)) : '').arg(currentRubberband && currentRubberband.model && currentRubberband.model.geometryType === Qgis.GeometryType.Polygon ? digitizingGeometryMeasure.perimeterValid ? '%1: %2\n'.arg(qsTr('Perimeter')).arg(UnitTypes.formatDistance(digitizingGeometryMeasure.convertLengthMeansurement(digitizingGeometryMeasure.perimeter, projectInfo.distanceUnits), 3, projectInfo.distanceUnits)) : '' : digitizingGeometryMeasure.lengthValid && digitizingGeometryMeasure.segmentLength != digitizingGeometryMeasure.length ? '%1: %2\n'.arg(qsTr('Length')).arg(UnitTypes.formatDistance(digitizingGeometryMeasure.convertLengthMeansurement(digitizingGeometryMeasure.length, projectInfo.distanceUnits), 3, projectInfo.distanceUnits)) : '').arg(digitizingGeometryMeasure.areaValid ? '%1: %2\n'.arg(qsTr('Area')).arg(UnitTypes.formatArea(digitizingGeometryMeasure.convertAreaMeansurement(digitizingGeometryMeasure.area, projectInfo.areaUnits), 3, projectInfo.areaUnits)) : '').arg(stateMachine.state === 'measure' && digitizingToolbar.isDigitizing ? coordinates : ''); } else { return ''; } @@ -1152,7 +1064,7 @@ ApplicationWindow { anchors.left: parent.left anchors.bottom: parent.bottom anchors.leftMargin: 4 - anchors.bottomMargin: 54 + anchors.bottomMargin: 54 round: true bgcolor: Theme.darkGraySemiOpaque iconSource: Theme.getThemeVectorIcon('ic_compass_arrow_24dp') @@ -1180,7 +1092,7 @@ ApplicationWindow { QfToolButton { id: alertIcon - iconSource: Theme.getThemeVectorIcon( "ic_alert_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_alert_black_24dp") round: true bgcolor: "transparent" visible: !screenLocker.enabled && messageLog.unreadMessages @@ -1196,7 +1108,7 @@ ApplicationWindow { anchors.right: parent.right anchors.rightMargin: 10 anchors.bottom: parent.bottom - anchors.bottomMargin: (parent.height - zoomToolbar.height / 2 ) / 2 + anchors.bottomMargin: (parent.height - zoomToolbar.height / 2) / 2 spacing: 8 visible: !screenLocker.enabled && (locationToolbar.height + digitizingToolbarContainer.height) / (digitizingToolbarContainer.y) < 0.41 @@ -1206,14 +1118,15 @@ ApplicationWindow { anchors.right: parent.right bgcolor: Theme.darkGray - iconSource: Theme.getThemeIcon( "ic_add_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_add_white_24dp") width: 36 height: 36 onClicked: { - if ( gnssButton.followActive ) gnssButton.followActiveSkipExtentChanged = true; - mapCanvasMap.zoomIn(Qt.point(mapCanvas.x + mapCanvas.width / 2,mapCanvas.y + mapCanvas.height / 2)); + if (gnssButton.followActive) + gnssButton.followActiveSkipExtentChanged = true; + mapCanvasMap.zoomIn(Qt.point(mapCanvas.x + mapCanvas.width / 2, mapCanvas.y + mapCanvas.height / 2)); } } QfToolButton { @@ -1222,14 +1135,15 @@ ApplicationWindow { anchors.right: parent.right bgcolor: Theme.darkGray - iconSource: Theme.getThemeIcon( "ic_remove_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_remove_white_24dp") width: 36 height: 36 onClicked: { - if ( gnssButton.followActive ) gnssButton.followActiveSkipExtentChanged = true; - mapCanvasMap.zoomOut(Qt.point(mapCanvas.x + mapCanvas.width / 2,mapCanvas.y + mapCanvas.height / 2)); + if (gnssButton.followActive) + gnssButton.followActiveSkipExtentChanged = true; + mapCanvasMap.zoomOut(Qt.point(mapCanvas.x + mapCanvas.width / 2, mapCanvas.y + mapCanvas.height / 2)); } } } @@ -1248,20 +1162,20 @@ ApplicationWindow { visible: !screenLocker.enabled && stateMachine.state !== 'measure' - Keys.onReleased: (event) => { - if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true - state = "off" - } - } + Keys.onReleased: event => { + if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { + event.accepted = true; + state = "off"; + } + } onStateChanged: { - if ( state == "off" ) { - focus = false - if ( featureForm.visible ) { - featureForm.focus = true + if (state == "off") { + focus = false; + if (featureForm.visible) { + featureForm.focus = true; } else { - keyHandler.focus = true + keyHandler.focus = true; } } } @@ -1289,30 +1203,30 @@ ApplicationWindow { QfToolButton { id: menuButton round: true - iconSource: Theme.getThemeIcon( "ic_menu_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_menu_white_24dp") bgcolor: dashBoard.opened ? Theme.mainColor : Theme.darkGray onClicked: dashBoard.opened ? dashBoard.close() : dashBoard.open() onPressAndHold: { - mainMenu.popup(menuButton.x, menuButton.y) + mainMenu.popup(menuButton.x, menuButton.y); } } QfCloseButton { id: closeMeasureTool visible: stateMachine.state === 'measure' - toolImage: Theme.getThemeVectorIcon( "ic_measurement_black_24dp" ) - toolText: qsTr( 'Close measure tool' ) + toolImage: Theme.getThemeVectorIcon("ic_measurement_black_24dp") + toolText: qsTr('Close measure tool') onClose: mainWindow.closeMeasureTool() } QfCloseButton { id: closeGeometryEditorsTool - visible: ( stateMachine.state === "digitize" && geometryEditingVertexModel.vertexCount > 0 ) + visible: (stateMachine.state === "digitize" && geometryEditingVertexModel.vertexCount > 0) toolImage: geometryEditorsToolbar.image - toolText: qsTr( 'Stop editing' ) + toolText: qsTr('Stop editing') onClose: geometryEditorsToolbar.cancelEditors() } @@ -1320,8 +1234,8 @@ ApplicationWindow { QfCloseButton { id: abortRequestGeometry visible: digitizingToolbar.geometryRequested - toolImage: Theme.getThemeIcon( "ic_edit_geometry_white" ) - toolText: qsTr( 'Cancel addition' ) + toolImage: Theme.getThemeIcon("ic_edit_geometry_white") + toolText: qsTr('Cancel addition') onClose: digitizingToolbar.cancel() } @@ -1344,14 +1258,7 @@ ApplicationWindow { iconSource: Theme.getThemeVectorIcon('ic_digitizing_settings_black_24dp') iconColor: "white" spacing: 4 - visible: stateMachine.state === "digitize" - && dashBoard.activeLayer - && dashBoard.activeLayer.isValid - && ( - dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Polygon - || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Line - || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Point - ) + visible: stateMachine.state === "digitize" && dashBoard.activeLayer && dashBoard.activeLayer.isValid && (dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Polygon || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Line || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Point) QfToolButton { id: snappingButton @@ -1360,7 +1267,7 @@ ApplicationWindow { padding: 2 round: true state: qgisProject && qgisProject.snappingConfig.enabled ? "On" : "Off" - iconSource: Theme.getThemeVectorIcon( "ic_snapping_white_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_snapping_white_24dp") iconColor: "white" bgcolor: Theme.darkGray @@ -1374,7 +1281,6 @@ ApplicationWindow { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -1386,11 +1292,11 @@ ApplicationWindow { ] onClicked: { - var snappingConfig = qgisProject.snappingConfig - snappingConfig.enabled = !snappingConfig.enabled - qgisProject.snappingConfig = snappingConfig - projectInfo.snappingEnabled = snappingConfig.enabled - displayToast( snappingConfig.enabled ? qsTr( "Snapping turned on" ) : qsTr( "Snapping turned off" ) ) + var snappingConfig = qgisProject.snappingConfig; + snappingConfig.enabled = !snappingConfig.enabled; + qgisProject.snappingConfig = snappingConfig; + projectInfo.snappingEnabled = snappingConfig.enabled; + displayToast(snappingConfig.enabled ? qsTr("Snapping turned on") : qsTr("Snapping turned off")); } } @@ -1401,7 +1307,7 @@ ApplicationWindow { padding: 2 round: true state: qgisProject && qgisProject.topologicalEditing ? "On" : "Off" - iconSource: Theme.getThemeVectorIcon( "ic_topology_white_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_topology_white_24dp") iconColor: "white" bgcolor: Theme.darkGray @@ -1415,7 +1321,6 @@ ApplicationWindow { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -1428,7 +1333,7 @@ ApplicationWindow { onClicked: { qgisProject.topologicalEditing = !qgisProject.topologicalEditing; - displayToast( qgisProject.topologicalEditing ? qsTr( "Topological editing turned on" ) : qsTr( "Topological editing turned off" ) ); + displayToast(qgisProject.topologicalEditing ? qsTr("Topological editing turned on") : qsTr("Topological editing turned off")); } } @@ -1438,14 +1343,8 @@ ApplicationWindow { height: visible ? 40 : 0 padding: 2 round: true - visible: hoverHandler.hasBeenHovered && !(positionSource.active && positioningSettings.positioningCoordinateLock) && stateMachine.state === "digitize" - && ((digitizingToolbar.geometryRequested && digitizingToolbar.geometryRequestedLayer && digitizingToolbar.geometryRequestedLayer.isValid && - (digitizingToolbar.geometryRequestedLayer.geometryType() === Qgis.GeometryType.Polygon - || digitizingToolbar.geometryRequestedLayer.geometryType() === Qgis.GeometryType.Line)) - || (!digitizingToolbar.geometryRequested && dashBoard.activeLayer && dashBoard.activeLayer.isValid && - (dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Polygon - || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Line))) - iconSource: Theme.getThemeVectorIcon( "ic_freehand_white_24dp" ) + visible: hoverHandler.hasBeenHovered && !(positionSource.active && positioningSettings.positioningCoordinateLock) && stateMachine.state === "digitize" && ((digitizingToolbar.geometryRequested && digitizingToolbar.geometryRequestedLayer && digitizingToolbar.geometryRequestedLayer.isValid && (digitizingToolbar.geometryRequestedLayer.geometryType() === Qgis.GeometryType.Polygon || digitizingToolbar.geometryRequestedLayer.geometryType() === Qgis.GeometryType.Line)) || (!digitizingToolbar.geometryRequested && dashBoard.activeLayer && dashBoard.activeLayer.isValid && (dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Polygon || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Line))) + iconSource: Theme.getThemeVectorIcon("ic_freehand_white_24dp") iconColor: "white" bgcolor: Theme.darkGray @@ -1461,7 +1360,6 @@ ApplicationWindow { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -1473,18 +1371,16 @@ ApplicationWindow { ] onClicked: { - freehandDigitizing = !freehandDigitizing - + freehandDigitizing = !freehandDigitizing; if (freehandDigitizing && positioningSettings.positioningCoordinateLock) { positioningSettings.positioningCoordinateLock = false; } - - displayToast( freehandDigitizing ? qsTr( "Freehand digitizing turned on" ) : qsTr( "Freehand digitizing turned off" ) ); - settings.setValue( "/QField/Digitizing/FreehandActive", freehandDigitizing ); + displayToast(freehandDigitizing ? qsTr("Freehand digitizing turned on") : qsTr("Freehand digitizing turned off")); + settings.setValue("/QField/Digitizing/FreehandActive", freehandDigitizing); } Component.onCompleted: { - freehandDigitizing = settings.valueBool( "/QField/Digitizing/FreehandActive", false ) + freehandDigitizing = settings.valueBool("/QField/Digitizing/FreehandActive", false); } } @@ -1494,12 +1390,8 @@ ApplicationWindow { width: visible ? 40 : 0 height: visible ? 40 : 0 round: true - visible: dashBoard.activeLayer - && ( - dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Polygon - || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Line - ) - iconSource: Theme.getThemeVectorIcon( "ic_common_angle_white_24dp" ) + visible: dashBoard.activeLayer && (dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Polygon || dashBoard.activeLayer.geometryType() === Qgis.GeometryType.Line) + iconSource: Theme.getThemeVectorIcon("ic_common_angle_white_24dp") iconColor: "white" bgcolor: Theme.darkGray @@ -1518,7 +1410,6 @@ ApplicationWindow { bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { @@ -1531,31 +1422,25 @@ ApplicationWindow { onClicked: { isSnapToCommonAngleEnabled = !isSnapToCommonAngleEnabled; - settings.setValue( "/QField/Digitizing/SnapToCommonAngleIsEnabled", isSnapToCommonAngleEnabled ); - - displayToast( - isSnapToCommonAngleEnabled - ? qsTr( "Snap to %1° angle turned on" ).arg( snapToCommonAngleDegrees ) - : qsTr( "Snap to common angle turned off" ) - ); + settings.setValue("/QField/Digitizing/SnapToCommonAngleIsEnabled", isSnapToCommonAngleEnabled); + displayToast(isSnapToCommonAngleEnabled ? qsTr("Snap to %1° angle turned on").arg(snapToCommonAngleDegrees) : qsTr("Snap to common angle turned off")); } onPressAndHold: { - snapToCommonAngleMenu.popup( parent.x, parent.y ); + snapToCommonAngleMenu.popup(parent.x, parent.y); } Component.onCompleted: { - isSnapToCommonAngleEnabled = settings.valueBool( "/QField/Digitizing/SnapToCommonAngleIsEnabled", false ); - isSnapToCommonAngleRelative = settings.valueBool( "/QField/Digitizing/SnapToCommonAngleIsRelative", true ); - snapToCommonAngleDegrees = settings.valueInt( "/QField/Digitizing/SnapToCommonAngleDegrees", snapToCommonAngleDegrees ); + isSnapToCommonAngleEnabled = settings.valueBool("/QField/Digitizing/SnapToCommonAngleIsEnabled", false); + isSnapToCommonAngleRelative = settings.valueBool("/QField/Digitizing/SnapToCommonAngleIsRelative", true); + snapToCommonAngleDegrees = settings.valueInt("/QField/Digitizing/SnapToCommonAngleDegrees", snapToCommonAngleDegrees); } - Menu { id: snapToCommonAngleMenu MenuItem { - text: qsTr( "Relative angle" ) + text: qsTr("Relative angle") font: Theme.defaultFont height: 48 leftPadding: Theme.menuItemCheckLeftPadding @@ -1565,11 +1450,13 @@ ApplicationWindow { onTriggered: { snapToCommonAngleButton.isSnapToCommonAngleRelative = checked; - settings.setValue( "/QField/Digitizing/SnapToCommonAngleIsRelative", snapToCommonAngleButton.isSnapToCommonAngleRelative ); + settings.setValue("/QField/Digitizing/SnapToCommonAngleIsRelative", snapToCommonAngleButton.isSnapToCommonAngleRelative); } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } Repeater { // list of common angles to snap to @@ -1577,7 +1464,7 @@ ApplicationWindow { delegate: MenuItem { required property int modelData - text: qsTr( "Snap every %1°" ).arg( modelData ) + text: qsTr("Snap every %1°").arg(modelData) font: Theme.defaultFont height: 48 @@ -1588,16 +1475,13 @@ ApplicationWindow { enabled: modelData !== snapToCommonAngleButton.snapToCommonAngleDegrees onTriggered: { - if ( !checked ) { + if (!checked) { return; } - snapToCommonAngleButton.isSnapToCommonAngleEnabled = true; snapToCommonAngleButton.snapToCommonAngleDegrees = modelData; - settings.setValue( "/QField/Digitizing/SnapToCommonAngleDegrees", snapToCommonAngleButton.snapToCommonAngleDegrees ); - - displayToast( qsTr( "Snap to %1° angle turned on" ).arg( modelData ) ); - + settings.setValue("/QField/Digitizing/SnapToCommonAngleDegrees", snapToCommonAngleButton.snapToCommonAngleDegrees); + displayToast(qsTr("Snap to %1° angle turned on").arg(modelData)); snapToCommonAngleMenu.close(); } } @@ -1610,7 +1494,7 @@ ApplicationWindow { id: elevationProfileButton round: true visible: stateMachine.state === 'measure' - iconSource: Theme.getThemeVectorIcon( "ic_elevation_white_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_elevation_white_24dp") bgcolor: Theme.darkGray @@ -1622,37 +1506,35 @@ ApplicationWindow { name: "Off" PropertyChanges { target: elevationProfileButton - iconSource: Theme.getThemeVectorIcon( "ic_elevation_white_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_elevation_white_24dp") bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { target: elevationProfileButton - iconSource: Theme.getThemeVectorIcon( "ic_elevation_green_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_elevation_green_24dp") bgcolor: Theme.darkGray } } ] onClicked: { - elevationProfileActive = !elevationProfileActive + elevationProfileActive = !elevationProfileActive; // Draw an elevation profile if we have enough points to do so - if ( digitizingToolbar.rubberbandModel.vertexCount > 2 ) { + if (digitizingToolbar.rubberbandModel.vertexCount > 2) { // Clear the pre-existing profile to trigger a zoom to full updated profile curve informationDrawer.elevationProfile.clear(); - informationDrawer.elevationProfile.profileCurve = GeometryUtils.lineFromRubberband(digitizingToolbar.rubberbandModel, informationDrawer.elevationProfile.crs) + informationDrawer.elevationProfile.profileCurve = GeometryUtils.lineFromRubberband(digitizingToolbar.rubberbandModel, informationDrawer.elevationProfile.crs); informationDrawer.elevationProfile.refresh(); } - - settings.setValue( "/QField/Measuring/ElevationProfile", elevationProfileActive ); + settings.setValue("/QField/Measuring/ElevationProfile", elevationProfileActive); } Component.onCompleted: { - elevationProfileActive = settings.valueBool( "/QField/Measuring/ElevationProfile", false ) + elevationProfileActive = settings.valueBool("/QField/Measuring/ElevationProfile", false); } } } @@ -1682,12 +1564,8 @@ ApplicationWindow { anchors.right: parent.right property bool isFollowLocationActive: positionSource.active && gnssButton.followActive && followIncludeDestination - iconSource: isFollowLocationActive - ? Theme.getThemeIcon( "ic_navigation_flag_white_24dp" ) - : Theme.getThemeIcon( "ic_navigation_flag_purple_24dp" ) - bgcolor: isFollowLocationActive - ? Theme.navigationColor - : Theme.darkGray + iconSource: isFollowLocationActive ? Theme.getThemeIcon("ic_navigation_flag_white_24dp") : Theme.getThemeIcon("ic_navigation_flag_purple_24dp") + bgcolor: isFollowLocationActive ? Theme.navigationColor : Theme.darkGray /* / When set to true, when the map follows the device's current position, the extent @@ -1697,24 +1575,20 @@ ApplicationWindow { onClicked: { if (positionSource.active && gnssButton.followActive) { - followIncludeDestination = !followIncludeDestination + followIncludeDestination = !followIncludeDestination; settings.setValue("/QField/Navigation/FollowIncludeDestination", followIncludeDestination); - - gnssButton.followLocation(true) + gnssButton.followLocation(true); } else { - mapCanvas.mapSettings.setCenter(navigation.destination) + mapCanvas.mapSettings.setCenter(navigation.destination); } } onPressAndHold: { - navigationMenu.popup( - locationToolbar.x + locationToolbar.width - navigationMenu.width, - locationToolbar.y + navigationButton.height - navigationMenu.height - ) + navigationMenu.popup(locationToolbar.x + locationToolbar.width - navigationMenu.width, locationToolbar.y + navigationButton.height - navigationMenu.height); } Component.onCompleted: { - followIncludeDestination = settings.valueBool("/QField/Navigation/FollowIncludeDestination", true) + followIncludeDestination = settings.valueBool("/QField/Navigation/FollowIncludeDestination", true); } } @@ -1722,7 +1596,7 @@ ApplicationWindow { id: gnssLockButton anchors.right: parent.right state: positionSource.active && positioningSettings.positioningCoordinateLock ? "On" : "Off" - visible: gnssButton.state === "On" && ( stateMachine.state === "digitize" || stateMachine.state === 'measure' ) + visible: gnssButton.state === "On" && (stateMachine.state === "digitize" || stateMachine.state === 'measure') round: true checkable: true checked: positioningSettings.positioningCoordinateLock @@ -1732,16 +1606,15 @@ ApplicationWindow { name: "Off" PropertyChanges { target: gnssLockButton - iconSource: Theme.getThemeIcon( "ic_gps_link_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_gps_link_white_24dp") bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { target: gnssLockButton - iconSource: Theme.getThemeIcon( "ic_gps_link_activated_white_24dp" ) + iconSource: Theme.getThemeIcon("ic_gps_link_activated_white_24dp") bgcolor: Theme.darkGray } } @@ -1754,17 +1627,16 @@ ApplicationWindow { // deactivate freehand digitizing when cursor locked is on freehandButton.clicked(); } - displayToast( qsTr( "Coordinate cursor now locked to position" ) ) + displayToast(qsTr("Coordinate cursor now locked to position")); if (positionSource.positionInformation.latitudeValid) { var screenLocation = mapCanvas.mapSettings.coordinateToScreen(locationMarker.location); - if ( screenLocation.x < 0 || screenLocation.x > mainWindow.width || - screenLocation.y < 0 || screenLocation.y > mainWindow.height ) { + if (screenLocation.x < 0 || screenLocation.x > mainWindow.width || screenLocation.y < 0 || screenLocation.y > mainWindow.height) { mapCanvas.mapSettings.setCenter(positionSource.projectedPosition); } } positioningSettings.positioningCoordinateLock = true; } else { - displayToast( qsTr( "Coordinate cursor unlocked" ) ) + displayToast(qsTr("Coordinate cursor unlocked")); positioningSettings.positioningCoordinateLock = false; // deactivate any active averaged position collection positionSource.averagedPosition = false; @@ -1782,11 +1654,11 @@ ApplicationWindow { anchors.right: parent.right onIconSourceChanged: { - if( state === "On" ){ - if( positionSource.positionInformation && positionSource.positionInformation.latitudeValid ) { - displayToast( qsTr( "Received position" ) ) + if (state === "On") { + if (positionSource.positionInformation && positionSource.positionInformation.latitudeValid) { + displayToast(qsTr("Received position")); } else { - displayToast( qsTr( "Searching for position" ) ) + displayToast(qsTr("Searching for position")); } } } @@ -1816,18 +1688,15 @@ ApplicationWindow { name: "Off" PropertyChanges { target: gnssButton - iconSource: Theme.getThemeVectorIcon( "ic_location_disabled_white_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_location_disabled_white_24dp") bgcolor: Theme.darkGraySemiOpaque } }, - State { name: "On" PropertyChanges { target: gnssButton - iconSource: positionSource.positionInformation && positionSource.positionInformation.latitudeValid - ? Theme.getThemeVectorIcon( "ic_location_valid_white_24dp" ) - : Theme.getThemeVectorIcon( "ic_location_white_24dp" ) + iconSource: positionSource.positionInformation && positionSource.positionInformation.latitudeValid ? Theme.getThemeVectorIcon("ic_location_valid_white_24dp") : Theme.getThemeVectorIcon("ic_location_white_24dp") iconColor: followActive ? "white" : Theme.positionColor bgcolor: followActive ? Theme.positionColor : Theme.darkGray } @@ -1836,34 +1705,24 @@ ApplicationWindow { onClicked: { if (followActive) { - followOrientationActive = true + followOrientationActive = true; followOrientation(); - displayToast( qsTr( "Canvas follows location and compass orientation" ) ) + displayToast(qsTr("Canvas follows location and compass orientation")); } else { - followActive = true - if ( positionSource.projectedPosition.x ) - { - if ( !positionSource.active ) - { - positioningSettings.positioningActivated = true - } - else - { + followActive = true; + if (positionSource.projectedPosition.x) { + if (!positionSource.active) { + positioningSettings.positioningActivated = true; + } else { followLocation(true); - displayToast( qsTr( "Canvas follows location" ) ) + displayToast(qsTr("Canvas follows location")); } - } - else - { - if ( positionSource.valid ) - { - if ( positionSource.active ) - { - displayToast( qsTr( "Waiting for location" ) ) - } - else - { - positioningSettings.positioningActivated = true + } else { + if (positionSource.valid) { + if (positionSource.active) { + displayToast(qsTr("Waiting for location")); + } else { + positioningSettings.positioningActivated = true; } } } @@ -1871,42 +1730,27 @@ ApplicationWindow { } onPressAndHold: { - gnssMenu.popup(locationToolbar.x + locationToolbar.width - gnssMenu.width, locationToolbar.y + locationToolbar.height - gnssMenu.height) + gnssMenu.popup(locationToolbar.x + locationToolbar.width - gnssMenu.width, locationToolbar.y + locationToolbar.height - gnssMenu.height); } property int followLocationMinScale: 125 property int followLocationMinMargin: 40 - property int followLocationScreenFraction: settings ? settings.value( "/QField/Positioning/FollowScreenFraction", 5 ) : 5 + property int followLocationScreenFraction: settings ? settings.value("/QField/Positioning/FollowScreenFraction", 5) : 5 function followLocation(forceRecenter) { var screenLocation = mapCanvas.mapSettings.coordinateToScreen(positionSource.projectedPosition); if (navigation.isActive && navigationButton.followIncludeDestination) { if (mapCanvas.mapSettings.scale > followLocationMinScale) { var screenDestination = mapCanvas.mapSettings.coordinateToScreen(navigation.destination); - if (forceRecenter - || screenDestination.x < followLocationMinMargin - || screenDestination.x > (mainWindow.width - followLocationMinMargin) - || screenDestination.y < followLocationMinMargin - || screenDestination.y > (mainWindow.height - followLocationMinMargin) - || screenLocation.x < followLocationMinMargin - || screenLocation.x > (mainWindow.width - followLocationMinMargin) - || screenLocation.y < followLocationMinMargin - || screenLocation.y > (mainWindow.height - followLocationMinMargin) - || (Math.abs(screenDestination.x - screenLocation.x) < mainWindow.width / 3 - && Math.abs(screenDestination.y - screenLocation.y) < mainWindow.height / 3)) { + if (forceRecenter || screenDestination.x < followLocationMinMargin || screenDestination.x > (mainWindow.width - followLocationMinMargin) || screenDestination.y < followLocationMinMargin || screenDestination.y > (mainWindow.height - followLocationMinMargin) || screenLocation.x < followLocationMinMargin || screenLocation.x > (mainWindow.width - followLocationMinMargin) || screenLocation.y < followLocationMinMargin || screenLocation.y > (mainWindow.height - followLocationMinMargin) || (Math.abs(screenDestination.x - screenLocation.x) < mainWindow.width / 3 && Math.abs(screenDestination.y - screenLocation.y) < mainWindow.height / 3)) { gnssButton.followActiveSkipExtentChanged = true; var points = [positionSource.projectedPosition, navigation.destination]; - mapCanvas.mapSettings.setExtentFromPoints(points, followLocationMinScale, true) + mapCanvas.mapSettings.setExtentFromPoints(points, followLocationMinScale, true); } } } else { - var threshold = Math.min( mainWindow.width, mainWindow.height ) / followLocationScreenFraction; - if ( forceRecenter - || screenLocation.x < mapCanvas.x + threshold - || screenLocation.x > mapCanvas.width - threshold - || screenLocation.y < mapCanvas.y + threshold - || screenLocation.y > mapCanvas.height - threshold ) - { + var threshold = Math.min(mainWindow.width, mainWindow.height) / followLocationScreenFraction; + if (forceRecenter || screenLocation.x < mapCanvas.x + threshold || screenLocation.x > mapCanvas.width - threshold || screenLocation.y < mapCanvas.y + threshold || screenLocation.y > mapCanvas.height - threshold) { gnssButton.followActiveSkipExtentChanged = true; mapCanvas.mapSettings.setCenter(positionSource.projectedPosition, true); } @@ -1914,8 +1758,8 @@ ApplicationWindow { } function followOrientation() { if (!isNaN(positionSource.orientation) && Math.abs(-positionSource.orientation - mapCanvas.mapSettings.rotation) >= 10) { - gnssButton.followActiveSkipRotationChanged = true - mapCanvas.mapSettings.rotation = -positionSource.orientation + gnssButton.followActiveSkipRotationChanged = true; + mapCanvas.mapSettings.rotation = -positionSource.orientation; } } @@ -1935,13 +1779,7 @@ ApplicationWindow { border.color: 'white' visible: positioningSettings.accuracyIndicator && gnssButton.state === "On" - color: !positionSource.positionInformation - || !positionSource.positionInformation.haccValid - || positionSource.positionInformation.hacc > positioningSettings.accuracyBad - ? Theme.accuracyBad - : positionSource.positionInformation.hacc > positioningSettings.accuracyExcellent - ? Theme.accuracyTolerated - : Theme.accuracyExcellent + color: !positionSource.positionInformation || !positionSource.positionInformation.haccValid || positionSource.positionInformation.hacc > positioningSettings.accuracyBad ? Theme.accuracyBad : positionSource.positionInformation.hacc > positioningSettings.accuracyExcellent ? Theme.accuracyTolerated : Theme.accuracyExcellent } } @@ -1949,23 +1787,23 @@ ApplicationWindow { target: mapCanvas.mapSettings function onExtentChanged() { - if ( gnssButton.followActive ) { - if ( gnssButton.followActiveSkipExtentChanged ) { + if (gnssButton.followActive) { + if (gnssButton.followActiveSkipExtentChanged) { gnssButton.followActiveSkipExtentChanged = false; } else { - gnssButton.followActive = false - gnssButton.followOrientationActive = false - displayToast( qsTr( "Canvas stopped following location" ) ) + gnssButton.followActive = false; + gnssButton.followOrientationActive = false; + displayToast(qsTr("Canvas stopped following location")); } } } function onRotationChanged() { - if ( gnssButton.followOrientationActive ) { - if ( gnssButton.followActiveSkipRotationChanged ) { - gnssButton.followActiveSkipRotationChanged = false + if (gnssButton.followOrientationActive) { + if (gnssButton.followActiveSkipRotationChanged) { + gnssButton.followActiveSkipRotationChanged = false; } else { - gnssButton.followOrientationActive = false + gnssButton.followOrientationActive = false; } } } @@ -1984,18 +1822,9 @@ ApplicationWindow { DigitizingToolbar { id: digitizingToolbar - stateVisible: !screenLocker.enabled && - (!positioningSettings.geofencingPreventDigitizingDuringAlert || !geofencer.isAlerting) && - ((stateMachine.state === "digitize" - && dashBoard.activeLayer - && !dashBoard.activeLayer.readOnly - // unfortunately there is no way to call QVariant::toBool in QML so the value is a string - && dashBoard.activeLayer.customProperty( 'QFieldSync/is_geometry_locked' ) !== 'true' - && !geometryEditorsToolbar.stateVisible - && !moveFeaturesToolbar.stateVisible - && (projectInfo.editRights || projectInfo.insertRights)) - || stateMachine.state === 'measure' - || (stateMachine.state === "digitize" && digitizingToolbar.geometryRequested)) + stateVisible: !screenLocker.enabled && (!positioningSettings.geofencingPreventDigitizingDuringAlert || !geofencer.isAlerting) && ((stateMachine.state === "digitize" && dashBoard.activeLayer && !dashBoard.activeLayer.readOnly && + // unfortunately there is no way to call QVariant::toBool in QML so the value is a string + dashBoard.activeLayer.customProperty('QFieldSync/is_geometry_locked') !== 'true' && !geometryEditorsToolbar.stateVisible && !moveFeaturesToolbar.stateVisible && (projectInfo.editRights || projectInfo.insertRights)) || stateMachine.state === 'measure' || (stateMachine.state === "digitize" && digitizingToolbar.geometryRequested)) rubberbandModel: currentRubberband ? currentRubberband.model : null mapSettings: mapCanvas.mapSettings showConfirmButton: stateMachine.state === "digitize" @@ -2020,137 +1849,119 @@ ApplicationWindow { property string previousStateMachineState: '' onGeometryRequestedChanged: { - if ( geometryRequested ) { - digitizingRubberband.model.reset() - previousStateMachineState = stateMachine.state - stateMachine.state = "digitize" - } - else - { - stateMachine.state = previousStateMachineState + if (geometryRequested) { + digitizingRubberband.model.reset(); + previousStateMachineState = stateMachine.state; + stateMachine.state = "digitize"; + } else { + stateMachine.state = previousStateMachineState; } } onVertexCountChanged: { - if ( stateMachine.state === 'measure' && elevationProfileButton.elevationProfileActive ) { - if ( rubberbandModel.vertexCount > 2 ) { + if (stateMachine.state === 'measure' && elevationProfileButton.elevationProfileActive) { + if (rubberbandModel.vertexCount > 2) { // Clear the pre-existing profile to trigger a zoom to full updated profile curve informationDrawer.elevationProfile.clear(); - informationDrawer.elevationProfile.profileCurve = GeometryUtils.lineFromRubberband(rubberbandModel, informationDrawer.elevationProfile.crs) + informationDrawer.elevationProfile.profileCurve = GeometryUtils.lineFromRubberband(rubberbandModel, informationDrawer.elevationProfile.crs); informationDrawer.elevationProfile.refresh(); } - } else if( qfieldSettings.autoSave && stateMachine.state === "digitize" ) { - if ( digitizingToolbar.geometryValid ) { - if (digitizingRubberband.model.geometryType === Qgis.GeometryType.Null) - { - digitizingRubberband.model.reset() - } - else - { - digitizingFeature.geometry.applyRubberband() - digitizingFeature.applyGeometry() + } else if (qfieldSettings.autoSave && stateMachine.state === "digitize") { + if (digitizingToolbar.geometryValid) { + if (digitizingRubberband.model.geometryType === Qgis.GeometryType.Null) { + digitizingRubberband.model.reset(); + } else { + digitizingFeature.geometry.applyRubberband(); + digitizingFeature.applyGeometry(); } - - if ( !overlayFeatureFormDrawer.featureForm.featureCreated ) - { - overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry - overlayFeatureFormDrawer.featureModel.applyGeometry() - overlayFeatureFormDrawer.featureModel.resetAttributes() - if( overlayFeatureFormDrawer.featureForm.model.constraintsHardValid ) { + if (!overlayFeatureFormDrawer.featureForm.featureCreated) { + overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry; + overlayFeatureFormDrawer.featureModel.applyGeometry(); + overlayFeatureFormDrawer.featureModel.resetAttributes(); + if (overlayFeatureFormDrawer.featureForm.model.constraintsHardValid) { // when the constrainst are fulfilled // indirect action, no need to check for success and display a toast, the log is enough - overlayFeatureFormDrawer.featureForm.featureCreated = overlayFeatureFormDrawer.featureForm.create() + overlayFeatureFormDrawer.featureForm.featureCreated = overlayFeatureFormDrawer.featureForm.create(); } } else { // indirect action, no need to check for success and display a toast, the log is enough - overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry - overlayFeatureFormDrawer.featureModel.applyGeometry() - overlayFeatureFormDrawer.featureForm.save() + overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry; + overlayFeatureFormDrawer.featureModel.applyGeometry(); + overlayFeatureFormDrawer.featureForm.save(); } } else { - if ( overlayFeatureFormDrawer.featureForm.featureCreated ) { + if (overlayFeatureFormDrawer.featureForm.featureCreated) { // delete the feature when the geometry gets invalid again // indirect action, no need to check for success and display a toast, the log is enough - overlayFeatureFormDrawer.featureForm.featureCreated = !overlayFeatureFormDrawer.featureForm.deleteFeature() + overlayFeatureFormDrawer.featureForm.featureCreated = !overlayFeatureFormDrawer.featureForm.deleteFeature(); } } } } onCancel: { - coordinateLocator.sourceLocation = undefined - if ( stateMachine.state === 'measure' && elevationProfileButton.elevationProfileActive ) { - informationDrawer.elevationProfile.clear() - informationDrawer.elevationProfile.refresh() + coordinateLocator.sourceLocation = undefined; + if (stateMachine.state === 'measure' && elevationProfileButton.elevationProfileActive) { + informationDrawer.elevationProfile.clear(); + informationDrawer.elevationProfile.refresh(); } else { - if ( geometryRequested ) { - if ( overlayFeatureFormDrawer.isAdding ) { - overlayFeatureFormDrawer.open() + if (geometryRequested) { + if (overlayFeatureFormDrawer.isAdding) { + overlayFeatureFormDrawer.open(); } - geometryRequested = false + geometryRequested = false; } } - if (homeButton.waitingForDigitizingFinish) { - openWelcomeScreen() + openWelcomeScreen(); } } onConfirmed: { - if ( geometryRequested ) - { - if ( overlayFeatureFormDrawer.isAdding ) { - overlayFeatureFormDrawer.open() + if (geometryRequested) { + if (overlayFeatureFormDrawer.isAdding) { + overlayFeatureFormDrawer.open(); } - - coordinateLocator.flash() - digitizingFeature.geometry.applyRubberband() - geometryRequestedItem.requestedGeometryReceived(digitizingFeature.geometry) - digitizingRubberband.model.reset() - geometryRequested = false - coordinateLocator.sourceLocation = undefined + coordinateLocator.flash(); + digitizingFeature.geometry.applyRubberband(); + geometryRequestedItem.requestedGeometryReceived(digitizingFeature.geometry); + digitizingRubberband.model.reset(); + geometryRequested = false; + coordinateLocator.sourceLocation = undefined; return; } - - if (digitizingRubberband.model.geometryType === Qgis.GeometryType.Null) - { - digitizingRubberband.model.reset() - } - else - { - coordinateLocator.flash() - digitizingFeature.geometry.applyRubberband() - digitizingFeature.applyGeometry() - digitizingRubberband.model.frozen = true - digitizingFeature.updateRubberband() - } - - if ( !digitizingFeature.suppressFeatureForm() ) - { - overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry - overlayFeatureFormDrawer.featureModel.applyGeometry() - overlayFeatureFormDrawer.featureModel.resetAttributes() - overlayFeatureFormDrawer.open() - overlayFeatureFormDrawer.state = "Add" + if (digitizingRubberband.model.geometryType === Qgis.GeometryType.Null) { + digitizingRubberband.model.reset(); + } else { + coordinateLocator.flash(); + digitizingFeature.geometry.applyRubberband(); + digitizingFeature.applyGeometry(); + digitizingRubberband.model.frozen = true; + digitizingFeature.updateRubberband(); } - else - { - if ( !overlayFeatureFormDrawer.featureForm.featureCreated ) { - overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry - overlayFeatureFormDrawer.featureModel.applyGeometry() - overlayFeatureFormDrawer.featureModel.resetAttributes() - if ( !overlayFeatureFormDrawer.featureModel.create() ) { - displayToast( qsTr( "Failed to create feature!" ), 'error' ) + if (!digitizingFeature.suppressFeatureForm()) { + overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry; + overlayFeatureFormDrawer.featureModel.applyGeometry(); + overlayFeatureFormDrawer.featureModel.resetAttributes(); + overlayFeatureFormDrawer.open(); + overlayFeatureFormDrawer.state = "Add"; + } else { + if (!overlayFeatureFormDrawer.featureForm.featureCreated) { + overlayFeatureFormDrawer.featureModel.geometry = digitizingFeature.geometry; + overlayFeatureFormDrawer.featureModel.applyGeometry(); + overlayFeatureFormDrawer.featureModel.resetAttributes(); + if (!overlayFeatureFormDrawer.featureModel.create()) { + displayToast(qsTr("Failed to create feature!"), 'error'); } } else { - if ( !overlayFeatureFormDrawer.featureModel.save() ) { - displayToast( qsTr( "Failed to save feature!" ), 'error' ) + if (!overlayFeatureFormDrawer.featureModel.save()) { + displayToast(qsTr("Failed to save feature!"), 'error'); } } - digitizingRubberband.model.reset() + digitizingRubberband.model.reset(); digitizingFeature.resetFeature(); } - coordinateLocator.sourceLocation = undefined + coordinateLocator.sourceLocation = undefined; } } @@ -2178,44 +1989,43 @@ ApplicationWindow { stateVisible: moveFeaturesRequested onConfirm: { - endPoint = GeometryUtils.point(mapCanvas.mapSettings.center.x, mapCanvas.mapSettings.center.y) - moveFeaturesRequested = false - moveConfirmed() + endPoint = GeometryUtils.point(mapCanvas.mapSettings.center.x, mapCanvas.mapSettings.center.y); + moveFeaturesRequested = false; + moveConfirmed(); } onCancel: { - startPoint = undefined - endPoint = undefined - moveFeaturesRequested = false - moveCanceled() + startPoint = undefined; + endPoint = undefined; + moveFeaturesRequested = false; + moveCanceled(); } function initializeMoveFeatures() { - if ( featureForm && featureForm.selection.model.selectedCount === 1 ) { - featureForm.extentController.zoomToSelected() + if (featureForm && featureForm.selection.model.selectedCount === 1) { + featureForm.extentController.zoomToSelected(); } - - startPoint = GeometryUtils.point(mapCanvas.mapSettings.center.x, mapCanvas.mapSettings.center.y) - moveFeaturesRequested = true + startPoint = GeometryUtils.point(mapCanvas.mapSettings.center.x, mapCanvas.mapSettings.center.y); + moveFeaturesRequested = true; } } } } LocatorSettings { - id: locatorSettings - locatorFiltersModel: locatorItem.locatorFiltersModel + id: locatorSettings + locatorFiltersModel: locatorItem.locatorFiltersModel - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - parent: Overlay.overlay + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + parent: Overlay.overlay } PluginManagerSettings { - id: pluginManagerSettings + id: pluginManagerSettings - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - parent: Overlay.overlay + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + parent: Overlay.overlay } DashBoard { @@ -2223,16 +2033,11 @@ ApplicationWindow { objectName: "dashBoard" allowActiveLayerChange: !digitizingToolbar.isDigitizing mapSettings: mapCanvas.mapSettings - interactive: !welcomeScreen.visible - && !qfieldSettings.visible - && !qfieldCloudScreen.visible - && !qfieldLocalDataPickerScreen.visible - && !codeReader.visible - && !screenLocker.enabled + interactive: !welcomeScreen.visible && !qfieldSettings.visible && !qfieldCloudScreen.visible && !qfieldLocalDataPickerScreen.visible && !codeReader.visible && !screenLocker.enabled onOpenedChanged: { - if ( !opened ) { - if ( featureForm.visible ) { + if (!opened) { + if (featureForm.visible) { featureForm.focus = true; } } @@ -2241,38 +2046,21 @@ ApplicationWindow { function ensureEditableLayerSelected() { var firstEditableLayer = null; var activeLayerLocked = false; - for (var i = 0; i < layerTree.rowCount(); i++) - { - var index = layerTree.index(i, 0) - if (firstEditableLayer === null) - { - if ( - layerTree.data(index,FlatLayerTreeModel.Type) === 'layer' - && layerTree.data(index, FlatLayerTreeModel.ReadOnly) === false - && layerTree.data(index, FlatLayerTreeModel.GeometryLocked) === false) - { - firstEditableLayer = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer); + for (var i = 0; i < layerTree.rowCount(); i++) { + var index = layerTree.index(i, 0); + if (firstEditableLayer === null) { + if (layerTree.data(index, FlatLayerTreeModel.Type) === 'layer' && layerTree.data(index, FlatLayerTreeModel.ReadOnly) === false && layerTree.data(index, FlatLayerTreeModel.GeometryLocked) === false) { + firstEditableLayer = layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer); } } - if (activeLayer != null && activeLayer === layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer)) - { - if ( - layerTree.data(index, FlatLayerTreeModel.ReadOnly) === true - || layerTree.data(index, FlatLayerTreeModel.GeometryLocked) === true - ) - { - activeLayerLocked = true; - } - else - { - break; - } + if (activeLayer != null && activeLayer === layerTree.data(index, FlatLayerTreeModel.VectorLayerPointer)) { + if (layerTree.data(index, FlatLayerTreeModel.ReadOnly) === true || layerTree.data(index, FlatLayerTreeModel.GeometryLocked) === true) { + activeLayerLocked = true; + } else { + break; + } } - if ( - firstEditableLayer !== null - && (activeLayer == null || activeLayerLocked === true) - ) - { + if (firstEditableLayer !== null && (activeLayer == null || activeLayerLocked === true)) { activeLayer = firstEditableLayer; break; } @@ -2284,32 +2072,32 @@ ApplicationWindow { id: bookmarkProperties } - function openWelcomeScreen(){ - mainMenu.close() - dashBoard.close() - welcomeScreen.visible = true - welcomeScreen.focus = true - homeButton.waitingForDigitizingFinish = false + function openWelcomeScreen() { + mainMenu.close(); + dashBoard.close(); + welcomeScreen.visible = true; + welcomeScreen.focus = true; + homeButton.waitingForDigitizingFinish = false; } Menu { id: mainMenu - title: qsTr( "Main Menu" ) + title: qsTr("Main Menu") topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - const toolbarWidth = mainMenuActionsToolbar.childrenRect.width + 4 - let result = 50; - let padding = 0; - // Skip first Row item - for (let i = 1; i < count; ++i) { - const item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return Math.max(toolbarWidth, result + padding); + const toolbarWidth = mainMenuActionsToolbar.childrenRect.width + 4; + let result = 50; + let padding = 0; + // Skip first Row item + for (let i = 1; i < count; ++i) { + const item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return Math.max(toolbarWidth, result + padding); } Row { @@ -2329,7 +2117,7 @@ ApplicationWindow { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_home_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_home_black_24dp") iconColor: Theme.mainTextColor bgcolor: hovered ? parent.hoveredColor : "#00ffffff" @@ -2338,10 +2126,10 @@ ApplicationWindow { onClicked: { if (currentRubberband && currentRubberband.model.vertexCount > 1) { digitizingToolbar.cancelDialog.open(); - waitingForDigitizingFinish = true + waitingForDigitizingFinish = true; } else if (!waitingForDigitizingFinish) { - openWelcomeScreen() - highlighted = false + openWelcomeScreen(); + highlighted = false; } } } @@ -2351,15 +2139,15 @@ ApplicationWindow { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_measurement_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_measurement_black_24dp") iconColor: Theme.mainTextColor bgcolor: hovered ? parent.hoveredColor : "#00ffffff" onClicked: { - mainMenu.close() - dashBoard.close() - changeMode( 'measure' ) - highlighted = false + mainMenu.close(); + dashBoard.close(); + changeMode('measure'); + highlighted = false; } } @@ -2368,14 +2156,14 @@ ApplicationWindow { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_lock_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_lock_black_24dp") iconColor: Theme.mainTextColor bgcolor: hovered ? parent.hoveredColor : "#00ffffff" onClicked: { - mainMenu.close() - dashBoard.close() - screenLocker.enabled = true + mainMenu.close(); + dashBoard.close(); + screenLocker.enabled = true; } } @@ -2386,18 +2174,16 @@ ApplicationWindow { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_undo_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_undo_black_24dp") iconColor: isEnabled ? Theme.mainTextColor : Theme.mainTextDisabledColor bgcolor: isEnabled && hovered ? parent.hoveredColor : "#00ffffff" onClicked: { if (isEnabled) { const msg = featureHistory.undoMessage(); - - if ( featureHistory.undo() ) { - displayToast( msg ); + if (featureHistory.undo()) { + displayToast(msg); } - dashBoard.close(); mainMenu.close(); } @@ -2411,18 +2197,16 @@ ApplicationWindow { height: 48 width: 48 round: true - iconSource: Theme.getThemeVectorIcon( "ic_redo_black_24dp" ) + iconSource: Theme.getThemeVectorIcon("ic_redo_black_24dp") iconColor: isEnabled ? Theme.mainTextColor : Theme.mainTextDisabledColor bgcolor: isEnabled && hovered ? parent.hoveredColor : "#00ffffff" onClicked: { if (isEnabled) { const msg = featureHistory.redoMessage(); - - if ( featureHistory.redo() ) { - displayToast( msg ); + if (featureHistory.redo()) { + displayToast(msg); } - dashBoard.close(); mainMenu.close(); } @@ -2430,152 +2214,155 @@ ApplicationWindow { } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { id: printItem - text: qsTr( "Print to PDF" ) + text: qsTr("Print to PDF") font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_print_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_print_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding rightPadding: 40 arrow: Canvas { - x: parent.width - width - y: (parent.height - height) / 2 - implicitWidth: 40 - implicitHeight: 40 - opacity: layoutListInstantiator.count > 1 ? 1 : 0 - onPaint: { - var ctx = getContext("2d") - ctx.strokeStyle = Theme.mainColor - ctx.lineWidth = 1 - ctx.moveTo(15, 15) - ctx.lineTo(width - 15, height / 2) - ctx.lineTo(15, height - 15) - ctx.stroke(); - } + x: parent.width - width + y: (parent.height - height) / 2 + implicitWidth: 40 + implicitHeight: 40 + opacity: layoutListInstantiator.count > 1 ? 1 : 0 + onPaint: { + var ctx = getContext("2d"); + ctx.strokeStyle = Theme.mainColor; + ctx.lineWidth = 1; + ctx.moveTo(15, 15); + ctx.lineTo(width - 15, height / 2); + ctx.lineTo(15, height - 15); + ctx.stroke(); + } } onTriggered: { - if (layoutListInstantiator.count > 1) - { - printMenu.popup( mainMenu.x, mainMenu.y + printItem.y ) - } - else if (layoutListInstantiator.count == 1) - { + if (layoutListInstantiator.count > 1) { + printMenu.popup(mainMenu.x, mainMenu.y + printItem.y); + } else if (layoutListInstantiator.count == 1) { mainMenu.close(); - displayToast( qsTr( 'Printing...') ) - printMenu.printName =layoutListInstantiator.model.titleAt( 0 ); + displayToast(qsTr('Printing...')); + printMenu.printName = layoutListInstantiator.model.titleAt(0); printMenu.printTimer.restart(); - } - else - { + } else { mainMenu.close(); - toast.show(qsTr('No print layout available'), 'info', qsTr('Learn more'), function() { Qt.openUrlExternally('https://docs.qfield.org/how-to/print-to-pdf/') }) + toast.show(qsTr('No print layout available'), 'info', qsTr('Learn more'), function () { + Qt.openUrlExternally('https://docs.qfield.org/how-to/print-to-pdf/'); + }); } - highlighted = false + highlighted = false; } } MenuItem { id: sensorItem - text: qsTr( "Sensors" ) + text: qsTr("Sensors") font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_sensor_on_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_sensor_on_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding rightPadding: 40 arrow: Canvas { - x: parent.width - width - y: (parent.height - height) / 2 - implicitWidth: 40 - implicitHeight: 40 - opacity: sensorListInstantiator.count > 0 ? 1 : 0 - onPaint: { - var ctx = getContext("2d") - ctx.strokeStyle = Theme.mainColor - ctx.lineWidth = 1 - ctx.moveTo(15, 15) - ctx.lineTo(width - 15, height / 2) - ctx.lineTo(15, height - 15) - ctx.stroke(); - } + x: parent.width - width + y: (parent.height - height) / 2 + implicitWidth: 40 + implicitHeight: 40 + opacity: sensorListInstantiator.count > 0 ? 1 : 0 + onPaint: { + var ctx = getContext("2d"); + ctx.strokeStyle = Theme.mainColor; + ctx.lineWidth = 1; + ctx.moveTo(15, 15); + ctx.lineTo(width - 15, height / 2); + ctx.lineTo(15, height - 15); + ctx.stroke(); + } } onTriggered: { if (sensorListInstantiator.count > 0) { - sensorMenu.popup( mainMenu.x, mainMenu.y + sensorItem.y ) + sensorMenu.popup(mainMenu.x, mainMenu.y + sensorItem.y); } else { mainMenu.close(); - toast.show(qsTr('No sensor available'), 'info', qsTr('Learn more'), function() { Qt.openUrlExternally('https://docs.qfield.org/how-to/sensors/') }) + toast.show(qsTr('No sensor available'), 'info', qsTr('Learn more'), function () { + Qt.openUrlExternally('https://docs.qfield.org/how-to/sensors/'); + }); } - highlighted = false + highlighted = false; } } MenuItem { - text: qsTr( "Project Folder" ) + text: qsTr("Project Folder") font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_project_folder_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_project_folder_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding rightPadding: 40 onTriggered: { - dashBoard.close() - qfieldLocalDataPickerScreen.projectFolderView = true - qfieldLocalDataPickerScreen.model.resetToPath(projectInfo.filePath) - qfieldLocalDataPickerScreen.visible = true + dashBoard.close(); + qfieldLocalDataPickerScreen.projectFolderView = true; + qfieldLocalDataPickerScreen.model.resetToPath(projectInfo.filePath); + qfieldLocalDataPickerScreen.visible = true; } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { - text: qsTr( "Settings" ) + text: qsTr("Settings") font: Theme.defaultFont height: 48 leftPadding: Theme.menuItemIconlessLeftPadding onTriggered: { - dashBoard.close() - qfieldSettings.visible = true - highlighted = false + dashBoard.close(); + qfieldSettings.visible = true; + highlighted = false; } } MenuItem { - text: qsTr( "Message Log" ) + text: qsTr("Message Log") font: Theme.defaultFont height: 48 leftPadding: Theme.menuItemIconlessLeftPadding onTriggered: { - dashBoard.close() - messageLog.visible = true - highlighted = false + dashBoard.close(); + messageLog.visible = true; + highlighted = false; } } MenuItem { - text: qsTr( "About QField" ) + text: qsTr("About QField") font: Theme.defaultFont height: 48 leftPadding: Theme.menuItemIconlessLeftPadding onTriggered: { - dashBoard.close() - aboutDialog.visible = true - highlighted = false + dashBoard.close(); + aboutDialog.visible = true; + highlighted = false; } } } @@ -2586,24 +2373,24 @@ ApplicationWindow { property alias printTimer: timer property alias printName: timer.printName - title: qsTr( "Sensors" ) + title: qsTr("Sensors") topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } MenuItem { - text: qsTr( 'Select sensor below' ) + text: qsTr('Select sensor below') font: Theme.defaultFont height: 48 @@ -2618,35 +2405,37 @@ ApplicationWindow { model: SensorListModel { project: qgisProject - onSensorErrorOccurred: (errorString) => { - displayToast(qsTr('Sensor error: %1').arg(errorString), 'error') + onSensorErrorOccurred: errorString => { + displayToast(qsTr('Sensor error: %1').arg(errorString), 'error'); } } MenuItem { text: SensorName - icon.source: SensorStatus == Qgis.DeviceConnectionStatus.Connected - ? Theme.getThemeVectorIcon( "ic_sensor_on_black_24dp" ) - : Theme.getThemeVectorIcon( "ic_sensor_off_black_24dp" ) + icon.source: SensorStatus == Qgis.DeviceConnectionStatus.Connected ? Theme.getThemeVectorIcon("ic_sensor_on_black_24dp") : Theme.getThemeVectorIcon("ic_sensor_off_black_24dp") font: Theme.defaultFont leftPadding: Theme.menuItemLeftPadding onTriggered: { if (SensorStatus == Qgis.DeviceConnectionStatus.Connected) { - displayToast( qsTr( 'Disconnecting sensor \'%1\'...').arg(SensorName) ) - sensorListInstantiator.model.disconnectSensorId(SensorId) - highlighted = false + displayToast(qsTr('Disconnecting sensor \'%1\'...').arg(SensorName)); + sensorListInstantiator.model.disconnectSensorId(SensorId); + highlighted = false; } else { - displayToast( qsTr( 'Connecting sensor \'%1\'...').arg(SensorName) ) - sensorListInstantiator.model.connectSensorId(SensorId) - highlighted = false + displayToast(qsTr('Connecting sensor \'%1\'...').arg(SensorName)); + sensorListInstantiator.model.connectSensorId(SensorId); + highlighted = false; } } } - onObjectAdded: (index, object) => { sensorMenu.insertItem(index+1, object) } - onObjectRemoved: (index, object) => { sensorMenu.removeItem(object) } + onObjectAdded: (index, object) => { + sensorMenu.insertItem(index + 1, object); + } + onObjectRemoved: (index, object) => { + sensorMenu.removeItem(object); + } } } @@ -2656,24 +2445,24 @@ ApplicationWindow { property alias printTimer: timer property alias printName: timer.printName - title: qsTr( "Print" ) + title: qsTr("Print") topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } MenuItem { - text: qsTr( 'Select layout below' ) + text: qsTr('Select layout below') font: Theme.defaultFont height: 48 @@ -2696,14 +2485,18 @@ ApplicationWindow { leftPadding: Theme.menuItemLeftPadding onTriggered: { - highlighted = false - displayToast( qsTr( 'Printing...') ) - printMenu.printName = Title - printMenu.printTimer.restart(); + highlighted = false; + displayToast(qsTr('Printing...')); + printMenu.printName = Title; + printMenu.printTimer.restart(); } } - onObjectAdded: (index, object) => { printMenu.insertItem(index+1, object) } - onObjectRemoved: (index, object) => { printMenu.removeItem(object) } + onObjectAdded: (index, object) => { + printMenu.insertItem(index + 1, object); + } + onObjectRemoved: (index, object) => { + printMenu.removeItem(object); + } } Timer { @@ -2713,7 +2506,7 @@ ApplicationWindow { interval: 500 repeat: false - onTriggered: iface.print( printName ) + onTriggered: iface.print(printName) } } @@ -2721,41 +2514,35 @@ ApplicationWindow { id: canvasMenu objectName: "canvasMenu" - title: qsTr( "Map Canvas Options" ) + title: qsTr("Map Canvas Options") font: Theme.defaultFont property var point onPointChanged: { - var displayPoint = GeometryUtils.reprojectPoint(canvasMenu.point, mapCanvas.mapSettings.destinationCrs, projectInfo.coordinateDisplayCrs) + var displayPoint = GeometryUtils.reprojectPoint(canvasMenu.point, mapCanvas.mapSettings.destinationCrs, projectInfo.coordinateDisplayCrs); var isXY = CoordinateReferenceSystemUtils.defaultCoordinateOrderForCrsIsXY(projectInfo.coordinateDisplayCrs); - var isGeographic = projectInfo.coordinateDisplayCrs.isGeographic - - var xLabel = isGeographic ? qsTr( 'Lon' ) : 'X'; - var xValue = Number( displayPoint.x ).toLocaleString( Qt.locale(), 'f', isGeographic ? 7 : 3 ) - var yLabel = isGeographic ? qsTr( 'Lat' ) : 'Y' - var yValue = Number( displayPoint.y ).toLocaleString( Qt.locale(), 'f', isGeographic ? 7 : 3 ) - const xItemText = isXY - ? xLabel + ': ' + xValue - : yLabel + ': ' + yValue - const yItemText = isXY - ? yLabel + ': ' + yValue - : xLabel + ': ' + xValue - - cordinateItem.text = xItemText + " " + yItemText + var isGeographic = projectInfo.coordinateDisplayCrs.isGeographic; + var xLabel = isGeographic ? qsTr('Lon') : 'X'; + var xValue = Number(displayPoint.x).toLocaleString(Qt.locale(), 'f', isGeographic ? 7 : 3); + var yLabel = isGeographic ? qsTr('Lat') : 'Y'; + var yValue = Number(displayPoint.y).toLocaleString(Qt.locale(), 'f', isGeographic ? 7 : 3); + const xItemText = isXY ? xLabel + ': ' + xValue : yLabel + ': ' + yValue; + const yItemText = isXY ? yLabel + ': ' + yValue : xLabel + ': ' + xValue; + cordinateItem.text = xItemText + " " + yItemText; } topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - const toolbarWidth = canvasMenuActionsToolbar.childrenRect.width + 4 + const toolbarWidth = canvasMenuActionsToolbar.childrenRect.width + 4; let result = 0; let padding = 0; // Skip first Row item for (let i = 1; i < count; ++i) { - const item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.padding, padding); + const item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.padding, padding); } return Math.min(Math.max(toolbarWidth, result + padding * 2), mainWindow.width - 20); } @@ -2772,7 +2559,10 @@ ApplicationWindow { property color hoveredColor: Qt.hsla(Theme.mainTextColor.hslHue, Theme.mainTextColor.hslSaturation, Theme.mainTextColor.hslLightness, 0.2) } - MenuSeparator { width: parent.width; height: canvasMenuActionsToolbar.children.length > 0 ? undefined : 0 } + MenuSeparator { + width: parent.width + height: canvasMenuActionsToolbar.children.length > 0 ? undefined : 0 + } MenuItem { id: cordinateItem @@ -2780,28 +2570,30 @@ ApplicationWindow { height: 48 leftPadding: Theme.menuItemLeftPadding font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_copy_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_copy_black_24dp") onTriggered: { - const displayPoint = GeometryUtils.reprojectPoint(canvasMenu.point, mapCanvas.mapSettings.destinationCrs, projectInfo.coordinateDisplayCrs) - platformUtilities.copyTextToClipboard(StringUtils.pointInformation(displayPoint, projectInfo.coordinateDisplayCrs)) + const displayPoint = GeometryUtils.reprojectPoint(canvasMenu.point, mapCanvas.mapSettings.destinationCrs, projectInfo.coordinateDisplayCrs); + platformUtilities.copyTextToClipboard(StringUtils.pointInformation(displayPoint, projectInfo.coordinateDisplayCrs)); displayToast(qsTr('Coordinates copied to clipboard')); } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { id: addBookmarkItem - text: qsTr( "Add Bookmark" ) - icon.source: Theme.getThemeIcon( "ic_bookmark_black_24dp" ) + text: qsTr("Add Bookmark") + icon.source: Theme.getThemeIcon("ic_bookmark_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding font: Theme.defaultFont onTriggered: { var name = qsTr('Untitled bookmark'); - var group = '' + var group = ''; var id = bookmarkModel.addBookmarkAtPoint(canvasMenu.point, name, group); if (id !== '') { bookmarkProperties.bookmarkId = id; @@ -2814,14 +2606,14 @@ ApplicationWindow { MenuItem { id: setDestinationItem - text: qsTr( "Set as Destination" ) - icon.source: Theme.getThemeIcon( "ic_navigation_flag_purple_24dp" ) + text: qsTr("Set as Destination") + icon.source: Theme.getThemeIcon("ic_navigation_flag_purple_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding font: Theme.defaultFont onTriggered: { - navigation.destination = canvasMenu.point + navigation.destination = canvasMenu.point; } } @@ -2841,18 +2633,20 @@ ApplicationWindow { onTriggered: qfieldSettings.enableMapRotation = checked } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { - text: qsTr( 'Lock Screen' ) + text: qsTr('Lock Screen') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_lock_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_lock_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding onTriggered: { - screenLocker.enabled = true + screenLocker.enabled = true; } } @@ -2883,19 +2677,19 @@ ApplicationWindow { font: Theme.defaultFont width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } Component.onCompleted: { if (featureMenu.icon !== undefined) { - featureMenu.icon.source = Theme.getThemeVectorIcon('ic_info_white_24dp') + featureMenu.icon.source = Theme.getThemeVectorIcon('ic_info_white_24dp'); } } @@ -2907,29 +2701,31 @@ ApplicationWindow { text: qsTr('Feature:') + ' ' + featureName enabled: false } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { text: qsTr('Open Feature Form') font: Theme.defaultFont - icon.source: Theme.getThemeIcon( "ic_baseline-list_alt-24px" ) + icon.source: Theme.getThemeIcon("ic_baseline-list_alt-24px") leftPadding: Theme.menuItemLeftPadding onTriggered: { - featureForm.model.setFeatures(menu.featureLayer, '$id = ' + menu.fid) - featureForm.selection.focusedItem = 0 - featureForm.state = "FeatureForm" + featureForm.model.setFeatures(menu.featureLayer, '$id = ' + menu.fid); + featureForm.selection.focusedItem = 0; + featureForm.state = "FeatureForm"; } } MenuItem { text: qsTr('Copy Feature Attributes') font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_copy_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_copy_black_24dp") leftPadding: Theme.menuItemLeftPadding onTriggered: { - clipboardManager.copyFeatureToClipboard(menu.featureLayer, menu.fid, true) + clipboardManager.copyFeatureToClipboard(menu.featureLayer, menu.fid, true); } } @@ -2937,56 +2733,59 @@ ApplicationWindow { text: qsTr('Duplicate Feature') font: Theme.defaultFont enabled: projectInfo.insertRights - icon.source: Theme.getThemeVectorIcon( "ic_duplicate_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_duplicate_black_24dp") leftPadding: Theme.menuItemLeftPadding onTriggered: { - featureForm.model.setFeatures(menu.featureLayer, '$id = ' + menu.fid) - featureForm.selection.focusedItem = 0 - featureForm.multiSelection = true - featureForm.selection.toggleSelectedItem(0) - featureForm.state = "FeatureList" + featureForm.model.setFeatures(menu.featureLayer, '$id = ' + menu.fid); + featureForm.selection.focusedItem = 0; + featureForm.multiSelection = true; + featureForm.selection.toggleSelectedItem(0); + featureForm.state = "FeatureList"; if (featureForm.model.canDuplicateSelection) { - if (featureForm.selection.model.duplicateFeature(featureForm.selection.focusedLayer,featureForm.selection.focusedFeature)) { - displayToast(qsTr('Successfully duplicated feature')) - - featureForm.selection.focusedItem = -1 - moveFeaturesToolbar.initializeMoveFeatures() + if (featureForm.selection.model.duplicateFeature(featureForm.selection.focusedLayer, featureForm.selection.focusedFeature)) { + displayToast(qsTr('Successfully duplicated feature')); + featureForm.selection.focusedItem = -1; + moveFeaturesToolbar.initializeMoveFeatures(); return; } } - displayToast(qsTr('Feature duplication not available')) + displayToast(qsTr('Feature duplication not available')); } } } - onObjectAdded: (index, object) => { canvasMenu.insertMenu(index + 11, object) } - onObjectRemoved: (index, object) => { canvasMenu.removeMenu(object) } + onObjectAdded: (index, object) => { + canvasMenu.insertMenu(index + 11, object); + } + onObjectRemoved: (index, object) => { + canvasMenu.removeMenu(object); + } } } Menu { id: navigationMenu - title: qsTr( "Navigation Options" ) + title: qsTr("Navigation Options") font: Theme.defaultFont topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } MenuItem { id: preciseViewItem - text: qsTr( "Precise View Settings" ) + text: qsTr("Precise View Settings") font: Theme.defaultFont height: 48 @@ -2994,33 +2793,35 @@ ApplicationWindow { rightPadding: 40 arrow: Canvas { - x: parent.width - width - y: (parent.height - height) / 2 - implicitWidth: 40 - implicitHeight: 40 - visible: true - onPaint: { - var ctx = getContext("2d") - ctx.strokeStyle = Theme.mainColor - ctx.lineWidth = 1 - ctx.moveTo(15, 15) - ctx.lineTo(width - 15, height / 2) - ctx.lineTo(15, height - 15) - ctx.stroke(); - } + x: parent.width - width + y: (parent.height - height) / 2 + implicitWidth: 40 + implicitHeight: 40 + visible: true + onPaint: { + var ctx = getContext("2d"); + ctx.strokeStyle = Theme.mainColor; + ctx.lineWidth = 1; + ctx.moveTo(15, 15); + ctx.lineTo(width - 15, height / 2); + ctx.lineTo(15, height - 15); + ctx.stroke(); + } } onTriggered: { - preciseViewMenu.popup( navigationMenu.x, navigationMenu.y - preciseViewItem.y ) - highlighted = false + preciseViewMenu.popup(navigationMenu.x, navigationMenu.y - preciseViewItem.y); + highlighted = false; } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { id: cancelNavigationItem - text: qsTr( "Clear Destination" ) + text: qsTr("Clear Destination") height: 48 leftPadding: Theme.menuItemLeftPadding font: Theme.defaultFont @@ -3033,25 +2834,25 @@ ApplicationWindow { Menu { id: preciseViewMenu - title: qsTr( "Precise View Settings" ) + title: qsTr("Precise View Settings") font: Theme.defaultFont topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding * 2, mainWindow.width - 20) : result + padding; } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(0.10, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(0.10, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3063,11 +2864,12 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 0.10 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 0.10 } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(0.25, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(0.25, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3079,11 +2881,12 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 0.25 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 0.25 } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(0.5, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(0.5, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3095,11 +2898,12 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 0.5 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 0.5 } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(1, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(1, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3111,11 +2915,12 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 1 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 1 } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(2.5, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(2.5, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3127,11 +2932,12 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 2.5 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 2.5 } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(5, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(5, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3143,11 +2949,12 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 5 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 5 } MenuItem { - text: qsTr( "%1 Precision" ).arg(UnitTypes.formatDistance(10, 2, projectInfo.distanceUnits)) + text: qsTr("%1 Precision").arg(UnitTypes.formatDistance(10, 2, projectInfo.distanceUnits)) height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3159,13 +2966,16 @@ ApplicationWindow { indicator.width: 20 indicator.implicitHeight: 24 indicator.implicitWidth: 24 - onCheckedChanged: if (checked) positioningSettings.preciseViewPrecision = 10 + onCheckedChanged: if (checked) + positioningSettings.preciseViewPrecision = 10 } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { - text: qsTr( "Always Show Precise View" ) + text: qsTr("Always Show Precise View") height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3180,7 +2990,7 @@ ApplicationWindow { } MenuItem { - text: qsTr( "Enable Audio Proximity Feedback" ) + text: qsTr("Enable Audio Proximity Feedback") height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3197,36 +3007,38 @@ ApplicationWindow { Menu { id: gnssMenu - title: qsTr( "Positioning Options" ) + title: qsTr("Positioning Options") font: Theme.defaultFont topMargin: sceneTopMargin bottomMargin: sceneBottomMargin width: { - let result = 50; - let padding = 0; - for (let i = 0; i < count; ++i) { - let item = itemAt(i); - result = Math.max(item.contentItem.implicitWidth, result); - padding = Math.max(item.leftPadding + item.rightPadding, padding); - } - return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; + let result = 50; + let padding = 0; + for (let i = 0; i < count; ++i) { + let item = itemAt(i); + result = Math.max(item.contentItem.implicitWidth, result); + padding = Math.max(item.leftPadding + item.rightPadding, padding); + } + return mainWindow.width > 0 ? Math.min(result + padding, mainWindow.width - 20) : result + padding; } MenuItem { - id: positioningDeviceName - text: positioningSettings.positioningDeviceName - height: 48 - font: Theme.defaultFont - enabled:false + id: positioningDeviceName + text: positioningSettings.positioningDeviceName + height: 48 + font: Theme.defaultFont + enabled: false } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { id: positioningItem - text: qsTr( "Enable Positioning" ) + text: qsTr("Enable Positioning") height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3241,7 +3053,7 @@ ApplicationWindow { } MenuItem { - text: qsTr( "Show Position Information" ) + text: qsTr("Show Position Information") height: 48 leftPadding: Theme.menuItemCheckLeftPadding font: Theme.defaultFont @@ -3256,33 +3068,35 @@ ApplicationWindow { } MenuItem { - text: qsTr( "Positioning Settings" ) + text: qsTr("Positioning Settings") height: 48 leftPadding: Theme.menuItemIconlessLeftPadding font: Theme.defaultFont onTriggered: { - qfieldSettings.currentPanel = 1 - qfieldSettings.visible = true + qfieldSettings.currentPanel = 1; + qfieldSettings.visible = true; } } - MenuSeparator { width: parent.width } + MenuSeparator { + width: parent.width + } MenuItem { - text: qsTr( "Center to Location" ) + text: qsTr("Center to Location") height: 48 leftPadding: Theme.menuItemIconlessLeftPadding font: Theme.defaultFont onTriggered: { - mapCanvas.mapSettings.setCenter(positionSource.projectedPosition, true) + mapCanvas.mapSettings.setCenter(positionSource.projectedPosition, true); } } MenuItem { - text: qsTr( "Add Bookmark at Location" ) - icon.source: Theme.getThemeIcon( "ic_bookmark_black_24dp" ) + text: qsTr("Add Bookmark at Location") + icon.source: Theme.getThemeIcon("ic_bookmark_black_24dp") height: 48 leftPadding: Theme.menuItemLeftPadding font: Theme.defaultFont @@ -3292,10 +3106,9 @@ ApplicationWindow { displayToast(qsTr('Current location unknown')); return; } - var name = qsTr('My location') + ' (' + new Date().toLocaleString() + ')'; var group = 'blue'; - var id = bookmarkModel.addBookmarkAtPoint(positionSource.projectedPosition, name, group) + var id = bookmarkModel.addBookmarkAtPoint(positionSource.projectedPosition, name, group); if (id !== '') { bookmarkProperties.bookmarkId = id; bookmarkProperties.bookmarkName = name; @@ -3306,26 +3119,21 @@ ApplicationWindow { } MenuItem { - text: qsTr( "Copy Location Coordinates" ) + text: qsTr("Copy Location Coordinates") height: 48 leftPadding: Theme.menuItemLeftPadding font: Theme.defaultFont - icon.source: Theme.getThemeVectorIcon( "ic_copy_black_24dp" ) + icon.source: Theme.getThemeVectorIcon("ic_copy_black_24dp") onTriggered: { if (!positioningSettings.positioningActivated || positionSource.positionInformation === undefined || !positionSource.positionInformation.latitudeValid) { displayToast(qsTr('Current location unknown')); return; } - - var point = GeometryUtils.reprojectPoint(positionSource.sourcePosition, CoordinateReferenceSystemUtils.wgs84Crs(), projectInfo.coordinateDisplayCrs) - var coordinates = StringUtils.pointInformation(point, projectInfo.coordinateDisplayCrs) - coordinates += ' ('+ qsTr('Accuracy') + ' ' + - ( positionSource.positionInformation && positionSource.positionInformation.haccValid - ? positionSource.positionInformation.hacc.toLocaleString(Qt.locale(), 'f', 3) + " m" - : qsTr( "N/A" ) ) + ')'; - - platformUtilities.copyTextToClipboard(coordinates) + var point = GeometryUtils.reprojectPoint(positionSource.sourcePosition, CoordinateReferenceSystemUtils.wgs84Crs(), projectInfo.coordinateDisplayCrs); + var coordinates = StringUtils.pointInformation(point, projectInfo.coordinateDisplayCrs); + coordinates += ' (' + qsTr('Accuracy') + ' ' + (positionSource.positionInformation && positionSource.positionInformation.haccValid ? positionSource.positionInformation.hacc.toLocaleString(Qt.locale(), 'f', 3) + " m" : qsTr("N/A")) + ')'; + platformUtilities.copyTextToClipboard(coordinates); displayToast(qsTr('Current location copied to clipboard')); } } @@ -3343,12 +3151,16 @@ ApplicationWindow { focus: visible - anchors { right: parent.right; bottom: parent.bottom } + anchors { + right: parent.right + bottom: parent.bottom + } allowEdit: stateMachine.state === "digitize" allowDelete: stateMachine.state === "digitize" - model: MultiFeatureListModel {} + model: MultiFeatureListModel { + } selection: FeatureListModelSelection { id: featureListModelSelection @@ -3362,29 +3174,24 @@ ApplicationWindow { onEditGeometry: { // Set overall selected (i.e. current) layer to that of the feature geometry being edited, // important for snapping settings to make sense when set to current layer - if ( dashBoard.activeLayer != featureForm.selection.focusedLayer ) { - dashBoard.activeLayer = featureForm.selection.focusedLayer - displayToast( qsTr( "Current layer switched to the one holding the selected geometry." ) ); - } - geometryEditingFeature.vertexModel.geometry = featureForm.selection.focusedGeometry - geometryEditingFeature.vertexModel.crs = featureForm.selection.focusedLayer.crs - geometryEditingFeature.currentLayer = featureForm.selection.focusedLayer - geometryEditingFeature.feature = featureForm.selection.focusedFeature - - if (!geometryEditingVertexModel.editingAllowed) - { - displayToast( qsTr( "Editing of multi geometry layer is not supported yet." ) ) - geometryEditingVertexModel.clear() - } - else - { - featureForm.state = "Hidden" + if (dashBoard.activeLayer != featureForm.selection.focusedLayer) { + dashBoard.activeLayer = featureForm.selection.focusedLayer; + displayToast(qsTr("Current layer switched to the one holding the selected geometry.")); + } + geometryEditingFeature.vertexModel.geometry = featureForm.selection.focusedGeometry; + geometryEditingFeature.vertexModel.crs = featureForm.selection.focusedLayer.crs; + geometryEditingFeature.currentLayer = featureForm.selection.focusedLayer; + geometryEditingFeature.feature = featureForm.selection.focusedFeature; + if (!geometryEditingVertexModel.editingAllowed) { + displayToast(qsTr("Editing of multi geometry layer is not supported yet.")); + geometryEditingVertexModel.clear(); + } else { + featureForm.state = "Hidden"; } - - geometryEditorsToolbar.init() + geometryEditorsToolbar.init(); } - Component.onCompleted: focusstack.addFocusTaker( this ) + Component.onCompleted: focusstack.addFocusTaker(this) //that the focus is set by selecting the empty space MouseArea { @@ -3393,17 +3200,17 @@ ApplicationWindow { enabled: !parent.activeFocus //onPressed because onClicked shall be handled in underlying MouseArea - onPressed: (mouse) => { - parent.focus=true - mouse.accepted=false + onPressed: mouse => { + parent.focus = true; + mouse.accepted = false; } } } QfDropShadow { anchors.fill: featureForm - horizontalOffset: mainWindow.width >= mainWindow.height ? -2: 0 - verticalOffset: mainWindow.width < mainWindow.height ? -2: 0 + horizontalOffset: mainWindow.width >= mainWindow.height ? -2 : 0 + verticalOffset: mainWindow.width < mainWindow.height ? -2 : 0 radius: 6.0 color: "#80000000" source: featureForm @@ -3419,8 +3226,8 @@ ApplicationWindow { function displayToast(message, type, action_text, action_function) { //toastMessage.text = message - if(!welcomeScreen.visible) - toast.show(message, type, action_text, action_function) + if (!welcomeScreen.visible) + toast.show(message, type, action_text, action_function); } Timer { @@ -3438,26 +3245,25 @@ ApplicationWindow { if (stateMachine.state === 'browse' || !mapCanvasMap.isEnabled) { return; } - switch (volumeKeyCode) { - case Qt.Key_VolumeDown: - if (mapCanvasMap.interactive) { - digitizingToolbar.removeVertex(); - } - break; - case Qt.Key_VolumeUp: - if (!geometryEditorsToolbar.canvasClicked(coordinateLocator.currentCoordinate)) { - digitizingToolbar.triggerAddVertex(); - } - break; - default: - break; + case Qt.Key_VolumeDown: + if (mapCanvasMap.interactive) { + digitizingToolbar.removeVertex(); + } + break; + case Qt.Key_VolumeUp: + if (!geometryEditorsToolbar.canvasClicked(coordinateLocator.currentCoordinate)) { + digitizingToolbar.triggerAddVertex(); + } + break; + default: + break; } } function onImportTriggered(name) { - busyOverlay.text = qsTr("Importing %1").arg(name) - busyOverlay.state = "visible" + busyOverlay.text = qsTr("Importing %1").arg(name); + busyOverlay.state = "visible"; } function onImportProgress(progress) { @@ -3465,135 +3271,112 @@ ApplicationWindow { } function onImportEnded(path) { - busyOverlay.state = "hidden" + busyOverlay.state = "hidden"; if (path !== '') { - qfieldLocalDataPickerScreen.model.currentPath = path - qfieldLocalDataPickerScreen.visible = true - welcomeScreen.visible = false + qfieldLocalDataPickerScreen.model.currentPath = path; + qfieldLocalDataPickerScreen.visible = true; + welcomeScreen.visible = false; } else { - displayToast(qsTr('Import URL failed')) + displayToast(qsTr('Import URL failed')); } } - function onLoadProjectTriggered(path,name) { - qfieldLocalDataPickerScreen.visible = false - qfieldLocalDataPickerScreen.focus = false - welcomeScreen.visible = false - welcomeScreen.focus = false - + function onLoadProjectTriggered(path, name) { + qfieldLocalDataPickerScreen.visible = false; + qfieldLocalDataPickerScreen.focus = false; + welcomeScreen.visible = false; + welcomeScreen.focus = false; if (changelogPopup.visible) - changelogPopup.close() - - dashBoard.layerTree.freeze() - mapCanvasMap.freeze('projectload') - - busyOverlay.text = qsTr( "Loading %1" ).arg( name !== '' ? name : path ) - busyOverlay.state = "visible" - - navigation.clearDestinationFeature() - - projectInfo.filePath = '' - readProjectTimer.start() - } - - function onLoadProjectEnded(path,name) { - mapCanvasMap.unfreeze('projectload') - busyOverlay.state = "hidden" - - projectInfo.filePath = path - stateMachine.state = projectInfo.stateMode - platformUtilities.setHandleVolumeKeys(qfieldSettings.digitizingVolumeKeys && stateMachine.state != 'browse') - dashBoard.activeLayer = projectInfo.activeLayer - - drawingTemplateModel.projectFilePath = path - - mapCanvasBackground.color = mapCanvas.mapSettings.backgroundColor - - var titleDecorationConfiguration = projectInfo.getTitleDecorationConfiguration() - titleDecoration.text = titleDecorationConfiguration["text"] - titleDecoration.color = titleDecorationConfiguration["color"] - titleDecoration.style = titleDecorationConfiguration["hasOutline"] === true ? Text.Outline : Text.Normal - titleDecoration.styleColor = titleDecorationConfiguration["outlineColor"] - titleDecorationBackground.color = titleDecorationConfiguration["backgroundColor"] - - var copyrightDecorationConfiguration = projectInfo.getCopyrightDecorationConfiguration() - copyrightDecoration.text = copyrightDecorationConfiguration["text"] - copyrightDecoration.color = copyrightDecorationConfiguration["color"] - copyrightDecoration.style = copyrightDecorationConfiguration["hasOutline"] === true ? Text.Outline : Text.Normal - copyrightDecoration.styleColor = copyrightDecorationConfiguration["outlineColor"] - copyrightDecorationBackground.color = copyrightDecorationConfiguration["backgroundColor"] - - var imageDecorationConfiguration = projectInfo.getImageDecorationConfiguration() - imageDecoration.source = imageDecorationConfiguration["source"] - imageDecoration.fillColor = imageDecorationConfiguration["fillColor"] - imageDecoration.strokeColor = imageDecorationConfiguration["strokeColor"] - - recentProjectListModel.reloadModel() - - const cloudProjectId = QFieldCloudUtils.getProjectId(qgisProject.fileName) - cloudProjectsModel.currentProjectId = cloudProjectId - cloudProjectsModel.refreshProjectModification(cloudProjectId) + changelogPopup.close(); + dashBoard.layerTree.freeze(); + mapCanvasMap.freeze('projectload'); + busyOverlay.text = qsTr("Loading %1").arg(name !== '' ? name : path); + busyOverlay.state = "visible"; + navigation.clearDestinationFeature(); + projectInfo.filePath = ''; + readProjectTimer.start(); + } + + function onLoadProjectEnded(path, name) { + mapCanvasMap.unfreeze('projectload'); + busyOverlay.state = "hidden"; + projectInfo.filePath = path; + stateMachine.state = projectInfo.stateMode; + platformUtilities.setHandleVolumeKeys(qfieldSettings.digitizingVolumeKeys && stateMachine.state != 'browse'); + dashBoard.activeLayer = projectInfo.activeLayer; + drawingTemplateModel.projectFilePath = path; + mapCanvasBackground.color = mapCanvas.mapSettings.backgroundColor; + var titleDecorationConfiguration = projectInfo.getTitleDecorationConfiguration(); + titleDecoration.text = titleDecorationConfiguration["text"]; + titleDecoration.color = titleDecorationConfiguration["color"]; + titleDecoration.style = titleDecorationConfiguration["hasOutline"] === true ? Text.Outline : Text.Normal; + titleDecoration.styleColor = titleDecorationConfiguration["outlineColor"]; + titleDecorationBackground.color = titleDecorationConfiguration["backgroundColor"]; + var copyrightDecorationConfiguration = projectInfo.getCopyrightDecorationConfiguration(); + copyrightDecoration.text = copyrightDecorationConfiguration["text"]; + copyrightDecoration.color = copyrightDecorationConfiguration["color"]; + copyrightDecoration.style = copyrightDecorationConfiguration["hasOutline"] === true ? Text.Outline : Text.Normal; + copyrightDecoration.styleColor = copyrightDecorationConfiguration["outlineColor"]; + copyrightDecorationBackground.color = copyrightDecorationConfiguration["backgroundColor"]; + var imageDecorationConfiguration = projectInfo.getImageDecorationConfiguration(); + imageDecoration.source = imageDecorationConfiguration["source"]; + imageDecoration.fillColor = imageDecorationConfiguration["fillColor"]; + imageDecoration.strokeColor = imageDecorationConfiguration["strokeColor"]; + recentProjectListModel.reloadModel(); + const cloudProjectId = QFieldCloudUtils.getProjectId(qgisProject.fileName); + cloudProjectsModel.currentProjectId = cloudProjectId; + cloudProjectsModel.refreshProjectModification(cloudProjectId); if (cloudProjectId !== '') { - var cloudProjectData = cloudProjectsModel.getProjectData(cloudProjectId) - switch(cloudProjectData.UserRole) { - case 'reader': - stateMachine.state = "browse" - projectInfo.hasInsertRights = false - projectInfo.hasEditRights = false - break; - case 'reporter': - projectInfo.hasInsertRights = true - projectInfo.hasEditRights = false - break; - case 'editor': - case 'manager': - case 'admin': - projectInfo.hasInsertRights = true - projectInfo.hasEditRights = true - break; - default: - projectInfo.hasInsertRights = true - projectInfo.hasEditRights = true - break; + var cloudProjectData = cloudProjectsModel.getProjectData(cloudProjectId); + switch (cloudProjectData.UserRole) { + case 'reader': + stateMachine.state = "browse"; + projectInfo.hasInsertRights = false; + projectInfo.hasEditRights = false; + break; + case 'reporter': + projectInfo.hasInsertRights = true; + projectInfo.hasEditRights = false; + break; + case 'editor': + case 'manager': + case 'admin': + projectInfo.hasInsertRights = true; + projectInfo.hasEditRights = true; + break; + default: + projectInfo.hasInsertRights = true; + projectInfo.hasEditRights = true; + break; } - if (cloudProjectsModel.layerObserver.deltaFileWrapper.hasError()) { - qfieldCloudPopup.show() + qfieldCloudPopup.show(); } - if (cloudConnection.status === QFieldCloudConnection.LoggedIn) { - cloudProjectsModel.refreshProjectFileOutdatedStatus(cloudProjectId) + cloudProjectsModel.refreshProjectFileOutdatedStatus(cloudProjectId); } } else { - projectInfo.hasInsertRights = true - projectInfo.hasEditRights = true + projectInfo.hasInsertRights = true; + projectInfo.hasEditRights = true; } - if (stateMachine.state === "digitize") { - dashBoard.ensureEditableLayerSelected(); + dashBoard.ensureEditableLayerSelected(); } - - var distanceString = iface.readProjectEntry("Measurement" ,"/DistanceUnits", "") - projectInfo.distanceUnits = distanceString !== "" ? UnitTypes.decodeDistanceUnit(distanceString) : Qgis.DistanceUnit.Meters - var areaString = iface.readProjectEntry("Measurement" ,"/AreaUnits", "") - projectInfo.areaUnits = areaString !== "" ? UnitTypes.decodeAreaUnit(areaString) : Qgis.AreaUnit.SquareMeters - + var distanceString = iface.readProjectEntry("Measurement", "/DistanceUnits", ""); + projectInfo.distanceUnits = distanceString !== "" ? UnitTypes.decodeDistanceUnit(distanceString) : Qgis.DistanceUnit.Meters; + var areaString = iface.readProjectEntry("Measurement", "/AreaUnits", ""); + projectInfo.areaUnits = areaString !== "" ? UnitTypes.decodeAreaUnit(areaString) : Qgis.AreaUnit.SquareMeters; if (qgisProject.displaySettings) { - projectInfo.coordinateDisplayCrs = qgisProject.displaySettings.coordinateCrs + projectInfo.coordinateDisplayCrs = qgisProject.displaySettings.coordinateCrs; } else { - projectInfo.coordinateDisplayCrs = !mapCanvas.mapSettings.destinationCrs.isGeographic - && iface.readProjectEntry("PositionPrecision", "/DegreeFormat", "MU") !== "MU" - ? CoordinateReferenceSystemUtils.wgs84Crs() - : mapCanvas.mapSettings.destinationCrs + projectInfo.coordinateDisplayCrs = !mapCanvas.mapSettings.destinationCrs.isGeographic && iface.readProjectEntry("PositionPrecision", "/DegreeFormat", "MU") !== "MU" ? CoordinateReferenceSystemUtils.wgs84Crs() : mapCanvas.mapSettings.destinationCrs; } - - layoutListInstantiator.model.reloadModel() - - geofencer.applyProjectSettings(qgisProject) + layoutListInstantiator.model.reloadModel(); + geofencer.applyProjectSettings(qgisProject); } function onSetMapExtent(extent) { - mapCanvas.mapSettings.extent = extent; + mapCanvas.mapSettings.extent = extent; } } @@ -3627,19 +3410,19 @@ ApplicationWindow { model: messageLogModel onFinished: { - visible = false + visible = false; } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true - visible = false + event.accepted = true; + visible = false; } } Component.onCompleted: { - focusstack.addFocusTaker( this ) - unreadMessages = messageLogModel.rowCount() !== 0 + focusstack.addFocusTaker(this); + unreadMessages = messageLogModel.rowCount() !== 0; } } @@ -3654,15 +3437,22 @@ ApplicationWindow { Connections { target: iface function onLoadProjectTriggered(path) { - messageLogModel.suppress({"WFS": [""], "WMS": [""], "PostGIS": ["fe_sendauth: no password supplied"]}) + messageLogModel.suppress({ + "WFS": [""], + "WMS": [""], + "PostGIS": ["fe_sendauth: no password supplied"] + }); } function onLoadProjectEnded() { - dashBoard.layerTree.unfreeze( true ); - if( !qfieldAuthRequestHandler.handleLayerLogins() ) - { + dashBoard.layerTree.unfreeze(true); + if (!qfieldAuthRequestHandler.handleLayerLogins()) { //project loaded without more layer handling needed - messageLogModel.unsuppress({"WFS": [], "WMS": [], "PostGIS": []}) + messageLogModel.unsuppress({ + "WFS": [], + "WMS": [], + "PostGIS": [] + }); } } } @@ -3671,25 +3461,25 @@ ApplicationWindow { target: qfieldAuthRequestHandler function onShowLoginDialog(realm, title) { - loginDialog.realm = realm || "" - loginDialog.credentialTitle = title - badLayersView.visible = false - loginDialogPopup.open() + loginDialog.realm = realm || ""; + loginDialog.credentialTitle = title; + badLayersView.visible = false; + loginDialogPopup.open(); } function onReloadEverything() { - iface.reloadProject() + iface.reloadProject(); } function onShowLoginBrowser(url) { - browserPopup.url = url; - browserPopup.fullscreen = false; - browserPopup.clearCookiesOnOpen = true - browserPopup.open(); + browserPopup.url = url; + browserPopup.fullscreen = false; + browserPopup.clearCookiesOnOpen = true; + browserPopup.open(); } function onHideLoginBrowser() { - browserPopup.close(); + browserPopup.close(); } } @@ -3727,24 +3517,23 @@ ApplicationWindow { property string realm: "" - onEnter: ( username, password ) => { - qfieldAuthRequestHandler.enterCredentials( loginDialog.realm, username, password) + onEnter: (username, password) => { + qfieldAuthRequestHandler.enterCredentials(loginDialog.realm, username, password); inCancelation = false; - loginDialogPopup.close() + loginDialogPopup.close(); } onCancel: { inCancelation = true; - loginDialogPopup.close() + loginDialogPopup.close(); } } onClosed: { // handled here with parameter inCancelation because the loginDialog needs to be closed before the signal is fired - qfieldAuthRequestHandler.loginDialogClosed(loginDialog.realm, loginDialog.inCancelation ) + qfieldAuthRequestHandler.loginDialogClosed(loginDialog.realm, loginDialog.inCancelation); } } - } About { @@ -3754,14 +3543,14 @@ ApplicationWindow { visible: false - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true - visible = false + event.accepted = true; + visible = false; } } - Component.onCompleted: focusstack.addFocusTaker( this ) + Component.onCompleted: focusstack.addFocusTaker(this) } TrackerSettings { @@ -3776,17 +3565,17 @@ ApplicationWindow { focus: visible onFinished: { - visible = false + visible = false; } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - event.accepted = true - finished() + event.accepted = true; + finished(); } } - Component.onCompleted: focusstack.addFocusTaker( this ) + Component.onCompleted: focusstack.addFocusTaker(this) } QFieldCloudConnection { @@ -3796,22 +3585,23 @@ ApplicationWindow { onStatusChanged: { if (cloudConnection.status === QFieldCloudConnection.Disconnected && previousStatus === QFieldCloudConnection.LoggedIn) { - displayToast(qsTr('Signed out')) + displayToast(qsTr('Signed out')); } else if (cloudConnection.status === QFieldCloudConnection.Connecting) { - displayToast(qsTr('Connecting...')) + displayToast(qsTr('Connecting...')); } else if (cloudConnection.status === QFieldCloudConnection.LoggedIn) { - displayToast(qsTr('Signed in')) + displayToast(qsTr('Signed in')); // Go ahead and upload pending attachments in the background platformUtilities.uploadPendingAttachments(cloudConnection); - - var cloudProjectId = QFieldCloudUtils.getProjectId(qgisProject.fileName) + var cloudProjectId = QFieldCloudUtils.getProjectId(qgisProject.fileName); if (cloudProjectId) { - cloudProjectsModel.refreshProjectFileOutdatedStatus(cloudProjectId) + cloudProjectsModel.refreshProjectFileOutdatedStatus(cloudProjectId); } } - previousStatus = cloudConnection.status + previousStatus = cloudConnection.status; + } + onLoginFailed: function (reason) { + displayToast(reason); } - onLoginFailed: function(reason) { displayToast( reason ) } } QFieldCloudProjectsModel { @@ -3820,37 +3610,34 @@ ApplicationWindow { layerObserver: layerObserverAlias gpkgFlusher: gpkgFlusherAlias - onProjectDownloaded: function ( projectId, projectName, hasError, errorString ) { - return hasError - ? displayToast( qsTr( "Project %1 failed to download" ).arg( projectName ), 'error' ) - : displayToast( qsTr( "Project %1 successfully downloaded, it's now available to open" ).arg( projectName ) ); + onProjectDownloaded: function (projectId, projectName, hasError, errorString) { + return hasError ? displayToast(qsTr("Project %1 failed to download").arg(projectName), 'error') : displayToast(qsTr("Project %1 successfully downloaded, it's now available to open").arg(projectName)); } - onPushFinished: function ( projectId, hasError, errorString ) { - if ( hasError ) { - displayToast( qsTr( "Changes failed to reach QFieldCloud: %1" ).arg( errorString ), 'error' ) + onPushFinished: function (projectId, hasError, errorString) { + if (hasError) { + displayToast(qsTr("Changes failed to reach QFieldCloud: %1").arg(errorString), 'error'); return; } - - displayToast( qsTr( "Changes successfully pushed to QFieldCloud" ) ) + displayToast(qsTr("Changes successfully pushed to QFieldCloud")); // Go ahead and upload pending attachments in the background platformUtilities.uploadPendingAttachments(cloudConnection); } - onWarning: displayToast( message ) + onWarning: displayToast(message) onDeltaListModelChanged: function () { - qfieldCloudDeltaHistory.model = cloudProjectsModel.currentProjectData.DeltaList + qfieldCloudDeltaHistory.model = cloudProjectsModel.currentProjectData.DeltaList; } } QFieldCloudDeltaHistory { - id: qfieldCloudDeltaHistory + id: qfieldCloudDeltaHistory - modal: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - parent: Overlay.overlay + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + parent: Overlay.overlay } QFieldCloudScreen { @@ -3861,11 +3648,11 @@ ApplicationWindow { focus: visible onFinished: { - visible = false - welcomeScreen.visible = true + visible = false; + welcomeScreen.visible = true; } - Component.onCompleted: focusstack.addFocusTaker( this ) + Component.onCompleted: focusstack.addFocusTaker(this) } QFieldCloudPopup { @@ -3895,13 +3682,13 @@ ApplicationWindow { focus: visible onFinished: { - visible = false + visible = false; if (model.currentPath === 'root') { - welcomeScreen.visible = loading ? false : true + welcomeScreen.visible = loading ? false : true; } } - Component.onCompleted: focusstack.addFocusTaker( this ) + Component.onCompleted: focusstack.addFocusTaker(this) } WelcomeScreen { @@ -3919,35 +3706,35 @@ ApplicationWindow { onOpenLocalDataPicker: { if (platformUtilities.capabilities & PlatformUtilities.CustomLocalDataPicker) { - welcomeScreen.visible = false - qfieldLocalDataPickerScreen.projectFolderView = false - qfieldLocalDataPickerScreen.model.resetToRoot() - qfieldLocalDataPickerScreen.visible = true + welcomeScreen.visible = false; + qfieldLocalDataPickerScreen.projectFolderView = false; + qfieldLocalDataPickerScreen.model.resetToRoot(); + qfieldLocalDataPickerScreen.visible = true; } else { - __projectSource = platformUtilities.openProject(this) + __projectSource = platformUtilities.openProject(this); } } onShowQFieldCloudScreen: { - welcomeScreen.visible = false - qfieldCloudScreen.visible = true + welcomeScreen.visible = false; + qfieldCloudScreen.visible = true; } - Keys.onReleased: (event) => { + Keys.onReleased: event => { if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) { - if ( qgisProject.fileName != '') { - event.accepted = true - visible = false - focus = false + if (qgisProject.fileName != '') { + event.accepted = true; + visible = false; + focus = false; } else { - event.accepted = false - mainWindow.close() + event.accepted = false; + mainWindow.close(); } } } Component.onCompleted: { - focusstack.addFocusTaker( this ) + focusstack.addFocusTaker(this); } } @@ -3957,8 +3744,8 @@ ApplicationWindow { parent: Overlay.overlay - property var expireDate: new Date(2038,1,19) - visible: settings && settings.value( "/QField/ChangelogVersion", "" ) !== appVersion && expireDate > new Date() + property var expireDate: new Date(2038, 1, 19) + visible: settings && settings.value("/QField/ChangelogVersion", "") !== appVersion && expireDate > new Date() } Toast { @@ -3970,7 +3757,7 @@ ApplicationWindow { anchors.fill: parent enabled: codeReader.visible - onClicked: (mouse) => { + onClicked: mouse => { // Needed to avoid people interacting with the UI while the barcode reader is visible // (e.g. close the feature form while scanning a code to fill an attribute) return; @@ -3993,7 +3780,7 @@ ApplicationWindow { function onSearchTermChanged(searchTerm) { var lowered = searchTerm.toLowerCase(); - if ( lowered === 'hello nyuki') { + if (lowered === 'hello nyuki') { Qt.inputMethod.hide(); locatorItem.searchTermHandled = true; nyuki.state = "shown"; @@ -4017,17 +3804,16 @@ ApplicationWindow { DropArea { id: dropArea anchors.fill: parent - onEntered: (drag) => { - if ( drag.urls.length !== 1 || !iface.isFileExtensionSupported( drag.urls[0] ) ) { - drag.accepted = false - } - else { - drag.accept (Qt.CopyAction) - drag.accepted = true + onEntered: drag => { + if (drag.urls.length !== 1 || !iface.isFileExtensionSupported(drag.urls[0])) { + drag.accepted = false; + } else { + drag.accept(Qt.CopyAction); + drag.accepted = true; } } - onDropped: (drop) => { - iface.loadFile( drop.urls[0] ) + onDropped: drop => { + iface.loadFile(drop.urls[0]); } } @@ -4038,20 +3824,19 @@ ApplicationWindow { property bool alreadyCloseRequested: false - onClosing: (close) => { + onClosing: close => { if (screenLocker.enabled) { - close.accepted = false - displayToast(qsTr("Unlock the screen to to close project and app")) - return + close.accepted = false; + displayToast(qsTr("Unlock the screen to to close project and app")); + return; } - if (!alreadyCloseRequested) { - close.accepted = false - alreadyCloseRequested = true - displayToast(qsTr("Press back again to close project and app")) - closingTimer.start() + close.accepted = false; + alreadyCloseRequested = true; + displayToast(qsTr("Press back again to close project and app")); + closingTimer.start(); } else { - close.accepted = true + close.accepted = true; } } @@ -4059,7 +3844,7 @@ ApplicationWindow { id: closingTimer interval: 2000 onTriggered: { - alreadyCloseRequested = false + alreadyCloseRequested = false; } } @@ -4067,7 +3852,7 @@ ApplicationWindow { target: welcomeScreen.__projectSource function onProjectOpened(path) { - iface.loadFile(path) + iface.loadFile(path); } } @@ -4103,8 +3888,8 @@ ApplicationWindow { font: Theme.defaultFont z: 10000 // 1000s are embedded feature forms, user a higher value to insure the dialog will always show above embedded feature forms - x: ( mainWindow.width - width ) / 2 - y: ( mainWindow.height - height ) / 2 + x: (mainWindow.width - width) / 2 + y: (mainWindow.height - height) / 2 property alias permanent: permanentCheckBox.checked @@ -4114,7 +3899,7 @@ ApplicationWindow { Label { width: parent.width wrapMode: Text.WordWrap - text: qsTr( "Do you grant permission to activate `%1`?" ).arg( pluginPermissionDialog.title ) + text: qsTr("Do you grant permission to activate `%1`?").arg(pluginPermissionDialog.title) } CheckBox { @@ -4125,13 +3910,13 @@ ApplicationWindow { } onAccepted: { - pluginManager.grantRequestedPluginPermission(permanent) - permanent = false + pluginManager.grantRequestedPluginPermission(permanent); + permanent = false; } onRejected: { - pluginManager.denyRequestedPluginPermission(permanent) - permanent = false + pluginManager.denyRequestedPluginPermission(permanent); + permanent = false; } standardButtons: Dialog.Yes | Dialog.No @@ -4141,8 +3926,8 @@ ApplicationWindow { target: pluginManager function onPluginPermissionRequested(pluginName) { - pluginPermissionDialog.title = pluginName - pluginPermissionDialog.open() + pluginPermissionDialog.title = pluginName; + pluginPermissionDialog.open(); } } } diff --git a/test/qml/tst_editorwidgets.qml b/test/qml/tst_editorwidgets.qml index ca1f08da1a..77798f2c5d 100644 --- a/test/qml/tst_editorwidgets.qml +++ b/test/qml/tst_editorwidgets.qml @@ -1,9 +1,7 @@ import QtQuick 2.3 import QtTest 1.0 - import org.qfield 1.0 import Theme 1.0 - import "../../src/qml/editorwidgets" as EditorWidgets TestCase { @@ -52,7 +50,7 @@ TestCase { Item { id: currentLayerTrue function customProperty(value) { - return 100 + return 100; } } @@ -60,19 +58,18 @@ TestCase { Item { id: currentLayerFalse function customProperty(value) { - return 0 + return 0; } } } - EditorWidgets.UuidGenerator{ + EditorWidgets.UuidGenerator { id: uuidGenerator property var value: undefined property var config: undefined property bool isAdding: false } - /** * Test case for textEdit widget * @@ -81,33 +78,28 @@ TestCase { * setting its value to "seven", and comparing its children's texts with "six" and "seven". */ function test_01_textEdit() { - const textReadonlyValue = textEdit.children[0] - const textField = textEdit.children[1] - const textArea = textEdit.children[2] - - compare(textReadonlyValue.text, "") // NOTE: If the config is undefined, the label will be an empty string. - compare(textField.text, "DEFAULT_VALUE") - compare(textArea.text, "DEFAULT_VALUE") - + const textReadonlyValue = textEdit.children[0]; + const textField = textEdit.children[1]; + const textArea = textEdit.children[2]; + compare(textReadonlyValue.text, ""); // NOTE: If the config is undefined, the label will be an empty string. + compare(textField.text, "DEFAULT_VALUE"); + compare(textArea.text, "DEFAULT_VALUE"); textEdit.config = { "IsMultiline": true, "UseHtml": true - } - textEdit.value = "SECOND_VALUE" - - verify(textReadonlyValue.text.search("SECOND_VALUE") !== -1) - compare(textField.text, "SECOND_VALUE") - verify(textArea.text.search("SECOND_VALUE") !== -1) - + }; + textEdit.value = "SECOND_VALUE"; + verify(textReadonlyValue.text.search("SECOND_VALUE") !== -1); + compare(textField.text, "SECOND_VALUE"); + verify(textArea.text.search("SECOND_VALUE") !== -1); textEdit.config = { "IsMultiline": false, "UseHtml": false - } - textEdit.value = "THIRD_VALUE" - - compare(textReadonlyValue.text, "SECOND_VALUE") // NOTE: If the values in the config are set to `false`, the label text will not change. - compare(textField.text, "THIRD_VALUE") - compare(textArea.text, "THIRD_VALUE") + }; + textEdit.value = "THIRD_VALUE"; + compare(textReadonlyValue.text, "SECOND_VALUE"); // NOTE: If the values in the config are set to `false`, the label text will not change. + compare(textField.text, "THIRD_VALUE"); + compare(textArea.text, "THIRD_VALUE"); } /** @@ -128,13 +120,11 @@ TestCase { * Finally, setting the value of the range and verifying that it is displayed correctly in both text and slider formats. */ function test_01_range() { - const sliderRow = range.children[0] - const textField = sliderRow.children[0] - const valueLabel = range.children[1].children[0] - const slider = range.children[1].children[1] - - compare(textField.text, range.default_value + "") - + const sliderRow = range.children[0]; + const textField = sliderRow.children[0]; + const valueLabel = range.children[1].children[0]; + const slider = range.children[1].children[1]; + compare(textField.text, range.default_value + ""); range.config = { "Style": undefined, "Precision": undefined, @@ -142,20 +132,18 @@ TestCase { "Max": undefined, "Step": undefined, "Suffix": undefined - } - range.value = 3 - compare(range.widgetStyle, "TextField") - compare(range.precision, 1) - compare(range.min, -Infinity) - compare(range.max, Infinity) - compare(range.step, 1) - compare(range.suffix, "") + }; + range.value = 3; + compare(range.widgetStyle, "TextField"); + compare(range.precision, 1); + compare(range.min, -Infinity); + compare(range.max, Infinity); + compare(range.step, 1); + compare(range.suffix, ""); // Row // compare(sliderRow.visible, true) // ERROR ? should work but not working! - - compare(textField.text, "3") - + compare(textField.text, "3"); range.config = { "Style": "Slider", "Precision": 2, @@ -163,18 +151,17 @@ TestCase { "Max": 10, "Step": 10, "Suffix": "DEFAULT_SUFFIX" - } - range.value = 4 - compare(range.widgetStyle, "Slider") - compare(range.precision, 2) - compare(range.min, -10) - compare(range.max, 10) - compare(range.step, 10) - compare(range.suffix, "DEFAULT_SUFFIX") - - compare(sliderRow.visible, false) - compare(valueLabel.text, range.min + ".00DEFAULT_SUFFIX") // NOTE: using `range.min` because of `rangeItem.parent.value` - compare(slider.value, range.min) // NOTE: using `range.min` because of `rangeItem.parent.value` + }; + range.value = 4; + compare(range.widgetStyle, "Slider"); + compare(range.precision, 2); + compare(range.min, -10); + compare(range.max, 10); + compare(range.step, 10); + compare(range.suffix, "DEFAULT_SUFFIX"); + compare(sliderRow.visible, false); + compare(valueLabel.text, range.min + ".00DEFAULT_SUFFIX"); // NOTE: using `range.min` because of `rangeItem.parent.value` + compare(slider.value, range.min); // NOTE: using `range.min` because of `rangeItem.parent.value` } /** @@ -193,16 +180,12 @@ TestCase { * TODO: Test `fieldIsDate = true` too, if the field is a date only -> revert the time zone offset. */ function test_01_dateTime() { - const label = dateTime.children[1].children[0] - - compare(label.text, "") // NOTE: setting value without setting `config` and `field` objects won't work - - const testTimes = ["2023-01-01", "2023-01-01 23:33:56"] - const displayFormats = ["yyyy-MM-dd", "yyyy-MM.dd", "yyyy-MM-dd HH:mm:ss", "HH:mm:ss", "HH:mm"] - const results = ["2023-01-01", "2023-01.01", "2023-01-01 00:00:00", "00:00:00", "00:00", - "2023-01-01", "2023-01.01", "2023-01-01 23:33:56", "23:33:56", "23:33"] - let resultIdx = 0 - + const label = dateTime.children[1].children[0]; + compare(label.text, ""); // NOTE: setting value without setting `config` and `field` objects won't work + const testTimes = ["2023-01-01", "2023-01-01 23:33:56"]; + const displayFormats = ["yyyy-MM-dd", "yyyy-MM.dd", "yyyy-MM-dd HH:mm:ss", "HH:mm:ss", "HH:mm"]; + const results = ["2023-01-01", "2023-01.01", "2023-01-01 00:00:00", "00:00:00", "00:00", "2023-01-01", "2023-01.01", "2023-01-01 23:33:56", "23:33:56", "23:33"]; + let resultIdx = 0; for (let time of testTimes) { for (let format of displayFormats) { dateTime.fieldIsDate = false; @@ -211,13 +194,12 @@ TestCase { "calendar_popup": true, "field_format": "UNKNOWN!", "allow_null": false - } + }; dateTime.field = { "isDateOrTime": true - } - - dateTime.value = time - compare(label.text, results[resultIdx++]) + }; + dateTime.value = time; + compare(label.text, results[resultIdx++]); } } } @@ -241,72 +223,63 @@ TestCase { * - Sets `type` of the field to 0 and verifies that the display is different */ function test_01_checkBox() { - const labelItem = checkBox.children[0] - const checkBoxItem = checkBox.children[1] - - compare(checkBox.value, true) - compare(checkBox.isBool, false) - compare(checkBox.isNull, false) - compare(checkBox.checkedLabel, "") // NOTE: `checkedLabel` initialized with "" when config is undefined - compare(checkBox.uncheckedLabel, "") // NOTE: `uncheckedLabel` initialized with "" when config is undefined - - compare(labelItem.text, "") - compare(checkBoxItem.checked, false) // NOTE: even if `value` be true, without config `checked` will be false - + const labelItem = checkBox.children[0]; + const checkBoxItem = checkBox.children[1]; + compare(checkBox.value, true); + compare(checkBox.isBool, false); + compare(checkBox.isNull, false); + compare(checkBox.checkedLabel, ""); // NOTE: `checkedLabel` initialized with "" when config is undefined + compare(checkBox.uncheckedLabel, ""); // NOTE: `uncheckedLabel` initialized with "" when config is undefined + compare(labelItem.text, ""); + compare(checkBoxItem.checked, false); // NOTE: even if `value` be true, without config `checked` will be false checkBox.config = { "TextDisplayMethod": 1, "CheckedState": "DEFAULT_CHECKED_STATE", "UncheckedState": "DEFAULT_UNCHECKED_STATE" - } + }; checkBox.field = { "type": 1 - } - checkBox.value = true - compare(checkBox.value, true) - compare(checkBox.isBool, true) - compare(checkBox.isNull, false) - compare(checkBox.checkedLabel, "DEFAULT_CHECKED_STATE") - compare(checkBox.uncheckedLabel, "DEFAULT_UNCHECKED_STATE") - - compare(labelItem.text, "DEFAULT_CHECKED_STATE") - compare(checkBoxItem.checked, true) - - checkBox.value = false - - compare(labelItem.text, "DEFAULT_UNCHECKED_STATE") - compare(checkBoxItem.checked, false) + }; + checkBox.value = true; + compare(checkBox.value, true); + compare(checkBox.isBool, true); + compare(checkBox.isNull, false); + compare(checkBox.checkedLabel, "DEFAULT_CHECKED_STATE"); + compare(checkBox.uncheckedLabel, "DEFAULT_UNCHECKED_STATE"); + compare(labelItem.text, "DEFAULT_CHECKED_STATE"); + compare(checkBoxItem.checked, true); + checkBox.value = false; + compare(labelItem.text, "DEFAULT_UNCHECKED_STATE"); + compare(checkBoxItem.checked, false); // test TextDisplayMethod = 0 checkBox.config = { "TextDisplayMethod": 0, "CheckedState": "DEFAULT_CHECKED_STATE", "UncheckedState": "DEFAULT_UNCHECKED_STATE" - } + }; checkBox.field = { "type": 1 - } - checkBox.value = true - compare(checkBox.checkedLabel, "True") - compare(checkBox.uncheckedLabel, "False") + }; + checkBox.value = true; + compare(checkBox.checkedLabel, "True"); + compare(checkBox.uncheckedLabel, "False"); // test field type = 0 checkBox.config = { "TextDisplayMethod": 1, "CheckedState": "DEFAULT_CHECKED_STATE", "UncheckedState": "DEFAULT_UNCHECKED_STATE" - } + }; checkBox.field = { "type": 0 - } - checkBox.value = true - - compare(labelItem.text, "DEFAULT_UNCHECKED_STATE") // NOTE: value is true but it in unchecked state - compare(checkBoxItem.checked, false) // NOTE: value is true but its not checked - - checkBox.value = false - - compare(labelItem.text, "DEFAULT_UNCHECKED_STATE") - compare(checkBoxItem.checked, false) + }; + checkBox.value = true; + compare(labelItem.text, "DEFAULT_UNCHECKED_STATE"); // NOTE: value is true but it in unchecked state + compare(checkBoxItem.checked, false); // NOTE: value is true but its not checked + checkBox.value = false; + compare(labelItem.text, "DEFAULT_UNCHECKED_STATE"); + compare(checkBoxItem.checked, false); } /** @@ -322,15 +295,13 @@ TestCase { * TODO: needs more checks on search and changing selected item in combobox or toggleButtons */ function test_01_valueMap() { - const toggleButtonsItem = valueMap.children[0].children[0] - const comboBoxItem = valueMap.children[0].children[1] - - compare(valueMap.toggleButtonsThreshold, 0) - compare(valueMap.state, "comboBoxItemView") - compare(valueMap.currentItemCount, 0) - compare(comboBoxItem.model.length, undefined) - compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex) - + const toggleButtonsItem = valueMap.children[0].children[0]; + const comboBoxItem = valueMap.children[0].children[1]; + compare(valueMap.toggleButtonsThreshold, 0); + compare(valueMap.state, "comboBoxItemView"); + compare(valueMap.currentItemCount, 0); + compare(comboBoxItem.model.length, undefined); + compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex); valueMap.config = { "map": [{ "Buckfast bee": "Apis Mellifera" @@ -339,21 +310,19 @@ TestCase { }, { "European honey bee": "Apis Mellifera Mellifera" }] - } - - valueMap.currentLayer = currentLayerTrue - valueMap.value = "Apis Mellifera" - compare(valueMap.state, "toggleButtonsView") - compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex) - compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex) - compare(valueMap.currentKeyValue, "Apis Mellifera") - - valueMap.currentLayer = currentLayerFalse - valueMap.value = "Apis Mellifera Carnica" - compare(valueMap.state, "comboBoxItemView") - compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex) - compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex) - compare(valueMap.currentKeyValue, "Apis Mellifera Carnica") + }; + valueMap.currentLayer = currentLayerTrue; + valueMap.value = "Apis Mellifera"; + compare(valueMap.state, "toggleButtonsView"); + compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex); + compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex); + compare(valueMap.currentKeyValue, "Apis Mellifera"); + valueMap.currentLayer = currentLayerFalse; + valueMap.value = "Apis Mellifera Carnica"; + compare(valueMap.state, "comboBoxItemView"); + compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex); + compare(comboBoxItem.currentIndex, toggleButtonsItem.selectedIndex); + compare(valueMap.currentKeyValue, "Apis Mellifera Carnica"); } /** @@ -369,16 +338,14 @@ TestCase { * - The generateUUID function */ function test_01_UuidGenerator() { - const label = uuidGenerator.children[0] + const label = uuidGenerator.children[0]; compare(label.text, ""); compare(uuidGenerator.isLoaded, false); - - uuidGenerator.value = "ANY_VALUE" + uuidGenerator.value = "ANY_VALUE"; compare(label.text, "ANY_VALUE"); - - uuidGenerator.isAdding = true - uuidGenerator.isLoaded = true - uuidGenerator.value = "" + uuidGenerator.isAdding = true; + uuidGenerator.isLoaded = true; + uuidGenerator.value = ""; // NOTE: with isAdding && isLoaded && empty value, label should be StringUtils.createUuid() // but because `StringUtils` is not defined it should remain as its previous value compare(label.text, "ANY_VALUE"); diff --git a/test/qml/tst_positioning.qml b/test/qml/tst_positioning.qml index 8121be9b86..f775bd3bbb 100644 --- a/test/qml/tst_positioning.qml +++ b/test/qml/tst_positioning.qml @@ -1,118 +1,113 @@ import QtQuick 2.3 import QtTest 1.0 - import org.qfield 1.0 TestCase { - name: "Positioning" - - Positioning { - id: positioning - deviceId: 'udp:localhost:1958' - active: true - elevationCorrectionMode: Positioning.ElevationCorrectionMode.None - - coordinateTransformer: CoordinateTransformer { - id: coordinateTransformer - destinationCrs: CoordinateReferenceSystemUtils.wgs84Crs() - transformContext: CoordinateReferenceSystemUtils.emptyTransformContext() - deltaZ: 0 - skipAltitudeTransformation: false - verticalGrid: '' - } - } - - function test_01_ellipsoidalElevation() { - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None - coordinateTransformer.deltaZ = 0 - coordinateTransformer.verticalGrid = '' - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - - // the elevation in the NMEA stream goes between 320 to 322, and the ellispodal adjustment is -26.0 meters - // we therefore simply check whether we are int the 200s value range, which indicates ellispodal elevation is - // being returned - compare(Math.floor(positioning.positionInformation.elevation / 100), 2) - } - - function test_02_orthometricElevation() { - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.OrthometricFromDevice - coordinateTransformer.deltaZ = 0 - coordinateTransformer.verticalGrid = '' - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - // the orthmoetric elevation in the NMEA stream goes between 320 to 322, - // we therefore simply check whether we are int the 300s value range, which indicates orthographic elevation is - // being returned - compare(Math.floor(positioning.positionInformation.elevation / 100), 3) - } - - function test_03_deltaZ() { - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None - coordinateTransformer.deltaZ = -100 - coordinateTransformer.verticalGrid = '' - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - // the elevation in the NMEA stream's range is in the 290s - // we therefore simply check whether we are in the 100s value range, which indicates - // the delta Z value has been applied - compare(Math.floor(positioning.projectedPosition.z / 100), 1) - } - - function test_04_verticalGrid() { - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile - coordinateTransformer.deltaZ = 0 - coordinateTransformer.verticalGrid = dataDir + '/testgrid.tif' - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - // the elevation in the NMEA stream's range is in the 290s - // we therefore simply check whether we have a negative value to see - // if the grid value (~300) has been applied - compare(Math.floor(positioning.projectedPosition.z / 100), -1) - } - - function test_05_tcpReceiver() { - positioning.deviceId = 'tcp:localhost:11111' - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None - coordinateTransformer.deltaZ = 0 - coordinateTransformer.verticalGrid = '' - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - compare(Math.floor(positioning.positionInformation.latitude), 46) - compare(Math.floor(positioning.positionInformation.longitude), 9) - compare(Math.floor(positioning.positionInformation.elevation / 10), 110 ) - compare(Math.floor(positioning.positionInformation.hacc), 2) - compare(Math.floor(positioning.positionInformation.vacc), 4) - } - - function test_06_happyIMU() { - positioning.deviceId = 'udp:localhost:1959' - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None - coordinateTransformer.deltaZ = 0 - coordinateTransformer.verticalGrid = '' - - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - compare(positioning.positionInformation.qualityDescription, "Float RTK + IMU") - compare(positioning.positionInformation.imuCorrection, true) - } - - function test_07_happyMonch2IMU() { - positioning.deviceId = 'udp:localhost:1960' - positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None - coordinateTransformer.deltaZ = 0 - coordinateTransformer.verticalGrid = '' - - // wait a few seconds so positioning can catch some NMEA strings - wait(2500) - - compare(positioning.positionInformation.qualityDescription, "Fixed RTK + IMU") - compare(positioning.positionInformation.imuCorrection, true) + name: "Positioning" + + Positioning { + id: positioning + deviceId: 'udp:localhost:1958' + active: true + elevationCorrectionMode: Positioning.ElevationCorrectionMode.None + + coordinateTransformer: CoordinateTransformer { + id: coordinateTransformer + destinationCrs: CoordinateReferenceSystemUtils.wgs84Crs() + transformContext: CoordinateReferenceSystemUtils.emptyTransformContext() + deltaZ: 0 + skipAltitudeTransformation: false + verticalGrid: '' } + } + + function test_01_ellipsoidalElevation() { + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None; + coordinateTransformer.deltaZ = 0; + coordinateTransformer.verticalGrid = ''; + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + + // the elevation in the NMEA stream goes between 320 to 322, and the ellispodal adjustment is -26.0 meters + // we therefore simply check whether we are int the 200s value range, which indicates ellispodal elevation is + // being returned + compare(Math.floor(positioning.positionInformation.elevation / 100), 2); + } + + function test_02_orthometricElevation() { + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.OrthometricFromDevice; + coordinateTransformer.deltaZ = 0; + coordinateTransformer.verticalGrid = ''; + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + + // the orthmoetric elevation in the NMEA stream goes between 320 to 322, + // we therefore simply check whether we are int the 300s value range, which indicates orthographic elevation is + // being returned + compare(Math.floor(positioning.positionInformation.elevation / 100), 3); + } + + function test_03_deltaZ() { + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None; + coordinateTransformer.deltaZ = -100; + coordinateTransformer.verticalGrid = ''; + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + + // the elevation in the NMEA stream's range is in the 290s + // we therefore simply check whether we are in the 100s value range, which indicates + // the delta Z value has been applied + compare(Math.floor(positioning.projectedPosition.z / 100), 1); + } + + function test_04_verticalGrid() { + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.OrthometricFromGeoidFile; + coordinateTransformer.deltaZ = 0; + coordinateTransformer.verticalGrid = dataDir + '/testgrid.tif'; + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + + // the elevation in the NMEA stream's range is in the 290s + // we therefore simply check whether we have a negative value to see + // if the grid value (~300) has been applied + compare(Math.floor(positioning.projectedPosition.z / 100), -1); + } + + function test_05_tcpReceiver() { + positioning.deviceId = 'tcp:localhost:11111'; + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None; + coordinateTransformer.deltaZ = 0; + coordinateTransformer.verticalGrid = ''; + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + compare(Math.floor(positioning.positionInformation.latitude), 46); + compare(Math.floor(positioning.positionInformation.longitude), 9); + compare(Math.floor(positioning.positionInformation.elevation / 10), 110); + compare(Math.floor(positioning.positionInformation.hacc), 2); + compare(Math.floor(positioning.positionInformation.vacc), 4); + } + + function test_06_happyIMU() { + positioning.deviceId = 'udp:localhost:1959'; + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None; + coordinateTransformer.deltaZ = 0; + coordinateTransformer.verticalGrid = ''; + + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + compare(positioning.positionInformation.qualityDescription, "Float RTK + IMU"); + compare(positioning.positionInformation.imuCorrection, true); + } + + function test_07_happyMonch2IMU() { + positioning.deviceId = 'udp:localhost:1960'; + positioning.elevationCorrectionMode = Positioning.ElevationCorrectionMode.None; + coordinateTransformer.deltaZ = 0; + coordinateTransformer.verticalGrid = ''; + + // wait a few seconds so positioning can catch some NMEA strings + wait(2500); + compare(positioning.positionInformation.qualityDescription, "Fixed RTK + IMU"); + compare(positioning.positionInformation.imuCorrection, true); + } }