QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 
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() );
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  containerDef->setIsGroupBox( false ); // Toplevel widgets are tabs not groupboxes
390  QString dummy1;
391  bool dummy2;
392  tabPageLayout->addWidget( createWidgetFromDef( widgDef, tabPage, mLayer, mContext, dummy1, dummy2 ) );
393  }
394  else
395  {
396  QgsDebugMsg( "No support for fields in attribute editor on top level" );
397  }
398  }
399  formWidget = tabWidget;
400  }
401 
402  // Autogenerate Layout
403  // If there is still no layout loaded (defined as autogenerate or other methods failed)
404  if ( !formWidget )
405  {
406  formWidget = new QWidget( this );
407  QGridLayout* gridLayout = new QGridLayout( formWidget );
408  formWidget->setLayout( gridLayout );
409 
410  // put the form into a scroll area to nicely handle cases with lots of attributes
411 
412  QScrollArea* scrollArea = new QScrollArea( this );
413  scrollArea->setWidget( formWidget );
414  scrollArea->setWidgetResizable( true );
415  scrollArea->setFrameShape( QFrame::NoFrame );
416  scrollArea->setFrameShadow( QFrame::Plain );
417  scrollArea->setFocusProxy( this );
418  layout()->addWidget( scrollArea );
419 
420  int row = 0;
421  Q_FOREACH ( const QgsField& field, mLayer->pendingFields().toList() )
422  {
423  int idx = mLayer->fieldNameIndex( field.name() );
424  //show attribute alias if available
425  QString fieldName = mLayer->attributeDisplayName( idx );
426 
427  const QString widgetType = mLayer->editorWidgetV2( idx );
428 
429  if ( widgetType == "Hidden" )
430  continue;
431 
432  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( idx );
433  bool labelOnTop = mLayer->labelOnTop( idx );
434 
435  // This will also create the widget
436  QWidget *l = new QLabel( fieldName );
437  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, idx, widgetConfig, 0, this, mContext );
438  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 ) );
439 
440  if ( w )
441  w->setObjectName( field.name() );
442 
443  if ( eww )
444  addWidgetWrapper( eww );
445 
446  if ( labelOnTop )
447  {
448  gridLayout->addWidget( l, row++, 0, 1, 2 );
449  gridLayout->addWidget( w, row++, 0, 1, 2 );
450  }
451  else
452  {
453  gridLayout->addWidget( l, row, 0 );
454  gridLayout->addWidget( w, row++, 1 );
455  }
456  }
457 
458  Q_FOREACH ( const QgsRelation& rel, QgsProject::instance()->relationManager()->referencedRelations( mLayer ) )
459  {
460  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, rel, 0, this );
461  rww->setContext( mContext );
462  gridLayout->addWidget( rww->widget(), row++, 0, 1, 2 );
463  mWidgets.append( rww );
464  }
465  }
466 
467  if ( !mButtonBox )
468  {
469  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
470  mButtonBox->setObjectName( "buttonBox" );
471  layout()->addWidget( mButtonBox );
472  }
473 
474  mButtonBox->setVisible( buttonBoxVisible );
475 
476  connectWrappers();
477 
478  connect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
479  connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( resetValues() ) );
480 
481  connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( synchronizeEnabledState() ) );
482  connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( synchronizeEnabledState() ) );
483 
484  Q_FOREACH ( QgsAttributeFormInterface* iface, mInterfaces )
485  {
486  iface->initForm();
487  }
488  QApplication::restoreOverrideCursor();
489 }
490 
491 void QgsAttributeForm::cleanPython()
492 {
493  if ( !mPyFormVarName.isNull() )
494  {
495  QString expr = QString( "if locals().has_key('%1'): del %1\n" ).arg( mPyFormVarName );
496  QgsPythonRunner::run( expr );
497  }
498 }
499 
500 void QgsAttributeForm::initPython()
501 {
502  cleanPython();
503 
504  // Init Python
505  if ( !mLayer->editFormInit().isEmpty() )
506  {
507  QString module = mLayer->editFormInit();
508 
509  int pos = module.lastIndexOf( "." );
510  if ( pos >= 0 )
511  {
512  QgsPythonRunner::run( QString( "import %1" ).arg( module.left( pos ) ) );
513  }
514 
515  /* Reload the module if the DEBUGMODE switch has been set in the module.
516  If set to False you have to reload QGIS to reset it to True due to Python
517  module caching */
518  QString reload = QString( "if hasattr(%1,'DEBUGMODE') and %1.DEBUGMODE:"
519  " reload(%1)" ).arg( module.left( pos ) );
520 
521  QgsPythonRunner::run( reload );
522 
523  QgsPythonRunner::run( "import inspect" );
524  QString numArgs;
525  QgsPythonRunner::eval( QString( "len(inspect.getargspec(%1)[0])" ).arg( module ), numArgs );
526 
527  mPyFormVarName = QString( "_qgis_featureform_%1" ).arg( mFormNr );
528 
529  QString form = QString( "%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
530  .arg( mPyFormVarName )
531  .arg(( unsigned long ) this );
532 
533  QgsPythonRunner::run( form );
534 
535  QgsDebugMsg( QString( "running featureForm init: %1" ).arg( mPyFormVarName ) );
536 
537  // Legacy
538  if ( numArgs == "3" )
539  {
540  addInterface( new QgsAttributeFormLegacyInterface( module, mPyFormVarName, this ) );
541  }
542  else
543  {
544 #if 0
545  QString expr = QString( "%1(%2)" )
546  .arg( mLayer->editFormInit() )
547  .arg( mPyFormVarName );
548  QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr, "QgsAttributeFormInterface" );
549  if ( iface )
550  addInterface( iface );
551 #endif
552  }
553  }
554 }
555 
556 QWidget* QgsAttributeForm::createWidgetFromDef( const QgsAttributeEditorElement *widgetDef, QWidget *parent, QgsVectorLayer *vl, QgsAttributeEditorContext &context, QString &labelText, bool &labelOnTop )
557 {
558  QWidget *newWidget = 0;
559 
560  switch ( widgetDef->type() )
561  {
563  {
564  const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( widgetDef );
565  int fldIdx = fieldDef->idx();
566  if ( fldIdx < vl->pendingFields().count() && fldIdx >= 0 )
567  {
568  const QString widgetType = mLayer->editorWidgetV2( fldIdx );
569  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( fldIdx );
570 
571  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, fldIdx, widgetConfig, 0, this, mContext );
572  newWidget = eww->widget();
573  addWidgetWrapper( eww );
574 
575  newWidget->setObjectName( mLayer->pendingFields()[ fldIdx ].name() );
576  }
577 
578  labelOnTop = mLayer->labelOnTop( fieldDef->idx() );
579  labelText = mLayer->attributeDisplayName( fieldDef->idx() );
580 
581  break;
582  }
583 
585  {
586  const QgsAttributeEditorRelation* relDef = dynamic_cast<const QgsAttributeEditorRelation*>( widgetDef );
587 
588  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, relDef->relation(), 0, this );
589  rww->setContext( context );
590  newWidget = rww->widget();
591  mWidgets.append( rww );
592  labelText = QString::null;
593  labelOnTop = true;
594  break;
595  }
596 
598  {
599  const QgsAttributeEditorContainer* container = dynamic_cast<const QgsAttributeEditorContainer*>( widgetDef );
600  QWidget* myContainer;
601 
602  if ( container->isGroupBox() )
603  {
604  QGroupBox* groupBox = new QGroupBox( parent );
605  groupBox->setTitle( container->name() );
606  myContainer = groupBox;
607  newWidget = myContainer;
608  }
609  else
610  {
611  QScrollArea *scrollArea = new QScrollArea( parent );
612 
613  myContainer = new QWidget( scrollArea );
614 
615  scrollArea->setWidget( myContainer );
616  scrollArea->setWidgetResizable( true );
617  scrollArea->setFrameShape( QFrame::NoFrame );
618 
619  newWidget = scrollArea;
620  }
621 
622  QGridLayout* gbLayout = new QGridLayout( myContainer );
623  myContainer->setLayout( gbLayout );
624 
625  int index = 0;
626 
627  QList<QgsAttributeEditorElement*> children = container->children();
628 
629  Q_FOREACH ( QgsAttributeEditorElement* childDef, children )
630  {
631  QString labelText;
632  bool labelOnTop;
633  QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, context, labelText, labelOnTop );
634 
635  if ( labelText.isNull() )
636  {
637  gbLayout->addWidget( editor, index, 0, 1, 2 );
638  }
639  else
640  {
641  QLabel* mypLabel = new QLabel( labelText );
642  if ( labelOnTop )
643  {
644  gbLayout->addWidget( mypLabel, index, 0, 1, 2 );
645  ++index;
646  gbLayout->addWidget( editor, index, 0, 1, 2 );
647  }
648  else
649  {
650  gbLayout->addWidget( mypLabel, index, 0 );
651  gbLayout->addWidget( editor, index, 1 );
652  }
653  }
654 
655  ++index;
656  }
657  gbLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ), index, 0 );
658 
659  labelText = QString::null;
660  labelOnTop = true;
661  break;
662  }
663 
664  default:
665  QgsDebugMsg( "Unknown attribute editor widget type encountered..." );
666  break;
667  }
668 
669  return newWidget;
670 }
671 
672 void QgsAttributeForm::addWidgetWrapper( QgsEditorWidgetWrapper* eww )
673 {
674  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
675  {
676  QgsEditorWidgetWrapper* meww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
677  if ( meww )
678  {
679  if ( meww->field() == eww->field() )
680  {
681  connect( meww, SIGNAL( valueChanged( QVariant ) ), eww, SLOT( setValue( QVariant ) ) );
682  connect( eww, SIGNAL( valueChanged( QVariant ) ), meww, SLOT( setValue( QVariant ) ) );
683  break;
684  }
685  }
686  }
687 
688  mWidgets.append( eww );
689 }
690 
691 void QgsAttributeForm::createWrappers()
692 {
693  QList<QWidget*> myWidgets = findChildren<QWidget*>();
694  const QList<QgsField> fields = mLayer->pendingFields().toList();
695 
696  Q_FOREACH ( QWidget* myWidget, myWidgets )
697  {
698  // Check the widget's properties for a relation definition
699  QVariant vRel = myWidget->property( "qgisRelation" );
700  if ( vRel.isValid() )
701  {
703  QgsRelation relation = relMgr->relation( vRel.toString() );
704  if ( relation.isValid() )
705  {
706  QgsRelationWidgetWrapper* rww = new QgsRelationWidgetWrapper( mLayer, relation, myWidget, this );
708  rww->setContext( mContext );
709  rww->widget(); // Will initialize the widget
710  mWidgets.append( rww );
711  }
712  }
713  else
714  {
715  Q_FOREACH ( const QgsField& field, fields )
716  {
717  if ( field.name() == myWidget->objectName() )
718  {
719  const QString widgetType = mLayer->editorWidgetV2( field.name() );
720  const QgsEditorWidgetConfig widgetConfig = mLayer->editorWidgetV2Config( field.name() );
721  int idx = mLayer->fieldNameIndex( field.name() );
722 
723  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, mLayer, idx, widgetConfig, myWidget, this, mContext );
724  addWidgetWrapper( eww );
725  }
726  }
727  }
728  }
729 }
730 
731 void QgsAttributeForm::connectWrappers()
732 {
733  bool isFirstEww = true;
734 
735  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
736  {
737  QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
738 
739  if ( eww )
740  {
741  if ( isFirstEww )
742  {
743  setFocusProxy( eww->widget() );
744  isFirstEww = false;
745  }
746 
747  connect( eww, SIGNAL( valueChanged( const QVariant& ) ), this, SLOT( onAttributeChanged( const QVariant& ) ) );
748  }
749  }
750 }
751 
752 
753 bool QgsAttributeForm::eventFilter( QObject* object, QEvent* e )
754 {
755  Q_UNUSED( object )
756 
757  if ( e->type() == QEvent::KeyPress )
758  {
759  QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>( e );
760  if ( keyEvent->key() == Qt::Key_Escape )
761  {
762  // Re-emit to this form so it will be forwarded to parent
763  event( e );
764  return true;
765  }
766  }
767 
768  return false;
769 }
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:200
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:59
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.
#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.
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's value.
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
QgsField field()
Access the field.
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 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.
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.
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.
QgsAttributeForm(QgsVectorLayer *vl, const QgsFeature &feature=QgsFeature(), QgsAttributeEditorContext context=QgsAttributeEditorContext(), QWidget *parent=0)
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...
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
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...
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 setContext(const QgsAttributeEditorContext context)
Set the context in which this widget is shown.
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.
int fieldIdx()
Access the field index.
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
QString editFormInit()
get python function for edit form initialization
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
Manages an editor widget Widget and wrapper share the same parent.
bool isNull(const QVariant &v)
#define tr(sourceText)