From 3e01e6d3d5782decb8ca519c11e21d981d270b10 Mon Sep 17 00:00:00 2001 From: jef Date: Sat, 30 May 2009 17:48:49 +0000 Subject: [PATCH] - allow setting of field width and precision when adding attributes - update vector data providers accordingly - postgres provider: - add support for more native types and setting of column comments - catch errors on retrieval of defaults values (fixes #1713) git-svn-id: http://svn.osgeo.org/qgis/trunk@10863 c8812cc2-4d05-0410-92ff-de0c093fc19c --- python/core/qgsvectordataprovider.sip | 11 +- python/core/qgsvectorlayer.sip | 2 +- src/app/qgsaddattrdialog.cpp | 68 ++++++++--- src/app/qgsaddattrdialog.h | 9 +- src/app/qgsvectorlayerproperties.cpp | 8 +- src/app/qgsvectorlayerproperties.h | 7 +- src/core/qgsvectordataprovider.cpp | 22 +++- src/core/qgsvectordataprovider.h | 39 +++++-- src/core/qgsvectorlayer.cpp | 52 ++++----- src/core/qgsvectorlayer.h | 7 +- src/providers/memory/qgsmemoryprovider.cpp | 26 ++--- src/providers/memory/qgsmemoryprovider.h | 2 +- src/providers/ogr/qgsogrprovider.cpp | 49 ++++---- src/providers/ogr/qgsogrprovider.h | 2 +- .../postgres/qgspostgresprovider.cpp | 70 +++++++++--- src/providers/postgres/qgspostgresprovider.h | 2 +- .../spatialite/qgsspatialiteprovider.cpp | 23 ++-- .../spatialite/qgsspatialiteprovider.h | 2 +- src/ui/qgsaddattrdialogbase.ui | 108 +++++++++++++----- 19 files changed, 342 insertions(+), 167 deletions(-) diff --git a/python/core/qgsvectordataprovider.sip b/python/core/qgsvectordataprovider.sip index 3a484865113..5143a9d7725 100644 --- a/python/core/qgsvectordataprovider.sip +++ b/python/core/qgsvectordataprovider.sip @@ -164,7 +164,7 @@ class QgsVectorDataProvider : QgsDataProvider * @param attributes map with attribute name as key and type as value * @return true in case of success and false in case of failure */ - virtual bool addAttributes(const QMap & attributes); + virtual bool addAttributes(const QList & attributes); /** * Deletes existing attributes @@ -231,9 +231,12 @@ class QgsVectorDataProvider : QgsDataProvider */ QList attributeIndexes(); - /**Returns the names of the numerical types*/ - const QMap &supportedNativeTypes() const; - + /** + * check if provider supports type of field + * @note added in 1.2 + */ + bool supportedType( const QgsField &field ) const; + /** * Set whether provider should return also features that don't have * associated geometry. FALSE by default diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip index 6467a9c8c59..36e0e9c49a6 100644 --- a/python/core/qgsvectorlayer.sip +++ b/python/core/qgsvectorlayer.sip @@ -325,7 +325,7 @@ public: /** add an attribute field (but does not commit it) returns the field index or -1 in case of failure */ - bool addAttribute(QString name, QString type); + bool addAttribute( const QgsField &field ); /** delete an attribute field (but does not commit it) */ bool deleteAttribute(int attr); diff --git a/src/app/qgsaddattrdialog.cpp b/src/app/qgsaddattrdialog.cpp index e7e668816cc..b5fecb381b9 100644 --- a/src/app/qgsaddattrdialog.cpp +++ b/src/app/qgsaddattrdialog.cpp @@ -17,6 +17,7 @@ #include "qgsaddattrdialog.h" #include "qgsvectordataprovider.h" +#include "qgslogger.h" QgsAddAttrDialog::QgsAddAttrDialog( QgsVectorDataProvider* provider, QWidget *parent, Qt::WFlags fl ) : QDialog( parent, fl ), mDataProvider( provider ) @@ -24,31 +25,66 @@ QgsAddAttrDialog::QgsAddAttrDialog( QgsVectorDataProvider* provider, QWidget *pa setupUi( this ); //fill data types into the combo box - const QgsNativeTypeMap &typelist = mDataProvider->supportedNativeTypes(); + const QList< QgsVectorDataProvider::NativeType > &typelist = mDataProvider->nativeTypes(); - for ( QgsNativeTypeMap::const_iterator it = typelist.constBegin(); it != typelist.constEnd(); ++it ) + for ( int i = 0; i < typelist.size(); i++ ) { - mTypeBox->addItem( it.key() ); + QgsDebugMsg( QString( "name:%1 type:%2 typeName:%3 length:%4-%5 prec:%6-%7" ) + .arg( typelist[i].mTypeDesc ) + .arg( typelist[i].mType ) + .arg( typelist[i].mTypeName ) + .arg( typelist[i].mMinLen ).arg( typelist[i].mMaxLen ) + .arg( typelist[i].mMinPrec ).arg( typelist[i].mMaxPrec ) ); + + mTypeBox->addItem( typelist[i].mTypeDesc ); + mTypeBox->setItemData( i, static_cast( typelist[i].mType ), Qt::UserRole ); + mTypeBox->setItemData( i, typelist[i].mTypeName, Qt::UserRole + 1 ); + mTypeBox->setItemData( i, typelist[i].mMinLen, Qt::UserRole + 2 ); + mTypeBox->setItemData( i, typelist[i].mMaxLen, Qt::UserRole + 3 ); + mTypeBox->setItemData( i, typelist[i].mMinPrec, Qt::UserRole + 4 ); + mTypeBox->setItemData( i, typelist[i].mMaxPrec, Qt::UserRole + 5 ); } + + on_mTypeBox_currentIndexChanged( 0 ); } -QgsAddAttrDialog::QgsAddAttrDialog( const std::list& typelist, QWidget *parent, Qt::WFlags fl ) - : QDialog( parent, fl ), mDataProvider( 0 ) +void QgsAddAttrDialog::on_mTypeBox_currentIndexChanged( int idx ) { - setupUi( this ); + mTypeName->setText( mTypeBox->itemData( idx, Qt::UserRole + 1 ).toString() ); - for ( std::list::const_iterator iter = typelist.begin();iter != typelist.end();++iter ) - { - mTypeBox->addItem( *iter ); - } + mLength->setMinimum( mTypeBox->itemData( idx, Qt::UserRole + 2 ).toInt() ); + mLength->setMaximum( mTypeBox->itemData( idx, Qt::UserRole + 3 ).toInt() ); + mLength->setVisible( mLength->minimum() < mLength->maximum() ); + if ( mLength->value() < mLength->minimum() ) + mLength->setValue( mLength->minimum() ); + if ( mLength->value() > mLength->maximum() ) + mLength->setValue( mLength->maximum() ); + + mPrec->setMinimum( mTypeBox->itemData( idx, Qt::UserRole + 4 ).toInt() ); + mPrec->setMaximum( mTypeBox->itemData( idx, Qt::UserRole + 5 ).toInt() ); + mPrec->setVisible( mPrec->minimum() < mPrec->maximum() ); + if ( mPrec->value() < mPrec->minimum() ) + mPrec->setValue( mPrec->minimum() ); + if ( mPrec->value() > mPrec->maximum() ) + mPrec->setValue( mPrec->maximum() ); } -QString QgsAddAttrDialog::name() const +QgsField QgsAddAttrDialog::field() const { - return mNameEdit->text(); -} + QgsDebugMsg( QString( "idx:%1 name:%2 type:%3 typeName:%4 length:%5 prec:%6 comment:%7" ) + .arg( mTypeBox->currentIndex() ) + .arg( mNameEdit->text() ) + .arg( mTypeBox->itemData( mTypeBox->currentIndex(), Qt::UserRole ).toInt() ) + .arg( mTypeBox->itemData( mTypeBox->currentIndex(), Qt::UserRole + 1 ).toString() ) + .arg( mLength->value() ) + .arg( mPrec->value() ) + .arg( mCommentEdit->text() ) ); -QString QgsAddAttrDialog::type() const -{ - return mTypeBox->currentText(); + return QgsField( + mNameEdit->text(), + ( QVariant::Type ) mTypeBox->itemData( mTypeBox->currentIndex(), Qt::UserRole ).toInt(), + mTypeBox->itemData( mTypeBox->currentIndex(), Qt::UserRole + 1 ).toString(), + mLength->value(), + mPrec->value(), + mCommentEdit->text() ); } diff --git a/src/app/qgsaddattrdialog.h b/src/app/qgsaddattrdialog.h index be385504f2b..56cbfacbcca 100644 --- a/src/app/qgsaddattrdialog.h +++ b/src/app/qgsaddattrdialog.h @@ -20,6 +20,7 @@ #include "ui_qgsaddattrdialogbase.h" #include "qgisgui.h" +#include "qgsfield.h" class QgsVectorDataProvider; @@ -31,8 +32,12 @@ class QgsAddAttrDialog: public QDialog, private Ui::QgsAddAttrDialogBase QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags ); QgsAddAttrDialog( const std::list& typelist, QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags ); - QString name() const; - QString type() const; + + QgsField field() const; + + public slots: + void on_mTypeBox_currentIndexChanged( int idx ); + protected: QgsVectorDataProvider* mDataProvider; }; diff --git a/src/app/qgsvectorlayerproperties.cpp b/src/app/qgsvectorlayerproperties.cpp index fe8b88bc4c5..1fd09ec47d4 100644 --- a/src/app/qgsvectorlayerproperties.cpp +++ b/src/app/qgsvectorlayerproperties.cpp @@ -261,17 +261,17 @@ void QgsVectorLayerProperties::addAttribute() QgsAddAttrDialog dialog( layer->dataProvider(), this ); if ( dialog.exec() == QDialog::Accepted ) { - if ( !addAttribute( dialog.name(), dialog.type() ) ) + if ( !addAttribute( dialog.field() ) ) { QMessageBox::information( this, tr( "Name conflict" ), tr( "The attribute could not be inserted. The name already exists in the table." ) ); } } } -bool QgsVectorLayerProperties::addAttribute( QString name, QString type ) +bool QgsVectorLayerProperties::addAttribute( const QgsField &field ) { - QgsDebugMsg( "inserting attribute " + name + " of type " + type ); - return layer->addAttribute( name, type ); + QgsDebugMsg( "inserting attribute " + field.name() + " of type " + field.typeName() ); + return layer->addAttribute( field ); } void QgsVectorLayerProperties::deleteAttribute() diff --git a/src/app/qgsvectorlayerproperties.h b/src/app/qgsvectorlayerproperties.h index 911300d9d44..6fe8a4e8b4d 100644 --- a/src/app/qgsvectorlayerproperties.h +++ b/src/app/qgsvectorlayerproperties.h @@ -50,10 +50,9 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope void setDisplayField( QString name ); /**Adds an attribute to the table (but does not commit it yet) - @param name attribute name - @param type attribute type - @return false in case of a name conflict, true in case of success*/ - bool addAttribute( QString name, QString type ); + @param field the field to add + @return false in case of a name conflict, true in case of success */ + bool addAttribute( const QgsField &field ); /**Deletes an attribute (but does not commit it) @param name attribute name diff --git a/src/core/qgsvectordataprovider.cpp b/src/core/qgsvectordataprovider.cpp index f37b31b3647..993c2a52c66 100644 --- a/src/core/qgsvectordataprovider.cpp +++ b/src/core/qgsvectordataprovider.cpp @@ -78,7 +78,7 @@ bool QgsVectorDataProvider::deleteFeatures( const QgsFeatureIds & id ) return false; } -bool QgsVectorDataProvider::addAttributes( const QgsNewAttributesMap & attributes ) +bool QgsVectorDataProvider::addAttributes( const QList & attributes ) { return false; } @@ -262,12 +262,28 @@ void QgsVectorDataProvider::enableGeometrylessFeatures( bool fetch ) mFetchFeaturesWithoutGeom = fetch; } -const QgsNativeTypeMap &QgsVectorDataProvider::supportedNativeTypes() const +const QList< QgsVectorDataProvider::NativeType > &QgsVectorDataProvider::nativeTypes() const { - return mSupportedNativeTypes; + return mNativeTypes; } +bool QgsVectorDataProvider::supportedType( const QgsField &field ) const +{ + int i; + for ( i = 0; i < mNativeTypes.size(); i++ ) + { + if ( field.type() == mNativeTypes[i].mType && + field.length() >= mNativeTypes[i].mMinLen && field.length() <= mNativeTypes[i].mMaxLen && + field.precision() >= mNativeTypes[i].mMinPrec && field.precision() <= mNativeTypes[i].mMaxPrec ) + { + break; + } + } + + return i < mNativeTypes.size(); +} + QVariant QgsVectorDataProvider::minimumValue( int index ) { if ( !fields().contains( index ) ) diff --git a/src/core/qgsvectordataprovider.h b/src/core/qgsvectordataprovider.h index d2d2aefbbfa..1b12a09b5c9 100644 --- a/src/core/qgsvectordataprovider.h +++ b/src/core/qgsvectordataprovider.h @@ -29,9 +29,6 @@ class QTextCodec; #include "qgsvectorlayer.h" #include "qgsfield.h" -typedef QMap QgsNewAttributesMap; -typedef QMap QgsNativeTypeMap; - /** \ingroup core * This is the base class for vector data providers. * @@ -208,21 +205,21 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider * @param attributes map with attribute name as key and type as value * @return true in case of success and false in case of failure */ - virtual bool addAttributes( const QgsNewAttributesMap & attributes ); + virtual bool addAttributes( const QList &attributes ); /** * Deletes existing attributes * @param attributes a set containing names of attributes * @return true in case of success and false in case of failure */ - virtual bool deleteAttributes( const QgsAttributeIds& attributes ); + virtual bool deleteAttributes( const QgsAttributeIds &attributes ); /** * Changes attribute values of existing features. * @param attr_map a map containing changed attributes * @return true in case of success and false in case of failure */ - virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ); + virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ); /** * Returns the default value for field specified by @c fieldId @@ -279,15 +276,37 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider */ virtual QgsAttributeList attributeIndexes(); - /**Returns the names of the numerical types*/ - const QgsNativeTypeMap &supportedNativeTypes() const; - /** * Set whether provider should also return features that don't have * associated geometry. FALSE by default */ void enableGeometrylessFeatures( bool fetch ); + /** + * check if provider supports type of field + * @note added in 1.2 + */ + bool supportedType( const QgsField &field ) const; + + struct NativeType + { + NativeType( QString typeDesc, QString typeName, QVariant::Type type, int minLen = 0, int maxLen = 0, int minPrec = 0, int maxPrec = 0 ) : + mTypeDesc( typeDesc ), mTypeName( typeName ), mType( type ), mMinLen( minLen ), mMaxLen( maxLen ), mMinPrec( minPrec ), mMaxPrec( maxPrec ) {}; + + QString mTypeDesc; + QString mTypeName; + QVariant::Type mType; + int mMinLen, mMaxLen; + int mMinPrec, mMaxPrec; + }; + + + /** + * Returns the names of the numerical types + * @note added in 1.2 + */ + const QList< NativeType > &nativeTypes() const; + protected: QVariant convertValue( QVariant::Type type, QString value ); @@ -309,7 +328,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider QgsAttributeList mAttributesToFetch; /**The names of the providers native types*/ - QgsNativeTypeMap mSupportedNativeTypes; + QList< NativeType > mNativeTypes; }; #endif diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 1203af6e7d9..78b79763b8a 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -172,9 +172,9 @@ QgsVectorLayer::~QgsVectorLayer() //delete remaining overlays QList::iterator overlayIt = mOverlays.begin(); - for(; overlayIt != mOverlays.end(); ++overlayIt) + for ( ; overlayIt != mOverlays.end(); ++overlayIt ) { - delete (*overlayIt); + delete *overlayIt; } } @@ -1469,7 +1469,7 @@ bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent ) // and add to the known added features. f.setFeatureId( addedIdLowWaterMark ); mAddedFeatures.append( f ); - mCachedGeometries[f.id()] = *(f.geometry()); + mCachedGeometries[f.id()] = *f.geometry(); setModified( true ); @@ -1666,7 +1666,7 @@ int QgsVectorLayer::addIsland( const QList& ring ) if ( addedIt->id() == selectedFeatureId ) { return addedIt->geometry()->addIsland( ring ); - mCachedGeometries[selectedFeatureId] = *(addedIt->geometry()); + mCachedGeometries[selectedFeatureId] = *addedIt->geometry(); } } @@ -1737,19 +1737,19 @@ int QgsVectorLayer::translateFeature( int featureId, double dx, double dy ) //else get the geometry from provider (may be slow) QgsFeature f; - if(mDataProvider && mDataProvider->featureAtId(featureId, f, true)) + if ( mDataProvider && mDataProvider->featureAtId( featureId, f, true ) ) { - if(f.geometry()) + if ( f.geometry() ) + { + QgsGeometry translateGeom( *( f.geometry() ) ); + int errorCode = translateGeom.translate( dx, dy ); + if ( errorCode == 0 ) { - QgsGeometry translateGeom(*(f.geometry())); - int errorCode = translateGeom.translate(dx, dy); - if(errorCode == 0) - { - mChangedGeometries.insert(featureId, translateGeom); - setModified(true, true); - } - return errorCode; + mChangedGeometries.insert( featureId, translateGeom ); + setModified( true, true ); } + return errorCode; + } } return 1; //geometry not found } @@ -2571,7 +2571,7 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& } -bool QgsVectorLayer::changeGeometry(int fid, QgsGeometry* geom) +bool QgsVectorLayer::changeGeometry( int fid, QgsGeometry* geom ) { if ( !mEditable || !mDataProvider ) { @@ -2621,24 +2621,22 @@ bool QgsVectorLayer::changeAttributeValue( int fid, int field, QVariant value, b return true; } -bool QgsVectorLayer::addAttribute( QString name, QString type ) +bool QgsVectorLayer::addAttribute( const QgsField &field ) { if ( !isEditable() ) return false; for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ ) { - if ( it.value().name() == name ) + if ( it.value().name() == field.name() ) return false; } - const QgsNativeTypeMap &types = mDataProvider->supportedNativeTypes(); - QVariant::Type typeType = QVariant::String; - if ( types.contains( type ) ) - typeType = ( QVariant::Type ) types[type]; + if ( !mDataProvider->supportedType( field ) ) + return false; mMaxUpdatedIndex++; - mUpdatedFields.insert( mMaxUpdatedIndex, QgsField( name, typeType, type ) ); + mUpdatedFields.insert( mMaxUpdatedIndex, field ); mAddedAttributeIds.insert( mMaxUpdatedIndex ); setModified( true, false ); @@ -2656,10 +2654,12 @@ bool QgsVectorLayer::deleteAttribute( int index ) if ( mDeletedAttributeIds.contains( index ) ) return false; - if ( !mDataProvider->fields().contains( index ) ) + if ( !mAddedAttributeIds.contains( index ) && + !mDataProvider->fields().contains( index ) ) return false; mDeletedAttributeIds.insert( index ); + mAddedAttributeIds.remove( index ); mUpdatedFields.remove( index ); setModified( true, false ); @@ -2748,9 +2748,9 @@ bool QgsVectorLayer::commitChanges() // if ( mAddedAttributeIds.size() > 0 ) { - QgsNewAttributesMap addedAttributes; + QList addedAttributes; for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.begin(); it != mAddedAttributeIds.end(); it++ ) - addedAttributes[ mUpdatedFields[ *it ].name()] = mUpdatedFields[ *it ].typeName(); + addedAttributes << mUpdatedFields[ *it ]; if (( cap & QgsVectorDataProvider::AddAttributes ) && mDataProvider->addAttributes( addedAttributes ) ) { @@ -3244,7 +3244,7 @@ int QgsVectorLayer::snapWithContext( const QgsPoint& startPoint, double snapping int n = 0; QgsFeature f; - if (mCachedGeometriesRect.contains( searchRect ) ) + if ( mCachedGeometriesRect.contains( searchRect ) ) { QgsDebugMsg( "Using cached geometries for snapping." ); diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index efd8bb2ba66..e04b7f1f59f 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -380,14 +380,15 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer /** change feature's geometry @note added in version 1.2 */ - bool changeGeometry(int fid, QgsGeometry* geom); + bool changeGeometry( int fid, QgsGeometry* geom ); /** changed an attribute value (but does not commit it) */ bool changeAttributeValue( int fid, int field, QVariant value, bool emitSignal = true ); /** add an attribute field (but does not commit it) - returns the field index or -1 in case of failure */ - bool addAttribute( QString name, QString type ); + returns true if the field was added + @note added in version 1.2 */ + bool addAttribute( const QgsField &field ); /** delete an attribute field (but does not commit it) */ bool deleteAttribute( int attr ); diff --git a/src/providers/memory/qgsmemoryprovider.cpp b/src/providers/memory/qgsmemoryprovider.cpp index 355f9d38fc0..0644391e9c3 100644 --- a/src/providers/memory/qgsmemoryprovider.cpp +++ b/src/providers/memory/qgsmemoryprovider.cpp @@ -271,30 +271,26 @@ bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds & id ) return TRUE; } -bool QgsMemoryProvider::addAttributes( const QgsNewAttributesMap & attributes ) +bool QgsMemoryProvider::addAttributes( const QList &attributes ) { - for ( QgsNewAttributesMap::const_iterator it = attributes.begin(); it != attributes.end(); ++it ) + for ( QList::const_iterator it = attributes.begin(); it != attributes.end(); ++it ) { - QString name = it.key(); - QString typeName = it.value(); - QVariant::Type type; - if ( typeName == "int" ) - type = QVariant::Int; - else if ( typeName == "double" ) - type = QVariant::Double; - else if ( typeName == "string" ) - type = QVariant::String; - else + switch ( it->type() ) { - QgsDebugMsg( "Field type not supported: " + typeName ); - continue; + case QVariant::Int: + case QVariant::Double: + case QVariant::String: + break; + default: + QgsDebugMsg( "Field type not supported: " + it->typeName() ); + continue; } // add new field as a last one int nextId = -1; for ( QgsFieldMap::iterator it2 = mFields.begin(); it2 != mFields.end(); ++it2 ) if ( it2.key() > nextId ) nextId = it2.key(); - mFields[nextId+1] = QgsField( name, type, typeName ); + mFields[nextId+1] = *it; } return TRUE; } diff --git a/src/providers/memory/qgsmemoryprovider.h b/src/providers/memory/qgsmemoryprovider.h index 0c492b17fee..7fd3cab15aa 100644 --- a/src/providers/memory/qgsmemoryprovider.h +++ b/src/providers/memory/qgsmemoryprovider.h @@ -115,7 +115,7 @@ class QgsMemoryProvider : public QgsVectorDataProvider * @param attributes map with attribute name as key and type as value * @return true in case of success and false in case of failure */ - virtual bool addAttributes( const QgsNewAttributesMap & attributes ); + virtual bool addAttributes( const QList &attributes ); /** * Deletes existing attributes diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp index 817acb6db06..222b893c777 100644 --- a/src/providers/ogr/qgsogrprovider.cpp +++ b/src/providers/ogr/qgsogrprovider.cpp @@ -184,9 +184,11 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri ) valid = false; } - mSupportedNativeTypes.insert( "Integer", QVariant::Int ); - mSupportedNativeTypes.insert( "Real", QVariant::Double ); - mSupportedNativeTypes.insert( "String", QVariant::String ); + mNativeTypes + << QgsVectorDataProvider::NativeType( tr( "Integer" ), "integer", QVariant::Int, 1, 10 ) + << QgsVectorDataProvider::NativeType( tr( "Real" ), "double", QVariant::Double, 1, 20, 0, 5 ) + << QgsVectorDataProvider::NativeType( tr( "String" ), "string", QVariant::String, 1, 20, 0, 5 ) + ; } QgsOgrProvider::~QgsOgrProvider() @@ -672,34 +674,35 @@ bool QgsOgrProvider::addFeatures( QgsFeatureList & flist ) return returnvalue; } -bool QgsOgrProvider::addAttributes( const QgsNewAttributesMap & attributes ) +bool QgsOgrProvider::addAttributes( const QList &attributes ) { bool returnvalue = true; - for ( QgsNewAttributesMap::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter ) + for ( QList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter ) { - OGRFieldDefnH fielddefn = OGR_Fld_Create( mEncoding->fromUnicode( iter.key() ).data(), OFTInteger ); + OGRFieldType type; - if ( *iter == "Integer" ) + switch ( iter->type() ) { - OGR_Fld_SetType( fielddefn, OFTInteger ); - OGR_Fld_SetWidth( fielddefn, 10 ); - } - else if ( *iter == "Real" ) - { - OGR_Fld_SetType( fielddefn, OFTReal ); - } - else if ( *iter == "String" ) - { - OGR_Fld_SetType( fielddefn, OFTString ); - } - else - { - QgsLogger::warning( QString( "QgsOgrProvider::addAttributes, type %1 not found" ).arg( *iter ) ); - returnvalue = false; - continue; + case QVariant::Int: + type = OFTInteger; + break; + case QVariant::Double: + type = OFTReal; + break; + case QVariant::String: + type = OFTString; + break; + default: + QgsLogger::warning( QString( "QgsOgrProvider::addAttributes, type %1 not found" ).arg( iter->typeName() ) ); + returnvalue = false; + continue; } + OGRFieldDefnH fielddefn = OGR_Fld_Create( mEncoding->fromUnicode( iter->name() ).data(), type ); + OGR_Fld_SetWidth( fielddefn, iter->length() ); + OGR_Fld_SetPrecision( fielddefn, iter->precision() ); + if ( OGR_L_CreateField( ogrLayer, fielddefn, TRUE ) != OGRERR_NONE ) { QgsLogger::warning( "QgsOgrProvider.cpp: writing of field failed" ); diff --git a/src/providers/ogr/qgsogrprovider.h b/src/providers/ogr/qgsogrprovider.h index c8f368a9d2c..dea34924114 100644 --- a/src/providers/ogr/qgsogrprovider.h +++ b/src/providers/ogr/qgsogrprovider.h @@ -133,7 +133,7 @@ class QgsOgrProvider : public QgsVectorDataProvider virtual bool deleteFeatures( const QgsFeatureIds & id ); /**Adds new attributess. Unfortunately not supported for layers with features in it*/ - virtual bool addAttributes( const QgsNewAttributesMap & attributes ); + virtual bool addAttributes( const QList &attributes ); /**Changes attribute values of existing features */ virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ); diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index 4c525743fd5..f8b655bbb55 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -224,11 +224,23 @@ QgsPostgresProvider::QgsPostgresProvider( QString const & uri ) #endif //fill type names into sets - mSupportedNativeTypes.insert( "double precision", QVariant::Double ); - mSupportedNativeTypes.insert( "int4", QVariant::Int ); - mSupportedNativeTypes.insert( "int8", QVariant::LongLong ); - mSupportedNativeTypes.insert( "text", QVariant::String ); - mSupportedNativeTypes.insert( "varchar(30)", QVariant::String ); + mNativeTypes + // integer types + << QgsVectorDataProvider::NativeType( tr( "smallint (16bit)" ), "int2", QVariant::Int ) + << QgsVectorDataProvider::NativeType( tr( "integer (32bit)" ), "int4", QVariant::Int ) + << QgsVectorDataProvider::NativeType( tr( "integer (64bit)" ), "int8", QVariant::LongLong ) + << QgsVectorDataProvider::NativeType( tr( "numeric" ), "numeric", QVariant::LongLong, 1, 20, 0, 20 ) + << QgsVectorDataProvider::NativeType( tr( "decimal" ), "decimal", QVariant::LongLong, 1, 20, 0, 20 ) + + // floating point + << QgsVectorDataProvider::NativeType( tr( "real" ), "real", QVariant::Double ) + << QgsVectorDataProvider::NativeType( tr( "double" ), "double precision", QVariant::Double ) + + // string types + << QgsVectorDataProvider::NativeType( tr( "char" ), "char", QVariant::String, 1, 255 ) + << QgsVectorDataProvider::NativeType( tr( "varchar" ), "varchar", QVariant::String, 1, 255 ) + << QgsVectorDataProvider::NativeType( tr( "text" ), "text", QVariant::String ) + ; if ( primaryKey.isEmpty() ) { @@ -875,9 +887,13 @@ void QgsPostgresProvider::loadFields() if ( fieldTypeName == "int8" ) fieldType = QVariant::LongLong; - else if ( fieldTypeName.startsWith( "int" ) || fieldTypeName == "serial" ) + else if ( fieldTypeName.startsWith( "int" ) || + fieldTypeName == "serial" ) fieldType = QVariant::Int; - else if ( fieldTypeName == "real" || fieldTypeName == "double precision" || fieldTypeName.startsWith( "float" ) || fieldTypeName == "numeric" ) + else if ( fieldTypeName == "real" || + fieldTypeName == "double precision" || + fieldTypeName.startsWith( "float" ) || + fieldTypeName == "numeric" ) fieldType = QVariant::Double; else if ( fieldTypeName == "text" || fieldTypeName == "char" || @@ -1828,15 +1844,19 @@ QByteArray QgsPostgresProvider::paramValue( QString fieldValue, const QString &d if ( fieldValue == defaultValue && !defaultValue.isNull() ) { - Result result = connectionRO->PQexec( QString( "select %1" ).arg( defaultValue ) ); + PGresult *result = connectionRW->PQexec( QString( "select %1" ).arg( defaultValue ) ); + if ( PQresultStatus( result ) == PGRES_FATAL_ERROR ) + throw PGException( result ); + if ( PQgetisnull( result, 0, 0 ) ) { + PQclear( result ); return QByteArray( 0 ); // QByteArray(0).isNull() is true } else { - QString val = QString::fromUtf8( PQgetvalue( result, 0, 0 ) ); - return val.toUtf8(); + PQclear( result ); + return QString::fromUtf8( PQgetvalue( result, 0, 0 ) ).toUtf8(); } } @@ -2060,7 +2080,7 @@ bool QgsPostgresProvider::deleteFeatures( const QgsFeatureIds & id ) return returnvalue; } -bool QgsPostgresProvider::addAttributes( const QgsNewAttributesMap & name ) +bool QgsPostgresProvider::addAttributes( const QList &attributes ) { bool returnvalue = true; @@ -2071,12 +2091,22 @@ bool QgsPostgresProvider::addAttributes( const QgsNewAttributesMap & name ) { connectionRW->PQexecNR( "BEGIN" ); - for ( QgsNewAttributesMap::const_iterator iter = name.begin();iter != name.end();++iter ) + for ( QList::const_iterator iter = attributes.begin();iter != attributes.end();++iter ) { + QString type = iter->typeName(); + if ( type == "char" || type == "varchar" ) + { + type = QString( "%1(%2)" ).arg( type ).arg( iter->length() ); + } + else if ( type == "numeric" || type == "decimal" ) + { + type = QString( "%1(%2,%3)" ).arg( type ).arg( iter->length() ).arg( iter->precision() ); + } + QString sql = QString( "ALTER TABLE %1 ADD COLUMN %2 %3" ) .arg( mSchemaTableName ) - .arg( quotedIdentifier( iter.key() ) ) - .arg( iter.value() ); + .arg( quotedIdentifier( iter->name() ) ) + .arg( type ); QgsDebugMsg( sql ); //send sql statement and do error handling @@ -2084,6 +2114,18 @@ bool QgsPostgresProvider::addAttributes( const QgsNewAttributesMap & name ) if ( result == 0 || PQresultStatus( result ) == PGRES_FATAL_ERROR ) throw PGException( result ); PQclear( result ); + + if ( !iter->comment().isEmpty() ) + { + sql = QString( "COMMENT ON COLUMN %1.%2 IS %3" ) + .arg( mSchemaTableName ) + .arg( quotedIdentifier( iter->name() ) ) + .arg( quotedValue( iter->comment() ) ); + result = connectionRW->PQexec( sql ); + if ( result == 0 || PQresultStatus( result ) == PGRES_FATAL_ERROR ) + throw PGException( result ); + PQclear( result ); + } } connectionRW->PQexecNR( "COMMIT" ); diff --git a/src/providers/postgres/qgspostgresprovider.h b/src/providers/postgres/qgspostgresprovider.h index 98005980ef1..4ae837af341 100644 --- a/src/providers/postgres/qgspostgresprovider.h +++ b/src/providers/postgres/qgspostgresprovider.h @@ -215,7 +215,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider /**Adds new attributes @param name map with attribute name as key and type as value @return true in case of success and false in case of failure*/ - bool addAttributes( const QgsNewAttributesMap & name ); + bool addAttributes( const QList &attributes ); /**Deletes existing attributes @param names of the attributes to delete diff --git a/src/providers/spatialite/qgsspatialiteprovider.cpp b/src/providers/spatialite/qgsspatialiteprovider.cpp index 088f83df11d..1b3b7bfec1f 100644 --- a/src/providers/spatialite/qgsspatialiteprovider.cpp +++ b/src/providers/spatialite/qgsspatialiteprovider.cpp @@ -42,7 +42,7 @@ const QString SPATIALITE_DESCRIPTION = "SpatiaLite data provider"; QMap < QString, QgsSpatiaLiteProvider::SqliteHandles * >QgsSpatiaLiteProvider::SqliteHandles::handles; QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri ): QgsVectorDataProvider( uri ), - geomType( QGis::WKBUnknown ), mSrid( -1 ), spatialIndexRTree( false ), sqliteHandle( NULL ), spatialIndexMbrCache( false ), sqliteStatement( NULL ) + geomType( QGis::WKBUnknown ), sqliteHandle( NULL ), sqliteStatement( NULL ), mSrid( -1 ), spatialIndexRTree( false ), spatialIndexMbrCache( false ) { QgsDataSourceURI mUri = QgsDataSourceURI( uri ); @@ -107,10 +107,12 @@ QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri ): QgsVectorDat return; } //fill type names into sets - mSupportedNativeTypes.insert( "SQLITE_BLOB", QVariant::ByteArray ); - mSupportedNativeTypes.insert( "SQLITE_TEXT", QVariant::String ); - mSupportedNativeTypes.insert( "SQLITE_FLOAT", QVariant::Double ); - mSupportedNativeTypes.insert( "SQLITE_INTEGER", QVariant::LongLong ); + mNativeTypes + << QgsVectorDataProvider::NativeType( tr( "BLOB" ), "SQLITE_BLOB", QVariant::ByteArray ) + << QgsVectorDataProvider::NativeType( tr( "Text" ), "SQLITE_TEXT", QVariant::String ) + << QgsVectorDataProvider::NativeType( tr( "Double" ), "SQLITE_FLOAT", QVariant::Double, 0, 20, 0, 20 ) + << QgsVectorDataProvider::NativeType( tr( "Integer" ), "SQLITE_INTEGER", QVariant::LongLong, 0, 20 ) + ; } QgsSpatiaLiteProvider::~QgsSpatiaLiteProvider() @@ -175,7 +177,7 @@ void QgsSpatiaLiteProvider::loadFields() fieldType = QVariant::Double; } - attributeFields.insert( i - 1, QgsField( name, fieldType, type, 0, 0, tr( "" ) ) ); + attributeFields.insert( i - 1, QgsField( name, fieldType, type, 0, 0, "" ) ); } } } @@ -1096,7 +1098,7 @@ abort: return false; } -bool QgsSpatiaLiteProvider::addAttributes( const QgsNewAttributesMap & name ) +bool QgsSpatiaLiteProvider::addAttributes( const QList &attributes ) { char *errMsg = NULL; bool toCommit = false; @@ -1112,9 +1114,12 @@ bool QgsSpatiaLiteProvider::addAttributes( const QgsNewAttributesMap & name ) } toCommit = true; - for ( QgsNewAttributesMap::const_iterator iter = name.begin(); iter != name.end(); ++iter ) + for ( QList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter ) { - sql = QString( "ALTER TABLE %1 ADD COLUMN %2 %3" ).arg( quotedValue( mTableName ) ).arg( quotedValue( iter.key() ) ).arg( iter.value() ); + sql = QString( "ALTER TABLE %1 ADD COLUMN %2 %3" ) + .arg( quotedValue( mTableName ) ) + .arg( quotedValue( iter->name() ) ) + .arg( iter->typeName() ); strcpy( xSql, sql.toUtf8().constData() ); ret = sqlite3_exec( sqliteHandle, xSql, NULL, NULL, &errMsg ); if ( ret != SQLITE_OK ) diff --git a/src/providers/spatialite/qgsspatialiteprovider.h b/src/providers/spatialite/qgsspatialiteprovider.h index 309e38566de..3e9f7ab6ece 100644 --- a/src/providers/spatialite/qgsspatialiteprovider.h +++ b/src/providers/spatialite/qgsspatialiteprovider.h @@ -168,7 +168,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider /**Adds new attributes @param name map with attribute name as key and type as value @return true in case of success and false in case of failure*/ - bool addAttributes( const QgsNewAttributesMap & name ); + bool addAttributes( const QList &attributes ); /**Changes attribute values of existing features @param attr_map a map containing the new attributes. The integer is the feature id, diff --git a/src/ui/qgsaddattrdialogbase.ui b/src/ui/qgsaddattrdialogbase.ui index 3ac17317bcd..03567483bf8 100644 --- a/src/ui/qgsaddattrdialogbase.ui +++ b/src/ui/qgsaddattrdialogbase.ui @@ -1,57 +1,107 @@ - + + QgsAddAttrDialogBase - - + + 0 0 - 312 - 132 + 356 + 207 - + Add Attribute - + true - - - - + + + + Name: - + mNameEdit - - + + - - - + + + + Comment: + + + mCommentEdit + + + + + + + + + Type: - + mTypeBox - - + + - - - - QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + Type: + + + mTypeBox + + + + + + + Width + + + mLength + + + + + + + + + + Precision + + + mPrec + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok - + mNameEdit mTypeBox @@ -64,11 +114,11 @@ QgsAddAttrDialogBase accept() - + 260 109 - + 307 68 @@ -80,11 +130,11 @@ QgsAddAttrDialogBase reject() - + 196 106 - + 6 77