[FEATURE] attribute editing extension

- allow resetting of fields to NULL by button
- use user defined date formats in forms, identify results and attribute table
- add support for date type in postgres provider
This commit is contained in:
Juergen E. Fischer 2013-03-13 23:30:14 +01:00
parent 93e0259843
commit 2c4ac0807b
16 changed files with 207 additions and 41 deletions

View File

@ -6,7 +6,7 @@ class QgsFieldValidator : QValidator
%End
public:
QgsFieldValidator( QObject *parent, const QgsField &field );
QgsFieldValidator( QObject *parent, const QgsField &field, QString dateFormat = "yyyy-MM-dd" );
~QgsFieldValidator();
virtual State validate( QString &, int & ) const;

View File

@ -79,6 +79,11 @@ QgsVectorLayer::ValueRelationData QgsAttributeTypeDialog::valueRelationData()
return mValueRelationData;
}
QString QgsAttributeTypeDialog::dateFormat()
{
return mDateFormat;
}
QMap<QString, QVariant> &QgsAttributeTypeDialog::valueMap()
{
return mValueMap;
@ -89,7 +94,7 @@ bool QgsAttributeTypeDialog::fieldEditable()
return isFieldEditableCheckBox->isChecked();
}
void QgsAttributeTypeDialog::setFieldEditable(bool editable)
void QgsAttributeTypeDialog::setFieldEditable( bool editable )
{
isFieldEditableCheckBox->setChecked( editable );
}
@ -338,6 +343,11 @@ void QgsAttributeTypeDialog::setValueRelation( QgsVectorLayer::ValueRelationData
mValueRelationData = valueRelation;
}
void QgsAttributeTypeDialog::setDateFormat( QString dateFormat )
{
mDateFormat = dateFormat;
}
void QgsAttributeTypeDialog::setIndex( int index, QgsVectorLayer::EditType editType )
{
mIndex = index;
@ -446,6 +456,7 @@ void QgsAttributeTypeDialog::setIndex( int index, QgsVectorLayer::EditType editT
maximumDoubleSpinBox->setValue( mRangeData.mMax.toDouble() );
stepDoubleSpinBox->setValue( mRangeData.mStep.toDouble() );
}
if ( editType == QgsVectorLayer::EditRange )
{
rangeWidget->setCurrentIndex( 0 );
@ -475,6 +486,10 @@ void QgsAttributeTypeDialog::setIndex( int index, QgsVectorLayer::EditType editT
valueRelationFilterExpression->setText( mValueRelationData.mFilterExpression );
break;
case QgsVectorLayer::Calendar:
leDateFormat->setText( mDateFormat );
break;
case QgsVectorLayer::LineEdit:
case QgsVectorLayer::UniqueValues:
case QgsVectorLayer::Classification:
@ -484,13 +499,11 @@ void QgsAttributeTypeDialog::setIndex( int index, QgsVectorLayer::EditType editT
case QgsVectorLayer::Immutable:
case QgsVectorLayer::Hidden:
case QgsVectorLayer::TextEdit:
case QgsVectorLayer::Calendar:
case QgsVectorLayer::UuidGenerator:
break;
}
}
void QgsAttributeTypeDialog::setPage( int index )
{
selectionListWidget->setCurrentRow( index );
@ -639,6 +652,7 @@ void QgsAttributeTypeDialog::accept()
break;
case 11:
mEditType = QgsVectorLayer::Calendar;
mDateFormat = leDateFormat->text();
break;
case 12:
mEditType = QgsVectorLayer::ValueRelation;

View File

@ -82,6 +82,12 @@ class QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog
*/
void setValueRelation( QgsVectorLayer::ValueRelationData valueRelationData );
/**
* Setter to date format
* @param dateFormat date format
*/
void setDateFormat( QString dateFormat );
/**
* Setter for checkbox for editable state of field
* @param bool editable
@ -111,6 +117,11 @@ class QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog
*/
QgsVectorLayer::ValueRelationData valueRelationData();
/**
* Getter for date format
*/
QString dateFormat();
/**
* Getter for checkbox for editable state of field
*/
@ -181,6 +192,7 @@ class QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog
QgsVectorLayer::RangeData mRangeData;
QgsVectorLayer::ValueRelationData mValueRelationData;
QgsVectorLayer::EditType mEditType;
QString mDateFormat;
};
#endif

View File

@ -487,6 +487,8 @@ void QgsFieldsProperties::attributeTypeDialog()
QPair<QString, QString> checkStates = mCheckedStates.value( index, mLayer->checkedState( index ) );
attributeTypeDialog.setCheckedState( checkStates.first, checkStates.second );
attributeTypeDialog.setDateFormat( mLayer->dateFormat( index ) );
attributeTypeDialog.setIndex( index, mEditTypeMap.value( index, mLayer->editType( index ) ) );
attributeTypeDialog.setFieldEditable( mLayer->fieldEditable( index ) );
@ -517,6 +519,9 @@ void QgsFieldsProperties::attributeTypeDialog()
case QgsVectorLayer::ValueRelation:
mValueRelationData.insert( index, attributeTypeDialog.valueRelationData() );
break;
case QgsVectorLayer::Calendar:
mDateFormat.insert( index, attributeTypeDialog.dateFormat() );
break;
case QgsVectorLayer::LineEdit:
case QgsVectorLayer::TextEdit:
case QgsVectorLayer::UniqueValues:
@ -526,7 +531,6 @@ void QgsFieldsProperties::attributeTypeDialog()
case QgsVectorLayer::Enumeration:
case QgsVectorLayer::Immutable:
case QgsVectorLayer::Hidden:
case QgsVectorLayer::Calendar:
case QgsVectorLayer::UuidGenerator:
break;
}
@ -820,7 +824,7 @@ void QgsFieldsProperties::apply()
QgsVectorLayer::EditType editType = editTypeFromButtonText( pb->text() );
mLayer->setEditType( idx, editType );
mLayer->setFieldEditable( idx, mFieldEditables.value( idx, true ));
mLayer->setFieldEditable( idx, mFieldEditables.value( idx, true ) );
switch ( editType )
{
@ -856,6 +860,13 @@ void QgsFieldsProperties::apply()
}
break;
case QgsVectorLayer::Calendar:
if ( mDateFormat.contains( idx ) )
{
mLayer->dateFormat( idx ) = mDateFormat[idx];
}
break;
case QgsVectorLayer::LineEdit:
case QgsVectorLayer::UniqueValues:
case QgsVectorLayer::UniqueValuesEditable:
@ -865,7 +876,6 @@ void QgsFieldsProperties::apply()
case QgsVectorLayer::Immutable:
case QgsVectorLayer::Hidden:
case QgsVectorLayer::TextEdit:
case QgsVectorLayer::Calendar:
case QgsVectorLayer::UuidGenerator:
break;
}

View File

@ -130,6 +130,7 @@ class QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPropertiesBase
QMap<int, QPair<QString, QString> > mCheckedStates;
QMap<int, QgsVectorLayer::EditType> mEditTypeMap;
QMap<int, QPushButton*> mButtonMap;
QMap<int, QString> mDateFormat;
enum attrColumns
{

View File

@ -361,6 +361,11 @@ void QgsIdentifyResultsDialog::addFeature( QgsVectorLayer *vlayer, const QgsFeat
value = vlayer->valueMap( i ).key( value.toString(), QString( "(%1)" ).arg( value.toString() ) );
break;
case QgsVectorLayer::Calendar:
if ( value.canConvert( QVariant::Date ) )
value = value.toDate().toString( vlayer->dateFormat( i ) );
break;
default:
break;
}

View File

@ -2678,13 +2678,16 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
}
break;
case Calendar:
mDateFormats[ name ] = editTypeElement.attribute( "dateFormat" );
break;
case Classification:
case FileName:
case Immutable:
case Hidden:
case LineEdit:
case TextEdit:
case Calendar:
case Enumeration:
case UniqueValues:
case UniqueValuesEditable:
@ -2988,6 +2991,10 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
}
break;
case Calendar:
editTypeElement.setAttribute( "dateFormat", mDateFormats[ it.key()] );
break;
case LineEdit:
case UniqueValues:
case UniqueValuesEditable:
@ -2995,7 +3002,6 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
case FileName:
case Hidden:
case TextEdit:
case Calendar:
case Enumeration:
case Immutable:
case UuidGenerator:
@ -3898,6 +3904,18 @@ QgsVectorLayer::RangeData &QgsVectorLayer::range( int idx )
return mRanges[fieldName];
}
QString &QgsVectorLayer::dateFormat( int idx )
{
const QgsFields &fields = pendingFields();
QString fieldName = fields[idx].name();
if ( !mDateFormats.contains( fieldName ) )
mDateFormats[fieldName] = "yyyy-MM-dd";
return mDateFormats[fieldName];
}
bool QgsVectorLayer::fieldEditable( int idx )
{
const QgsFields &fields = pendingFields();

View File

@ -767,6 +767,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
**/
ValueRelationData &valueRelation( int idx );
/**access date format
* @note added in 1.9
*/
QString &dateFormat( int idx );
/**is edit widget editable
* @note added in 1.9
**/
@ -1074,6 +1079,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
QMap< QString, RangeData > mRanges;
QMap< QString, QPair<QString, QString> > mCheckedStates;
QMap< QString, ValueRelationData > mValueRelations;
QMap< QString, QString> mDateFormats;
/** Defines the default layout to use for the attribute editor (Drag and drop, UI File, Generated) */
EditorLayout mEditorLayout;

View File

@ -643,11 +643,20 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
}
}
if ( role == Qt::DisplayRole && mValueMaps.contains( fieldId ) )
if ( role == Qt::DisplayRole )
{
return mValueMaps[ fieldId ]->key( val.toString(), QString( "(%1)" ).arg( val.toString() ) );
if ( mValueMaps.contains( fieldId ) )
{
return mValueMaps[ fieldId ]->key( val.toString(), QString( "(%1)" ).arg( val.toString() ) );
}
if ( mLayer->editType( fieldId ) == QgsVectorLayer::Calendar && val.canConvert( QVariant::Date ) )
{
return val.toDate().toString( mLayer->dateFormat( fieldId ) );
}
}
return val.toString();
}

View File

@ -26,6 +26,7 @@
#include <qgsmaplayerregistry.h>
#include <qgslogger.h>
#include <qgsexpression.h>
#include <qgsfilterlineedit.h>
#include <QScrollArea>
#include <QPushButton>
@ -87,8 +88,12 @@ void QgsAttributeEditor::selectDate()
dlg->setWindowTitle( tr( "Select a date" ) );
QVBoxLayout *vl = new QVBoxLayout( dlg );
const QgsFieldValidator *v = dynamic_cast<const QgsFieldValidator *>( le->validator() );
QString dateFormat = v ? v->dateFormat() : "yyyy-MM-dd";
QCalendarWidget *cw = new QCalendarWidget( dlg );
cw->setSelectedDate( QDate::fromString( le->text(), Qt::ISODate ) );
QString prevValue = le->text();
cw->setSelectedDate( QDate::fromString( prevValue, dateFormat ) );
vl->addWidget( cw );
QDialogButtonBox *buttonBox = new QDialogButtonBox( dlg );
@ -101,7 +106,9 @@ void QgsAttributeEditor::selectDate()
if ( dlg->exec() == QDialog::Accepted )
{
le->setText( cw->selectedDate().toString( Qt::ISODate ) );
QString newValue = cw->selectedDate().toString( dateFormat );
le->setText( newValue );
le->setModified( newValue != prevValue );
}
}
@ -483,7 +490,7 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
}
else
{
le = new QLineEdit( parent );
le = new QgsFilterLineEdit( parent );
}
if ( le )
@ -507,7 +514,7 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
le->setReadOnly( true );
}
le->setValidator( new QgsFieldValidator( le, field ) );
le->setValidator( new QgsFieldValidator( le, field, vl->dateFormat( idx ) ) );
myWidget = le;
}
@ -526,13 +533,13 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
if ( cb )
{
if ( cb->isEditable() )
cb->setValidator( new QgsFieldValidator( cb, field ) );
cb->setValidator( new QgsFieldValidator( cb, field, vl->dateFormat( idx ) ) );
myWidget = cb;
}
if ( myWidget )
{
if (editType == QgsVectorLayer::Immutable)
if ( editType == QgsVectorLayer::Immutable )
myWidget->setDisabled( true );
QgsStringRelay* relay = NULL;
@ -611,7 +618,7 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
}
else
{
le = new QLineEdit();
le = new QgsFilterLineEdit();
pb = new QPushButton( tr( "..." ) );
@ -625,6 +632,9 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
myWidget->setLayout( hbl );
}
if ( le )
le->setValidator( new QgsFieldValidator( le, field, vl->dateFormat( idx ) ) );
if ( pb )
{
if ( editType == QgsVectorLayer::FileName )
@ -783,7 +793,7 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int
QCalendarWidget *cw = qobject_cast<QCalendarWidget *>( widget );
if ( cw )
{
text = cw->selectedDate().toString( Qt::ISODate );
text = cw->selectedDate().toString( vl->dateFormat( idx ) );
}
le = widget->findChild<QLineEdit *>();
@ -792,6 +802,11 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int
if ( !cw && !gb && le )
{
text = le->text();
modified = le->isModified();
if ( text == nullValue )
{
text = QString::null;
}
}
switch ( theField.type() )
@ -842,7 +857,7 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int
break;
case QVariant::Date:
{
QDate myDateValue = QDate::fromString( text, Qt::ISODate );
QDate myDateValue = QDate::fromString( text, vl->dateFormat( idx ) );
if ( myDateValue.isValid() && !text.isEmpty() )
{
value = myDateValue;
@ -856,7 +871,10 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int
break;
default: //string
modified = true;
value = QVariant( text );
if ( text.isNull() )
value = QVariant();
else
value = QVariant( text );
break;
}
@ -957,8 +975,9 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx,
case QgsVectorLayer::UniqueValuesEditable:
case QgsVectorLayer::Immutable:
case QgsVectorLayer::UuidGenerator:
default:
case QgsVectorLayer::TextEdit:
{
QgsFilterLineEdit *fle = qobject_cast<QgsFilterLineEdit *>( editor );
QLineEdit *le = qobject_cast<QLineEdit *>( editor );
QComboBox *cb = qobject_cast<QComboBox *>( editor );
QTextEdit *te = qobject_cast<QTextEdit *>( editor );
@ -966,10 +985,15 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx,
if ( !le && ! cb && !te && !pte )
return false;
if ( fle && !( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date ) )
{
fle->setNullValue( nullValue );
}
QString text;
if ( value.isNull() )
{
if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong )
if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date )
text = "";
else if ( editType == QgsVectorLayer::UuidGenerator )
text = QUuid::createUuid().toString();
@ -1002,18 +1026,47 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx,
break;
}
QLineEdit* le = qobject_cast<QLineEdit*>( editor );
QgsFilterLineEdit *fle = qobject_cast<QgsFilterLineEdit*>( editor );
QLineEdit *le = qobject_cast<QLineEdit*>( editor );
if ( !le )
{
le = editor->findChild<QLineEdit *>();
fle = qobject_cast<QgsFilterLineEdit *>( le );
}
if ( !le )
{
return false;
}
le->setText( value.toString() );
if ( fle && !( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date ) )
{
fle->setNullValue( nullValue );
}
QString text;
if ( value.isNull() )
{
if ( myFieldType == QVariant::Int || myFieldType == QVariant::Double || myFieldType == QVariant::LongLong || myFieldType == QVariant::Date )
text = "";
else
text = nullValue;
}
else if ( editType == QgsVectorLayer::Calendar && value.canConvert( QVariant::Date ) )
{
text = value.toDate().toString( vl->dateFormat( idx ) );
}
else
{
text = value.toString();
}
le->setText( text );
}
break;
case QgsVectorLayer::Hidden:
break;
}
return true;
@ -1030,7 +1083,6 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( widgetDef );
newWidget = createAttributeEditor( parent, 0, vl, fieldDef->idx(), attrs.value( fieldDef->idx(), QVariant() ), proxyWidgets );
if ( vl->editType( fieldDef->idx() ) != QgsVectorLayer::Immutable )
{
newWidget->setEnabled( newWidget->isEnabled() && vl->isEditable() );

View File

@ -29,9 +29,10 @@
#include "qgslonglongvalidator.h"
#include "qgsfield.h"
QgsFieldValidator::QgsFieldValidator( QObject *parent, const QgsField &field )
QgsFieldValidator::QgsFieldValidator( QObject *parent, const QgsField &field, QString dateFormat )
: QValidator( parent )
, mField( field )
, mDateFormat( dateFormat )
{
switch ( mField.type() )
{
@ -128,7 +129,7 @@ QValidator::State QgsFieldValidator::validate( QString &s, int &i ) const
}
else if ( mField.type() == QVariant::Date )
{
return QDate::fromString( s ).isValid() ? Acceptable : Intermediate;
return QDate::fromString( s, mDateFormat ).isValid() ? Acceptable : Intermediate;
}
else
{

View File

@ -31,12 +31,14 @@ class GUI_EXPORT QgsFieldValidator : public QValidator
Q_OBJECT
public:
QgsFieldValidator( QObject *parent, const QgsField &field );
QgsFieldValidator( QObject *parent, const QgsField &field, QString dateFormat );
~QgsFieldValidator();
virtual State validate( QString &, int & ) const;
virtual void fixup( QString & ) const;
QString dateFormat() const { return mDateFormat; }
private:
// Disables copy constructing
Q_DISABLE_COPY( QgsFieldValidator )
@ -44,6 +46,7 @@ class GUI_EXPORT QgsFieldValidator : public QValidator
QValidator *mValidator;
QgsField mField;
QString mNullValue;
QString mDateFormat;
};
#endif // QGSFIELDVALIDATOR_H

View File

@ -21,7 +21,9 @@
#include <QToolButton>
#include <QStyle>
QgsFilterLineEdit::QgsFilterLineEdit( QWidget* parent ) : QLineEdit( parent )
QgsFilterLineEdit::QgsFilterLineEdit( QWidget* parent, QString nullValue )
: QLineEdit( parent )
, mNullValue( nullValue )
{
btnClear = new QToolButton( this );
btnClear->setIcon( QgsApplication::getThemeIcon( "/mIconClear.png" ) );
@ -51,7 +53,13 @@ void QgsFilterLineEdit::resizeEvent( QResizeEvent * )
( rect().bottom() + 1 - sz.height() ) / 2 );
}
void QgsFilterLineEdit::clear()
{
setText( mNullValue );
setModified( true );
}
void QgsFilterLineEdit::toggleClearButton( const QString &text )
{
btnClear->setVisible( !text.isEmpty() );
btnClear->setVisible( !isReadOnly() && text != mNullValue );
}

View File

@ -29,7 +29,9 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
{
Q_OBJECT
public:
QgsFilterLineEdit( QWidget* parent = 0 );
QgsFilterLineEdit( QWidget* parent = 0, QString nullValue = QString::null );
void setNullValue( QString nullValue ) { mNullValue = nullValue; }
signals:
void cleared();
@ -38,9 +40,11 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
void resizeEvent( QResizeEvent * );
private slots:
void clear();
void toggleClearButton( const QString &text );
private:
QString mNullValue;
QToolButton *btnClear;
};

View File

@ -168,6 +168,9 @@ QgsPostgresProvider::QgsPostgresProvider( QString const & uri )
<< QgsVectorDataProvider::NativeType( tr( "Text, fixed length (char)" ), "char", QVariant::String, 1, 255 )
<< QgsVectorDataProvider::NativeType( tr( "Text, limited variable length (varchar)" ), "varchar", QVariant::String, 1, 255 )
<< QgsVectorDataProvider::NativeType( tr( "Text, unlimited length (text)" ), "text", QVariant::String )
// date type
<< QgsVectorDataProvider::NativeType( tr( "Date" ), "date", QVariant::Date )
;
QString key;
@ -708,6 +711,11 @@ bool QgsPostgresProvider::loadFields()
fieldSize = -1;
}
}
else if ( fieldTypeName == "date" )
{
fieldType = QVariant::Date;
fieldSize = -1;
}
else if ( fieldTypeName == "text" ||
fieldTypeName == "bpchar" ||
fieldTypeName == "bool" ||
@ -2777,6 +2785,11 @@ bool QgsPostgresProvider::convertField( QgsField &field )
fieldPrec = 0;
break;
case QVariant::Date:
fieldType = "numeric";
fieldSize = -1;
break;
case QVariant::Double:
if ( fieldSize > 18 )
{

View File

@ -504,15 +504,8 @@
</layout>
</widget>
<widget class="QWidget" name="calendarPage">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>A calendar widget to enter a date.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_5">
<item row="3" column="1">
<spacer name="verticalSpacer_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -525,6 +518,23 @@
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Date format</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>A calendar widget to enter a date.</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="leDateFormat"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="valueRelationPage">