- 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
This commit is contained in:
jef 2009-05-30 17:48:49 +00:00
parent d8b93214e8
commit 3e01e6d3d5
19 changed files with 342 additions and 167 deletions

View File

@ -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<QString, QString> & attributes);
virtual bool addAttributes(const QList<QgsField> & attributes);
/**
* Deletes existing attributes
@ -231,9 +231,12 @@ class QgsVectorDataProvider : QgsDataProvider
*/
QList<int> attributeIndexes();
/**Returns the names of the numerical types*/
const QMap<QString,QVariant::Type> &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

View File

@ -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);

View File

@ -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<int>( 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<QString>& 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<QString>::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() );
}

View File

@ -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<QString>& 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;
};

View File

@ -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()

View File

@ -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

View File

@ -78,7 +78,7 @@ bool QgsVectorDataProvider::deleteFeatures( const QgsFeatureIds & id )
return false;
}
bool QgsVectorDataProvider::addAttributes( const QgsNewAttributesMap & attributes )
bool QgsVectorDataProvider::addAttributes( const QList<QgsField> & 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 ) )

View File

@ -29,9 +29,6 @@ class QTextCodec;
#include "qgsvectorlayer.h"
#include "qgsfield.h"
typedef QMap<QString, QString> QgsNewAttributesMap;
typedef QMap<QString, QVariant::Type> 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<QgsField> &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

View File

@ -172,9 +172,9 @@ QgsVectorLayer::~QgsVectorLayer()
//delete remaining overlays
QList<QgsVectorOverlay*>::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<QgsPoint>& 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<QgsField> 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." );

View File

@ -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 );

View File

@ -271,30 +271,26 @@ bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds & id )
return TRUE;
}
bool QgsMemoryProvider::addAttributes( const QgsNewAttributesMap & attributes )
bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
{
for ( QgsNewAttributesMap::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
for ( QList<QgsField>::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;
}

View File

@ -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<QgsField> &attributes );
/**
* Deletes existing attributes

View File

@ -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<QgsField> &attributes )
{
bool returnvalue = true;
for ( QgsNewAttributesMap::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
for ( QList<QgsField>::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" );

View File

@ -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<QgsField> &attributes );
/**Changes attribute values of existing features */
virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map );

View File

@ -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<QgsField> &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<QgsField>::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" );

View File

@ -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<QgsField> &attributes );
/**Deletes existing attributes
@param names of the attributes to delete

View File

@ -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<QgsField> &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<QgsField>::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 )

View File

@ -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<QgsField> &attributes );
/**Changes attribute values of existing features
@param attr_map a map containing the new attributes. The integer is the feature id,

View File

@ -1,57 +1,107 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsAddAttrDialogBase</class>
<widget class="QDialog" name="QgsAddAttrDialogBase" >
<property name="geometry" >
<widget class="QDialog" name="QgsAddAttrDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>312</width>
<height>132</height>
<width>356</width>
<height>207</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Add Attribute</string>
</property>
<property name="modal" >
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="textLabel1" >
<property name="text" >
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>Name:</string>
</property>
<property name="buddy" >
<property name="buddy">
<cstring>mNameEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="mNameEdit" />
<item row="0" column="1">
<widget class="QLineEdit" name="mNameEdit"/>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="textLabel2" >
<property name="text" >
<item row="1" column="0">
<widget class="QLabel" name="textLabel1_2">
<property name="text">
<string>Comment:</string>
</property>
<property name="buddy">
<cstring>mCommentEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="mCommentEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="textLabel2">
<property name="text">
<string>Type:</string>
</property>
<property name="buddy" >
<property name="buddy">
<cstring>mTypeBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QComboBox" name="mTypeBox" />
<item row="2" column="1">
<widget class="QComboBox" name="mTypeBox"/>
</item>
<item row="2" column="0" colspan="2" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
<item row="3" column="1">
<widget class="QLabel" name="mTypeName">
<property name="text">
<string>Type:</string>
</property>
<property name="buddy">
<cstring>mTypeBox</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="textLabel2_2">
<property name="text">
<string>Width</string>
</property>
<property name="buddy">
<cstring>mLength</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="mLength"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="textLabel2_3">
<property name="text">
<string>Precision</string>
</property>
<property name="buddy">
<cstring>mPrec</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="mPrec"/>
</item>
<item row="6" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11" />
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>mNameEdit</tabstop>
<tabstop>mTypeBox</tabstop>
@ -64,11 +114,11 @@
<receiver>QgsAddAttrDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>260</x>
<y>109</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>307</x>
<y>68</y>
</hint>
@ -80,11 +130,11 @@
<receiver>QgsAddAttrDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>196</x>
<y>106</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>6</x>
<y>77</y>
</hint>