diff --git a/app/fieldsmodel.cpp b/app/fieldsmodel.cpp index 49c78965e..4e2e5367d 100644 --- a/app/fieldsmodel.cpp +++ b/app/fieldsmodel.cpp @@ -1,13 +1,21 @@ +/*************************************************************************** +* * + * 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 "fieldsmodel.h" -#include FieldsModel::FieldsModel( QObject *parent ) : QAbstractListModel( parent ) { // fill the model with initial data - addField( "Date", "DateTime" ); - addField( "Notes", "TextEdit" ); - addField( "Photo", "ExternalResource" ); + addField( tr( "Date" ), "DateTime" ); + addField( tr( "Notes" ), "TextEdit" ); + addField( tr( "Photo" ), "ExternalResource" ); } bool FieldsModel::addField( const QString &name, const QString &widgetType ) @@ -36,13 +44,13 @@ bool FieldsModel::addField( const QString &name, const QString &widgetType ) return true; } -bool FieldsModel::removeField( int row ) +bool FieldsModel::removeField( const int rowIndex ) { - if ( row < 0 || row >= mFields.count() ) + if ( rowIndex < 0 || rowIndex >= mFields.count() ) return false; beginResetModel(); - mFields.removeAt( row ); + mFields.removeAt( rowIndex ); endResetModel(); return true; } @@ -55,8 +63,8 @@ QList FieldsModel::fields() const QHash FieldsModel::roleNames() const { QHash roles = QAbstractListModel::roleNames(); - roles[AttributeName] = QByteArrayLiteral( "AttributeName" ); - roles[WidgetType] = QByteArrayLiteral( "WidgetType" ); + roles[AttributeName] = QByteArrayLiteral( "attributeName" ); + roles[WidgetType] = QByteArrayLiteral( "widgetType" ); return roles; } @@ -65,12 +73,12 @@ QHash FieldsModel::roleNames() const int FieldsModel::rowCount( const QModelIndex &parent ) const { Q_UNUSED( parent ); - return mFields.count(); + return static_cast( mFields.count() ); } -QVariant FieldsModel::data( const QModelIndex &index, int role ) const +QVariant FieldsModel::data( const QModelIndex &index, const int role ) const { - int row = index.row(); + const int row = index.row(); if ( row < 0 || row >= mFields.count() ) return QVariant(); @@ -80,22 +88,21 @@ QVariant FieldsModel::data( const QModelIndex &index, int role ) const { case AttributeName: return field.attributeName; - break; case WidgetType: return field.widgetType; - break; - } - return QVariant(); + default: + return QVariant(); + } } -bool FieldsModel::setData( const QModelIndex &index, const QVariant &value, int role ) +bool FieldsModel::setData( const QModelIndex &index, const QVariant &value, const int role ) { if ( data( index, role ) == value ) return true; - int row = index.row(); + const int row = index.row(); if ( row < 0 || row >= mFields.count() ) return false; @@ -111,18 +118,20 @@ bool FieldsModel::setData( const QModelIndex &index, const QVariant &value, int emit dataChanged( index, index, {AttributeName} ); return true; } + case WidgetType: { mFields[row].widgetType = value.toString(); emit dataChanged( index, index, {WidgetType} ); return true; } - } - return false; + default: + return false; + } } -bool FieldsModel::contains( const QString &name ) +bool FieldsModel::contains( const QString &name ) const { for ( int i = 0; i < mFields.count(); ++i ) { diff --git a/app/fieldsmodel.h b/app/fieldsmodel.h index f33ee6135..350daebd0 100644 --- a/app/fieldsmodel.h +++ b/app/fieldsmodel.h @@ -10,13 +10,10 @@ #ifndef FIELDSMODEL_H #define FIELDSMODEL_H -#include #include -#include -#include +#include -#include "qgsfield.h" -#include "qgsfields.h" +#include struct FieldConfiguration { @@ -28,18 +25,18 @@ struct FieldConfiguration class FieldsModel: public QAbstractListModel { Q_OBJECT + QML_ELEMENT + public: /** * Feature roles enum. */ - Q_ENUMS( FeatureRoles ) - - //! Feature roles enum FeatureRoles { AttributeName = Qt::UserRole + 1, //!< Attribute's display name (the original field name) WidgetType, //!< Widget type name. Should match QT/QML editor widgets names. }; + Q_ENUM( FeatureRoles ) //! Creates a new fields model explicit FieldsModel( QObject *parent = nullptr ); @@ -62,7 +59,7 @@ class FieldsModel: public QAbstractListModel QList mFields; - bool contains( const QString &name ); + bool contains( const QString &name ) const; }; #endif // FIELDSMODEL_H diff --git a/app/main.cpp b/app/main.cpp index e91cb18ec..069dd1215 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -55,7 +55,6 @@ #include "variablesmanager.h" #include "inputhelp.h" #include "inputprojutils.h" -#include "fieldsmodel.h" #include "projectwizard.h" #include "qrcodedecoder.h" #include "inputexpressionfunctions.h" @@ -270,7 +269,6 @@ void initDeclarative() qmlRegisterUncreatableType( "mm", 1, 0, "RegistrationError", "RegistrationError Enum" ); qmlRegisterType( "mm", 1, 0, "PositionDirection" ); qmlRegisterType( "mm", 1, 0, "Compass" ); - qmlRegisterType( "mm", 1, 0, "FieldsModel" ); qmlRegisterType( "mm", 1, 0, "QrCodeDecoder" ); qmlRegisterType( "mm", 1, 0, "ProjectsModel" ); qmlRegisterType( "mm", 1, 0, "ProjectsProxyModel" ); diff --git a/app/projectwizard.cpp b/app/projectwizard.cpp index 41310a972..c0e08f6ad 100644 --- a/app/projectwizard.cpp +++ b/app/projectwizard.cpp @@ -15,17 +15,13 @@ #include "qgsvectortilelayer.h" #include "qgsvectorlayer.h" #include "qgsvectorfilewriter.h" -#include "qgsdatetimefieldformatter.h" #include "qgsmarkersymbollayer.h" -#include "qgis.h" #include "qgslinesymbol.h" #include "qgssymbollayer.h" #include "qgssymbollayerutils.h" #include "qgssymbol.h" #include "qgsmarkersymbol.h" #include "qgssinglesymbolrenderer.h" -#include "inpututils.h" -#include "coreutils.h" const QString TILES_URL = QStringLiteral( "https://tiles.merginmaps.com" ); @@ -39,17 +35,17 @@ ProjectWizard::ProjectWizard( const QString &dataDir, QObject *parent ) QgsVectorLayer *ProjectWizard::createGpkgLayer( QString const &projectDir, QList const &fieldsConfig ) { - QString gpkgName( QStringLiteral( "data" ) ); - QString projectGpkgPath( QString( "%1/%2.%3" ).arg( projectDir ).arg( gpkgName ).arg( "gpkg" ) ); - QString layerName( QStringLiteral( "Survey" ) ); - QgsCoordinateReferenceSystem layerCrs( LAYER_CRS_ID ); + const QString gpkgName( QStringLiteral( "data" ) ); + const QString projectGpkgPath( QString( "%1/%2.%3" ).arg( projectDir ).arg( gpkgName ).arg( "gpkg" ) ); + const QString layerName( QStringLiteral( "Survey" ) ); + const QgsCoordinateReferenceSystem layerCrs( LAYER_CRS_ID ); QgsFields predefinedFields = createFields( fieldsConfig ); // Write layer as gpkg QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "PointZ?crs=%1" ).arg( LAYER_CRS_ID ), layerName, "memory" ); layer->startEditing(); layer->setCrs( layerCrs ); - for ( QgsField f : predefinedFields ) + for ( const QgsField &f : predefinedFields ) { layer->addAttribute( f ); } @@ -103,19 +99,19 @@ QgsVectorLayer *ProjectWizard::createTrackingLayer( const QString &trackingGpkgP options.driverName = "GPKG"; options.layerName = "tracking_layer"; - QgsVectorFileWriter *writer = QgsVectorFileWriter::create( - trackingGpkgPath, - fields, - Qgis::WkbType::LineStringZM, - QgsCoordinateReferenceSystem( "EPSG:4326" ), - mSettings->transformContext(), - options ); + const QgsVectorFileWriter *writer = QgsVectorFileWriter::create( + trackingGpkgPath, + fields, + Qgis::WkbType::LineStringZM, + QgsCoordinateReferenceSystem( "EPSG:4326" ), + mSettings->transformContext(), + options ); delete writer; QgsVectorLayer *layer = new QgsVectorLayer( trackingGpkgPath, "tracking_layer", "ogr" ); int idx = layer->fields().indexFromName( "fid" ); - QgsEditorWidgetSetup cfg( "Hidden", QVariantMap() ); + const QgsEditorWidgetSetup cfg( "Hidden", QVariantMap() ); layer->setEditorWidgetSetup( idx, cfg ); idx = layer->fields().indexFromName( "tracking_start_time" ); @@ -154,7 +150,7 @@ QgsVectorLayer *ProjectWizard::createTrackingLayer( const QString &trackingGpkgP return layer; } -void ProjectWizard::createProject( QString const &projectNameRaw, FieldsModel *fieldsModel ) +void ProjectWizard::createProject( QString const &projectNameRaw, const FieldsModel *fieldsModel ) { if ( !CoreUtils::isValidName( projectNameRaw ) ) { @@ -165,10 +161,10 @@ void ProjectWizard::createProject( QString const &projectNameRaw, FieldsModel *f QString projectName( projectNameRaw ); projectName = InputUtils::sanitizeNode( projectName ); - QString projectDir = CoreUtils::createUniqueProjectDirectory( mDataDir, projectName ); - QString projectFilepath( QString( "%1/%2.qgz" ).arg( projectDir ).arg( projectName ) ); - QString projectGpkgPath( QString( "%1/data.gpkg" ).arg( projectDir ) ); - QString trackingGpkgPath( QString( "%1/tracking_layer.gpkg" ).arg( projectDir ) ); + const QString projectDir = CoreUtils::createUniqueProjectDirectory( mDataDir, projectName ); + const QString projectFilepath( QString( "%1/%2.qgz" ).arg( projectDir ).arg( projectName ) ); + const QString projectGpkgPath( QString( "%1/data.gpkg" ).arg( projectDir ) ); + const QString trackingGpkgPath( QString( "%1/tracking_layer.gpkg" ).arg( projectDir ) ); QgsProject project; @@ -197,7 +193,7 @@ void ProjectWizard::createProject( QString const &projectNameRaw, FieldsModel *f project.addMapLayers( layers ); // Configurate mapSettings - QgsCoordinateReferenceSystem projectCrs( PROJECT_CRS_ID ); + const QgsCoordinateReferenceSystem projectCrs( PROJECT_CRS_ID ); mSettings->setExtent( bgLayer->extent() ); mSettings->setEllipsoid( "WGS84" ); mSettings->setDestinationCrs( projectCrs ); @@ -218,7 +214,7 @@ void ProjectWizard::createProject( QString const &projectNameRaw, FieldsModel *f void ProjectWizard::writeMapCanvasSetting( QDomDocument &doc ) { - QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) ); + const QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) ); if ( !nl.count() ) { QgsDebugError( QStringLiteral( "Unable to find qgis element in project file" ) ); @@ -232,14 +228,14 @@ void ProjectWizard::writeMapCanvasSetting( QDomDocument &doc ) mSettings->writeXml( mapcanvasNode, doc ); } -QgsFields ProjectWizard::createFields( const QList fieldsConfig ) const +QgsFields ProjectWizard::createFields( const QList &fieldsConfig ) const { QgsFields fields; for ( const FieldConfiguration &fc : fieldsConfig ) { QString type = widgetToType( fc.widgetType ); - QVariant::Type qtype = parseType( type ); + const QMetaType::Type qtype = parseType( type ); QgsField field( fc.attributeName, qtype, type ); fields.append( field ); } @@ -257,45 +253,53 @@ QgsSingleSymbolRenderer *ProjectWizard::surveyLayerRenderer() return new QgsSingleSymbolRenderer( symbol ); } -QVariant::Type ProjectWizard::parseType( const QString &type ) const +QMetaType::Type ProjectWizard::parseType( const QString &type ) const { if ( type == QLatin1String( "text" ) ) - return QVariant::String; - else if ( type == QLatin1String( "integer" ) ) - return QVariant::Int; - else if ( type == QLatin1String( "integer64" ) ) - return QVariant::Int; - else if ( type == QLatin1String( "real" ) ) - return QVariant::Double; - else if ( type == QLatin1String( "date" ) ) - return QVariant::Date; - else if ( type == QLatin1String( "datetime" ) ) - return QVariant::DateTime; - else if ( type == QLatin1String( "bool" ) ) - return QVariant::Bool; - else if ( type == QLatin1String( "binary" ) ) - return QVariant::ByteArray; - - return QVariant::Invalid; + return QMetaType::QString; + + if ( type == QLatin1String( "integer" ) || type == QLatin1String( "integer64" ) ) + return QMetaType::Int; + + if ( type == QLatin1String( "real" ) ) + return QMetaType::Double; + + if ( type == QLatin1String( "date" ) ) + return QMetaType::QDate; + + if ( type == QLatin1String( "datetime" ) ) + return QMetaType::QDateTime; + + if ( type == QLatin1String( "bool" ) ) + return QMetaType::Bool; + + if ( type == QLatin1String( "binary" ) ) + return QMetaType::QByteArray; + + return QMetaType::UnknownType; } QString ProjectWizard::widgetToType( const QString &widgetType ) const { if ( widgetType == QStringLiteral( "TextEdit" ) ) return QStringLiteral( "text" ); - else if ( widgetType == QStringLiteral( "Range" ) ) + + if ( widgetType == QStringLiteral( "Range" ) ) return QStringLiteral( "integer" ); - else if ( widgetType == QStringLiteral( "DateTime" ) ) + + if ( widgetType == QStringLiteral( "DateTime" ) ) return QStringLiteral( "datetime" ); - else if ( widgetType == QStringLiteral( "CheckBox" ) ) + + if ( widgetType == QStringLiteral( "CheckBox" ) ) return QStringLiteral( "bool" ); - else if ( widgetType == QStringLiteral( "ExternalResource" ) ) + + if ( widgetType == QStringLiteral( "ExternalResource" ) ) return QStringLiteral( "text" ); return QStringLiteral( "text" ); } -QString ProjectWizard::findWidgetTypeByFieldName( const QString name, const QList fieldsConfig ) const +QString ProjectWizard::findWidgetTypeByFieldName( const QString &name, const QList &fieldsConfig ) const { for ( int i = 0; i < fieldsConfig.count(); ++i ) diff --git a/app/projectwizard.h b/app/projectwizard.h index f55c734e4..38bc4a4c0 100644 --- a/app/projectwizard.h +++ b/app/projectwizard.h @@ -10,13 +10,10 @@ #ifndef PROJECTWIZARD_H #define PROJECTWIZARD_H -#include - #include "fieldsmodel.h" #include "qgsfieldmodel.h" #include "qgsvectorlayer.h" #include "qgsmapsettings.h" -#include /** * Controller for creating new Input project. @@ -26,14 +23,14 @@ class ProjectWizard : public QObject Q_OBJECT public: explicit ProjectWizard( const QString &dataDir, QObject *parent = nullptr ); - ~ProjectWizard() = default; + ~ProjectWizard() override = default; /** - * Creates a new project in unique directory named accoridng project name. + * Creates a new project in unique directory named according to project name. * \param projectName Project's name for newly created project. * \param fieldsModel Fields configuration model for a new project */ - Q_INVOKABLE void createProject( QString const &projectName, FieldsModel *fieldsModel ); + Q_INVOKABLE void createProject( QString const &projectName, const FieldsModel *fieldsModel ); public slots: //! To append "mapcanvas" property to project file required to correctly show a project. @@ -41,7 +38,7 @@ class ProjectWizard : public QObject signals: /** - * Emitted after a project has been craeted. + * Emitted after a project has been created. */ void projectCreationFailed( const QString &message ); void projectCreated( const QString &projectDir, const QString &projectName ); @@ -49,11 +46,11 @@ class ProjectWizard : public QObject private: QgsVectorLayer *createGpkgLayer( QString const &projectDir, QList const &fieldsConfig ); QgsVectorLayer *createTrackingLayer( const QString &trackingGpkgPath ); - QgsFields createFields( const QList fieldsConfig ) const; + QgsFields createFields( const QList &fieldsConfig ) const; QgsSingleSymbolRenderer *surveyLayerRenderer(); - QVariant::Type parseType( const QString &type ) const; + QMetaType::Type parseType( const QString &type ) const; QString widgetToType( const QString &widgetType ) const; - QString findWidgetTypeByFieldName( const QString name, const QList fieldsConfig ) const; + QString findWidgetTypeByFieldName( const QString &name, const QList &fieldsConfig ) const; QString mDataDir; std::unique_ptr mSettings = nullptr; diff --git a/app/qml/project/MMProjectWizardPage.qml b/app/qml/project/MMProjectWizardPage.qml index b154c2141..1e1ff8009 100644 --- a/app/qml/project/MMProjectWizardPage.qml +++ b/app/qml/project/MMProjectWizardPage.qml @@ -9,8 +9,9 @@ import QtQuick import QtQuick.Controls +import QtQml.Models -import mm 1.0 as MM +import MMInput import "./components" as MMProjectComponents import "../components" as MMComponents @@ -68,7 +69,8 @@ MMComponents.MMPage { spacing: __style.margin20 delegate: MMProjectComponents.MMProjectWizardDelegate { - id: fieldDelegate + required property string widgetType + required property string attributeName width: ListView.view.width @@ -77,16 +79,16 @@ MMComponents.MMPage { comboboxField.valueRole: "type" comboboxField.onCurrentIndexChanged: { - WidgetType = typesmodel.get(comboboxField.currentIndex)?.type ?? "" + widgetType = typesmodel.get( comboboxField.currentIndex )?.type ?? "" } - onAttrNameChanged: ( attrname ) => AttributeName = attrname + onAttrNameChanged: ( attrName ) => attributeName = attrName onRemoveClicked: () => fieldsModel.removeField( index ) Component.onCompleted: { // assign initial values without binding - attrname = AttributeName - comboboxField.currentIndex = comboboxField.indexFromValue( WidgetType ) + attrname = attributeName + comboboxField.currentIndex = comboboxField.indexFromValue( widgetType ) } } @@ -127,14 +129,14 @@ MMComponents.MMPage { if (!projectNameField.text) { __notificationModel.addWarning( qsTr("Empty project name") ) } else { - __projectWizard.createProject(projectNameField.text, fieldsModel ) + __projectWizard.createProject( projectNameField.text, fieldsModel ) } } } } } - MM.FieldsModel { + FieldsModel { id: fieldsModel onNotifyError: function( message ) { @@ -145,10 +147,10 @@ MMComponents.MMPage { ListModel { id: typesmodel - ListElement { text: "Text"; type: "TextEdit" } - ListElement { text: "Date&time"; type: "DateTime" } - ListElement { text: "Number"; type: "Range" } - ListElement { text: "Checkbox"; type: "CheckBox" } - ListElement { text: "Photo"; type: "ExternalResource" } + ListElement { text: qsTr( "Text" ); type: "TextEdit" } + ListElement { text: qsTr( "Date & Time" ); type: "DateTime" } + ListElement { text: qsTr( "Number" ); type: "Range" } + ListElement { text: qsTr( "Checkbox" ); type: "CheckBox" } + ListElement { text: qsTr( "Photo" ); type: "ExternalResource" } } }