Skip to content
Merged
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: 3 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ set(MM_SRCS
featurelayerpair.cpp
featuresmodel.cpp
fieldsmodel.cpp
filter/uniquevaluesfiltermodel.cpp
filtercontroller.cpp
guidelinecontroller.cpp
hapticsmodel.cpp
Expand Down Expand Up @@ -148,6 +149,7 @@ set(MM_HDRS
featurelayerpair.h
featuresmodel.h
fieldsmodel.h
filter/uniquevaluesfiltermodel.h
filtercontroller.h
guidelinecontroller.h
hapticsmodel.h
Expand Down Expand Up @@ -320,6 +322,7 @@ target_include_directories(
MerginMaps
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/
${CMAKE_CURRENT_SOURCE_DIR}/attributes
${CMAKE_CURRENT_SOURCE_DIR}/filter
${CMAKE_CURRENT_SOURCE_DIR}/map
${CMAKE_CURRENT_SOURCE_DIR}/layer
${CMAKE_CURRENT_SOURCE_DIR}/maptools
Expand Down
2 changes: 1 addition & 1 deletion app/attributes/attributeformmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ bool AttributeFormModel::setData( const QModelIndex &index, const QVariant &valu
case AttributeValue:
{
const FormItem *item = mController->formItem( uuid );
//if ( mController->formValue( item->fieldIndex() ) == value )

if ( item->rawValue() == value )
{
return false;
Expand Down
141 changes: 141 additions & 0 deletions app/filter/uniquevaluesfiltermodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#include "uniquevaluesfiltermodel.h"
#include "coreutils.h"

#include <qgsproject.h>
#include <qgsvectorlayer.h>
#include <QtConcurrentRun>


UniqueValuesFilterModel::UniqueValuesFilterModel( QObject *parent )
: QAbstractListModel( parent )
{
// <TODO> remove me once this class is used! :)
const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
{
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( it.value() );
if ( vectorLayer )
{
setLayer( vectorLayer );
setFieldName( "fid" );
break;
}
}
// </TODO>

connect( &mResultWatcher, &QFutureWatcher<QVariantList>::finished, this, &UniqueValuesFilterModel::onLoadingFinished );
}

int UniqueValuesFilterModel::rowCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent )
return mItems.size();
}

QVariant UniqueValuesFilterModel::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() || index.row() >= mItems.size() )
return {};

switch ( role )
{
case Qt::DisplayRole:
return mItems.at( index.row() );
default:
return {};
}
}

QgsVectorLayer *UniqueValuesFilterModel::layer() const
{
return mLayer;
}

void UniqueValuesFilterModel::setLayer( QgsVectorLayer *layer )
{
if ( mLayer == layer )
return;

mLayer = layer;
emit layerChanged();
}

QString UniqueValuesFilterModel::fieldName() const
{
return mFieldName;
}

void UniqueValuesFilterModel::setFieldName( const QString &fieldName )
{
if ( mFieldName == fieldName )
return;

mFieldName = fieldName;
emit fieldNameChanged();
}

void UniqueValuesFilterModel::populate()
{
if ( !mLayer || mFieldName.isEmpty() )
return;

int fieldIndex = mLayer->fields().lookupField( mFieldName );
if ( fieldIndex < 0 )
{
CoreUtils::log( QStringLiteral( "Filtering" ), QStringLiteral( "Error, field %1 could not be found, dropdown filter won't work." ).arg( mFieldName ) );
return;
}

if ( mItems.size() > 0 ) return;

if ( mResultWatcher.isRunning() ) return;

QgsVectorLayer *layerClone = mLayer->clone();

mResultWatcher.setFuture( QtConcurrent::run( &UniqueValuesFilterModel::loadUniqueValues, this, layerClone, fieldIndex ) );
}

QVariantList UniqueValuesFilterModel::loadUniqueValues( QgsVectorLayer *layer, int fieldIndex )
{
std::unique_ptr<QgsVectorLayer> l( layer );

const QSet<QVariant> uniqueValues = l->uniqueValues( fieldIndex, 1000000 );

QVariantList results;

results.reserve( uniqueValues.size() );

for ( const QVariant &v : uniqueValues )
{
results.append( v );
}

std::sort( results.begin(), results.end(), []( const QVariant & a, const QVariant & b )
{
return a.toString() < b.toString();
} );

return results;
}

void UniqueValuesFilterModel::onLoadingFinished()
{
beginResetModel();

mItems.clear();
mItems = mResultWatcher.result();

// TODO: do we need boolean to indicate if the model is loading?
// TODO: measure how long it takes to move results from future result to mItems ~ there might be a way to avoid the copy

endResetModel();
}
60 changes: 60 additions & 0 deletions app/filter/uniquevaluesfiltermodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#ifndef UNIQUEVALUESFILTERMODEL_H
#define UNIQUEVALUESFILTERMODEL_H

#include <QAbstractListModel>
#include <QFutureWatcher>
#include <QtQml/qqmlregistration.h>

class QgsVectorLayer;

// This model loads unique values from the selected layer+field and exposes them via Qt::DisplayRole
class UniqueValuesFilterModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT

Q_PROPERTY( QgsVectorLayer *layer READ layer WRITE setLayer NOTIFY layerChanged )
Q_PROPERTY( QString fieldName READ fieldName WRITE setFieldName NOTIFY fieldNameChanged )

public:
explicit UniqueValuesFilterModel( QObject *parent = nullptr );
~UniqueValuesFilterModel() override = default;

int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;

QgsVectorLayer *layer() const;
void setLayer( QgsVectorLayer *layer );

QString fieldName() const;
void setFieldName( const QString &fieldName );

Q_INVOKABLE void populate();

signals:
void layerChanged();
void fieldNameChanged();

public slots:
void onLoadingFinished();

private:
QVariantList loadUniqueValues( QgsVectorLayer *layer, int fieldIndex );

QgsVectorLayer *mLayer = nullptr;
QString mFieldName;

QVariantList mItems;
QFutureWatcher<QVariantList> mResultWatcher;
};

#endif // UNIQUEVALUESFILTERMODEL_H
Loading