QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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"
22 #include "qgsproject.h"
23 #include "qgspythonrunner.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 
38 int QgsAttributeForm::sFormCounter = 0;
39 
40 QgsAttributeForm::QgsAttributeForm( QgsVectorLayer* vl, const QgsFeature &feature, const QgsAttributeEditorContext &context, QWidget* parent )
41  : QWidget( parent )
42  , mLayer( vl )
43  , mContext( context )
44  , mButtonBox( 0 )
45  , mFormNr( sFormCounter++ )
46  , mIsSaving( false )
47  , mIsAddDialog( false )
48  , mEditCommandMessage( tr( "Attributes changed" ) )
49 {
50  init();
51  initPython();
52  setFeature( feature );
53 
54  connect( vl, SIGNAL( attributeAdded( int ) ), this, SLOT( onAttributeAdded( int ) ) );
55  connect( vl, SIGNAL( attributeDeleted( int ) ), this, SLOT( onAttributeDeleted( int ) ) );
56 }
57 
59 {
60  cleanPython();
61  qDeleteAll( mInterfaces );
62 }
63 
65 {
66  mButtonBox->hide();
67 
68  // Make sure that changes are taken into account if somebody tries to figure out if there have been some
69  if ( !mIsAddDialog )
70  connect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
71 }
72 
74 {
75  mButtonBox->show();
76 
77  disconnect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
78 }
79 
81 {
82  disconnect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
83  disconnect( mButtonBox, SIGNAL( rejected() ), this, SLOT( resetValues() ) );
84 }
85 
87 {
88  mInterfaces.append( iface );
89 }
90 
92 {
93  return mFeature.isValid() && mLayer->isEditable();
94 }
95 
96 void QgsAttributeForm::setIsAddDialog( bool isAddDialog )
97 {
98  mIsAddDialog = isAddDialog;
99 
100  synchronizeEnabledState();
101 }
102 
103 void QgsAttributeForm::changeAttribute( const QString& field, const QVariant& value )
104 {
105  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
106  {
107  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
108  if ( eww && eww->field().name() == field )
109  {
110  eww->setValue( value );
111  }
112  }
113 }
114 
116 {
117  mFeature = feature;
118 
119  resetValues();
120 
121  synchronizeEnabledState();
122 
123  Q_FOREACH ( QgsAttributeFormInterface* iface, mInterfaces )
124  {
125  iface->featureChanged();
126  }
127 }
128 
130 {
131  if ( mIsSaving )
132  return true;
133 
134  mIsSaving = true;
135 
136  bool changedLayer = false;
137 
138  bool success = true;
139 
140  emit beforeSave( success );
141 
142  // Somebody wants to prevent this form from saving
143  if ( !success )
144  return false;
145 
146  QgsFeature updatedFeature = QgsFeature( mFeature );
147 
148  if ( mFeature.isValid() || mIsAddDialog )
149  {
150  bool doUpdate = false;
151 
152  // An add dialog should perform an action by default
153  // and not only if attributes have "changed"
154  if ( mIsAddDialog )
155  doUpdate = true;
156 
157  QgsAttributes src = mFeature.attributes();
158  QgsAttributes dst = mFeature.attributes();
159 
160  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
161  {
162  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
163  if ( eww )
164  {
165  QVariant dstVar = dst[eww->fieldIdx()];
166  QVariant srcVar = eww->value();
167  // need to check dstVar.isNull() != srcVar.isNull()
168  // otherwise if dstVar=NULL and scrVar=0, then dstVar = srcVar
169  if (( dstVar != srcVar || dstVar.isNull() != srcVar.isNull() ) && srcVar.isValid() && mLayer->fieldEditable( eww->fieldIdx() ) )
170  {
171  dst[eww->fieldIdx()] = srcVar;
172 
173  doUpdate = true;
174  }
175  }
176  }
177 
178  updatedFeature.setAttributes( dst );
179 
180  Q_FOREACH ( QgsAttributeFormInterface* iface, mInterfaces )
181  {
182  if ( !iface->acceptChanges( updatedFeature ) )
183  {
184  doUpdate = false;
185  }
186  }
187 
188  if ( doUpdate )
189  {
190  if ( mIsAddDialog )
191  {
192  mFeature.setValid( true );
193  mLayer->beginEditCommand( mEditCommandMessage );
194  bool res = mLayer->addFeature( updatedFeature );
195  if ( res )
196  {
197  mFeature.setAttributes( updatedFeature.attributes() );
198  mLayer->endEditCommand();
199  changedLayer = true;
200  }
201  else
202  mLayer->destroyEditCommand();
203  }
204  else
205  {
206  mLayer->beginEditCommand( mEditCommandMessage );
207 
208  int n = 0;
209  for ( int i = 0; i < dst.count(); ++i )
210  {
211  if (( dst[i] == src[i] && dst[i].isNull() == src[i].isNull() ) // If field is not changed...
212  || !dst[i].isValid() // or the widget returns invalid (== do not change)
213  || !mLayer->fieldEditable( i ) ) // or the field cannot be edited ...
214  {
215  continue;
216  }
217 
218  QgsDebugMsg( QString( "Updating field %1" ).arg( i ) );
219  QgsDebugMsg( QString( "dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
220  .arg( dst[i].toString() ).arg( dst[i].typeName() ).arg( dst[i].isNull() ).arg( dst[i].isValid() ) );
221  QgsDebugMsg( QString( "src:'%1' (type:%2, isNull:%3, isValid:%4)" )
222  .arg( src[i].toString() ).arg( src[i].typeName() ).arg( src[i].isNull() ).arg( src[i].isValid() ) );
223 
224  success &= mLayer->changeAttributeValue( mFeature.id(), i, dst[i], src[i] );
225  n++;
226  }
227 
228  if ( success && n > 0 )
229  {
230  mLayer->endEditCommand();
231  mFeature.setAttributes( dst );
232  changedLayer = true;
233  }
234  else
235  {
236  mLayer->destroyEditCommand();
237  }
238  }
239  }
240  }
241 
242  emit featureSaved( updatedFeature );
243 
244  // [MD] Refresh canvas only when absolutely necessary - it interferes with other stuff (#11361).
245  // This code should be revisited - and the signals should be fired (+ layer repainted)
246  // only when actually doing any changes. I am unsure if it is actually a good idea
247  // to call save() whenever some code asks for vector layer's modified status
248  // (which is the case when attribute table is open)
249  if ( changedLayer )
250  mLayer->triggerRepaint();
251 
252  mIsSaving = false;
253 
254  return success;
255 }
256 
258 {
259  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
260  {
261  ww->setFeature( mFeature );
262  }
263 }
264 
265 void QgsAttributeForm::onAttributeChanged( const QVariant& value )
266 {
267  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( sender() );
268 
269  Q_ASSERT( eww );
270 
271  emit attributeChanged( eww->field().name(), value );
272 }
273 
274 void QgsAttributeForm::onAttributeAdded( int idx )
275 {
276  Q_UNUSED( idx ) // only used for Q_ASSERT
277  if ( mFeature.isValid() )
278  {
279  QgsAttributes attrs = mFeature.attributes();
280  Q_ASSERT( attrs.size() == idx );
281  attrs.append( QVariant( layer()->pendingFields()[idx].type() ) );
282  mFeature.setFields( &layer()->pendingFields() );
283  mFeature.setAttributes( attrs );
284  }
285  init();
286  setFeature( mFeature );
287 }
288 
289 void QgsAttributeForm::onAttributeDeleted( int idx )
290 {
291  if ( mFeature.isValid() )
292  {
293  QgsAttributes attrs = mFeature.attributes();
294  attrs.remove( idx );
295  mFeature.setFields( &layer()->pendingFields() );
296  mFeature.setAttributes( attrs );
297  }
298  init();
299  setFeature( mFeature );
300 }
301 
302 void QgsAttributeForm::synchronizeEnabledState()
303 {
304  bool isEditable = ( mFeature.isValid() || mIsAddDialog ) && mLayer->isEditable();
305 
306  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
307  {
308  bool fieldEditable = true;
309  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
310  if ( eww )
311  {
312  fieldEditable = mLayer->fieldEditable( eww->fieldIdx() );
313  }
314  ww->setEnabled( isEditable && fieldEditable );
315  }
316 
317  QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
318  if ( okButton )
319  okButton->setEnabled( isEditable );
320 }
321 
322 void QgsAttributeForm::init()
323 {
324  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
325 
326  // Cleanup of any previously shown widget, we start from scratch
327  QWidget* formWidget = 0;
328 
329  bool buttonBoxVisible = true;
330  // Cleanup button box but preserve visibility
331  if ( mButtonBox )
332  {
333  buttonBoxVisible = mButtonBox->isVisible();
334  delete mButtonBox;
335  mButtonBox = 0;
336  }
337 
338  qDeleteAll( mWidgets );
339  mWidgets.clear();
340 
341  while ( QWidget* w = this->findChild<QWidget*>() )
342  {
343  delete w;
344  }
345  delete layout();
346 
347  // Get a layout
348  setLayout( new QGridLayout( this ) );
349 
350  // Try to load Ui-File for layout
351  if ( mLayer->editorLayout() == QgsVectorLayer::UiFileLayout && !mLayer->editForm().isEmpty() )
352  {
353  QFile file( mLayer->editForm() );
354 
355  if ( file.open( QFile::ReadOnly ) )
356  {
357  QUiLoader loader;
358 
359  QFileInfo fi( mLayer->editForm() );
360  loader.setWorkingDirectory( fi.dir() );
361  formWidget = loader.load( &file, this );
362  formWidget->setWindowFlags( Qt::Widget );
363  layout()->addWidget( formWidget );
364  formWidget->show();
365  file.close();
366  mButtonBox = findChild<QDialogButtonBox*>();
367  createWrappers();
368 
369  formWidget->installEventFilter( this );
370  }
371  }
372 
373  // Tab layout
374  if ( !formWidget && mLayer->editorLayout() == QgsVectorLayer::TabLayout )
375  {
376  QTabWidget* tabWidget = new QTabWidget( this );
377  layout()->addWidget( tabWidget );
378 
379  Q_FOREACH ( QgsAttributeEditorElement *widgDef, mLayer->attributeEditorElements() )
380  {
381  QWidget* tabPage = new QWidget( tabWidget );
382 
383  tabWidget->addTab( tabPage, widgDef->name() );
384  QGridLayout *tabPageLayout = new QGridLayout( tabPage );
385 
387  {
388  QgsAttributeEditorContainer* containerDef = dynamic_cast<QgsAttributeEditorContainer*>( widgDef );
389  if ( !containerDef )
390  continue;
391 
392  containerDef->setIsGroupBox( false ); // Toplevel widgets are tabs not groupboxes
393  QString dummy1;
394  bool dummy2;
395  tabPageLayout->addWidget( createWidgetFromDef( widgDef, tabPage, mLayer, mContext, dummy1, dummy2 ) );
396  }
397  else
398  {
399  QgsDebugMsg( "No support for fields in attribute editor on top level" );
400  }
401  }
402  formWidget = tabWidget;
403  }
404 
405  // Autogenerate Layout
406  // If there is still no layout loaded (defined as autogenerate or other methods failed)
407  if ( !formWidget )
408  {
409  formWidget = new QWidget( this );
410  QGridLayout* gridLayout = new QGridLayout( formWidget );
411  formWidget->setLayout( gridLayout );
412 
413  // put the form into a scroll area to nicely handle cases with lots of attributes
414 
415  QScrollArea* scrollArea = new QScrollArea( this );
416  scrollArea->setWidget( formWidget );
417  scrollArea->setWidgetResizable( true );
418  scrollArea->setFrameShape( QFrame::NoFrame );
419  scrollArea->setFrameShadow( QFrame::Plain );
420  scrollArea->setFocusProxy( this );
421  layout()->addWidget( scrollArea );
422 
423  int row = 0;
424  Q_FOREACH ( const QgsField& field, mLayer->pendingFields().toList() )
425  {
426  int idx = mLayer->fieldNameIndex( field.name() );
427  if ( idx < 0 )
428  continue;
429 
430  //show attribute alias if available
431  QString fieldName = mLayer->attributeDisplayName( idx );
432 
433  const QString widgetType = mLayer->editorWidgetV2( idx );
434 
435  if ( widgetType == "Hidden" )
436  continue;
437 
438  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( idx );
439  bool labelOnTop = mLayer->labelOnTop( idx );
440 
441  // This will also create the widget
442  QWidget *l = new QLabel( fieldName );
443  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, idx, widgetConfig, 0, this, mContext );
444  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 ) );
445 
446  if ( w )
447  w->setObjectName( field.name() );
448 
449  if ( eww )
450  addWidgetWrapper( eww );
451 
452  if ( labelOnTop )
453  {
454  gridLayout->addWidget( l, row++, 0, 1, 2 );
455  gridLayout->addWidget( w, row++, 0, 1, 2 );
456  }
457  else
458  {
459  gridLayout->addWidget( l, row, 0 );
460  gridLayout->addWidget( w, row++, 1 );
461  }
462  }
463 
464  Q_FOREACH ( const QgsRelation& rel, QgsProject::instance()->relationManager()->referencedRelations( mLayer ) )
465  {
466  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, rel, 0, this );
467  rww->setContext( mContext );
468  gridLayout->addWidget( rww->widget(), row++, 0, 1, 2 );
469  mWidgets.append( rww );
470  }
471  }
472 
473  if ( !mButtonBox )
474  {
475  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
476  mButtonBox->setObjectName( "buttonBox" );
477  layout()->addWidget( mButtonBox );
478  }
479 
480  mButtonBox->setVisible( buttonBoxVisible );
481 
482  connectWrappers();
483 
484  connect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
485  connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( resetValues() ) );
486 
487  connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( synchronizeEnabledState() ) );
488  connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( synchronizeEnabledState() ) );
489 
490  Q_FOREACH ( QgsAttributeFormInterface* iface, mInterfaces )
491  {
492  iface->initForm();
493  }
494  QApplication::restoreOverrideCursor();
495 }
496 
497 void QgsAttributeForm::cleanPython()
498 {
499  if ( !mPyFormVarName.isNull() )
500  {
501  QString expr = QString( "if locals().has_key('%1'): del %1\n" ).arg( mPyFormVarName );
502  QgsPythonRunner::run( expr );
503  }
504 }
505 
506 void QgsAttributeForm::initPython()
507 {
508  cleanPython();
509 
510  // Init Python
511  if ( !mLayer->editFormInit().isEmpty() )
512  {
513  QString module = mLayer->editFormInit();
514 
515  int pos = module.lastIndexOf( "." );
516  if ( pos >= 0 )
517  {
518  QgsPythonRunner::run( QString( "import %1" ).arg( module.left( pos ) ) );
519  }
520 
521  /* Reload the module if the DEBUGMODE switch has been set in the module.
522  If set to False you have to reload QGIS to reset it to True due to Python
523  module caching */
524  QString reload = QString( "if hasattr(%1,'DEBUGMODE') and %1.DEBUGMODE:"
525  " reload(%1)" ).arg( module.left( pos ) );
526 
527  QgsPythonRunner::run( reload );
528 
529  QgsPythonRunner::run( "import inspect" );
530  QString numArgs;
531  QgsPythonRunner::eval( QString( "len(inspect.getargspec(%1)[0])" ).arg( module ), numArgs );
532 
533  mPyFormVarName = QString( "_qgis_featureform_%1" ).arg( mFormNr );
534 
535  QString form = QString( "%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
536  .arg( mPyFormVarName )
537  .arg(( unsigned long ) this );
538 
539  QgsPythonRunner::run( form );
540 
541  QgsDebugMsg( QString( "running featureForm init: %1" ).arg( mPyFormVarName ) );
542 
543  // Legacy
544  if ( numArgs == "3" )
545  {
546  addInterface( new QgsAttributeFormLegacyInterface( module, mPyFormVarName, this ) );
547  }
548  else
549  {
550 #if 0
551  QString expr = QString( "%1(%2)" )
552  .arg( mLayer->editFormInit() )
553  .arg( mPyFormVarName );
554  QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr, "QgsAttributeFormInterface" );
555  if ( iface )
556  addInterface( iface );
557 #endif
558  }
559  }
560 }
561 
562 QWidget* QgsAttributeForm::createWidgetFromDef( const QgsAttributeEditorElement *widgetDef, QWidget *parent, QgsVectorLayer *vl, QgsAttributeEditorContext &context, QString &labelText, bool &labelOnTop )
563 {
564  QWidget *newWidget = 0;
565 
566  switch ( widgetDef->type() )
567  {
569  {
570  const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( widgetDef );
571  if ( !fieldDef )
572  break;
573 
574  int fldIdx = vl->fieldNameIndex( fieldDef->name() );
575  if ( fldIdx < vl->pendingFields().count() && fldIdx >= 0 )
576  {
577  const QString widgetType = mLayer->editorWidgetV2( fldIdx );
578  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( fldIdx );
579 
580  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, fldIdx, widgetConfig, 0, this, mContext );
581  newWidget = eww->widget();
582  addWidgetWrapper( eww );
583 
584  newWidget->setObjectName( mLayer->pendingFields()[ fldIdx ].name() );
585  }
586 
587  labelOnTop = mLayer->labelOnTop( fieldDef->idx() );
588  labelText = mLayer->attributeDisplayName( fieldDef->idx() );
589 
590  break;
591  }
592 
594  {
595  const QgsAttributeEditorRelation* relDef = dynamic_cast<const QgsAttributeEditorRelation*>( widgetDef );
596 
597  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, relDef->relation(), 0, this );
598  rww->setContext( context );
599  newWidget = rww->widget();
600  mWidgets.append( rww );
601  labelText = QString::null;
602  labelOnTop = true;
603  break;
604  }
605 
607  {
608  const QgsAttributeEditorContainer* container = dynamic_cast<const QgsAttributeEditorContainer*>( widgetDef );
609  if ( !container )
610  break;
611 
612  QWidget* myContainer;
613  if ( container->isGroupBox() )
614  {
615  QGroupBox* groupBox = new QGroupBox( parent );
616  groupBox->setTitle( container->name() );
617  myContainer = groupBox;
618  newWidget = myContainer;
619  }
620  else
621  {
622  QScrollArea *scrollArea = new QScrollArea( parent );
623 
624  myContainer = new QWidget( scrollArea );
625 
626  scrollArea->setWidget( myContainer );
627  scrollArea->setWidgetResizable( true );
628  scrollArea->setFrameShape( QFrame::NoFrame );
629 
630  newWidget = scrollArea;
631  }
632 
633  QGridLayout* gbLayout = new QGridLayout( myContainer );
634  myContainer->setLayout( gbLayout );
635 
636  int index = 0;
637 
638  QList<QgsAttributeEditorElement*> children = container->children();
639 
640  Q_FOREACH ( QgsAttributeEditorElement* childDef, children )
641  {
642  QString labelText;
643  bool labelOnTop;
644  QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, context, labelText, labelOnTop );
645 
646  if ( labelText.isNull() )
647  {
648  gbLayout->addWidget( editor, index, 0, 1, 2 );
649  }
650  else
651  {
652  QLabel* mypLabel = new QLabel( labelText );
653  if ( labelOnTop )
654  {
655  gbLayout->addWidget( mypLabel, index, 0, 1, 2 );
656  ++index;
657  gbLayout->addWidget( editor, index, 0, 1, 2 );
658  }
659  else
660  {
661  gbLayout->addWidget( mypLabel, index, 0 );
662  gbLayout->addWidget( editor, index, 1 );
663  }
664  }
665 
666  ++index;
667  }
668  gbLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ), index, 0 );
669 
670  labelText = QString::null;
671  labelOnTop = true;
672  break;
673  }
674 
675  default:
676  QgsDebugMsg( "Unknown attribute editor widget type encountered..." );
677  break;
678  }
679 
680  return newWidget;
681 }
682 
683 void QgsAttributeForm::addWidgetWrapper( QgsEditorWidgetWrapper* eww )
684 {
685  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
686  {
687  QgsEditorWidgetWrapper* meww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
688  if ( meww )
689  {
690  if ( meww->field() == eww->field() )
691  {
692  connect( meww, SIGNAL( valueChanged( QVariant ) ), eww, SLOT( setValue( QVariant ) ) );
693  connect( eww, SIGNAL( valueChanged( QVariant ) ), meww, SLOT( setValue( QVariant ) ) );
694  break;
695  }
696  }
697  }
698 
699  mWidgets.append( eww );
700 }
701 
702 void QgsAttributeForm::createWrappers()
703 {
704  QList<QWidget*> myWidgets = findChildren<QWidget*>();
705  const QList<QgsField> fields = mLayer->pendingFields().toList();
706 
707  Q_FOREACH ( QWidget* myWidget, myWidgets )
708  {
709  // Check the widget's properties for a relation definition
710  QVariant vRel = myWidget->property( "qgisRelation" );
711  if ( vRel.isValid() )
712  {
714  QgsRelation relation = relMgr->relation( vRel.toString() );
715  if ( relation.isValid() )
716  {
717  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, relation, myWidget, this );
719  rww->setContext( mContext );
720  rww->widget(); // Will initialize the widget
721  mWidgets.append( rww );
722  }
723  }
724  else
725  {
726  Q_FOREACH ( const QgsField& field, fields )
727  {
728  if ( field.name() == myWidget->objectName() )
729  {
730  const QString widgetType = mLayer->editorWidgetV2( field.name() );
731  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( field.name() );
732  int idx = mLayer->fieldNameIndex( field.name() );
733 
734  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, idx, widgetConfig, myWidget, this, mContext );
735  addWidgetWrapper( eww );
736  }
737  }
738  }
739  }
740 }
741 
742 void QgsAttributeForm::connectWrappers()
743 {
744  bool isFirstEww = true;
745 
746  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
747  {
748  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
749 
750  if ( eww )
751  {
752  if ( isFirstEww )
753  {
754  setFocusProxy( eww->widget() );
755  isFirstEww = false;
756  }
757 
758  connect( eww, SIGNAL( valueChanged( const QVariant& ) ), this, SLOT( onAttributeChanged( const QVariant& ) ) );
759  }
760  }
761 }
762 
763 
764 bool QgsAttributeForm::eventFilter( QObject* object, QEvent* e )
765 {
766  Q_UNUSED( object )
767 
768  if ( e->type() == QEvent::KeyPress )
769  {
770  QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>( e );
771  if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
772  {
773  // Re-emit to this form so it will be forwarded to parent
774  event( e );
775  return true;
776  }
777  }
778 
779  return false;
780 }