29 #include <QFormLayout> 30 #include <QGridLayout> 34 #include <QPushButton> 35 #include <QScrollArea> 39 int QgsAttributeForm::sFormCounter = 0;
46 , mFormNr( sFormCounter++ )
48 , mIsAddDialog( false )
49 , mEditCommandMessage(
tr(
"Attributes changed" ) )
55 connect( vl, SIGNAL( attributeAdded(
int ) ),
this, SLOT( onAttributeAdded(
int ) ) );
56 connect( vl, SIGNAL( attributeDeleted(
int ) ),
this, SLOT( onAttributeDeleted(
int ) ) );
62 qDeleteAll( mInterfaces );
71 connect( mLayer, SIGNAL( beforeModifiedCheck() ),
this, SLOT(
save() ) );
78 disconnect( mLayer, SIGNAL( beforeModifiedCheck() ),
this, SLOT(
save() ) );
83 disconnect( mButtonBox, SIGNAL( accepted() ),
this, SLOT(
accept() ) );
84 disconnect( mButtonBox, SIGNAL( rejected() ),
this, SLOT(
resetValues() ) );
89 mInterfaces.append( iface );
99 mIsAddDialog = isAddDialog;
101 synchronizeEnabledState();
109 if ( eww && eww->
field().
name() == field )
122 synchronizeEnabledState();
137 bool changedLayer =
false;
149 if ( mFeature.
isValid() || mIsAddDialog )
151 bool doUpdate =
false;
166 QVariant dstVar = dst[eww->
fieldIdx()];
167 QVariant srcVar = eww->
value();
170 if (( dstVar != srcVar || dstVar.isNull() != srcVar.isNull() ) && srcVar.isValid() && mLayer->
fieldEditable( eww->
fieldIdx() ) )
195 bool res = mLayer->
addFeature( updatedFeature );
210 for (
int i = 0; i < dst.count(); ++i )
212 if (( dst[i] == src[i] && dst[i].
isNull() == src[i].
isNull() )
219 QgsDebugMsg( QString(
"Updating field %1" ).arg( i ) );
220 QgsDebugMsg( QString(
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
221 .arg( dst[i].toString() ).arg( dst[i].typeName() ).arg( dst[i].
isNull() ).arg( dst[i].isValid() ) );
222 QgsDebugMsg( QString(
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
223 .arg( src[i].toString() ).arg( src[i].typeName() ).arg( src[i].
isNull() ).arg( src[i].isValid() ) );
229 if ( success && n > 0 )
266 void QgsAttributeForm::onAttributeChanged(
const QVariant& value )
275 void QgsAttributeForm::onAttributeAdded(
int idx )
281 Q_ASSERT( attrs.size() == idx );
282 attrs.append( QVariant(
layer()->pendingFields()[idx].type() ) );
290 void QgsAttributeForm::onAttributeDeleted(
int idx )
317 void QgsAttributeForm::synchronizeEnabledState()
319 bool isEditable = ( mFeature.
isValid() || mIsAddDialog ) && mLayer->
isEditable();
323 bool fieldEditable =
true;
331 ww->
setEnabled( isEditable && fieldEditable );
334 QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
336 okButton->setEnabled( isEditable );
339 void QgsAttributeForm::init()
341 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
344 QWidget* formWidget = 0;
346 bool buttonBoxVisible =
true;
350 buttonBoxVisible = mButtonBox->isVisible();
355 qDeleteAll( mWidgets );
358 while ( QWidget* w = this->findChild<QWidget*>() )
365 setLayout(
new QGridLayout(
this ) );
372 if ( file.open( QFile::ReadOnly ) )
377 loader.setWorkingDirectory( fi.dir() );
378 formWidget = loader.load( &file,
this );
379 formWidget->setWindowFlags( Qt::Widget );
380 layout()->addWidget( formWidget );
383 mButtonBox = findChild<QDialogButtonBox*>();
386 formWidget->installEventFilter(
this );
393 QTabWidget* tabWidget =
new QTabWidget(
this );
394 layout()->addWidget( tabWidget );
398 QWidget* tabPage =
new QWidget( tabWidget );
400 tabWidget->addTab( tabPage, widgDef->
name() );
401 QGridLayout *tabPageLayout =
new QGridLayout( tabPage );
412 tabPageLayout->addWidget( createWidgetFromDef( widgDef, tabPage, mLayer, mContext, dummy1, dummy2 ) );
416 QgsDebugMsg(
"No support for fields in attribute editor on top level" );
419 formWidget = tabWidget;
426 formWidget =
new QWidget(
this );
427 QGridLayout* gridLayout =
new QGridLayout( formWidget );
428 formWidget->setLayout( gridLayout );
432 QScrollArea* scrollArea =
new QScrollArea(
this );
433 scrollArea->setWidget( formWidget );
434 scrollArea->setWidgetResizable(
true );
435 scrollArea->setFrameShape( QFrame::NoFrame );
436 scrollArea->setFrameShadow( QFrame::Plain );
437 scrollArea->setFocusProxy(
this );
438 layout()->addWidget( scrollArea );
452 if ( widgetType ==
"Hidden" )
459 QWidget *l =
new QLabel( fieldName );
461 QWidget *w = eww ? eww->
widget() :
new QLabel( QString(
"<p style=\"color: red; font-style: italic;\">Failed to create widget with type '%1'</p>" ).arg( widgetType ) );
464 w->setObjectName( field.
name() );
467 addWidgetWrapper( eww );
471 gridLayout->addWidget( l, row++, 0, 1, 2 );
472 gridLayout->addWidget( w, row++, 0, 1, 2 );
476 gridLayout->addWidget( l, row, 0 );
477 gridLayout->addWidget( w, row++, 1 );
485 gridLayout->addWidget( rww->
widget(), row++, 0, 1, 2 );
486 mWidgets.append( rww );
492 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
493 mButtonBox->setObjectName(
"buttonBox" );
494 layout()->addWidget( mButtonBox );
497 mButtonBox->setVisible( buttonBoxVisible );
501 connect( mButtonBox, SIGNAL( accepted() ),
this, SLOT(
accept() ) );
502 connect( mButtonBox, SIGNAL( rejected() ),
this, SLOT(
resetValues() ) );
504 connect( mLayer, SIGNAL( editingStarted() ),
this, SLOT( synchronizeEnabledState() ) );
505 connect( mLayer, SIGNAL( editingStopped() ),
this, SLOT( synchronizeEnabledState() ) );
511 QApplication::restoreOverrideCursor();
514 void QgsAttributeForm::cleanPython()
516 if ( !mPyFormVarName.isNull() )
518 QString expr = QString(
"if locals().has_key('%1'): del %1\n" ).arg( mPyFormVarName );
523 void QgsAttributeForm::initPython()
532 int pos = module.lastIndexOf(
"." );
541 QString reload = QString(
"if hasattr(%1,'DEBUGMODE') and %1.DEBUGMODE:" 542 " reload(%1)" ).arg( module.left( pos ) );
550 static int sFormId = 0;
551 mPyFormVarName = QString(
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
553 QString form = QString(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
554 .arg( mPyFormVarName )
555 .arg((
unsigned long )
this );
559 QgsDebugMsg( QString(
"running featureForm init: %1" ).arg( mPyFormVarName ) );
562 if ( numArgs ==
"3" )
569 QString expr = QString(
"%1(%2)" )
571 .arg( mPyFormVarName );
572 QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr,
"QgsAttributeFormInterface" );
582 QWidget *newWidget = 0;
584 switch ( widgetDef->
type() )
593 if ( fldIdx < vl->pendingFields().count() && fldIdx >= 0 )
599 newWidget = eww->
widget();
600 addWidgetWrapper( eww );
602 newWidget->setObjectName( mLayer->
pendingFields()[ fldIdx ].name() );
617 newWidget = rww->
widget();
618 mWidgets.append( rww );
619 labelText = QString::null;
630 QWidget* myContainer;
633 QGroupBox* groupBox =
new QGroupBox( parent );
634 groupBox->setTitle( container->
name() );
635 myContainer = groupBox;
636 newWidget = myContainer;
640 QScrollArea *scrollArea =
new QScrollArea( parent );
642 myContainer =
new QWidget( scrollArea );
644 scrollArea->setWidget( myContainer );
645 scrollArea->setWidgetResizable(
true );
646 scrollArea->setFrameShape( QFrame::NoFrame );
648 newWidget = scrollArea;
651 QGridLayout* gbLayout =
new QGridLayout( myContainer );
652 myContainer->setLayout( gbLayout );
656 QList<QgsAttributeEditorElement*> children = container->
children();
662 QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, context, labelText, labelOnTop );
664 if ( labelText.isNull() )
666 gbLayout->addWidget( editor, index, 0, 1, 2 );
670 QLabel* mypLabel =
new QLabel( labelText );
673 gbLayout->addWidget( mypLabel, index, 0, 1, 2 );
675 gbLayout->addWidget( editor, index, 0, 1, 2 );
679 gbLayout->addWidget( mypLabel, index, 0 );
680 gbLayout->addWidget( editor, index, 1 );
686 gbLayout->addItem(
new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Preferred ), index, 0 );
688 labelText = QString::null;
694 QgsDebugMsg(
"Unknown attribute editor widget type encountered..." );
710 connect( meww, SIGNAL( valueChanged( QVariant ) ), eww, SLOT( setValue( QVariant ) ) );
711 connect( eww, SIGNAL( valueChanged( QVariant ) ), meww, SLOT( setValue( QVariant ) ) );
717 mWidgets.append( eww );
720 void QgsAttributeForm::createWrappers()
722 QList<QWidget*> myWidgets = findChildren<QWidget*>();
725 Q_FOREACH ( QWidget* myWidget, myWidgets )
728 QVariant vRel = myWidget->property(
"qgisRelation" );
729 if ( vRel.isValid() )
739 mWidgets.append( rww );
744 Q_FOREACH (
const QgsField& field, fields )
746 if ( field.
name() == myWidget->objectName() )
753 addWidgetWrapper( eww );
760 void QgsAttributeForm::connectWrappers()
762 bool isFirstEww =
true;
772 setFocusProxy( eww->
widget() );
776 connect( eww, SIGNAL( valueChanged(
const QVariant& ) ),
this, SLOT( onAttributeChanged(
const QVariant& ) ) );
786 if ( e->type() == QEvent::KeyPress )
788 QKeyEvent* keyEvent =
dynamic_cast<QKeyEvent*
>( e );
789 if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
QgsFeatureId id() const
Get the feature id for this feature.
const QgsEditorWidgetConfig editorWidgetV2Config(int fieldIdx) const
Get the configuration for the editor widget used to represent the field at the given index...
const QString & name() const
Gets the name of the field.
bool isValid() const
Returns the validity of this relation.
bool fieldEditable(int idx)
is edit widget editable
EditorLayout editorLayout()
get the active layout for the attribute editor for this layer
virtual bool isGroupBox() const
bool isValid() const
Return the validity of this feature.
This class contains context information for attribute editor widgets.
void beginEditCommand(QString text)
Create edit command for undo/redo operations.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
static bool eval(QString command, QString &result)
Eval a python statement.
void setAttributes(const QgsAttributes &attrs)
bool addFeature(QgsFeature &f, bool alsoUpdateExtent=true)
Adds a feature.
const QgsRelation & relation() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
QString editForm()
get edit form
QString attributeDisplayName(int attributeIndex) const
Convenience function that returns the attribute alias if defined or the field name else...
static bool run(QString command, QString messageOnError=QString())
execute a python statement
QgsRelation relation(const QString &id) const
Get access to a relation by its id.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
const QString editorWidgetV2(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
void triggerRepaint()
Will advice the map canvas (and any other interested party) that this layer requires to be repainted...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
AttributeEditorType type() const
void destroyEditCommand()
Destroy active command and reverts all changes in it.
Q_DECL_DEPRECATED bool changeAttributeValue(QgsFeatureId fid, int field, QVariant value, bool emitSignal)
Changes an attribute value (but does not commit it)
const QgsAttributes & attributes() const
Encapsulate a field in an attribute table or data source.
void setFields(const QgsFields *fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
bool labelOnTop(int idx)
label widget on top
QList< QgsAttributeEditorElement * > children() const
void setValid(bool validity)
Set the validity of the feature.
virtual void setIsGroupBox(bool isGroupBox)
This class manages a set of relations between layers.
static QgsProject * instance()
access to canonical QgsProject instance
QList< QgsAttributeEditorElement * > & attributeEditorElements()
Returns a list of tabs holding groups and fields.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
QgsVectorDataProvider * dataProvider()
Returns the data provider.
QString editFormInit()
get python function for edit form initialization
bool nextFeature(QgsFeature &f)
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
QgsRelationManager * relationManager() const
allows modification of attribute values
bool isNull(const QVariant &v)