QGIS API Documentation  2.4.0-Chugiak
qgsattributeform.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsattributeform.cpp
3  --------------------------------------
4  Date : 3.5.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias dot kuhn at gmx dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsattributeform.h"
17 
18 #include "qgsattributeeditor.h"
21 #include "qgseditorwidgetregistry.h"
22 #include "qgsproject.h"
23 #include "qgspythonrunner.h"
24 #include "qgsrelationwidgetwrapper.h"
25 
26 #include <QDir>
27 #include <QFileInfo>
28 #include <QFormLayout>
29 #include <QGridLayout>
30 #include <QGroupBox>
31 #include <QKeyEvent>
32 #include <QLabel>
33 #include <QPushButton>
34 #include <QScrollArea>
35 #include <QTabWidget>
36 #include <QUiLoader>
37 
39 
41  : QWidget( parent )
42  , mLayer( vl )
43  , mContext( context )
44  , mFormNr( sFormCounter++ )
45  , mIsSaving( false )
46  , mIsAddDialog( false )
47  , mEditCommandMessage( tr( "Attributes changed" ) )
48 {
49  init();
50  initPython();
51  setFeature( feature );
52 
53  connect( vl, SIGNAL( attributeAdded( int ) ), this, SLOT( onAttributeAdded( int ) ) );
54  connect( vl, SIGNAL( attributeDeleted( int ) ), this, SLOT( onAttributeDeleted( int ) ) );
55 }
56 
58 {
59  cleanPython();
60  qDeleteAll( mInterfaces );
61 }
62 
64 {
65  mButtonBox->hide();
66 
67  // Make sure that changes are taken into account if somebody tries to figure out if there have been some
68  connect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
69 }
70 
72 {
73  mButtonBox->show();
74 
75  disconnect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
76 }
77 
79 {
80  mInterfaces.append( iface );
81 }
82 
84 {
85  return mFeature.isValid() && mLayer->isEditable() ;
86 }
87 
88 void QgsAttributeForm::setIsAddDialog( bool isAddDialog )
89 {
90  mIsAddDialog = isAddDialog;
91 
93 }
94 
95 void QgsAttributeForm::changeAttribute( const QString& field, const QVariant& value )
96 {
97  Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
98  {
99  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
100  if ( eww && eww->field().name() == field )
101  {
102  eww->setValue( value );
103  }
104  }
105 }
106 
108 {
109  mFeature = feature;
110 
111  resetValues();
112 
114 
115  Q_FOREACH( QgsAttributeFormInterface* iface, mInterfaces )
116  {
117  iface->featureChanged();
118  }
119 }
120 
122 {
123  if ( mIsSaving )
124  return true;
125 
126  mIsSaving = true;
127 
128  bool success = true;
129 
130  emit beforeSave( success );
131 
132  // Somebody wants to prevent this form from saving
133  if ( !success )
134  return false;
135 
136  QgsFeature updatedFeature = QgsFeature( mFeature );
137 
138  if ( mFeature.isValid() || mIsAddDialog )
139  {
140  bool doUpdate = false;
141 
142  // An add dialog should perform an action by default
143  // and not only if attributes have "changed"
144  if ( mIsAddDialog )
145  doUpdate = true;
146 
149 
150  Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
151  {
152  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
153  if ( eww )
154  {
155  QVariant dstVar = dst[eww->fieldIdx()];
156  QVariant srcVar = eww->value();
157  // need to check dstVar.isNull() != srcVar.isNull()
158  // otherwise if dstVar=NULL and scrVar=0, then dstVar = srcVar
159  if ( ( dstVar != srcVar || dstVar.isNull() != srcVar.isNull() ) && srcVar.isValid() )
160  {
161  dst[eww->fieldIdx()] = srcVar;
162 
163  doUpdate = true;
164  }
165  }
166  }
167 
168  updatedFeature.setAttributes( dst );
169 
170  Q_FOREACH( QgsAttributeFormInterface* iface, mInterfaces )
171  {
172  if ( !iface->acceptChanges( updatedFeature ) )
173  {
174  doUpdate = false;
175  }
176  }
177 
178  if ( doUpdate )
179  {
180  if ( mIsAddDialog )
181  {
182  mFeature.setValid( true );
184  bool res = mLayer->addFeature( updatedFeature );
185  if ( res )
187  else
189  }
190  else
191  {
193 
194  int n = 0;
195  for ( int i = 0; i < dst.count(); ++i )
196  {
197  if ( ( dst[i] == src[i] && dst[i].isNull() == src[i].isNull() ) || !dst[i].isValid() )
198  {
199  QgsDebugMsg( "equal or invalid destination" );
200  QgsDebugMsg( QString( "dst:'%1' (type:%2,isNull:%3,isValid:%4)" )
201  .arg( dst[i].toString() ).arg( dst[i].typeName() ).arg( dst[i].isNull() ).arg( dst[i].isValid() ) );
202  QgsDebugMsg( QString( "src:'%1' (type:%2,isNull:%3,isValid:%4)" )
203  .arg( src[i].toString() ).arg( src[i].typeName() ).arg( src[i].isNull() ).arg( src[i].isValid() ) );
204  continue;
205  }
206 
207  success &= mLayer->changeAttributeValue( mFeature.id(), i, dst[i], src[i] );
208  n++;
209  }
210 
211  if ( success && n > 0 )
212  {
214  mFeature.setAttributes( dst );
215  }
216  else
217  {
219  }
220  }
221  }
222  }
223 
224  emit featureSaved( updatedFeature );
225 
226  mIsSaving = false;
227 
228  return success;
229 }
230 
232 {
233  Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
234  {
235  ww->setFeature( mFeature );
236  }
237 }
238 
239 void QgsAttributeForm::onAttributeChanged( const QVariant& value )
240 {
241  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( sender() );
242 
243  Q_ASSERT( eww );
244 
245  emit attributeChanged( eww->field().name(), value );
246 }
247 
249 {
250  if ( mFeature.isValid() )
251  {
253  Q_ASSERT( attrs.size() == idx );
254  attrs.append( QVariant() );
255  mFeature.setFields( &layer()->pendingFields() );
256  mFeature.setAttributes( attrs );
257  }
258  init();
259  setFeature( mFeature );
260 }
261 
263 {
264  if ( mFeature.isValid() )
265  {
267  attrs.remove( idx );
268  mFeature.setFields( &layer()->pendingFields() );
269  mFeature.setAttributes( attrs );
270  }
271  init();
272  setFeature( mFeature );
273 }
274 
276 {
277  bool isEditable = ( mFeature.isValid() || mIsAddDialog ) && mLayer->isEditable();
278 
279  Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
280  {
281  bool fieldEditable = true;
282  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
283  if ( eww )
284  {
285  fieldEditable = mLayer->fieldEditable( eww->fieldIdx() );
286  }
287  ww->setEnabled( isEditable && fieldEditable );
288  }
289 
290  QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
291  if ( okButton )
292  okButton->setEnabled( isEditable );
293 }
294 
296 {
297  QWidget* formWidget = 0;
298 
299  qDeleteAll( mWidgets );
300  mWidgets.clear();
301 
302  while ( QWidget* w = this->findChild<QWidget*>() )
303  {
304  delete w;
305  }
306  delete this->layout();
307 
308  // Get a layout
309  setLayout( new QGridLayout( this ) );
310 
311  // Try to load Ui-File for layout
312  if ( mLayer->editorLayout() == QgsVectorLayer::UiFileLayout && !mLayer->editForm().isEmpty() )
313  {
314  QFile file( mLayer->editForm() );
315 
316  if ( file.open( QFile::ReadOnly ) )
317  {
318  QUiLoader loader;
319 
320  QFileInfo fi( mLayer->editForm() );
321  loader.setWorkingDirectory( fi.dir() );
322  formWidget = loader.load( &file, this );
323  formWidget->setWindowFlags( Qt::Widget );
324  layout()->addWidget( formWidget );
325  formWidget->show();
326  file.close();
327  createWrappers();
328 
329  formWidget->installEventFilter( this );
330  }
331  }
332 
333  // Tab layout
334  if ( !formWidget && mLayer->editorLayout() == QgsVectorLayer::TabLayout )
335  {
336  QTabWidget* tabWidget = new QTabWidget( this );
337  layout()->addWidget( tabWidget );
338 
340  {
341  QWidget* tabPage = new QWidget( tabWidget );
342 
343  tabWidget->addTab( tabPage, widgDef->name() );
344  QGridLayout *tabPageLayout = new QGridLayout( tabPage );
345 
347  {
348  QgsAttributeEditorContainer* containerDef = dynamic_cast<QgsAttributeEditorContainer*>( widgDef );
349  containerDef->setIsGroupBox( false ); // Toplevel widgets are tabs not groupboxes
350  QString dummy1;
351  bool dummy2;
352  tabPageLayout->addWidget( createWidgetFromDef( widgDef, tabPage, mLayer, mContext, dummy1, dummy2 ) );
353  }
354  else
355  {
356  QgsDebugMsg( "No support for fields in attribute editor on top level" );
357  }
358  }
359  formWidget = tabWidget;
360  }
361 
362  // Autogenerate Layout
363  // If there is still no layout loaded (defined as autogenerate or other methods failed)
364  if ( !formWidget )
365  {
366  formWidget = new QWidget( this );
367  QGridLayout* gridLayout = new QGridLayout( formWidget );
368  formWidget->setLayout( gridLayout );
369 
370  // put the form into a scroll area to nicely handle cases with lots of attributes
371  QScrollArea* scrollArea = new QScrollArea( this );
372  scrollArea->setWidget( formWidget );
373  scrollArea->setWidgetResizable( true );
374  scrollArea->setFrameShape( QFrame::NoFrame );
375  scrollArea->setFrameShadow( QFrame::Plain );
376  layout()->addWidget( scrollArea );
377 
378  int row = 0;
379  Q_FOREACH( const QgsField& field, mLayer->pendingFields().toList() )
380  {
381  int idx = mLayer->fieldNameIndex( field.name() );
382  //show attribute alias if available
383  QString fieldName = mLayer->attributeDisplayName( idx );
384 
385  const QString widgetType = mLayer->editorWidgetV2( idx );
386 
387  if ( widgetType != "Hidden" )
388  {
389  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( idx );
390  bool labelOnTop = mLayer->labelOnTop( idx );
391 
392  // This will also create the widget
393  QWidget *l = new QLabel( fieldName );
394  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, idx, widgetConfig, 0, this, mContext );
395  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 ) );
396 
397  if ( eww )
398  mWidgets.append( eww );
399 
400  if ( labelOnTop )
401  {
402  gridLayout->addWidget( l, row++, 0, 1, 2 );
403  gridLayout->addWidget( w, row++, 0, 1, 2 );
404  }
405  else
406  {
407  gridLayout->addWidget( l, row, 0 );
408  gridLayout->addWidget( w, row++, 1 );
409  }
410  }
411  }
412 
413  Q_FOREACH( const QgsRelation& rel, QgsProject::instance()->relationManager()->referencedRelations( mLayer ) )
414  {
415  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, rel, 0, this );
416  rww->setContext( mContext );
417  gridLayout->addWidget( rww->widget(), row++, 0, 1, 2 );
418  mWidgets.append( rww );
419  }
420  }
421 
422  mButtonBox = findChild<QDialogButtonBox*>();
423 
424  if ( !mButtonBox )
425  {
426  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
427  mButtonBox->setObjectName( "buttonBox" );
428  layout()->addWidget( mButtonBox );
429  }
430 
431  connectWrappers();
432 
433  connect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
434  connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( resetValues() ) );
435 
436  connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( synchronizeEnabledState() ) );
437  connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( synchronizeEnabledState() ) );
438 
439  Q_FOREACH( QgsAttributeFormInterface* iface, mInterfaces )
440  {
441  iface->initForm();
442  }
443 }
444 
446 {
447  if ( !mPyFormVarName.isNull() )
448  {
449  QString expr = QString( "if locals().has_key('%1'): del %1\n" ).arg( mPyFormVarName );
450  QgsPythonRunner::run( expr );
451  }
452 }
453 
455 {
456  cleanPython();
457 
458  // Init Python
459  if ( !mLayer->editFormInit().isEmpty() )
460  {
461  QString module = mLayer->editFormInit();
462 
463  int pos = module.lastIndexOf( "." );
464  if ( pos >= 0 )
465  {
466  QgsPythonRunner::run( QString( "import %1" ).arg( module.left( pos ) ) );
467  }
468 
469  /* Reload the module if the DEBUGMODE switch has been set in the module.
470  If set to False you have to reload QGIS to reset it to True due to Python
471  module caching */
472  QString reload = QString( "if hasattr(%1,'DEBUGMODE') and %1.DEBUGMODE:"
473  " reload(%1)" ).arg( module.left( pos ) );
474 
475  QgsPythonRunner::run( reload );
476 
477  QgsPythonRunner::run( "import inspect" );
478  QString numArgs;
479  QgsPythonRunner::eval( QString( "len(inspect.getargspec(%1)[0])" ).arg( module ), numArgs );
480 
481  mPyFormVarName = QString( "_qgis_featureform_%1" ).arg( mFormNr );
482 
483  QString form = QString( "%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
484  .arg( mPyFormVarName )
485  .arg(( unsigned long ) this );
486 
487  QgsPythonRunner::run( form );
488 
489  QgsDebugMsg( QString( "running featureForm init: %1" ).arg( mPyFormVarName ) );
490 
491  // Legacy
492  if ( numArgs == "3" )
493  {
495  }
496  else
497  {
498 #if 0
499  QString expr = QString( "%1(%2)" )
500  .arg( mLayer->editFormInit() )
501  .arg( mPyFormVarName );
502  QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr, "QgsAttributeFormInterface" );
503  if ( iface )
504  addInterface( iface );
505 #endif
506  }
507  }
508 }
509 
510 QWidget* QgsAttributeForm::createWidgetFromDef( const QgsAttributeEditorElement *widgetDef, QWidget *parent, QgsVectorLayer *vl, QgsAttributeEditorContext &context, QString &labelText, bool &labelOnTop )
511 {
512  QWidget *newWidget = 0;
513 
514  switch ( widgetDef->type() )
515  {
517  {
518  const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( widgetDef );
519  int fldIdx = fieldDef->idx();
520  if ( fldIdx < vl->pendingFields().count() && fldIdx >= 0 )
521  {
522  const QString widgetType = mLayer->editorWidgetV2( fldIdx );
523  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( fldIdx );
524 
525  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, fldIdx, widgetConfig, 0, this, mContext );
526  newWidget = eww->widget();
527  mWidgets.append( eww );
528  }
529 
530  labelOnTop = mLayer->labelOnTop( fieldDef->idx() );
531  labelText = mLayer->attributeDisplayName( fieldDef->idx() );
532  break;
533  }
534 
536  {
537  const QgsAttributeEditorRelation* relDef = dynamic_cast<const QgsAttributeEditorRelation*>( widgetDef );
538 
539  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, relDef->relation(), 0, this );
540  rww->setContext( context );
541  newWidget = rww->widget();
542  mWidgets.append( rww );
543  labelText = QString::null;
544  labelOnTop = true;
545  break;
546  }
547 
549  {
550  const QgsAttributeEditorContainer* container = dynamic_cast<const QgsAttributeEditorContainer*>( widgetDef );
551  QWidget* myContainer;
552 
553  if ( container->isGroupBox() )
554  {
555  QGroupBox* groupBox = new QGroupBox( parent );
556  groupBox->setTitle( container->name() );
557  myContainer = groupBox;
558  newWidget = myContainer;
559  }
560  else
561  {
562  QScrollArea *scrollArea = new QScrollArea( parent );
563 
564  myContainer = new QWidget( scrollArea );
565 
566  scrollArea->setWidget( myContainer );
567  scrollArea->setWidgetResizable( true );
568  scrollArea->setFrameShape( QFrame::NoFrame );
569 
570  newWidget = scrollArea;
571  }
572 
573  QGridLayout* gbLayout = new QGridLayout( myContainer );
574  myContainer->setLayout( gbLayout );
575 
576  int index = 0;
577 
578  QList<QgsAttributeEditorElement*> children = container->children();
579 
580  Q_FOREACH( QgsAttributeEditorElement* childDef, children )
581  {
582  QString labelText;
583  bool labelOnTop;
584  QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, context, labelText, labelOnTop );
585 
586  if ( labelText.isNull() )
587  {
588  gbLayout->addWidget( editor, index, 0, 1, 2 );
589  }
590  else
591  {
592  QLabel* mypLabel = new QLabel( labelText );
593  if ( labelOnTop )
594  {
595  gbLayout->addWidget( mypLabel, index, 0, 1, 2 );
596  ++index;
597  gbLayout->addWidget( editor, index, 0, 1 , 2 );
598  }
599  else
600  {
601  gbLayout->addWidget( mypLabel, index, 0 );
602  gbLayout->addWidget( editor, index, 1 );
603  }
604  }
605 
606  ++index;
607  }
608  gbLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ), index , 0 );
609 
610  labelText = QString::null;
611  labelOnTop = true;
612  break;
613  }
614 
615  default:
616  QgsDebugMsg( "Unknown attribute editor widget type encountered..." );
617  break;
618  }
619 
620  return newWidget;
621 }
622 
624 {
625  QList<QWidget*> myWidgets = findChildren<QWidget*>();
626  const QList<QgsField> fields = mLayer->pendingFields().toList();
627 
628  Q_FOREACH( QWidget* myWidget, myWidgets )
629  {
630  // Check the widget's properties for a relation definition
631  QVariant vRel = myWidget->property( "qgisRelation" );
632  if ( vRel.isValid() )
633  {
635  QgsRelation relation = relMgr->relation( vRel.toString() );
636  if ( relation.isValid() )
637  {
638  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, relation, myWidget, this );
639  rww->setConfig( QgsEditorWidgetConfig() );
640  rww->setContext( mContext );
641  mWidgets.append( rww );
642  }
643  }
644  else
645  {
646  Q_FOREACH( const QgsField& field, fields )
647  {
648  if ( field.name() == myWidget->objectName() )
649  {
650  const QString widgetType = mLayer->editorWidgetV2( field.name() );
651  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( field.name() );
652  int idx = mLayer->fieldNameIndex( field.name() );
653 
654  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, idx, widgetConfig, myWidget, this, mContext );
655  mWidgets.append( eww );
656  }
657  }
658  }
659  }
660 }
661 
663 {
664  Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
665  {
666  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
667 
668  if ( eww )
669  connect( eww, SIGNAL( valueChanged( const QVariant& ) ), this, SLOT( onAttributeChanged( const QVariant& ) ) );
670  }
671 }
672 
673 
674 bool QgsAttributeForm::eventFilter( QObject* object, QEvent* e )
675 {
676  Q_UNUSED( object )
677 
678  if ( e->type() == QEvent::KeyPress )
679  {
680  QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>( e );
681  if ( keyEvent->key() == Qt::Key_Escape )
682  {
683  // Re-emit to this form so it will be forwarded to parent
684  event( e );
685  return true;
686  }
687  }
688 
689  return false;
690 }
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:167
QgsFeatureId id() const
Get the feature id for this feature.
Definition: qgsfeature.cpp:100
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.
Definition: qgsfield.cpp:58
void resetValues()
Sets all values to the values of the current feature.
bool isValid() const
Returns the validity of this relation.
void createWrappers()
Creates widget wrappers for all suitable widgets found.
static unsigned index
bool fieldEditable(int idx)
is edit widget editable
EditorLayout editorLayout()
get the active layout for the attribute editor for this layer (added in 1.9)
virtual bool isGroupBox() const
Q_DECL_DEPRECATED void accept()
Alias for save()
bool isValid() const
Return the validity of this feature.
Definition: qgsfeature.cpp:171
void hideButtonBox()
Hides the button box (Ok/Cancel) and enables auto-commit.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
This class contains context information for attribute editor widgets.
void beginEditCommand(QString text)
Create edit command for undo/redo operations.
bool editable()
Returns if the form is currently in editable mode.
bool save()
Save all the values from the editors to the layer.
void setIsAddDialog(bool isAddDialog)
Toggles the form mode between edit feature and add feature.
static bool eval(QString command, QString &result)
Eval a python statement.
void setAttributes(const QgsAttributes &attrs)
Definition: qgsfeature.h:144
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...
Definition: qgsfeature.h:113
QDialogButtonBox * mButtonBox
QgsVectorLayer * layer()
Returns the layer for which this form is shown.
QgsAttributeEditorContext mContext
QWidget * createWidgetFromDef(const QgsAttributeEditorElement *widgetDef, QWidget *parent, QgsVectorLayer *vl, QgsAttributeEditorContext &context, QString &labelText, bool &labelOnTop)
QList< QgsAttributeFormInterface * > mInterfaces
QString editForm()
get edit form (added in 1.4)
void showButtonBox()
Shows the button box (Ok/Cancel) and disables auto-commit.
QgsVectorLayer * mLayer
QString attributeDisplayName(int attributeIndex) const
Convenience function that returns the attribute alias if defined or the field name else...
void onAttributeChanged(const QVariant &value)
void setFeature(const QgsFeature &feature)
Update all editors to correspond to a different feature.
static bool run(QString command, QString messageOnError=QString())
execute a python statement
QgsRelation relation(const QString &id) const
QList< QgsWidgetWrapper * > mWidgets
const QString editorWidgetV2(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
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
Definition: qgsfeature.h:142
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:31
static int sFormCounter
void beforeSave(bool &ok)
Will be emitted before the feature is saved.
void setFields(const QgsFields *fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:161
void endEditCommand()
Finish edit command and add it to undo/redo stack.
bool labelOnTop(int idx)
label widget on top
void onAttributeAdded(int idx)
QList< QgsAttributeEditorElement * > children() const
QgsAttributeForm(QgsVectorLayer *vl, const QgsFeature feature=QgsFeature(), QgsAttributeEditorContext context=QgsAttributeEditorContext(), QWidget *parent=0)
This class helps to support legacy open form scripts to be compatible with the new QgsAttributeForm s...
void featureSaved(const QgsFeature &feature)
Is emitted, when a feature is changed or added.
virtual bool acceptChanges(const QgsFeature &feature)
QString file
Definition: qgssvgcache.cpp:76
void setValid(bool validity)
Set the validity of the feature.
Definition: qgsfeature.cpp:176
bool eventFilter(QObject *object, QEvent *event)
Intercepts keypress on custom form (escape should not close it)
void changeAttribute(const QString &field, const QVariant &value)
Call this to change the content of a given attribute.
void attributeChanged(QString attribute, const QVariant &value)
Notifies about changes of attributes.
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:100
virtual void setIsGroupBox(bool isGroupBox)
This class manages a set of relations between layers.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
QList< QgsAttributeEditorElement * > & attributeEditorElements()
Returns a list of tabs holding groups and fields.
void addInterface(QgsAttributeFormInterface *iface)
Takes ownership.
QMap< QString, QVariant > QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
const QgsFeature & feature()
bool mIsSaving
Set to true while saving to prevent recursive saves.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
void onAttributeDeleted(int idx)
QString editFormInit()
get python function for edit form initialization (added in 1.4)
virtual bool isEditable() const
Returns true if the provider is in editing mode.
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
bool isNull(const QVariant &v)
#define tr(sourceText)