@@ -318,30 +318,6 @@ void FilterController::processFilters( const QVariantMap &newFilters )
318318 applyFiltersToAllLayers ();
319319}
320320
321- QStringList FilterController::getFieldUniqueValues ( QgsVectorLayer *layer, const QString &fieldName ) const
322- {
323- QStringList result;
324-
325- if ( !layer )
326- return result;
327-
328- int fieldIndex = layer->fields ().lookupField ( fieldName );
329- if ( fieldIndex < 0 )
330- return result;
331-
332- QSet<QVariant> uniqueValues = layer->uniqueValues ( fieldIndex, 100 );
333- for ( const QVariant &v : uniqueValues )
334- {
335- if ( !v.isNull () && !v.toString ().isEmpty () )
336- {
337- result << v.toString ();
338- }
339- }
340-
341- result.sort ();
342- return result;
343- }
344-
345321bool FilterController::hasActiveFilterOnLayer ( const QString &layerId )
346322{
347323 const QgsProject *project = QgsProject::instance ();
@@ -352,237 +328,53 @@ bool FilterController::hasActiveFilterOnLayer( const QString &layerId )
352328 return !layer->subsetString ().isEmpty ();
353329}
354330
355- QVariantList FilterController::getDropdownOptions ( const QString &filterId, const QString &searchText, const int limit )
331+ QVariantMap FilterController::getDropdownConfiguration ( const QString &filterId )
356332{
357- if ( filterId.isEmpty () )
358- return {};
333+ if ( filterId.isEmpty () ) return {};
359334
360335 FieldFilter fieldFilter;
361- for ( const FieldFilter &filter : mFieldFilters )
336+ for ( const FieldFilter &filter : std::as_const ( mFieldFilters ) )
362337 {
363338 if ( filterId == filter.filterId )
364- {
339+ {
365340 fieldFilter = filter;
341+ break ;
366342 }
367343 }
368344
369- const QgsProject *project = QgsProject::instance ();
370- if ( !project )
371- return {};
372-
373- const QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( project->mapLayers ().value ( fieldFilter.layerId ) );
374- const int fieldIndex = layer->fields ().lookupField ( fieldFilter.fieldName );
375- if ( fieldIndex < 0 )
376- return {};
377-
378- const QgsEditorWidgetSetup widgetSetup = layer->editorWidgetSetup ( fieldIndex );
379- const QString widgetType = widgetSetup.type ();
380- const QVariantMap config = widgetSetup.config ();
381-
382- if ( widgetType == QLatin1String ( " ValueMap" ) )
383- {
384- return extractValueMapOptions ( config, searchText );
385- }
386- else if ( widgetType == QLatin1String ( " ValueRelation" ) )
387- {
388- return extractValueRelationOptions ( config, searchText, limit, fieldFilter.value .toStringList () );
389- }
390-
391- return {};
392- }
393-
394- QVariantList FilterController::extractValueMapOptions ( const QVariantMap &config, const QString &searchText ) const
395- {
396- QVariantList result;
397-
398- QVariantList mapList = config.value ( QStringLiteral ( " map" ) ).toList ();
399- for ( const QVariant &entry : mapList )
400- {
401- QVariantMap entryMap = entry.toMap ();
402- if ( entryMap.isEmpty () )
403- continue ;
404-
405- // Each entry is a single-key map: {"Display Text": "stored_value"}
406- QString displayText = entryMap.constBegin ().key ();
407- QString storedValue = entryMap.constBegin ().value ().toString ();
408-
409- // Filter by search text
410- if ( !searchText.isEmpty () && !displayText.contains ( searchText, Qt::CaseInsensitive ) )
411- continue ;
412-
413- QVariantMap option;
414- option[QStringLiteral ( " text" )] = displayText;
415- option[QStringLiteral ( " value" )] = storedValue;
416- result << option;
417- }
418-
419- return result;
420- }
345+ if ( !fieldFilter.hasFilterInfo () ) return {};
421346
422- QVariantList FilterController::extractValueRelationOptions ( const QVariantMap &config, const QString &searchText, int limit, const QStringList &alwaysIncludeKeys ) const
423- {
424- QVariantList result;
347+ if ( fieldFilter.filterType != FieldFilter::SingleSelectFilter && fieldFilter.filterType != FieldFilter::MultiSelectFilter ) return {};
425348
426- QgsVectorLayer *referencedLayer = QgsValueRelationFieldFormatter::resolveLayer ( config, QgsProject::instance () );
427- if ( !referencedLayer )
428- return result;
349+ QVariantMap map;
429350
430- QString keyFieldName = config.value ( QStringLiteral ( " Key" ) ).toString ();
431- QString valueFieldName = config.value ( QStringLiteral ( " Value" ) ).toString ();
432-
433- if ( referencedLayer->fields ().indexOf ( keyFieldName ) < 0 || referencedLayer->fields ().indexOf ( valueFieldName ) < 0 )
434- return result;
435-
436- // Build feature request
437- QgsFeatureRequest request;
438- request.setFlags ( Qgis::FeatureRequestFlag::NoGeometry );
439- request.setSubsetOfAttributes ( QStringList ( { keyFieldName, valueFieldName } ), referencedLayer->fields () );
440-
441- // Apply search filter
442- if ( !searchText.isEmpty () )
443- {
444- QString escapedSearch = searchText;
445- escapedSearch.replace ( " '" , " ''" );
446- QString filterExpr = QStringLiteral ( " LOWER(%1) LIKE '%%2%'" )
447- .arg ( QgsExpression::quotedColumnRef ( valueFieldName ), escapedSearch.toLower () );
448- request.setFilterExpression ( filterExpr );
449- }
450-
451- // Apply configured filter expression (only if it doesn't require form scope)
452- QString configFilterExpr = config.value ( QStringLiteral ( " FilterExpression" ) ).toString ();
453- if ( !configFilterExpr.isEmpty () && !QgsValueRelationFieldFormatter::expressionRequiresFormScope ( configFilterExpr ) )
454- {
455- request.combineFilterExpression ( configFilterExpr );
456- }
457-
458- // Apply ordering
459- if ( config.value ( QStringLiteral ( " OrderByValue" ) ).toBool () )
460- {
461- request.setOrderBy ( QgsFeatureRequest::OrderBy ( { QgsFeatureRequest::OrderByClause ( valueFieldName ) } ) );
462- }
463-
464- request.setLimit ( limit );
465-
466- // Fetch features
467- QSet<QString> seenKeys;
468- QgsFeatureIterator it = referencedLayer->getFeatures ( request );
469- QgsFeature feature;
470- while ( it.nextFeature ( feature ) )
471- {
472- QString key = feature.attribute ( keyFieldName ).toString ();
473- QString value = feature.attribute ( valueFieldName ).toString ();
474- seenKeys.insert ( key );
475-
476- QVariantMap option;
477- option[QStringLiteral ( " text" )] = value;
478- option[QStringLiteral ( " value" )] = key;
479- result << option;
480- }
481-
482- // Ensure currently selected keys are always visible in the list
483- if ( !alwaysIncludeKeys.isEmpty () )
484- {
485- QStringList missingKeys;
486- for ( const QString &key : alwaysIncludeKeys )
487- {
488- if ( !seenKeys.contains ( key ) )
489- {
490- missingKeys << key;
491- }
492- }
351+ const QgsProject *project = QgsProject::instance ();
493352
494- if ( !missingKeys.isEmpty () )
495- {
496- QStringList quotedKeys;
497- for ( const QString &k : missingKeys )
498- {
499- quotedKeys << QgsExpression::quotedValue ( k );
500- }
353+ if ( !project ) return {};
501354
502- QgsFeatureRequest selectedRequest;
503- selectedRequest.setFlags ( Qgis::FeatureRequestFlag::NoGeometry );
504- selectedRequest.setSubsetOfAttributes ( QStringList ( { keyFieldName, valueFieldName } ), referencedLayer->fields () );
505- selectedRequest.setFilterExpression (
506- QStringLiteral ( " %1 IN (%2)" ).arg ( QgsExpression::quotedColumnRef ( keyFieldName ), quotedKeys.join ( QStringLiteral ( " , " ) ) )
507- );
508-
509- QVariantList selectedItems;
510- QgsFeatureIterator selIt = referencedLayer->getFeatures ( selectedRequest );
511- QgsFeature selFeature;
512- while ( selIt.nextFeature ( selFeature ) )
513- {
514- QVariantMap option;
515- option[QStringLiteral ( " text" )] = selFeature.attribute ( valueFieldName ).toString ();
516- option[QStringLiteral ( " value" )] = selFeature.attribute ( keyFieldName ).toString ();
517- selectedItems << option;
518- }
519-
520- // Prepend selected items so they appear first
521- selectedItems.append ( result );
522- result = selectedItems;
523- }
524- }
355+ const QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( project->mapLayers ().value ( fieldFilter.layerId ) );
525356
526- return result;
527- }
357+ if ( !layer ) return {};
528358
529- QStringList FilterController::lookupValueMapTexts ( const QVariantMap &config, const QStringList &keys ) const
530- {
531- QStringList texts;
532- QSet<QString> keySet ( keys.begin (), keys.end () );
359+ const int fieldIndex = layer->fields ().lookupField ( fieldFilter.fieldName );
360+ const QgsEditorWidgetSetup fieldConfig = layer->editorWidgetSetup ( fieldIndex );
533361
534- QVariantList mapList = config.value ( QStringLiteral ( " map" ) ).toList ();
535- for ( const QVariant &entry : mapList )
362+ if ( QString::compare ( fieldConfig.type (), QStringLiteral ( " ValueMap" ), Qt::CaseInsensitive ) == 0 )
536363 {
537- QVariantMap entryMap = entry.toMap ();
538- if ( entryMap.isEmpty () )
539- continue ;
540-
541- QString displayText = entryMap.constBegin ().key ();
542- QString storedValue = entryMap.constBegin ().value ().toString ();
543-
544- if ( keySet.contains ( storedValue ) )
545- {
546- texts << displayText;
547- }
364+ map[" type" ] = QStringLiteral (" value_map" );
365+ map[" config" ] = fieldConfig.config ();
548366 }
549-
550- return texts;
551- }
552-
553- QStringList FilterController::lookupValueRelationTexts ( const QVariantMap &config, const QStringList &keys ) const
554- {
555- QStringList texts;
556-
557- QgsVectorLayer *referencedLayer = QgsValueRelationFieldFormatter::resolveLayer ( config, QgsProject::instance () );
558- if ( !referencedLayer )
559- return texts;
560-
561- QString keyFieldName = config.value ( QStringLiteral ( " Key" ) ).toString ();
562- QString valueFieldName = config.value ( QStringLiteral ( " Value" ) ).toString ();
563-
564- if ( referencedLayer->fields ().indexOf ( keyFieldName ) < 0 || referencedLayer->fields ().indexOf ( valueFieldName ) < 0 )
565- return texts;
566-
567- QStringList quotedKeys;
568- for ( const QString &k : keys )
367+ else if ( QString::compare ( fieldConfig.type (), QStringLiteral ( " ValueRelation" ), Qt::CaseInsensitive ) == 0 )
569368 {
570- quotedKeys << QgsExpression::quotedValue ( k );
369+ map[" type" ] = QStringLiteral (" value_relation" );
370+ map[" config" ] = fieldConfig.config ();
571371 }
572-
573- QgsFeatureRequest request;
574- request.setFlags ( Qgis::FeatureRequestFlag::NoGeometry );
575- request.setSubsetOfAttributes ( QStringList ( { keyFieldName, valueFieldName } ), referencedLayer->fields () );
576- request.setFilterExpression (
577- QStringLiteral ( " %1 IN (%2)" ).arg ( QgsExpression::quotedColumnRef ( keyFieldName ), quotedKeys.join ( QStringLiteral ( " , " ) ) )
578- );
579-
580- QgsFeatureIterator it = referencedLayer->getFeatures ( request );
581- QgsFeature feature;
582- while ( it.nextFeature ( feature ) )
372+ else
583373 {
584- texts << feature.attribute ( valueFieldName ).toString ();
374+ map[" type" ] = QStringLiteral (" unique_values" );
375+ map[" layer_id" ] = fieldFilter.layerId ;
376+ map[" field_name" ] = fieldFilter.fieldName ;
585377 }
586378
587- return texts ;
379+ return map ;
588380}
0 commit comments