Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ Input_keystore.keystore
CMakeLists.txt.user
.github/secrets/ios/LutraConsulting*.mobileprovision
google_play_key.json
fastlane/report.xml
fastlane/report.xml
CMakeUserPresets.json
2 changes: 2 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ set(MM_SRCS
streamingintervaltype.cpp
synchronizationerror.cpp
synchronizationmanager.cpp
valuerelationcontroller.cpp
valuerelationfeaturesmodel.cpp
variablesmanager.cpp
workspacesmodel.cpp
Expand Down Expand Up @@ -189,6 +190,7 @@ set(MM_HDRS
synchronizationerror.h
synchronizationmanager.h
synchronizationoptions.h
valuerelationcontroller.h
valuerelationfeaturesmodel.h
variablesmanager.h
workspacesmodel.h
Expand Down
3 changes: 2 additions & 1 deletion app/layerfeaturesmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class LayerFeaturesModel : public FeaturesModel

virtual void setupFeatureRequest( QgsFeatureRequest &request );

virtual QString buildSearchExpression();

virtual void populate();
void reset() override;

Expand All @@ -104,7 +106,6 @@ class LayerFeaturesModel : public FeaturesModel
void onFutureFinished();

private:
QString buildSearchExpression();

//! Performs getFeatures on layer. Takes ownership of \a layer and tries to move it to current thread.
QgsFeatureList fetchFeatures( QgsVectorLayerFeatureSource *layer, QgsFeatureRequest req, int searchId );
Expand Down
2 changes: 2 additions & 0 deletions app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
#include "relationreferencefeaturesmodel.h"
#include "fieldvalidator.h"
#include "valuerelationfeaturesmodel.h"
#include "valuerelationcontroller.h"
#include "snaputils.h"
#include "guidelinecontroller.h"
#include "multieditmanager.h"
Expand Down Expand Up @@ -332,6 +333,7 @@ void initDeclarative()
qmlRegisterType< LayerFeaturesModel >( "mm", 1, 0, "LayerFeaturesModel" );
qmlRegisterType< RelationFeaturesModel >( "mm", 1, 0, "RelationFeaturesModel" );
qmlRegisterType< ValueRelationFeaturesModel >( "mm", 1, 0, "ValueRelationFeaturesModel" );
qmlRegisterType< ValueRelationController >( "mm", 1, 0, "ValueRelationController" );
qmlRegisterType< RelationReferenceFeaturesModel >( "mm", 1, 0, "RelationReferenceFeaturesModel" );
qmlRegisterType< BluetoothDiscoveryModel >( "mm", 1, 0, "BluetoothDiscoveryModel" );
qmlRegisterType< PositionTrackingManager >( "mm", 1, 0, "PositionTrackingManager" );
Expand Down
1 change: 1 addition & 0 deletions app/qml/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ set(MM_QML
filters/components/MMFilterDropdownValueMapInput.qml
filters/components/MMFilterDropdownValueRelationInput.qml
filters/components/MMFilterDropdownUniqueValuesInput.qml
filters/components/MMFilterNoValueDelegate.qml
filters/components/MMFilterRangeInput.qml
filters/components/MMFilterTextInput.qml
filters/components/MMFilterBaseInput.qml
Expand Down
6 changes: 4 additions & 2 deletions app/qml/components/MMButton.qml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ Button {

implicitWidth: {
let margin = __style.margin20
if ( root.size === MMButton.Sizes.ExtraSmall ) margin = __style.margin8
if ( root.type === MMButton.Types.Tertiary ) margin = 0
else if ( root.size === MMButton.Sizes.ExtraSmall ) margin = __style.margin8
else if ( root.size === MMButton.Sizes.Small ) margin = __style.margin16
return row.paintedChildrenWidth + 2 * margin
}
Expand Down Expand Up @@ -214,7 +215,8 @@ Button {
property real paintedChildrenWidth: buttonIconLeft.paintedWidth + buttonContent.implicitWidth + buttonIconRight.paintedWidth + spacing
property real maxWidth: {
let margin = __style.margin20
if ( root.size === MMButton.Sizes.ExtraSmall ) margin = __style.margin8
if ( root.type === MMButton.Types.Tertiary ) margin = 0
else if ( root.size === MMButton.Sizes.ExtraSmall ) margin = __style.margin8
else if ( root.size === MMButton.Sizes.Small ) margin = __style.margin16
return parent.width - 2 * margin
}
Expand Down
11 changes: 9 additions & 2 deletions app/qml/components/MMDrawerHeader.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import QtQuick.Layouts

import "."

//! Best to use MMDrawerHeader as the header component for the MMPage object
//! Best to use MMDrawerHeader as the header component for the MMDrawer object

Rectangle {
id: root
Expand All @@ -25,6 +25,8 @@ Rectangle {

property alias closeButton: closeBtn
property alias topLeftItemContent: topLeftButtonGroup.children
property alias topLeftItem: topLeftButtonGroup
property alias titleComponent: headerTitleText

color: __style.transparentColor

Expand All @@ -36,11 +38,16 @@ Rectangle {
Item {
id: topLeftButtonGroup

x: __style.pageMargins + __style.safeAreaLeft
y: root.height / 2 - height / 2

width: childrenRect.width
height: parent.height
height: childrenRect.height
}

Text {
id: headerTitleText

property real leftMarginShift: {
return Math.max( internal.closeBtnRealWidth, topLeftButtonGroup.width ) + internal.headerSpacing + __style.pageMargins
}
Expand Down
23 changes: 18 additions & 5 deletions app/qml/components/MMListMultiselectDrawer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ MMDrawer {

property bool withSearch: true
property bool multiSelect: false
property bool isLoading: false
property var selected: [] // in/out property, contains a list of (pre-)selected item values

property bool showFullScreen: false
Expand All @@ -33,7 +34,7 @@ MMDrawer {

interactive: !listViewComponent.interactive

drawerBottomMargin: listViewComponent.count === 0
drawerBottomMargin: listViewComponent.count === 0 && !listViewComponent.headerItem
? ( __style.margin20 + __style.safeAreaBottom )
: 0

Expand Down Expand Up @@ -71,12 +72,17 @@ MMDrawer {

Item {
width: parent.width
height: listViewComponent.count === 0 ? emptyStateDelegateLoader.height : listViewComponent.height
height: {
if ( listViewComponent.count > 0 ) return listViewComponent.height
if ( listViewComponent.headerItem ) return listViewComponent.height + emptyStateDelegateLoader.height
return emptyStateDelegateLoader.height
}

Loader {
id: emptyStateDelegateLoader

width: parent.width
y: listViewComponent.headerItem && listViewComponent.count === 0 ? listViewComponent.height : 0

visible: listViewComponent.count === 0
sourceComponent: defaultEmptyStateComponent
Expand All @@ -88,7 +94,7 @@ MMDrawer {
width: parent.width
height: Math.min( contentHeight, root.drawerContentAvailableHeight - internal.searchBarVerticalSpace )

visible: count > 0
visible: count > 0 || headerItem !== null
interactive: contentHeight > height

clip: true
Expand Down Expand Up @@ -133,7 +139,7 @@ MMDrawer {
bottomMargin: __style.margin8 + __style.safeAreaBottom
}

visible: root.multiSelect && listViewComponent.count > 0
visible: root.multiSelect && ( listViewComponent.count > 0 || listViewComponent.headerItem !== null )

text: qsTr( "Confirm selection" )

Expand All @@ -150,7 +156,9 @@ MMDrawer {
Component {
id: defaultEmptyStateComponent

MMListEmptyLoaderDelegate {}
MMListEmptyLoaderDelegate {
isLoading: root.isLoading
}
}

// QDate/QDateTime values get parsed to JS Date objects in QML, and they do strict comparison by default, which also
Expand All @@ -173,4 +181,9 @@ MMDrawer {
root.selected = root.selected.filter( x => !isEqualDate( x, value ) )
}
}

function focusSearchBar() {
root.showFullScreen = true
searchBar.textField.forceActiveFocus()
}
}
6 changes: 0 additions & 6 deletions app/qml/filters/MMFiltersDrawer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,6 @@ MMComponents.MMDrawer {
bgndColorHover: __style.grapeColor
fontColorHover: __style.negativeLightColor

anchors {
left: parent.left
leftMargin: __style.pageMargins + __style.safeAreaLeft
verticalCenter: parent.verticalCenter
}

onClicked: {
internal.filterValues = {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,10 @@ Column {
sourceComponent: MMComponents.MMListMultiselectDrawer {
drawerHeader.title: root.filterName

withSearch: uniqueValuesModel.count > 5
withSearch: uniqueValuesModel.count > 8
multiSelect: root.isMultiSelect

emptyStateDelegate: Component {
MMComponents.MMListEmptyLoaderDelegate {
isLoading: uniqueValuesModel.isLoading
}
}
isLoading: uniqueValuesModel.isLoading

list.model: MM.SearchProxyModel {
id: searchProxyModel
Expand Down
8 changes: 2 additions & 6 deletions app/qml/filters/components/MMFilterDropdownValueMapInput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,10 @@ Column {
sourceComponent: MMComponents.MMListMultiselectDrawer {
drawerHeader.title: root.filterName

withSearch: valueMapModel.count > 5
withSearch: valueMapModel.count > 8
multiSelect: root.isMultiSelect

emptyStateDelegate: Component {
MMComponents.MMListEmptyLoaderDelegate {
isLoading: valueMapModel.isLoading
}
}
isLoading: valueMapModel.isLoading

list.model: MM.SearchProxyModel {
id: searchProxyModel
Expand Down
50 changes: 41 additions & 9 deletions app/qml/filters/components/MMFilterDropdownValueRelationInput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* *
***************************************************************************/

pragma ComponentBehavior: Bound

import QtQuick

import mm 1.0 as MM
Expand Down Expand Up @@ -65,35 +67,65 @@ Column {

active: false


sourceComponent: MMComponents.MMListMultiselectDrawer {
id: listDrawer

drawerHeader.title: root.filterName

withSearch: vrDropdownModel.count > 5
withSearch: vrDropdownModel.count > 8
multiSelect: root.isMultiSelect

emptyStateDelegate: Component {
MMComponents.MMListEmptyLoaderDelegate {
isLoading: vrDropdownModel.fetchingResults
isLoading: vrDropdownModel.fetchingResults

list.header: MMFilterNoValueDelegate {
width: listDrawer.list.width
currentValue: root.currentValue
isMultiSelect: root.isMultiSelect

onAddOrRemoveRequested: listDrawer.addOrRemoveSelected( null )
onSelectionRequested: {
listDrawer.selectionFinished( [null] )
listDrawer.close()
}
}

list.model: MM.ValueRelationFeaturesModel {
id: vrDropdownModel

config: root.widgetConfig

property bool firstFetchFinished: false

// We show search for lists with more then 8 features.
// We need to intentionally break the binding here because "count" changes
// when users search for something and that would hide the search bar
onFetchingResultsChanged: {
if ( !fetchingResults && !firstFetchFinished )
{
if ( count > 8 )
{
listDrawer.withSearch = true
}
else
{
listDrawer.withSearch = false
}

firstFetchFinished = true
}
}
}

textRole: "FeatureTitle"
valueRole: "Key"
textRole: "ValueColumn"
valueRole: "KeyColumn"

onSelectionFinished: function( selectedItems ) {

//
// Large fids could be converted to scientific notation on their way to cpp,
// so we convert them to string first in JS.
// Null values (representing "No value") are preserved as-is.
//
selectedItems = selectedItems.map( x => x.toString() )
selectedItems = selectedItems.map( x => x !== null && x !== undefined ? x.toString() : null )

root.currentValue = selectedItems

Expand Down
45 changes: 45 additions & 0 deletions app/qml/filters/components/MMFilterNoValueDelegate.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

import QtQuick
import "../../components" as MMComponents

//
// Header delegate for filter drawers that adds a "No value" option,
// letting users filter features where the field has no value set.
//

MMComponents.MMListDelegate {
id: root

required property var currentValue
required property bool isMultiSelect

signal addOrRemoveRequested()
signal selectionRequested()

property bool checked: root.currentValue ? root.currentValue.some( v => v === null ) : false

text: qsTr( "No value" )

rightContent: MMComponents.MMIcon {
source: __style.doneCircleIcon
visible: root.checked
}

onClicked: {
if ( root.isMultiSelect ) {
root.checked = !root.checked
root.addOrRemoveRequested()
}
else {
root.selectionRequested()
}
}
}
Loading
Loading