void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const { QgsVectorLayer *vl = layer( model ); if ( !vl ) return; int fieldIdx = model->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt(); QgsFeatureId fid = model->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong(); QVariant oldValue = model->data( index, Qt::EditRole ); QVariant newValue; QgsEditorWidgetWrapper *eww = QgsEditorWidgetWrapper::fromWidget( editor ); if ( !eww ) return; newValue = eww->value(); if ( ( oldValue != newValue && newValue.isValid() ) || oldValue.isNull() != newValue.isNull() ) { // This fixes https://issues.qgis.org/issues/16492 QgsFeatureRequest request( fid ); request.setFlags( QgsFeatureRequest::NoGeometry ); request.setSubsetOfAttributes( QgsAttributeList() ); QgsFeature feature; vl->getFeatures( request ).nextFeature( feature ); if ( feature.isValid() ) { vl->beginEditCommand( tr( "Attribute changed" ) ); vl->changeAttributeValue( fid, fieldIdx, newValue, oldValue ); vl->endEditCommand(); } } }
QWidget *QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const { Q_UNUSED( option ); QgsVectorLayer *vl = layer( index.model() ); if ( !vl ) return nullptr; int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt(); QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup ); QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vl, fieldIdx, nullptr, parent, context ); QWidget *w = eww->widget(); w->setAutoFillBackground( true ); w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget const int fieldOrigin = vl->fields().fieldOrigin( fieldIdx ); bool readOnly = true; if ( fieldOrigin == QgsFields::OriginJoin ) { int srcFieldIndex; const QgsVectorLayerJoinInfo *info = vl->joinBuffer()->joinForFieldIndex( fieldIdx, vl->fields(), srcFieldIndex ); if ( info && info->isEditable() ) readOnly = info->joinLayer()->editFormConfig().readOnly( srcFieldIndex ); } else readOnly = vl->editFormConfig().readOnly( fieldIdx ); eww->setEnabled( !readOnly ); return w; }
void testUpdate() { const QgsKeyValueWidgetFactory factory( QStringLiteral( "testKeyValue" ) ); QgsEditorWidgetWrapper* wrapper = factory.create( nullptr, 0, nullptr, nullptr ); QVERIFY( wrapper ); QSignalSpy spy( wrapper, SIGNAL( valueChanged( const QVariant& ) ) ); QgsKeyValueWidget* widget = qobject_cast< QgsKeyValueWidget* >( wrapper->widget() ); QVERIFY( widget ); QVariantMap initial; initial[QStringLiteral( "1" )] = "one"; initial[QStringLiteral( "2" )] = "two"; wrapper->setValue( initial ); const QVariant value = wrapper->value(); QCOMPARE( int( value.type() ), int( QVariant::Map ) ); QCOMPARE( value.toMap(), initial ); QCOMPARE( spy.count(), 0 ); QAbstractItemModel* model = widget->tableView->model(); model->setData( model->index( 0, 1 ), "hello" ); QCOMPARE( spy.count(), 1 ); QVariantMap expected = initial; expected[QStringLiteral( "1" )] = "hello"; QVariant eventValue = spy.at( 0 ).at( 0 ).value<QVariant>(); QCOMPARE( int( eventValue.type() ), int( QVariant::Map ) ); QCOMPARE( eventValue.toMap(), expected ); QCOMPARE( wrapper->value().toMap(), expected ); QCOMPARE( spy.count(), 1 ); }
void QgsAttributeTableDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const { QgsEditorWidgetWrapper* eww = QgsEditorWidgetWrapper::fromWidget( editor ); if ( !eww ) return; eww->setValue( index.model()->data( index, Qt::EditRole ) ); }
Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets ) { QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww ); if ( eww && eww->field().name() == field ) { eww->setValue( value ); } }
QWidget* QgsAttributeEditor::createAttributeEditor( QWidget* parent, QWidget* editor, QgsVectorLayer* vl, int idx, const QVariant& value, QgsAttributeEditorContext& context ) { QString widgetType = vl->editFormConfig()->widgetType( idx ); QgsEditorWidgetConfig cfg = vl->editFormConfig()->widgetConfig( idx ); QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, vl, idx, cfg, editor, parent, context ); if ( eww ) { eww->setValue( value ); return eww->widget(); } else { return 0; } }
QgsEditorWidgetWrapper* QgsEditorWidgetRegistry::create( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, const QVariantMap& config, QWidget* editor, QWidget* parent, const QgsAttributeEditorContext &context ) { if ( mWidgetFactories.contains( widgetId ) ) { QgsEditorWidgetWrapper* ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent ); if ( ww ) { ww->setConfig( config ); ww->setContext( context ); // Make sure that there is a widget created at this point // so setValue() et al won't crash ww->widget(); // If we tried to set a widget which is not supported by this wrapper if ( !ww->valid() ) { delete ww; QString wid = findSuitableWrapper( editor, QStringLiteral( "TextEdit" ) ); ww = mWidgetFactories[wid]->create( vl, fieldIdx, editor, parent ); ww->setConfig( config ); ww->setContext( context ); } return ww; } } return nullptr; }
QgsEditorWidgetWrapper* QgsEditorWidgetRegistry::create( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, QWidget* editor, QWidget* parent, const QgsAttributeEditorContext &context ) { if ( mWidgetFactories.contains( widgetId ) ) { QgsEditorWidgetWrapper* ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent ); if ( ww ) { ww->setConfig( config ); ww->setContext( context ); // Make sure that there is a widget created at this point // so setValue() et al won't crash ww->widget(); return ww; } } return 0; }
QWidget* QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const { Q_UNUSED( option ); QgsVectorLayer *vl = layer( index.model() ); if ( !vl ) return nullptr; int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt(); QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup ); QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( vl, fieldIdx, nullptr, parent, context ); QWidget* w = eww->widget(); w->setAutoFillBackground( true ); w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget eww->setEnabled( !vl->editFormConfig().readOnly( fieldIdx ) ); return w; }
QWidget* QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const { Q_UNUSED( option ); QgsVectorLayer *vl = layer( index.model() ); if ( !vl ) return nullptr; int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt(); QString widgetType = vl->editFormConfig()->widgetType( fieldIdx ); QgsEditorWidgetConfig cfg = vl->editFormConfig()->widgetConfig( fieldIdx ); QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup ); QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, vl, fieldIdx, cfg, nullptr, parent, context ); QWidget* w = eww->widget(); w->setAutoFillBackground( true ); eww->setEnabled( !vl->editFormConfig()->readOnly( fieldIdx ) ); return w; }
QWidget *QgsFormAnnotation::createDesignerWidget( const QString &filePath ) { QFile file( filePath ); if ( !file.open( QFile::ReadOnly ) ) { return nullptr; } QUiLoader loader; QFileInfo fi( file ); loader.setWorkingDirectory( fi.dir() ); QWidget *widget = loader.load( &file, nullptr ); file.close(); //get feature and set attribute information QgsAttributeEditorContext context; QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer * >( mapLayer() ); if ( vectorLayer && associatedFeature().isValid() ) { QgsFields fields = vectorLayer->fields(); QgsAttributes attrs = associatedFeature().attributes(); for ( int i = 0; i < attrs.count(); ++i ) { if ( i < fields.count() ) { QWidget *attWidget = widget->findChild<QWidget *>( fields.at( i ).name() ); if ( attWidget ) { QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vectorLayer, i, attWidget, widget, context ); if ( eww ) { eww->setValue( attrs.at( i ) ); } } } } } return widget; }
void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const { QgsVectorLayer *vl = layer( model ); if ( vl == NULL ) return; int fieldIdx = model->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt(); QgsFeatureId fid = model->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong(); QVariant oldValue = model->data( index, Qt::EditRole ); QVariant newValue; QgsEditorWidgetWrapper* eww = QgsEditorWidgetWrapper::fromWidget( editor ); if ( !eww ) return; newValue = eww->value(); if (( oldValue != newValue && newValue.isValid() ) || oldValue.isNull() != newValue.isNull() ) { vl->beginEditCommand( tr( "Attribute changed" ) ); vl->changeAttributeValue( fid, fieldIdx, newValue, oldValue ); vl->endEditCommand(); } }
void QgsMergeAttributesDialog::createTableWidgetContents() { //get information about attributes from vector layer if ( !mVectorLayer ) { return; } //combo box row, attributes titles, feature values and current merge results mTableWidget->setRowCount( mFeatureList.size() + 2 ); //create combo boxes and insert attribute names mFields = mVectorLayer->fields(); QSet<int> pkAttrList = mVectorLayer->pkAttributeList().toSet(); int col = 0; mHiddenAttributes.clear(); for ( int idx = 0; idx < mFields.count(); ++idx ) { const QgsEditorWidgetSetup setup = QgsEditorWidgetRegistry::instance()->findBest( mVectorLayer, mFields.at( idx ).name() ); if ( setup.type() == "Hidden" || setup.type() == "Immutable" ) { mHiddenAttributes.insert( idx ); continue; } mTableWidget->setColumnCount( col + 1 ); QComboBox *cb = createMergeComboBox( mFields.at( idx ).type() ); if ( pkAttrList.contains( idx ) ) { cb->setCurrentIndex( cb->findData( "skip" ) ); } mTableWidget->setCellWidget( 0, col, cb ); QTableWidgetItem *item = new QTableWidgetItem( mFields.at( idx ).name() ); item->setData( FieldIndex, idx ); mTableWidget->setHorizontalHeaderItem( col++, item ); } //insert the attribute values QStringList verticalHeaderLabels; //the id column is in the verticalHeaderLabels << tr( "Id" ); QgsAttributeEditorContext context; for ( int i = 0; i < mFeatureList.size(); ++i ) { verticalHeaderLabels << FID_TO_STRING( mFeatureList[i].id() ); QgsAttributes attrs = mFeatureList.at( i ).attributes(); for ( int j = 0; j < mTableWidget->columnCount(); j++ ) { int idx = mTableWidget->horizontalHeaderItem( j )->data( FieldIndex ).toInt(); QTableWidgetItem* attributeValItem = new QTableWidgetItem( attrs.at( idx ).toString() ); attributeValItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); mTableWidget->setItem( i + 1, j, attributeValItem ); QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( mVectorLayer, idx, nullptr, mTableWidget, context ); if ( eww ) { eww->setValue( attrs.at( idx ) ); } mTableWidget->setCellWidget( i + 1, j, eww->widget() ); } } //merge verticalHeaderLabels << tr( "Merge" ); mTableWidget->setVerticalHeaderLabels( verticalHeaderLabels ); //insert currently merged values for ( int i = 0; i < mTableWidget->columnCount(); ++i ) { refreshMergedValue( i ); } }
void TestQgsAttributeForm::testFieldConstraint() { // make a temporary vector layer QString def = QStringLiteral( "Point?field=col0:integer" ); QgsVectorLayer* layer = new QgsVectorLayer( def, QStringLiteral( "test" ), QStringLiteral( "memory" ) ); layer->setEditorWidgetSetup( 0, QgsEditorWidgetSetup( QStringLiteral( "TextEdit" ), QVariantMap() ) ); // add a feature to the vector layer QgsFeature ft( layer->dataProvider()->fields(), 1 ); ft.setAttribute( QStringLiteral( "col0" ), 0 ); // build a form for this feature QgsAttributeForm form( layer ); form.setFeature( ft ); // testing stuff QString validLabel = QStringLiteral( "col0<font color=\"green\">✔</font>" ); QString invalidLabel = QStringLiteral( "col0<font color=\"red\">✘</font>" ); QString warningLabel = QStringLiteral( "col0<font color=\"orange\">✘</font>" ); // set constraint layer->setConstraintExpression( 0, QString() ); // get wrapper QgsEditorWidgetWrapper *ww; ww = qobject_cast<QgsEditorWidgetWrapper*>( form.mWidgets[0] ); // no constraint so we expect a label with just the field name QLabel *label = form.mBuddyMap.value( ww->widget() ); QCOMPARE( label->text(), QString( "col0" ) ); // set a not null constraint layer->setConstraintExpression( 0, QStringLiteral( "col0 is not null" ) ); // build a form for this feature QgsAttributeForm form2( layer ); form2.setFeature( ft ); QSignalSpy spy( &form2, SIGNAL( attributeChanged( QString, QVariant ) ) ); ww = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[0] ); label = form2.mBuddyMap.value( ww->widget() ); // set value to 1 ww->setValue( 1 ); QCOMPARE( spy.count(), 2 ); QCOMPARE( label->text(), validLabel ); // set value to null spy.clear(); ww->setValue( QVariant() ); QCOMPARE( spy.count(), 2 ); QCOMPARE( label->text(), invalidLabel ); // set value to 1 spy.clear(); ww->setValue( 1 ); QCOMPARE( spy.count(), 2 ); QCOMPARE( label->text(), validLabel ); // set a soft constraint layer->setConstraintExpression( 0, QStringLiteral( "col0 is not null" ) ); layer->setFieldConstraint( 0, QgsFieldConstraints::ConstraintExpression, QgsFieldConstraints::ConstraintStrengthSoft ); // build a form for this feature QgsAttributeForm form3( layer ); form3.setFeature( ft ); ww = qobject_cast<QgsEditorWidgetWrapper*>( form3.mWidgets[0] ); label = form3.mBuddyMap.value( ww->widget() ); // set value to 1 ww->setValue( 1 ); QCOMPARE( label->text(), validLabel ); // set value to null ww->setValue( QVariant() ); QCOMPARE( label->text(), warningLabel ); // set value to 1 ww->setValue( 1 ); QCOMPARE( label->text(), validLabel ); }
void TestQgsAttributeForm::testOKButtonStatus() { // make a temporary vector layer QString def = QStringLiteral( "Point?field=col0:integer" ); QgsVectorLayer* layer = new QgsVectorLayer( def, QStringLiteral( "test" ), QStringLiteral( "memory" ) ); // add a feature to the vector layer QgsFeature ft( layer->dataProvider()->fields(), 1 ); ft.setAttribute( QStringLiteral( "col0" ), 0 ); ft.setValid( true ); // set constraint layer->setConstraintExpression( 0, QString() ); // build a form for this feature QgsAttributeForm form( layer ); form.setFeature( ft ); QPushButton *okButton = form.mButtonBox->button( QDialogButtonBox::Ok ); // get wrapper QgsEditorWidgetWrapper *ww; ww = qobject_cast<QgsEditorWidgetWrapper*>( form.mWidgets[0] ); // testing stuff QSignalSpy spy1( &form, SIGNAL( attributeChanged( QString, QVariant ) ) ); QSignalSpy spy2( layer, SIGNAL( editingStarted() ) ); QSignalSpy spy3( layer, SIGNAL( editingStopped() ) ); // no constraint but layer not editable : OK button disabled QCOMPARE( layer->isEditable(), false ); QCOMPARE( okButton->isEnabled(), false ); // no constraint and editable layer : OK button enabled layer->startEditing(); QCOMPARE( spy2.count(), 1 ); QCOMPARE( layer->isEditable(), true ); QCOMPARE( okButton->isEnabled(), true ); // invalid constraint and editable layer : OK button disabled layer->setConstraintExpression( 0, QStringLiteral( "col0 = 0" ) ); QgsAttributeForm form2( layer ); form2.setFeature( ft ); ww = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[0] ); okButton = form2.mButtonBox->button( QDialogButtonBox::Ok ); ww->setValue( 1 ); QCOMPARE( okButton->isEnabled(), false ); // valid constraint and editable layer : OK button enabled layer->setConstraintExpression( 0, QStringLiteral( "col0 = 2" ) ); QgsAttributeForm form3( layer ); form3.setFeature( ft ); ww = qobject_cast<QgsEditorWidgetWrapper*>( form3.mWidgets[0] ); okButton = form3.mButtonBox->button( QDialogButtonBox::Ok ); ww->setValue( 2 ); QCOMPARE( okButton->isEnabled(), true ); // valid constraint and not editable layer : OK button disabled layer->rollBack(); QCOMPARE( spy3.count(), 1 ); QCOMPARE( layer->isEditable(), false ); QCOMPARE( okButton->isEnabled(), false ); // set soft constraint layer->setFieldConstraint( 0, QgsFieldConstraints::ConstraintExpression, QgsFieldConstraints::ConstraintStrengthSoft ); QgsAttributeForm form4( layer ); form4.setFeature( ft ); ww = qobject_cast<QgsEditorWidgetWrapper*>( form4.mWidgets[0] ); okButton = form4.mButtonBox->button( QDialogButtonBox::Ok ); ww->setValue( 1 ); QVERIFY( !okButton->isEnabled() ); layer->startEditing(); // just a soft constraint, so OK should be enabled QVERIFY( okButton->isEnabled() ); layer->rollBack(); QVERIFY( !okButton->isEnabled() ); }