diff --git a/app/filtercontroller.cpp b/app/filtercontroller.cpp index 237991341..da1907d94 100644 --- a/app/filtercontroller.cpp +++ b/app/filtercontroller.cpp @@ -359,7 +359,7 @@ QString FilterController::buildFieldExpression( const FieldFilter &filter ) cons // Match all positions: only value {k}, first {k,...}, last ...,k}, middle ...,k,... keyConditions << QStringLiteral( "(%1 LIKE '{%2}' OR %1 LIKE '{%2,%%' OR %1 LIKE '%%,%2}' OR %1 LIKE '%%,%2,%%')" ) - .arg( quotedField, escapedKey ); + .arg( quotedField, escapedKey ); } return keyConditions.join( QStringLiteral( " OR " ) ); } @@ -726,7 +726,7 @@ QVariantList FilterController::extractValueRelationOptions( const QVariantMap &c QString escapedSearch = searchText; escapedSearch.replace( "'", "''" ); QString filterExpr = QStringLiteral( "LOWER(%1) LIKE '%%2%'" ) - .arg( QgsExpression::quotedColumnRef( valueFieldName ), escapedSearch.toLower() ); + .arg( QgsExpression::quotedColumnRef( valueFieldName ), escapedSearch.toLower() ); request.setFilterExpression( filterExpr ); } @@ -785,8 +785,8 @@ QVariantList FilterController::extractValueRelationOptions( const QVariantMap &c selectedRequest.setFlags( Qgis::FeatureRequestFlag::NoGeometry ); selectedRequest.setSubsetOfAttributes( QStringList( { keyFieldName, valueFieldName } ), referencedLayer->fields() ); selectedRequest.setFilterExpression( - QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( keyFieldName ), quotedKeys.join( QStringLiteral( ", " ) ) ) - ); + QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( keyFieldName ), quotedKeys.join( QStringLiteral( ", " ) ) ) + ); QVariantList selectedItems; QgsFeatureIterator selIt = referencedLayer->getFeatures( selectedRequest ); @@ -856,8 +856,8 @@ QStringList FilterController::lookupValueRelationTexts( const QVariantMap &confi request.setFlags( Qgis::FeatureRequestFlag::NoGeometry ); request.setSubsetOfAttributes( QStringList( { keyFieldName, valueFieldName } ), referencedLayer->fields() ); request.setFilterExpression( - QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( keyFieldName ), quotedKeys.join( QStringLiteral( ", " ) ) ) - ); + QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( keyFieldName ), quotedKeys.join( QStringLiteral( ", " ) ) ) + ); QgsFeatureIterator it = referencedLayer->getFeatures( request ); QgsFeature feature; diff --git a/app/icons/Filter.svg b/app/icons/Filter.svg index d62e7cf66..f9b351a07 100644 --- a/app/icons/Filter.svg +++ b/app/icons/Filter.svg @@ -1,3 +1,3 @@ - + diff --git a/app/icons/FilterFilled.svg b/app/icons/FilterFilled.svg deleted file mode 100644 index 03a60d659..000000000 --- a/app/icons/FilterFilled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/icons.qrc b/app/icons/icons.qrc index ce46904c9..656d4b479 100644 --- a/app/icons/icons.qrc +++ b/app/icons/icons.qrc @@ -28,7 +28,6 @@ Features.svg FeaturesFilled.svg Filter.svg - FilterFilled.svg GPSAntennaHeight.svg GPSIcon.svg GPSSatellite.svg diff --git a/app/mmstyle.h b/app/mmstyle.h index f7d896d36..aa2207657 100644 --- a/app/mmstyle.h +++ b/app/mmstyle.h @@ -128,7 +128,6 @@ class MMStyle: public QObject Q_PROPERTY( QUrl facebookIcon READ facebookIcon CONSTANT ) Q_PROPERTY( QUrl featuresIcon READ featuresIcon CONSTANT ) Q_PROPERTY( QUrl filterIcon READ filterIcon CONSTANT ) - Q_PROPERTY( QUrl filterFilledIcon READ filterFilledIcon CONSTANT ) Q_PROPERTY( QUrl globeIcon READ globeIcon CONSTANT ) Q_PROPERTY( QUrl globalIcon READ globalIcon CONSTANT ) Q_PROPERTY( QUrl gpsIcon READ gpsIcon CONSTANT ) @@ -433,7 +432,6 @@ class MMStyle: public QObject QUrl deleteIcon() const {return QUrl( "qrc:/Delete.svg" );} QUrl featuresIcon() const {return QUrl( "qrc:/Features.svg" );} QUrl filterIcon() const {return QUrl( "qrc:/Filter.svg" );} - QUrl filterFilledIcon() const {return QUrl( "qrc:/FilterFilled.svg" );} QUrl downloadIcon() const {return QUrl( "qrc:/Download.svg" );} QUrl uploadIcon() const {return QUrl( "qrc:/Upload.svg" );} QUrl editIcon() const {return QUrl( "qrc:/Edit.svg" );} diff --git a/app/qml/filters/MMFilterLayerSection.qml b/app/qml/filters/MMFilterLayerSection.qml index b1c948aab..297739079 100644 --- a/app/qml/filters/MMFilterLayerSection.qml +++ b/app/qml/filters/MMFilterLayerSection.qml @@ -50,14 +50,14 @@ Column { Repeater { id: fieldsRepeater - model: root.vectorLayer ? root.filterController.getFilterableFields(root.vectorLayer) : [] + model: root.vectorLayer ? root.filterController.getFilterableFields( root.vectorLayer ) : [] delegate: Column { id: fieldDelegate property var fieldInfo: modelData property string fieldName: fieldInfo ? fieldInfo.name : "" - property string fieldDisplayName: fieldInfo ? (fieldInfo.displayName || fieldInfo.name) : "" + property string fieldDisplayName: fieldInfo ? ( fieldInfo.displayName || fieldInfo.name ) : "" property string filterType: fieldInfo ? fieldInfo.filterType : "text" property var currentValue: fieldInfo ? fieldInfo.currentValue : null property var currentValueTo: fieldInfo ? fieldInfo.currentValueTo : null @@ -85,39 +85,39 @@ Column { spacing: __style.margin12 property bool rangeInvalid: { - let fromVal = parseFloat(fromNumberInput.text) - let toVal = parseFloat(toNumberInput.text) - return !isNaN(fromVal) && !isNaN(toVal) && fromVal > toVal + let fromVal = parseFloat( fromNumberInput.text ) + let toVal = parseFloat( toNumberInput.text ) + return !isNaN( fromVal ) && !isNaN( toVal ) && fromVal > toVal } MMTextInput { id: fromNumberInput - width: (parent.width - __style.margin12) / 2 - placeholderText: qsTr("From") - text: fieldDelegate.currentValue !== null && fieldDelegate.currentValue !== undefined ? String(fieldDelegate.currentValue) : "" - errorMsg: parent.rangeInvalid ? qsTr("\"From\" must be less than \"To\"") : "" + width: ( parent.width - __style.margin12 ) / 2 + placeholderText: qsTr( "From" ) + text: fieldDelegate.currentValue !== null && fieldDelegate.currentValue !== undefined ? String( fieldDelegate.currentValue ) : "" + errorMsg: parent.rangeInvalid ? qsTr( "\"From\" must be less than \"To\"" ) : "" property bool initialized: false Component.onCompleted: initialized = true onTextChanged: { - if (!initialized || !toNumberInput.initialized) return - root.filterController.setNumberFilter(root.layerId, fieldDelegate.fieldName, text, toNumberInput.text) + if ( !initialized || !toNumberInput.initialized ) return + root.filterController.setNumberFilter( root.layerId, fieldDelegate.fieldName, text, toNumberInput.text ) } } MMTextInput { id: toNumberInput - width: (parent.width - __style.margin12) / 2 - placeholderText: qsTr("To") - text: fieldDelegate.currentValueTo !== null && fieldDelegate.currentValueTo !== undefined ? String(fieldDelegate.currentValueTo) : "" + width: ( parent.width - __style.margin12 ) / 2 + placeholderText: qsTr( "To" ) + text: fieldDelegate.currentValueTo !== null && fieldDelegate.currentValueTo !== undefined ? String( fieldDelegate.currentValueTo ) : "" property bool initialized: false Component.onCompleted: initialized = true onTextChanged: { - if (!initialized || !fromNumberInput.initialized) return - root.filterController.setNumberFilter(root.layerId, fieldDelegate.fieldName, fromNumberInput.text, text) + if ( !initialized || !fromNumberInput.initialized ) return + root.filterController.setNumberFilter( root.layerId, fieldDelegate.fieldName, fromNumberInput.text, text ) } } } @@ -141,12 +141,12 @@ Column { spacing: __style.margin12 property bool rangeInvalid: { - if (!fromDateInput.selectedDate || !toDateInput.selectedDate) return false + if ( !fromDateInput.selectedDate || !toDateInput.selectedDate ) return false return fromDateInput.selectedDate > toDateInput.selectedDate } Item { - width: (parent.width - __style.margin12) / 2 + width: ( parent.width - __style.margin12 ) / 2 height: fromDateInput.height MMPrivateComponents.MMBaseSingleLineInput { @@ -157,20 +157,20 @@ Column { Component.onCompleted: { let val = fieldDelegate.currentValue - if (val !== null && val !== undefined) { - let d = new Date(val) - if (!isNaN(d.getTime())) selectedDate = d + if ( val !== null && val !== undefined ) { + let d = new Date( val ) + if ( !isNaN( d.getTime() ) ) selectedDate = d } } - placeholderText: qsTr("From") + placeholderText: qsTr( "From" ) text: { - if (!selectedDate) return "" - if (fieldDelegate.hasTime) return Qt.formatDateTime(selectedDate, Qt.DefaultLocaleShortDate) - return Qt.formatDate(selectedDate, Qt.DefaultLocaleShortDate) + if ( !selectedDate ) return "" + if ( fieldDelegate.hasTime ) return Qt.formatDateTime( selectedDate, Qt.DefaultLocaleShortDate ) + return Qt.formatDate( selectedDate, Qt.DefaultLocaleShortDate ) } textField.readOnly: true - errorMsg: dateRangeRow.rangeInvalid ? qsTr("\"From\" must be less than \"To\"") : "" + errorMsg: dateRangeRow.rangeInvalid ? qsTr( "\"From\" must be less than \"To\"" ) : "" rightContent: MMIcon { size: __style.icon24 @@ -180,10 +180,10 @@ Column { onTextClicked: fromCalendarLoader.active = true onRightContentClicked: { - if (fromDateInput.selectedDate) { + if ( fromDateInput.selectedDate ) { fromDateInput.selectedDate = null let toDate = toDateInput.selectedDate ? toDateInput.selectedDate : null - root.filterController.setDateFilter(root.layerId, fieldDelegate.fieldName, null, toDate, fieldDelegate.hasTime) + root.filterController.setDateFilter( root.layerId, fieldDelegate.fieldName, null, toDate, fieldDelegate.hasTime ) } else { fromCalendarLoader.active = true @@ -208,7 +208,7 @@ Column { onPrimaryButtonClicked: { fromDateInput.selectedDate = dateTime let toDate = toDateInput.selectedDate ? toDateInput.selectedDate : null - root.filterController.setDateFilter(root.layerId, fieldDelegate.fieldName, dateTime, toDate, fieldDelegate.hasTime) + root.filterController.setDateFilter( root.layerId, fieldDelegate.fieldName, dateTime, toDate, fieldDelegate.hasTime ) } onClosed: fromCalendarLoader.active = false @@ -219,7 +219,7 @@ Column { } Item { - width: (parent.width - __style.margin12) / 2 + width: ( parent.width - __style.margin12 ) / 2 height: toDateInput.height MMPrivateComponents.MMBaseSingleLineInput { @@ -230,17 +230,17 @@ Column { Component.onCompleted: { let val = fieldDelegate.currentValueTo - if (val !== null && val !== undefined) { - let d = new Date(val) - if (!isNaN(d.getTime())) selectedDate = d + if ( val !== null && val !== undefined ) { + let d = new Date( val ) + if ( !isNaN( d.getTime() ) ) selectedDate = d } } - placeholderText: qsTr("To") + placeholderText: qsTr( "To" ) text: { - if (!selectedDate) return "" - if (fieldDelegate.hasTime) return Qt.formatDateTime(selectedDate, Qt.DefaultLocaleShortDate) - return Qt.formatDate(selectedDate, Qt.DefaultLocaleShortDate) + if ( !selectedDate ) return "" + if ( fieldDelegate.hasTime ) return Qt.formatDateTime( selectedDate, Qt.DefaultLocaleShortDate ) + return Qt.formatDate( selectedDate, Qt.DefaultLocaleShortDate ) } textField.readOnly: true @@ -252,10 +252,10 @@ Column { onTextClicked: toCalendarLoader.active = true onRightContentClicked: { - if (toDateInput.selectedDate) { + if ( toDateInput.selectedDate ) { toDateInput.selectedDate = null let fromDate = fromDateInput.selectedDate ? fromDateInput.selectedDate : null - root.filterController.setDateFilter(root.layerId, fieldDelegate.fieldName, fromDate, null, fieldDelegate.hasTime) + root.filterController.setDateFilter( root.layerId, fieldDelegate.fieldName, fromDate, null, fieldDelegate.hasTime ) } else { toCalendarLoader.active = true @@ -280,7 +280,7 @@ Column { onPrimaryButtonClicked: { toDateInput.selectedDate = dateTime let fromDate = fromDateInput.selectedDate ? fromDateInput.selectedDate : null - root.filterController.setDateFilter(root.layerId, fieldDelegate.fieldName, fromDate, dateTime, fieldDelegate.hasTime) + root.filterController.setDateFilter( root.layerId, fieldDelegate.fieldName, fromDate, dateTime, fieldDelegate.hasTime ) } onClosed: toCalendarLoader.active = false @@ -298,13 +298,13 @@ Column { width: parent.width visible: fieldDelegate.filterType === "text" title: fieldDelegate.fieldDisplayName - placeholderText: qsTr("Type to filter...") + placeholderText: qsTr( "Type to filter..." ) // Explicitly handle undefined/null values text: { let val = fieldDelegate.currentValue - if (val !== null && val !== undefined && val !== "") { - return String(val) + if ( val !== null && val !== undefined && val !== "" ) { + return String( val ) } return "" } @@ -314,9 +314,9 @@ Column { Component.onCompleted: initialized = true onTextChanged: { - if (!initialized) return + if ( !initialized ) return // Pass raw text to C++ - validation happens there - root.filterController.setTextFilter(root.layerId, fieldDelegate.fieldName, text) + root.filterController.setTextFilter( root.layerId, fieldDelegate.fieldName, text ) } } @@ -341,14 +341,14 @@ Column { width: parent.width textField.readOnly: true - placeholderText: qsTr("Select...") + placeholderText: qsTr( "Select..." ) text: { let texts = fieldDelegate.currentValueTexts - if (!texts || texts.length === 0) return "" - if (fieldDelegate.multiSelect && texts.length > 1) { - return qsTr("%1 selected").arg(texts.length) + if ( !texts || texts.length === 0 ) return "" + if ( fieldDelegate.multiSelect && texts.length > 1 ) { + return qsTr( "%1 selected" ).arg( texts.length ) } - return texts.join(", ") + return texts.join( ", " ) } rightContent: MMIcon { @@ -359,10 +359,10 @@ Column { onTextClicked: dropdownDrawerLoader.active = true onRightContentClicked: { - if (dropdownInput.text !== "") { - root.filterController.setDropdownFilter(root.layerId, fieldDelegate.fieldName, [], fieldDelegate.multiSelect) + if ( dropdownInput.text !== "" ) { + root.filterController.setDropdownFilter( root.layerId, fieldDelegate.fieldName, [], fieldDelegate.multiSelect ) // Refresh the fields model to clear currentValueTexts - fieldsRepeater.model = root.vectorLayer ? root.filterController.getFilterableFields(root.vectorLayer) : [] + fieldsRepeater.model = root.vectorLayer ? root.filterController.getFilterableFields( root.vectorLayer ) : [] } else { dropdownDrawerLoader.active = true @@ -389,15 +389,15 @@ Column { list.model: ListModel { id: dropdownListModel } - onSearchTextChanged: function(searchText) { + onSearchTextChanged: function( searchText ) { internal.pendingSearchText = searchText searchDebounceTimer.restart() } - onSelectionFinished: function(selectedItems) { - root.filterController.setDropdownFilter(root.layerId, fieldDelegate.fieldName, selectedItems, fieldDelegate.multiSelect) + onSelectionFinished: function( selectedItems ) { + root.filterController.setDropdownFilter( root.layerId, fieldDelegate.fieldName, selectedItems, fieldDelegate.multiSelect ) // Refresh the fields model to update currentValueTexts - fieldsRepeater.model = root.vectorLayer ? root.filterController.getFilterableFields(root.vectorLayer) : [] + fieldsRepeater.model = root.vectorLayer ? root.filterController.getFilterableFields( root.vectorLayer ) : [] close() } @@ -413,15 +413,15 @@ Column { interval: 300 repeat: false onTriggered: { - populateOptions(internal.pendingSearchText) + populateOptions( internal.pendingSearchText ) } } - function populateOptions(searchText) { - let options = root.filterController.getDropdownOptions(root.vectorLayer, fieldDelegate.fieldName, searchText, 100) + function populateOptions( searchText ) { + let options = root.filterController.getDropdownOptions( root.vectorLayer, fieldDelegate.fieldName, searchText, 100 ) dropdownListModel.clear() - for (let i = 0; i < options.length; i++) { - dropdownListModel.append(options[i]) + for ( let i = 0; i < options.length; i++ ) { + dropdownListModel.append( options[i] ) } } @@ -429,14 +429,14 @@ Column { // Set selected imperatively — QStringList from C++ needs // conversion to a plain JS array for includes() to work let val = fieldDelegate.currentValue - if (val && val.length > 0) { + if ( val && val.length > 0 ) { let arr = [] - for (let i = 0; i < val.length; i++) { - arr.push(String(val[i])) + for ( let i = 0; i < val.length; i++ ) { + arr.push( String( val[i] ) ) } selected = arr } - populateOptions("") + populateOptions( "" ) open() } } diff --git a/app/qml/filters/MMFiltersPanel.qml b/app/qml/filters/MMFiltersPanel.qml index d80055a92..3874f3584 100644 --- a/app/qml/filters/MMFiltersPanel.qml +++ b/app/qml/filters/MMFiltersPanel.qml @@ -93,7 +93,7 @@ MMComponents.MMDrawer { drawerContent: Item { width: parent.width - height: root.maxHeightHit ? root.drawerContentAvailableHeight : (contentColumn.implicitHeight + __style.margin12 + showResultsButton.height) + height: root.maxHeightHit ? root.drawerContentAvailableHeight : ( contentColumn.implicitHeight + __style.margin12 + showResultsButton.height ) MMComponents.MMScrollView { id: scrollView @@ -174,7 +174,7 @@ MMComponents.MMDrawer { Connections { target: __activeProject - function onProjectReloaded(qgsProject) { + function onProjectReloaded( qgsProject ) { internal.refreshLayers() } } diff --git a/app/qml/layers/MMFeaturesListPage.qml b/app/qml/layers/MMFeaturesListPage.qml index e5232c7d7..f4183072b 100644 --- a/app/qml/layers/MMFeaturesListPage.qml +++ b/app/qml/layers/MMFeaturesListPage.qml @@ -43,7 +43,7 @@ MMComponents.MMPage { height: filterRow.implicitHeight + 2 * __style.margin8 radius: __style.radius12 - visible: root.selectedLayer && globalFilterController.filteredLayerIds.indexOf(root.selectedLayer.id) >= 0 + visible: root.selectedLayer && globalFilterController.filteredLayerIds.indexOf( root.selectedLayer.id ) >= 0 color: __style.sandColor border.width: 1 * __dp diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index ef37784e5..e6374bb30 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -591,25 +591,6 @@ Item { } } - // Filter indicator button - left side, 20% from top - MMMapButton { - id: filterIndicatorButton - - visible: root.state === "view" && root.filterController && (root.filterController.hasActiveFilters || AppSettings.alwaysShowFilterButton) - iconSource: root.filterController && root.filterController.hasActiveFilters ? __style.filterFilledIcon : __style.filterIcon - bgndColor: root.filterController && root.filterController.hasActiveFilters ? __style.sandColor : __style.polarColor - - anchors { - left: parent.left - top: parent.top - topMargin: parent.height * 0.2 - } - - onClicked: { - root.openFiltersPanel() - } - } - Item { // bottom buttons group width: parent.width @@ -879,6 +860,18 @@ Item { } } + MMMapButton { + id: filterIndicatorButton + + visible: root.state === "view" && root.filterController && root.filterController.hasActiveFilters + iconSource: __style.filterIcon + bgndColor: __style.positiveColor + + onClicked: { + root.openFiltersPanel() + } + } + MMMapButton { id: gpsButton