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